summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/alpha/include/console.h224
-rw-r--r--sys/alpha/include/pc/display.h45
-rw-r--r--sys/alpha/include/pc/msdos.h65
-rw-r--r--sys/amd64/Makefile25
-rw-r--r--sys/amd64/amd64/autoconf.c209
-rw-r--r--sys/amd64/amd64/cpu_switch.S458
-rw-r--r--sys/amd64/amd64/db_disasm.c1375
-rw-r--r--sys/amd64/amd64/db_interface.c240
-rw-r--r--sys/amd64/amd64/db_trace.c339
-rw-r--r--sys/amd64/amd64/exception.S275
-rw-r--r--sys/amd64/amd64/exception.s275
-rw-r--r--sys/amd64/amd64/fpu.c552
-rw-r--r--sys/amd64/amd64/genassym.c194
-rw-r--r--sys/amd64/amd64/locore.S552
-rw-r--r--sys/amd64/amd64/locore.s552
-rw-r--r--sys/amd64/amd64/machdep.c1449
-rw-r--r--sys/amd64/amd64/mem.c260
-rw-r--r--sys/amd64/amd64/pmap.c1938
-rw-r--r--sys/amd64/amd64/support.S1153
-rw-r--r--sys/amd64/amd64/support.s1153
-rw-r--r--sys/amd64/amd64/swtch.s458
-rw-r--r--sys/amd64/amd64/sys_machdep.c328
-rw-r--r--sys/amd64/amd64/trap.c728
-rw-r--r--sys/amd64/amd64/tsc.c430
-rw-r--r--sys/amd64/amd64/vm_machdep.c1151
-rw-r--r--sys/amd64/include/asmacros.h49
-rw-r--r--sys/amd64/include/cpu.h110
-rw-r--r--sys/amd64/include/cpufunc.h240
-rw-r--r--sys/amd64/include/cputypes.h53
-rw-r--r--sys/amd64/include/db_machdep.h120
-rw-r--r--sys/amd64/include/float.h72
-rw-r--r--sys/amd64/include/floatingpoint.h109
-rw-r--r--sys/amd64/include/fpu.h141
-rw-r--r--sys/amd64/include/frame.h114
-rw-r--r--sys/amd64/include/npx.h141
-rw-r--r--sys/amd64/include/pc/display.h45
-rw-r--r--sys/amd64/include/pcb.h86
-rw-r--r--sys/amd64/include/pmap.h285
-rw-r--r--sys/amd64/include/proc.h52
-rw-r--r--sys/amd64/include/psl.h65
-rw-r--r--sys/amd64/include/reg.h96
-rw-r--r--sys/amd64/include/segments.h235
-rw-r--r--sys/amd64/include/specialreg.h64
-rw-r--r--sys/amd64/include/sysarch.h24
-rw-r--r--sys/amd64/include/trap.h101
-rw-r--r--sys/amd64/include/tss.h82
-rw-r--r--sys/amd64/include/vmparam.h277
-rw-r--r--sys/amd64/isa/clock.c430
-rw-r--r--sys/amd64/isa/icu.h97
-rw-r--r--sys/amd64/isa/isa.c670
-rw-r--r--sys/amd64/isa/isa.h181
-rw-r--r--sys/amd64/isa/npx.c552
-rw-r--r--sys/amd64/isa/timerreg.h93
-rw-r--r--sys/amd64/isa/vector.S360
-rw-r--r--sys/amd64/isa/vector.s360
-rw-r--r--sys/conf/Makefile.i386179
-rw-r--r--sys/conf/Makefile.powerpc179
-rw-r--r--sys/conf/NOTES197
-rw-r--r--sys/conf/files.i386116
-rw-r--r--sys/ddb/db_access.c103
-rw-r--r--sys/ddb/db_access.h47
-rw-r--r--sys/ddb/db_aout.c407
-rw-r--r--sys/ddb/db_break.c353
-rw-r--r--sys/ddb/db_break.h64
-rw-r--r--sys/ddb/db_command.c483
-rw-r--r--sys/ddb/db_command.h57
-rw-r--r--sys/ddb/db_examine.c340
-rw-r--r--sys/ddb/db_expr.c226
-rw-r--r--sys/ddb/db_input.c256
-rw-r--r--sys/ddb/db_lex.c279
-rw-r--r--sys/ddb/db_lex.h77
-rw-r--r--sys/ddb/db_output.c370
-rw-r--r--sys/ddb/db_output.h44
-rw-r--r--sys/ddb/db_print.c70
-rw-r--r--sys/ddb/db_run.c391
-rw-r--r--sys/ddb/db_sym.c333
-rw-r--r--sys/ddb/db_sym.h102
-rw-r--r--sys/ddb/db_trap.c79
-rw-r--r--sys/ddb/db_variables.c165
-rw-r--r--sys/ddb/db_variables.h57
-rw-r--r--sys/ddb/db_watch.c270
-rw-r--r--sys/ddb/db_watch.h60
-rw-r--r--sys/ddb/db_write_cmd.c99
-rw-r--r--sys/ddb/ddb.h109
-rw-r--r--sys/dev/ed/if_ed.c2488
-rw-r--r--sys/dev/ed/if_edreg.h962
-rw-r--r--sys/dev/ep/if_ep.c994
-rw-r--r--sys/dev/ep/if_epreg.h295
-rw-r--r--sys/dev/fdc/fdc.c1255
-rw-r--r--sys/dev/fdc/fdcreg.h65
-rw-r--r--sys/dev/ic/i8237.h11
-rw-r--r--sys/dev/ic/i82586.h325
-rw-r--r--sys/dev/ic/nec765.h72
-rw-r--r--sys/dev/ic/ns16550.h51
-rw-r--r--sys/dev/ie/if_ie.c1802
-rw-r--r--sys/dev/ie/if_iereg.h24
-rw-r--r--sys/dev/kbd/kbdtables.h859
-rw-r--r--sys/dev/mcd/mcd.c1335
-rw-r--r--sys/dev/mcd/mcdreg.h159
-rw-r--r--sys/dev/mse/mse.c503
-rw-r--r--sys/dev/ppbus/lptio.h24
-rw-r--r--sys/dev/sio/sio.c1919
-rw-r--r--sys/dev/sio/sioreg.h114
-rw-r--r--sys/dev/speaker/speaker.h30
-rw-r--r--sys/dev/speaker/spkr.c541
-rw-r--r--sys/dev/syscons/syscons.c2659
-rw-r--r--sys/gnu/i386/fpemul/Changelog36
-rw-r--r--sys/gnu/i386/fpemul/README267
-rw-r--r--sys/gnu/i386/fpemul/bde_trapinfo.mail35
-rw-r--r--sys/gnu/i386/fpemul/control_w.h85
-rw-r--r--sys/gnu/i386/fpemul/div_small.s91
-rw-r--r--sys/gnu/i386/fpemul/errors.c602
-rw-r--r--sys/gnu/i386/fpemul/exception.h92
-rw-r--r--sys/gnu/i386/fpemul/fpu_arith.c225
-rw-r--r--sys/gnu/i386/fpemul/fpu_asm.h72
-rw-r--r--sys/gnu/i386/fpemul/fpu_aux.c223
-rw-r--r--sys/gnu/i386/fpemul/fpu_emu.h178
-rw-r--r--sys/gnu/i386/fpemul/fpu_entry.c503
-rw-r--r--sys/gnu/i386/fpemul/fpu_etc.c165
-rw-r--r--sys/gnu/i386/fpemul/fpu_proto.h115
-rw-r--r--sys/gnu/i386/fpemul/fpu_system.h87
-rw-r--r--sys/gnu/i386/fpemul/fpu_trig.c1357
-rw-r--r--sys/gnu/i386/fpemul/get_address.c193
-rw-r--r--sys/gnu/i386/fpemul/load_store.c259
-rw-r--r--sys/gnu/i386/fpemul/math_emu.h47
-rw-r--r--sys/gnu/i386/fpemul/poly_2xm1.c131
-rw-r--r--sys/gnu/i386/fpemul/poly_atan.c242
-rw-r--r--sys/gnu/i386/fpemul/poly_div.s134
-rw-r--r--sys/gnu/i386/fpemul/poly_l2.c308
-rw-r--r--sys/gnu/i386/fpemul/poly_mul64.s114
-rw-r--r--sys/gnu/i386/fpemul/poly_sin.c182
-rw-r--r--sys/gnu/i386/fpemul/poly_tan.c219
-rw-r--r--sys/gnu/i386/fpemul/polynomial.s182
-rw-r--r--sys/gnu/i386/fpemul/reg_add_sub.c293
-rw-r--r--sys/gnu/i386/fpemul/reg_compare.c374
-rw-r--r--sys/gnu/i386/fpemul/reg_constant.c165
-rw-r--r--sys/gnu/i386/fpemul/reg_constant.h72
-rw-r--r--sys/gnu/i386/fpemul/reg_div.s285
-rw-r--r--sys/gnu/i386/fpemul/reg_ld_str.c1377
-rw-r--r--sys/gnu/i386/fpemul/reg_mul.c152
-rw-r--r--sys/gnu/i386/fpemul/reg_norm.s172
-rw-r--r--sys/gnu/i386/fpemul/reg_round.s643
-rw-r--r--sys/gnu/i386/fpemul/reg_u_add.s234
-rw-r--r--sys/gnu/i386/fpemul/reg_u_div.s496
-rw-r--r--sys/gnu/i386/fpemul/reg_u_mul.s189
-rw-r--r--sys/gnu/i386/fpemul/reg_u_sub.s351
-rw-r--r--sys/gnu/i386/fpemul/status_w.h96
-rw-r--r--sys/gnu/i386/fpemul/version.h51
-rw-r--r--sys/gnu/i386/fpemul/wm_shrx.s251
-rw-r--r--sys/gnu/i386/fpemul/wm_sqrt.s486
-rw-r--r--sys/i386/Makefile25
-rw-r--r--sys/i386/boot/Makefile103
-rw-r--r--sys/i386/boot/README.386BSD151
-rw-r--r--sys/i386/boot/README.MACH210
-rw-r--r--sys/i386/boot/asm.S260
-rw-r--r--sys/i386/boot/asm.h144
-rw-r--r--sys/i386/boot/asm.s270
-rw-r--r--sys/i386/boot/bios.S329
-rw-r--r--sys/i386/boot/bios.s326
-rw-r--r--sys/i386/boot/biosboot/Makefile103
-rw-r--r--sys/i386/boot/biosboot/README.386BSD151
-rw-r--r--sys/i386/boot/biosboot/README.MACH210
-rw-r--r--sys/i386/boot/biosboot/asm.S260
-rw-r--r--sys/i386/boot/biosboot/asm.h144
-rw-r--r--sys/i386/boot/biosboot/bios.S329
-rw-r--r--sys/i386/boot/biosboot/boot.c310
-rw-r--r--sys/i386/boot/biosboot/boot.h40
-rw-r--r--sys/i386/boot/biosboot/boot2.S169
-rw-r--r--sys/i386/boot/biosboot/disk.c281
-rw-r--r--sys/i386/boot/biosboot/io.c202
-rw-r--r--sys/i386/boot/biosboot/start.S291
-rw-r--r--sys/i386/boot/biosboot/sys.c232
-rw-r--r--sys/i386/boot/biosboot/table.c125
-rw-r--r--sys/i386/boot/boot.c310
-rw-r--r--sys/i386/boot/boot.h40
-rw-r--r--sys/i386/boot/boot.sed3
-rw-r--r--sys/i386/boot/boot2.S169
-rw-r--r--sys/i386/boot/boot2.s73
-rw-r--r--sys/i386/boot/disk.c281
-rw-r--r--sys/i386/boot/io.c202
-rw-r--r--sys/i386/boot/rmaouthdr6
-rw-r--r--sys/i386/boot/start.S291
-rw-r--r--sys/i386/boot/start.s323
-rw-r--r--sys/i386/boot/sys.c232
-rw-r--r--sys/i386/boot/table.c125
-rw-r--r--sys/i386/conf/GENERICAH90
-rw-r--r--sys/i386/conf/GENERICBT90
-rw-r--r--sys/i386/conf/LINT197
-rw-r--r--sys/i386/conf/Makefile.i386179
-rw-r--r--sys/i386/conf/NOTES197
-rw-r--r--sys/i386/conf/SYSCONS87
-rw-r--r--sys/i386/conf/devices.i38613
-rw-r--r--sys/i386/conf/files.i386116
-rw-r--r--sys/i386/eisa/aha1742.c1244
-rw-r--r--sys/i386/i386/autoconf.c209
-rw-r--r--sys/i386/i386/conf.c636
-rw-r--r--sys/i386/i386/cons.c244
-rw-r--r--sys/i386/i386/cons.h86
-rw-r--r--sys/i386/i386/db_disasm.c1375
-rw-r--r--sys/i386/i386/db_interface.c240
-rw-r--r--sys/i386/i386/db_trace.c339
-rw-r--r--sys/i386/i386/dkbad.c69
-rw-r--r--sys/i386/i386/exception.s275
-rw-r--r--sys/i386/i386/genassym.c194
-rw-r--r--sys/i386/i386/in_cksum.c237
-rw-r--r--sys/i386/i386/locore.s552
-rw-r--r--sys/i386/i386/machdep.c1449
-rw-r--r--sys/i386/i386/math_emu.h156
-rw-r--r--sys/i386/i386/math_emulate.c1475
-rw-r--r--sys/i386/i386/mem.c260
-rw-r--r--sys/i386/i386/microtime.s137
-rw-r--r--sys/i386/i386/ns_cksum.c207
-rw-r--r--sys/i386/i386/pmap.c1938
-rw-r--r--sys/i386/i386/support.s1153
-rw-r--r--sys/i386/i386/swapgeneric.c169
-rw-r--r--sys/i386/i386/swtch.s458
-rw-r--r--sys/i386/i386/symbols.raw84
-rw-r--r--sys/i386/i386/sys_machdep.c328
-rw-r--r--sys/i386/i386/trap.c728
-rw-r--r--sys/i386/i386/tsc.c430
-rw-r--r--sys/i386/i386/vm_machdep.c1151
-rw-r--r--sys/i386/include/_limits.h69
-rw-r--r--sys/i386/include/ansi.h75
-rw-r--r--sys/i386/include/asmacros.h49
-rw-r--r--sys/i386/include/cons.h6
-rw-r--r--sys/i386/include/console.h224
-rw-r--r--sys/i386/include/cpu.h110
-rw-r--r--sys/i386/include/cpufunc.h240
-rw-r--r--sys/i386/include/cputypes.h53
-rw-r--r--sys/i386/include/db_machdep.h120
-rw-r--r--sys/i386/include/dkio.h53
-rw-r--r--sys/i386/include/eflags.h54
-rw-r--r--sys/i386/include/endian.h120
-rw-r--r--sys/i386/include/float.h72
-rw-r--r--sys/i386/include/floatingpoint.h109
-rw-r--r--sys/i386/include/frame.h114
-rw-r--r--sys/i386/include/ioctl_fd.h98
-rw-r--r--sys/i386/include/ioctl_pc.h797
-rw-r--r--sys/i386/include/ipl.h7
-rw-r--r--sys/i386/include/limits.h69
-rw-r--r--sys/i386/include/lpt.h24
-rw-r--r--sys/i386/include/mtpr.h4
-rw-r--r--sys/i386/include/npx.h141
-rw-r--r--sys/i386/include/param.h167
-rw-r--r--sys/i386/include/pc/display.h45
-rw-r--r--sys/i386/include/pc/msdos.h65
-rw-r--r--sys/i386/include/pcaudioio.h75
-rw-r--r--sys/i386/include/pcb.h86
-rw-r--r--sys/i386/include/pio.h48
-rw-r--r--sys/i386/include/pmap.h285
-rw-r--r--sys/i386/include/proc.h52
-rw-r--r--sys/i386/include/psl.h65
-rw-r--r--sys/i386/include/pte.h125
-rw-r--r--sys/i386/include/reg.h96
-rw-r--r--sys/i386/include/segments.h235
-rw-r--r--sys/i386/include/soundcard.h763
-rw-r--r--sys/i386/include/speaker.h30
-rw-r--r--sys/i386/include/specialreg.h64
-rw-r--r--sys/i386/include/spl.h104
-rw-r--r--sys/i386/include/stdarg.h58
-rw-r--r--sys/i386/include/sysarch.h24
-rw-r--r--sys/i386/include/trap.h101
-rw-r--r--sys/i386/include/tss.h82
-rw-r--r--sys/i386/include/types.h51
-rw-r--r--sys/i386/include/ultrasound.h121
-rw-r--r--sys/i386/include/vmparam.h277
-rw-r--r--sys/i386/isa/aha1542.c1475
-rw-r--r--sys/i386/isa/aha1742.c1244
-rw-r--r--sys/i386/isa/bt742a.c1529
-rw-r--r--sys/i386/isa/clock.c430
-rw-r--r--sys/i386/isa/fd.c1255
-rw-r--r--sys/i386/isa/fdc.h75
-rw-r--r--sys/i386/isa/fdreg.h65
-rw-r--r--sys/i386/isa/ft.c2129
-rw-r--r--sys/i386/isa/ftreg.h81
-rw-r--r--sys/i386/isa/ic/i8042.h27
-rw-r--r--sys/i386/isa/ic/i8237.h11
-rw-r--r--sys/i386/isa/ic/i82586.h325
-rw-r--r--sys/i386/isa/ic/nec765.h72
-rw-r--r--sys/i386/isa/ic/ns16450.h50
-rw-r--r--sys/i386/isa/ic/ns16550.h51
-rw-r--r--sys/i386/isa/icu.h97
-rw-r--r--sys/i386/isa/icu.s328
-rw-r--r--sys/i386/isa/if_ed.c2488
-rw-r--r--sys/i386/isa/if_edreg.h962
-rw-r--r--sys/i386/isa/if_el.c800
-rw-r--r--sys/i386/isa/if_elreg.h76
-rw-r--r--sys/i386/isa/if_ep.c994
-rw-r--r--sys/i386/isa/if_epreg.h295
-rw-r--r--sys/i386/isa/if_ie.c1802
-rw-r--r--sys/i386/isa/if_iereg.h24
-rw-r--r--sys/i386/isa/if_is.c1148
-rw-r--r--sys/i386/isa/if_isreg.h129
-rw-r--r--sys/i386/isa/isa.c670
-rw-r--r--sys/i386/isa/isa.h181
-rw-r--r--sys/i386/isa/isa_device.h82
-rw-r--r--sys/i386/isa/iso8859.font1243
-rw-r--r--sys/i386/isa/kbd.h56
-rw-r--r--sys/i386/isa/kbdtables.h859
-rw-r--r--sys/i386/isa/lpt.c653
-rw-r--r--sys/i386/isa/lptreg.h33
-rw-r--r--sys/i386/isa/mcd.c1335
-rw-r--r--sys/i386/isa/mcdreg.h159
-rw-r--r--sys/i386/isa/mse.c503
-rw-r--r--sys/i386/isa/npx.c552
-rw-r--r--sys/i386/isa/pcaudio.c403
-rw-r--r--sys/i386/isa/rtc.h91
-rw-r--r--sys/i386/isa/sio.c1919
-rw-r--r--sys/i386/isa/sioreg.h114
-rw-r--r--sys/i386/isa/sound/CHANGELOG75
-rw-r--r--sys/i386/isa/sound/COPYING25
-rw-r--r--sys/i386/isa/sound/HOWTO_MIDI51
-rw-r--r--sys/i386/isa/sound/README17
-rw-r--r--sys/i386/isa/sound/RELNOTES38
-rw-r--r--sys/i386/isa/sound/RELNOTES.Linux255
-rw-r--r--sys/i386/isa/sound/adlib_card.c51
-rw-r--r--sys/i386/isa/sound/audio.c356
-rw-r--r--sys/i386/isa/sound/dev_table.c217
-rw-r--r--sys/i386/isa/sound/dev_table.h273
-rw-r--r--sys/i386/isa/sound/dmabuf.c902
-rw-r--r--sys/i386/isa/sound/finetune.h49
-rw-r--r--sys/i386/isa/sound/gus_card.c142
-rw-r--r--sys/i386/isa/sound/gus_hw.h50
-rw-r--r--sys/i386/isa/sound/gus_linearvol.h18
-rw-r--r--sys/i386/isa/sound/gus_midi.c283
-rw-r--r--sys/i386/isa/sound/gus_vol.c147
-rw-r--r--sys/i386/isa/sound/gus_wave.c3575
-rw-r--r--sys/i386/isa/sound/gustest/Makefile16
-rw-r--r--sys/i386/isa/sound/gustest/Readme67
-rw-r--r--sys/i386/isa/sound/gustest/gmidi.h131
-rw-r--r--sys/i386/isa/sound/gustest/gmod.c1588
-rw-r--r--sys/i386/isa/sound/gustest/gpatinfo.c175
-rw-r--r--sys/i386/isa/sound/gustest/gusload.c349
-rw-r--r--sys/i386/isa/sound/gustest/midithru.c325
-rw-r--r--sys/i386/isa/sound/gustest/pmtest.c409
-rw-r--r--sys/i386/isa/sound/ics2101.c265
-rw-r--r--sys/i386/isa/sound/local.h15
-rw-r--r--sys/i386/isa/sound/midi.c204
-rw-r--r--sys/i386/isa/sound/midibuf.c123
-rw-r--r--sys/i386/isa/sound/mpu401.c282
-rw-r--r--sys/i386/isa/sound/opl3.c960
-rw-r--r--sys/i386/isa/sound/opl3.h260
-rw-r--r--sys/i386/isa/sound/os.h319
-rw-r--r--sys/i386/isa/sound/pas.h250
-rw-r--r--sys/i386/isa/sound/pas2_card.c383
-rw-r--r--sys/i386/isa/sound/pas2_midi.c295
-rw-r--r--sys/i386/isa/sound/pas2_mixer.c492
-rw-r--r--sys/i386/isa/sound/pas2_pcm.c429
-rw-r--r--sys/i386/isa/sound/patmgr.c262
-rw-r--r--sys/i386/isa/sound/pro_midi.c187
-rw-r--r--sys/i386/isa/sound/sb.h28
-rw-r--r--sys/i386/isa/sound/sb16_dsp.c627
-rw-r--r--sys/i386/isa/sound/sb16_midi.c287
-rw-r--r--sys/i386/isa/sound/sb_card.c52
-rw-r--r--sys/i386/isa/sound/sb_dsp.c785
-rw-r--r--sys/i386/isa/sound/sb_midi.c224
-rw-r--r--sys/i386/isa/sound/sb_mixer.c422
-rw-r--r--sys/i386/isa/sound/sb_mixer.h212
-rw-r--r--sys/i386/isa/sound/sequencer.c1167
-rw-r--r--sys/i386/isa/sound/sound_calls.h208
-rw-r--r--sys/i386/isa/sound/sound_config.h241
-rw-r--r--sys/i386/isa/sound/sound_switch.c445
-rw-r--r--sys/i386/isa/sound/soundcard.c394
-rw-r--r--sys/i386/isa/sound/tuning.h29
-rw-r--r--sys/i386/isa/sound/ulaw.h69
-rw-r--r--sys/i386/isa/spkr.c541
-rw-r--r--sys/i386/isa/syscons.c2659
-rw-r--r--sys/i386/isa/timerreg.h93
-rw-r--r--sys/i386/isa/ultra14f.c1151
-rw-r--r--sys/i386/isa/vector.s360
-rw-r--r--sys/i386/isa/wd.c1823
-rw-r--r--sys/i386/isa/wdreg.h144
-rw-r--r--sys/i386/isa/wt.c902
-rw-r--r--sys/i386/isa/wtreg.h125
-rw-r--r--sys/isa/atrtc.c430
-rw-r--r--sys/isa/fd.c1255
-rw-r--r--sys/isa/fdc.h75
-rw-r--r--sys/isa/fdreg.h65
-rw-r--r--sys/isa/ic/nec765.h72
-rw-r--r--sys/isa/ic/ns16550.h51
-rw-r--r--sys/isa/kbdtables.h859
-rw-r--r--sys/isa/rtc.h91
-rw-r--r--sys/isa/sio.c1919
-rw-r--r--sys/isa/sioreg.h114
-rw-r--r--sys/isa/syscons.c2659
-rw-r--r--sys/isa/timerreg.h93
-rw-r--r--sys/kern/imgact_aout.c189
-rw-r--r--sys/kern/imgact_shell.c144
-rw-r--r--sys/kern/subr_rlist.c290
-rw-r--r--sys/kern/subr_trap.c728
-rw-r--r--sys/kern/tty_cons.c244
-rw-r--r--sys/powerpc/include/_limits.h69
-rw-r--r--sys/powerpc/include/limits.h69
-rw-r--r--sys/scsi/README196
-rw-r--r--sys/scsi/cd.c1317
-rw-r--r--sys/scsi/ch.c487
-rw-r--r--sys/scsi/scsi_all.h340
-rw-r--r--sys/scsi/scsi_base.c901
-rw-r--r--sys/scsi/scsi_cd.h229
-rw-r--r--sys/scsi/scsi_changer.h98
-rw-r--r--sys/scsi/scsi_debug.h53
-rw-r--r--sys/scsi/scsi_disk.h216
-rw-r--r--sys/scsi/scsi_generic.h63
-rw-r--r--sys/scsi/scsi_ioctl.c338
-rw-r--r--sys/scsi/scsi_tape.h204
-rw-r--r--sys/scsi/scsiconf.c699
-rw-r--r--sys/scsi/scsiconf.h249
-rw-r--r--sys/scsi/sd.c1055
-rw-r--r--sys/scsi/st.c1936
-rw-r--r--sys/scsi/su.c4
-rw-r--r--sys/scsi/uk.c158
-rw-r--r--sys/sys/bitstring.h143
-rw-r--r--sys/sys/cdio.h170
-rw-r--r--sys/sys/chio.h92
-rw-r--r--sys/sys/cons.h86
-rw-r--r--sys/sys/fdcio.h98
-rw-r--r--sys/sys/imgact.h71
-rw-r--r--sys/sys/link_aout.h289
-rw-r--r--sys/sys/link_elf.h289
-rw-r--r--sys/sys/nlist_aout.h85
-rw-r--r--sys/sys/rlist.h41
-rw-r--r--sys/sys/scsiio.h63
-rw-r--r--sys/sys/soundcard.h763
423 files changed, 156963 insertions, 0 deletions
diff --git a/sys/alpha/include/console.h b/sys/alpha/include/console.h
new file mode 100644
index 0000000..e663dea
--- /dev/null
+++ b/sys/alpha/include/console.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 1992, 1993, 1994 Søren Schmidt
+ *
+ * This program is free software; you may redistribute it and/or
+ * modify it, provided that it retain the above copyright notice
+ * and the following disclaimer.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Søren Schmidt Email: sos@login.dkuug.dk
+ * Tritonvej 36 UUCP: ...uunet!dkuug!login!sos
+ * DK9210 Aalborg SO Phone: +45 9814 8076
+ *
+ * from:@(#)console.h 1.1 940105
+ * $Id: console.h,v 1.7 1994/02/04 10:35:29 chmr Exp $
+ */
+
+#ifndef _CONSOLE_H_
+#define _CONSOLE_H_
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#define KDGKBMODE _IOR('K', 6, int)
+#define KDSKBMODE _IO('K', 7)
+#define KDMKTONE _IO('K', 8)
+#define KDGETMODE _IOR('K', 9, int)
+#define KDSETMODE _IO('K', 10)
+#define KDSBORDER _IO('K', 13)
+#define KDGKBSTATE _IOR('K', 19, int)
+#define KDSKBSTATE _IO('K', 20)
+#define KDENABIO _IO('K', 60)
+#define KDDISABIO _IO('K', 61)
+#define KIOCSOUND _IO('K', 63)
+#define KDGKBTYPE _IOR('K', 64, int)
+#define KDGETLED _IOR('K', 65, int)
+#define KDSETLED _IO('K', 66)
+#define KDSETRAD _IO('K', 67)
+
+#define GETFKEY _IOWR('k', 0, fkeyarg_t)
+#define SETFKEY _IOWR('k', 1, fkeyarg_t)
+#define GIO_SCRNMAP _IOR('k', 2, scrmap_t)
+#define PIO_SCRNMAP _IOW('k', 3, scrmap_t)
+#define GIO_KEYMAP _IOR('k', 6, keymap_t)
+#define PIO_KEYMAP _IOW('k', 7, keymap_t)
+
+#define CONS_BLANKTIME _IOW('c', 4, long)
+#define CONS_SSAVER _IOW('c', 5, ssaver_t)
+#define CONS_GSAVER _IOWR('c', 6, ssaver_t)
+#define PIO_FONT8x8 _IOW('c', 64, fnt8_t)
+#define GIO_FONT8x8 _IOR('c', 65, fnt8_t)
+#define PIO_FONT8x14 _IOW('c', 66, fnt14_t)
+#define GIO_FONT8x14 _IOR('c', 67, fnt14_t)
+#define PIO_FONT8x16 _IOW('c', 68, fnt16_t)
+#define GIO_FONT8x16 _IOR('c', 69, fnt16_t)
+#define CONS_GETINFO _IOWR('c', 73, vid_info_t)
+#define CONS_GETVERS _IOR('c', 74, long)
+#define CONS_80x25TEXT _IO('c', 102)
+#define CONS_80x50TEXT _IO('c', 103)
+
+#define VT_OPENQRY _IOR('v', 1, int)
+#define VT_SETMODE _IOW('v', 2, vtmode_t)
+#define VT_GETMODE _IOR('v', 3, vtmode_t)
+#define VT_RELDISP _IO('v', 4)
+#define VT_ACTIVATE _IO('v', 5)
+#define VT_WAITACTIVE _IO('v', 6)
+#define VT_GETACTIVE _IOR('v', 7, int)
+
+#define VT_FALSE 0
+#define VT_TRUE 1
+#define VT_ACKACQ 2
+
+#define VT_AUTO 0 /* switching is automatic */
+#define VT_PROCESS 1 /* switching controlled by prog */
+
+/* compatibility to old pccons & X386 */
+#define CONSOLE_X_MODE_ON _IO('t', 121)
+#define CONSOLE_X_MODE_OFF _IO('t', 122)
+#define CONSOLE_X_BELL _IOW('t',123,int[2])
+
+struct vt_mode {
+ char mode;
+ char waitv; /* not implemented yet SOS */
+ short relsig;
+ short acqsig;
+ short frsig; /* not implemented yet SOS */
+};
+
+
+#define KD_MONO 1 /* monochrome adapter */
+#define KD_HERCULES 2 /* hercules adapter */
+#define KD_CGA 3 /* color graphics adapter */
+#define KD_EGA 4 /* enhanced graphics adapter */
+#define KD_VGA 5 /* video graohics adapter */
+
+#define KD_TEXT 0 /* set text mode restore fonts */
+#define KD_TEXT0 0 /* ditto */
+#define KD_TEXT1 2 /* set text mode !restore fonts */
+#define KD_GRAPHICS 1 /* set graphics mode */
+
+#define K_RAW 0 /* keyboard returns scancodes */
+#define K_XLATE 1 /* keyboard returns ascii */
+
+#define KB_84 1 /* 'old' 84 key AT-keyboard */
+#define KB_101 2 /* MF-101 or MF-102 keyboard */
+#define KB_OTHER 3 /* keyboard not known */
+
+#define CLKED 1 /* Caps locked */
+#define NLKED 2 /* Num locked */
+#define SLKED 4 /* Scroll locked */
+#define ALKED 8 /* AltGr locked */
+#define LED_CAP 1 /* Caps lock LED */
+#define LED_NUM 2 /* Num lock LED */
+#define LED_SCR 4 /* Scroll lock LED */
+
+/* possible flag values */
+#define FLAG_LOCK_O 0
+#define FLAG_LOCK_C 1
+#define FLAG_LOCK_N 2
+
+#define NUM_KEYS 256 /* number of keys in table */
+#define NUM_STATES 8 /* states per key */
+#define ALTGR_OFFSET 128 /* offset for altlock keys */
+
+struct keymap {
+ u_short n_keys;
+ struct key_t {
+ u_char map[NUM_STATES];
+ u_char spcl;
+ u_char flgs;
+ } key[NUM_KEYS];
+};
+
+#define MAXFK 16
+
+struct fkeytab {
+ u_char str[MAXFK];
+ u_char len;
+};
+
+struct fkeyarg {
+ u_short keynum;
+ char keydef[MAXFK];
+ char flen;
+};
+
+struct colors {
+ char fore;
+ char back;
+};
+
+struct vid_info {
+ short size;
+ short m_num;
+ u_short mv_row, mv_col;
+ u_short mv_rsz, mv_csz;
+ struct colors mv_norm,
+ mv_rev,
+ mv_grfc;
+ u_char mv_ovscan;
+ u_char mk_keylock;
+};
+
+#define MAXSSAVER 16
+
+struct ssaver {
+ char name[MAXSSAVER];
+ int num;
+ long time;
+};
+
+typedef struct keymap keymap_t;
+typedef struct fkeytab fkeytab_t;
+typedef struct fkeyarg fkeyarg_t;
+typedef struct vid_info vid_info_t;
+typedef struct vt_mode vtmode_t;
+typedef struct {char scrmap[256];} scrmap_t;
+typedef struct {char fnt8x8[8*256];} fnt8_t;
+typedef struct {char fnt8x14[14*256];} fnt14_t;
+typedef struct {char fnt8x16[16*256];} fnt16_t;
+typedef struct ssaver ssaver_t;
+
+/* defines for "special" keys (spcl bit set in keymap) */
+#define NOP 0x00 /* nothing (dead key) */
+#define LSH 0x02 /* left shift key */
+#define RSH 0x03 /* right shift key */
+#define CLK 0x04 /* caps lock key */
+#define NLK 0x05 /* num lock key */
+#define SLK 0x06 /* scroll lock key */
+#define LALT 0x07 /* left alt key */
+#define LCTR 0x09 /* left control key */
+#define NEXT 0x0a /* switch to next screen */
+#define F_SCR 0x0b /* switch to first screen */
+#define L_SCR 0x1a /* switch to last screen */
+#define F_FN 0x1b /* first function key */
+#define L_FN 0x7a /* last function key */
+#define RCTR 0x7b /* right control key */
+#define RALT 0x7c /* right alt (altgr) key */
+#define ALK 0x7d /* alt lock key */
+#define ASH 0x7e /* alt shift key */
+#define META 0x7f /* meta key */
+#define RBT 0x80 /* boot machine */
+#define DBG 0x81 /* call debugger */
+
+#define F(x) ((x)+F_FN-1)
+#define S(x) ((x)+F_SCR-1)
+#define NOKEY 0x100 /* no key pressed marker */
+#define FKEY 0x200 /* funtion key marker */
+#define MKEY 0x400 /* meta key marker (prepend ESC)*/
+
+#define KB_DATA 0x60 /* kbd data port */
+#define KB_STAT 0x64 /* kbd status port */
+#define KB_BUF_FULL 0x01 /* kbd has char pending */
+#define KB_READY 0x02 /* kbd ready for command */
+#define KB_WRITE 0x60 /* kbd write command */
+#define KB_SETLEDS 0xed /* kbd set leds */
+#define KB_SETRAD 0xf3 /* kbd set repeat&delay command */
+#define KB_ACK 0xfa /* kbd acknowledge answer */
+#define KB_RESET_CPU 0xfe /* kbd reset main cpu command */
+#define KB_RESET 0xff /* kbd reset */
+
+#endif
diff --git a/sys/alpha/include/pc/display.h b/sys/alpha/include/pc/display.h
new file mode 100644
index 0000000..9e64a3f
--- /dev/null
+++ b/sys/alpha/include/pc/display.h
@@ -0,0 +1,45 @@
+/*
+ * IBM PC display definitions
+ *
+ * $Id$
+ */
+
+/* Color attributes for foreground text */
+
+#define FG_BLACK 0
+#define FG_BLUE 1
+#define FG_GREEN 2
+#define FG_CYAN 3
+#define FG_RED 4
+#define FG_MAGENTA 5
+#define FG_BROWN 6
+#define FG_LIGHTGREY 7
+#define FG_DARKGREY 8
+#define FG_LIGHTBLUE 9
+#define FG_LIGHTGREEN 10
+#define FG_LIGHTCYAN 11
+#define FG_LIGHTRED 12
+#define FG_LIGHTMAGENTA 13
+#define FG_YELLOW 14
+#define FG_WHITE 15
+#define FG_BLINK 0x80
+
+/* Color attributes for text background */
+
+#define BG_BLACK 0x00
+#define BG_BLUE 0x10
+#define BG_GREEN 0x20
+#define BG_CYAN 0x30
+#define BG_RED 0x40
+#define BG_MAGENTA 0x50
+#define BG_BROWN 0x60
+#define BG_LIGHTGREY 0x70
+
+/* Monochrome attributes for foreground text */
+
+#define FG_UNDERLINE 0x01
+#define FG_INTENSE 0x08
+
+/* Monochrome attributes for text background */
+
+#define BG_INTENSE 0x10
diff --git a/sys/alpha/include/pc/msdos.h b/sys/alpha/include/pc/msdos.h
new file mode 100644
index 0000000..ea221c7
--- /dev/null
+++ b/sys/alpha/include/pc/msdos.h
@@ -0,0 +1,65 @@
+/*
+ * msdos common header file
+ * [obtained from mtools -wfj]
+ * how to decipher DOS disk structures in coexisting with DOS
+ *
+ * $Id$
+ */
+
+#define MSECTOR_SIZE 512 /* MSDOS sector size in bytes */
+#define MDIR_SIZE 32 /* MSDOS directory size in bytes */
+#define MAX_CLUSTER 8192 /* largest cluster size */
+#define MAX_PATH 128 /* largest MSDOS path length */
+#define MAX_DIR_SECS 64 /* largest directory (in sectors) */
+
+#define NEW 1
+#define OLD 0
+
+struct directory {
+ unsigned char name[8]; /* file name */
+ unsigned char ext[3]; /* file extension */
+ unsigned char attr; /* attribute byte */
+ unsigned char reserved[10]; /* ?? */
+ unsigned char time[2]; /* time stamp */
+ unsigned char date[2]; /* date stamp */
+ unsigned char start[2]; /* starting cluster number */
+ unsigned char size[4]; /* size of the file */
+};
+
+struct bootsector {
+ unsigned char jump[3]; /* Jump to boot code */
+ unsigned char banner[8]; /* OEM name & version */
+ unsigned char secsiz[2]; /* Bytes per sector hopefully 512 */
+ unsigned char clsiz; /* Cluster size in sectors */
+ unsigned char nrsvsect[2]; /* Number of reserved (boot) sectors */
+ unsigned char nfat; /* Number of FAT tables hopefully 2 */
+ unsigned char dirents[2]; /* Number of directory slots */
+ unsigned char psect[2]; /* Total sectors on disk */
+ unsigned char descr; /* Media descriptor=first byte of FAT */
+ unsigned char fatlen[2]; /* Sectors in FAT */
+ unsigned char nsect[2]; /* Sectors/track */
+ unsigned char nheads[2]; /* Heads */
+ unsigned char nhs[4]; /* number of hidden sectors */
+ unsigned char bigsect[4]; /* big total sectors */
+ unsigned char junk[476]; /* who cares? */
+};
+
+/* DOS partition table -- located in boot block */
+
+#define DOSBBSECTOR 0 /* DOS boot block relative sector number */
+#define DOSPARTOFF 446
+#define NDOSPART 4
+
+struct dos_partition {
+ unsigned char dp_flag; /* bootstrap flags */
+ unsigned char dp_shd; /* starting head */
+ unsigned char dp_ssect; /* starting sector */
+ unsigned char dp_scyl; /* starting cylinder */
+ unsigned char dp_typ; /* partition type */
+#define DOSPTYP_386BSD 0xa5 /* 386BSD partition type */
+ unsigned char dp_ehd; /* end head */
+ unsigned char dp_esect; /* end sector */
+ unsigned char dp_ecyl; /* end cylinder */
+ unsigned long dp_start; /* absolute starting sector number */
+ unsigned long dp_size; /* partition size in sectors */
+} dos_partitions[NDOSPART];
diff --git a/sys/amd64/Makefile b/sys/amd64/Makefile
new file mode 100644
index 0000000..4ad5a34
--- /dev/null
+++ b/sys/amd64/Makefile
@@ -0,0 +1,25 @@
+# from: @(#)Makefile 7.3 (Berkeley) 6/9/91
+# $Id$
+
+# Makefile for i386 tags file
+
+all:
+ @echo "make tags or links only"
+
+TI386= ../i386/tags
+SI386= ../i386/i386/*.[ch] ../i386/include/*.h ../i386/isa/*.[ch]
+AI386= ../i386/i386/*.s
+
+# Directories in which to place i386 tags links
+DI386= eisa isa mca include
+
+tags:
+ -ctags -dtf ${TI386} ${COMM} ${SI386}
+ egrep "^ENTRY(.*)|^ALTENTRY(.*)" ${AI386} | \
+ sed "s;\([^:]*\):\([^(]*\)(\([^, )]*\)\(.*\);\3 \1 /^\2(\3\4$$/;" \
+ >> ${TI386}
+ sort -o ${TI386} ${TI386}
+
+links:
+ -for i in ${DI386}; do \
+ cd $$i && rm -f tags; ln -s ../tags tags; done
diff --git a/sys/amd64/amd64/autoconf.c b/sys/amd64/amd64/autoconf.c
new file mode 100644
index 0000000..3575d1c
--- /dev/null
+++ b/sys/amd64/amd64/autoconf.c
@@ -0,0 +1,209 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)autoconf.c 7.1 (Berkeley) 5/9/91
+ * $Id: autoconf.c,v 1.10 1994/03/21 14:53:08 ache Exp $
+ */
+
+/*
+ * Setup the system to run on the current machine.
+ *
+ * Configure() is called at boot time and initializes the vba
+ * device tables and the memory controller monitoring. Available
+ * devices are determined (from possibilities mentioned in ioconf.c),
+ * and the drivers are initialized.
+ */
+#include "param.h"
+#include "systm.h"
+#include "buf.h"
+#include "dkstat.h"
+#include "conf.h"
+#include "dmap.h"
+#include "reboot.h"
+#include "kernel.h"
+
+#include "machine/pte.h"
+
+static void swapconf(void);
+static void setroot(void);
+
+/*
+ * The following several variables are related to
+ * the configuration process, and are used in initializing
+ * the machine.
+ */
+int dkn; /* number of iostat dk numbers assigned so far */
+extern int cold; /* cold start flag initialized in locore.s */
+
+/*
+ * Determine i/o configuration for a machine.
+ */
+void
+configure()
+{
+
+#include "isa.h"
+#if NISA > 0
+ isa_configure();
+#endif
+
+#if GENERICxxx && !defined(DISKLESS)
+ if ((boothowto & RB_ASKNAME) == 0)
+ setroot();
+ setconf();
+#else
+#ifndef DISKLESS
+ setroot();
+#endif
+#endif
+ /*
+ * Configure swap area and related system
+ * parameter based on device(s) used.
+ */
+ swapconf();
+ cold = 0;
+}
+
+/*
+ * Configure swap space and related parameters.
+ */
+static void
+swapconf()
+{
+ register struct swdevt *swp;
+ register int nblks;
+ extern int Maxmem;
+
+ for (swp = swdevt; swp->sw_dev > 0; swp++)
+ {
+ unsigned d = major(swp->sw_dev);
+
+ if (d > nblkdev) break;
+ if (bdevsw[d].d_psize) {
+ nblks = (*bdevsw[d].d_psize)(swp->sw_dev);
+ if (nblks > 0 &&
+ (swp->sw_nblks == 0 || swp->sw_nblks > nblks))
+ swp->sw_nblks = nblks;
+ else
+ swp->sw_nblks = 0;
+ }
+ swp->sw_nblks = ctod(dtoc(swp->sw_nblks));
+ }
+ if (dumplo == 0 && bdevsw[major(dumpdev)].d_psize)
+ dumplo = (*bdevsw[major(dumpdev)].d_psize)(dumpdev) -
+ Maxmem*NBPG/512;
+ if (dumplo < 0)
+ dumplo = 0;
+}
+
+#define DOSWAP /* change swdevt and dumpdev */
+u_long bootdev = 0; /* should be dev_t, but not until 32 bits */
+
+static char devname[][2] = {
+ 'w','d', /* 0 = wd */
+ 's','w', /* 1 = sw */
+#define FDMAJOR 2
+ 'f','d', /* 2 = fd */
+ 'w','t', /* 3 = wt */
+ 's','d', /* 4 = sd -- new SCSI system */
+};
+
+#define PARTITIONMASK 0x7
+#define PARTITIONSHIFT 3
+#define FDUNITSHIFT 6
+
+/*
+ * Attempt to find the device from which we were booted.
+ * If we can do so, and not instructed not to do so,
+ * change rootdev to correspond to the load device.
+ */
+static void
+setroot()
+{
+ int majdev, mindev, unit, part, adaptor;
+ dev_t temp = 0, orootdev;
+ struct swdevt *swp;
+
+/*printf("howto %x bootdev %x ", boothowto, bootdev);*/
+ if (boothowto & RB_DFLTROOT ||
+ (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC)
+ return;
+ majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK;
+ if (majdev > sizeof(devname) / sizeof(devname[0]))
+ return;
+ adaptor = (bootdev >> B_ADAPTORSHIFT) & B_ADAPTORMASK;
+ unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK;
+ if (majdev == FDMAJOR) {
+ part = 3; /* raw */
+ mindev = unit << FDUNITSHIFT;
+ }
+ else {
+ part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK;
+ mindev = (unit << PARTITIONSHIFT) + part;
+ }
+ orootdev = rootdev;
+ rootdev = makedev(majdev, mindev);
+ /*
+ * If the original rootdev is the same as the one
+ * just calculated, don't need to adjust the swap configuration.
+ */
+ if (rootdev == orootdev)
+ return;
+ printf("changing root device to %c%c%d%c\n",
+ devname[majdev][0], devname[majdev][1],
+ mindev >> (majdev == FDMAJOR ? FDUNITSHIFT : PARTITIONSHIFT),
+ part + 'a');
+#ifdef DOSWAP
+ mindev &= ~PARTITIONMASK;
+ for (swp = swdevt; swp->sw_dev; swp++) {
+ if (majdev == major(swp->sw_dev) &&
+ mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) {
+
+ temp = swdevt[0].sw_dev;
+ swdevt[0].sw_dev = swp->sw_dev;
+ swp->sw_dev = temp;
+ break;
+ }
+ }
+ if (swp->sw_dev == 0)
+ return;
+ /*
+ * If dumpdev was the same as the old primary swap
+ * device, move it to the new primary swap device.
+ */
+ if (temp == dumpdev)
+ dumpdev = swdevt[0].sw_dev;
+#endif
+}
diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S
new file mode 100644
index 0000000..4dbc672
--- /dev/null
+++ b/sys/amd64/amd64/cpu_switch.S
@@ -0,0 +1,458 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: swtch.s,v 1.5 1994/04/02 07:00:30 davidg Exp $
+ */
+
+#include "npx.h" /* for NNPX */
+#include "assym.s" /* for preprocessor defines */
+#include "errno.h" /* for error codes */
+
+#include "machine/asmacros.h" /* for miscellaneous assembly macros */
+#define LOCORE /* XXX inhibit C declarations */
+#include "machine/spl.h" /* for SWI_AST_MASK ... */
+
+
+/*****************************************************************************/
+/* Scheduling */
+/*****************************************************************************/
+
+/*
+ * The following primitives manipulate the run queues.
+ * _whichqs tells which of the 32 queues _qs
+ * have processes in them. Setrq puts processes into queues, Remrq
+ * removes them from queues. The running process is on no queue,
+ * other processes are on a queue related to p->p_pri, divided by 4
+ * actually to shrink the 0-127 range of priorities into the 32 available
+ * queues.
+ */
+ .data
+ .globl _curpcb, _whichqs
+_curpcb: .long 0 /* pointer to curproc's PCB area */
+_whichqs: .long 0 /* which run queues have data */
+
+ .globl _qs,_cnt,_panic
+ .comm _noproc,4
+ .comm _runrun,4
+
+ .globl _want_resched
+_want_resched: .long 0 /* we need to re-run the scheduler */
+
+ .text
+/*
+ * Setrq(p)
+ *
+ * Call should be made at spl6(), and p->p_stat should be SRUN
+ */
+ENTRY(setrq)
+ movl 4(%esp),%eax
+ cmpl $0,P_RLINK(%eax) /* should not be on q already */
+ je set1
+ pushl $set2
+ call _panic
+set1:
+ movzbl P_PRI(%eax),%edx
+ shrl $2,%edx
+ btsl %edx,_whichqs /* set q full bit */
+ shll $3,%edx
+ addl $_qs,%edx /* locate q hdr */
+ movl %edx,P_LINK(%eax) /* link process on tail of q */
+ movl P_RLINK(%edx),%ecx
+ movl %ecx,P_RLINK(%eax)
+ movl %eax,P_RLINK(%edx)
+ movl %eax,P_LINK(%ecx)
+ ret
+
+set2: .asciz "setrq"
+
+/*
+ * Remrq(p)
+ *
+ * Call should be made at spl6().
+ */
+ENTRY(remrq)
+ movl 4(%esp),%eax
+ movzbl P_PRI(%eax),%edx
+ shrl $2,%edx
+ btrl %edx,_whichqs /* clear full bit, panic if clear already */
+ jb rem1
+ pushl $rem3
+ call _panic
+rem1:
+ pushl %edx
+ movl P_LINK(%eax),%ecx /* unlink process */
+ movl P_RLINK(%eax),%edx
+ movl %edx,P_RLINK(%ecx)
+ movl P_RLINK(%eax),%ecx
+ movl P_LINK(%eax),%edx
+ movl %edx,P_LINK(%ecx)
+ popl %edx
+ movl $_qs,%ecx
+ shll $3,%edx
+ addl %edx,%ecx
+ cmpl P_LINK(%ecx),%ecx /* q still has something? */
+ je rem2
+ shrl $3,%edx /* yes, set bit as still full */
+ btsl %edx,_whichqs
+rem2:
+ movl $0,P_RLINK(%eax) /* zap reverse link to indicate off list */
+ ret
+
+rem3: .asciz "remrq"
+sw0: .asciz "swtch"
+
+/*
+ * When no processes are on the runq, swtch() branches to _idle
+ * to wait for something to come ready.
+ */
+ ALIGN_TEXT
+_idle:
+ MCOUNT
+ movl _IdlePTD,%ecx
+ movl %ecx,%cr3
+ movl $tmpstk-4,%esp
+ sti
+
+ /*
+ * XXX callers of swtch() do a bogus splclock(). Locking should
+ * be left to swtch().
+ */
+ movl $SWI_AST_MASK,_cpl
+ testl $~SWI_AST_MASK,_ipending
+ je idle_loop
+ call _splz
+
+ ALIGN_TEXT
+idle_loop:
+ cli
+ cmpl $0,_whichqs
+ jne sw1a
+ sti
+ hlt /* wait for interrupt */
+ jmp idle_loop
+
+badsw:
+ pushl $sw0
+ call _panic
+ /*NOTREACHED*/
+
+/*
+ * Swtch()
+ */
+ENTRY(swtch)
+ incl _cnt+V_SWTCH
+
+ /* switch to new process. first, save context as needed */
+
+ movl _curproc,%ecx
+
+ /* if no process to save, don't bother */
+ testl %ecx,%ecx
+ je sw1
+
+ movl P_ADDR(%ecx),%ecx
+
+ movl (%esp),%eax /* Hardware registers */
+ movl %eax,PCB_EIP(%ecx)
+ movl %ebx,PCB_EBX(%ecx)
+ movl %esp,PCB_ESP(%ecx)
+ movl %ebp,PCB_EBP(%ecx)
+ movl %esi,PCB_ESI(%ecx)
+ movl %edi,PCB_EDI(%ecx)
+
+#if NNPX > 0
+ /* have we used fp, and need a save? */
+ mov _curproc,%eax
+ cmp %eax,_npxproc
+ jne 1f
+ pushl %ecx /* h/w bugs make saving complicated */
+ leal PCB_SAVEFPU(%ecx),%eax
+ pushl %eax
+ call _npxsave /* do it in a big C function */
+ popl %eax
+ popl %ecx
+1:
+#endif /* NNPX > 0 */
+
+ movl _CMAP2,%eax /* save temporary map PTE */
+ movl %eax,PCB_CMAP2(%ecx) /* in our context */
+ movl $0,_curproc /* out of process */
+
+# movw _cpl,%ax
+# movw %ax,PCB_IML(%ecx) /* save ipl */
+
+ /* save is done, now choose a new process or idle */
+sw1:
+ cli
+sw1a:
+ movl _whichqs,%edi
+2:
+ /* XXX - bsf is sloow */
+ bsfl %edi,%eax /* find a full q */
+ je _idle /* if none, idle */
+
+ /* XX update whichqs? */
+ btrl %eax,%edi /* clear q full status */
+ jnb 2b /* if it was clear, look for another */
+ movl %eax,%ebx /* save which one we are using */
+
+ shll $3,%eax
+ addl $_qs,%eax /* select q */
+ movl %eax,%esi
+
+#ifdef DIAGNOSTIC
+ cmpl P_LINK(%eax),%eax /* linked to self? (e.g. not on list) */
+ je badsw /* not possible */
+#endif
+
+ movl P_LINK(%eax),%ecx /* unlink from front of process q */
+ movl P_LINK(%ecx),%edx
+ movl %edx,P_LINK(%eax)
+ movl P_RLINK(%ecx),%eax
+ movl %eax,P_RLINK(%edx)
+
+ cmpl P_LINK(%ecx),%esi /* q empty */
+ je 3f
+ btsl %ebx,%edi /* nope, set to indicate full */
+3:
+ movl %edi,_whichqs /* update q status */
+
+ movl $0,%eax
+ movl %eax,_want_resched
+
+#ifdef DIAGNOSTIC
+ cmpl %eax,P_WCHAN(%ecx)
+ jne badsw
+ cmpb $SRUN,P_STAT(%ecx)
+ jne badsw
+#endif
+
+ movl %eax,P_RLINK(%ecx) /* isolate process to run */
+ movl P_ADDR(%ecx),%edx
+ movl PCB_CR3(%edx),%ebx
+
+ /* switch address space */
+ movl %ebx,%cr3
+
+ /* restore context */
+ movl PCB_EBX(%edx),%ebx
+ movl PCB_ESP(%edx),%esp
+ movl PCB_EBP(%edx),%ebp
+ movl PCB_ESI(%edx),%esi
+ movl PCB_EDI(%edx),%edi
+ movl PCB_EIP(%edx),%eax
+ movl %eax,(%esp)
+
+ movl PCB_CMAP2(%edx),%eax /* get temporary map */
+ movl %eax,_CMAP2 /* reload temporary map PTE */
+
+ movl %ecx,_curproc /* into next process */
+ movl %edx,_curpcb
+
+#ifdef USER_LDT
+ cmpl $0, PCB_USERLDT(%edx)
+ jnz 1f
+ movl __default_ldt,%eax
+ cmpl _currentldt,%eax
+ je 2f
+ lldt __default_ldt
+ movl %eax,_currentldt
+ jmp 2f
+1: pushl %edx
+ call _set_user_ldt
+ popl %edx
+2:
+#endif
+
+ pushl %edx /* save p to return */
+/*
+ * XXX - 0.0 forgot to save it - is that why this was commented out in 0.1?
+ * I think restoring the cpl is unnecessary, but we must turn off the cli
+ * now that spl*() don't do it as a side affect.
+ */
+ pushl PCB_IML(%edx)
+ sti
+#if 0
+ call _splx
+#endif
+ addl $4,%esp
+/*
+ * XXX - 0.0 gets here via swtch_to_inactive(). I think 0.1 gets here in the
+ * same way. Better return a value.
+ */
+ popl %eax /* return(p); */
+ ret
+
+ENTRY(mvesp)
+ movl %esp,%eax
+ ret
+/*
+ * struct proc *swtch_to_inactive(struct proc *p);
+ *
+ * At exit of a process, move off the address space of the
+ * process and onto a "safe" one. Then, on a temporary stack
+ * return and run code that disposes of the old state.
+ * Since this code requires a parameter from the "old" stack,
+ * pass it back as a return value.
+ */
+ENTRY(swtch_to_inactive)
+ popl %edx /* old pc */
+ popl %eax /* arg, our return value */
+ movl _IdlePTD,%ecx
+ movl %ecx,%cr3 /* good bye address space */
+ #write buffer?
+ movl $tmpstk-4,%esp /* temporary stack, compensated for call */
+ MEXITCOUNT
+ jmp %edx /* return, execute remainder of cleanup */
+
+/*
+ * savectx(pcb, altreturn)
+ * Update pcb, saving current processor state and arranging
+ * for alternate return ala longjmp in swtch if altreturn is true.
+ */
+ENTRY(savectx)
+ movl 4(%esp),%ecx
+ movw _cpl,%ax
+ movw %ax,PCB_IML(%ecx)
+ movl (%esp),%eax
+ movl %eax,PCB_EIP(%ecx)
+ movl %ebx,PCB_EBX(%ecx)
+ movl %esp,PCB_ESP(%ecx)
+ movl %ebp,PCB_EBP(%ecx)
+ movl %esi,PCB_ESI(%ecx)
+ movl %edi,PCB_EDI(%ecx)
+
+#if NNPX > 0
+ /*
+ * If npxproc == NULL, then the npx h/w state is irrelevant and the
+ * state had better already be in the pcb. This is true for forks
+ * but not for dumps (the old book-keeping with FP flags in the pcb
+ * always lost for dumps because the dump pcb has 0 flags).
+ *
+ * If npxproc != NULL, then we have to save the npx h/w state to
+ * npxproc's pcb and copy it to the requested pcb, or save to the
+ * requested pcb and reload. Copying is easier because we would
+ * have to handle h/w bugs for reloading. We used to lose the
+ * parent's npx state for forks by forgetting to reload.
+ */
+ mov _npxproc,%eax
+ testl %eax,%eax
+ je 1f
+
+ pushl %ecx
+ movl P_ADDR(%eax),%eax
+ leal PCB_SAVEFPU(%eax),%eax
+ pushl %eax
+ pushl %eax
+ call _npxsave
+ popl %eax
+ popl %eax
+ popl %ecx
+
+ pushl %ecx
+ pushl $108+8*2 /* XXX h/w state size + padding */
+ leal PCB_SAVEFPU(%ecx),%ecx
+ pushl %ecx
+ pushl %eax
+ call _bcopy
+ addl $12,%esp
+ popl %ecx
+1:
+#endif /* NNPX > 0 */
+
+ movl _CMAP2,%edx /* save temporary map PTE */
+ movl %edx,PCB_CMAP2(%ecx) /* in our context */
+
+ cmpl $0,8(%esp)
+ je 1f
+ movl %esp,%edx /* relocate current sp relative to pcb */
+ subl $_kstack,%edx /* (sp is relative to kstack): */
+ addl %edx,%ecx /* pcb += sp - kstack; */
+ movl %eax,(%ecx) /* write return pc at (relocated) sp@ */
+
+/* this mess deals with replicating register state gcc hides */
+ movl 12(%esp),%eax
+ movl %eax,12(%ecx)
+ movl 16(%esp),%eax
+ movl %eax,16(%ecx)
+ movl 20(%esp),%eax
+ movl %eax,20(%ecx)
+ movl 24(%esp),%eax
+ movl %eax,24(%ecx)
+1:
+ xorl %eax,%eax /* return 0 */
+ ret
+
+/*
+ * addupc(int pc, struct uprof *up, int ticks):
+ * update profiling information for the user process.
+ */
+ENTRY(addupc)
+ pushl %ebp
+ movl %esp,%ebp
+ movl 12(%ebp),%edx /* up */
+ movl 8(%ebp),%eax /* pc */
+
+ subl PR_OFF(%edx),%eax /* pc -= up->pr_off */
+ jb L1 /* if (pc was < off) return */
+
+ shrl $1,%eax /* praddr = pc >> 1 */
+ imull PR_SCALE(%edx),%eax /* praddr *= up->pr_scale */
+ shrl $15,%eax /* praddr = praddr << 15 */
+ andl $-2,%eax /* praddr &= ~1 */
+
+ cmpl PR_SIZE(%edx),%eax /* if (praddr > up->pr_size) return */
+ ja L1
+
+/* addl %eax,%eax /* praddr -> word offset */
+ addl PR_BASE(%edx),%eax /* praddr += up-> pr_base */
+ movl 16(%ebp),%ecx /* ticks */
+
+ movl _curpcb,%edx
+ movl $proffault,PCB_ONFAULT(%edx)
+ addl %ecx,(%eax) /* storage location += ticks */
+ movl $0,PCB_ONFAULT(%edx)
+L1:
+ leave
+ ret
+
+ ALIGN_TEXT
+proffault:
+ /* if we get a fault, then kill profiling all together */
+ movl $0,PCB_ONFAULT(%edx) /* squish the fault handler */
+ movl 12(%ebp),%ecx
+ movl $0,PR_SCALE(%ecx) /* up->pr_scale = 0 */
+ leave
+ ret
diff --git a/sys/amd64/amd64/db_disasm.c b/sys/amd64/amd64/db_disasm.c
new file mode 100644
index 0000000..98e251b
--- /dev/null
+++ b/sys/amd64/amd64/db_disasm.c
@@ -0,0 +1,1375 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_disasm.c,v 1.4 1993/11/25 01:30:51 wollman Exp $
+ */
+
+/*
+ * Instruction disassembler.
+ */
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "ddb/ddb.h"
+
+#include <ddb/db_access.h>
+#include <ddb/db_sym.h>
+
+/*
+ * Size attributes
+ */
+#define BYTE 0
+#define WORD 1
+#define LONG 2
+#define QUAD 3
+#define SNGL 4
+#define DBLR 5
+#define EXTR 6
+#define SDEP 7
+#define NONE 8
+
+/*
+ * Addressing modes
+ */
+#define E 1 /* general effective address */
+#define Eind 2 /* indirect address (jump, call) */
+#define Ew 3 /* address, word size */
+#define Eb 4 /* address, byte size */
+#define R 5 /* register, in 'reg' field */
+#define Rw 6 /* word register, in 'reg' field */
+#define Ri 7 /* register in instruction */
+#define S 8 /* segment reg, in 'reg' field */
+#define Si 9 /* segment reg, in instruction */
+#define A 10 /* accumulator */
+#define BX 11 /* (bx) */
+#define CL 12 /* cl, for shifts */
+#define DX 13 /* dx, for IO */
+#define SI 14 /* si */
+#define DI 15 /* di */
+#define CR 16 /* control register */
+#define DR 17 /* debug register */
+#define TR 18 /* test register */
+#define I 19 /* immediate, unsigned */
+#define Is 20 /* immediate, signed */
+#define Ib 21 /* byte immediate, unsigned */
+#define Ibs 22 /* byte immediate, signed */
+#define Iw 23 /* word immediate, unsigned */
+#define Il 24 /* long immediate */
+#define O 25 /* direct address */
+#define Db 26 /* byte displacement from EIP */
+#define Dl 27 /* long displacement from EIP */
+#define o1 28 /* constant 1 */
+#define o3 29 /* constant 3 */
+#define OS 30 /* immediate offset/segment */
+#define ST 31 /* FP stack top */
+#define STI 32 /* FP stack */
+#define X 33 /* extended FP op */
+#define XA 34 /* for 'fstcw %ax' */
+
+struct inst {
+ char * i_name; /* name */
+ short i_has_modrm; /* has regmodrm byte */
+ short i_size; /* operand size */
+ int i_mode; /* addressing modes */
+ char * i_extra; /* pointer to extra opcode table */
+};
+
+#define op1(x) (x)
+#define op2(x,y) ((x)|((y)<<8))
+#define op3(x,y,z) ((x)|((y)<<8)|((z)<<16))
+
+struct finst {
+ char * f_name; /* name for memory instruction */
+ int f_size; /* size for memory instruction */
+ int f_rrmode; /* mode for rr instruction */
+ char * f_rrname; /* name for rr instruction
+ (or pointer to table) */
+};
+
+char * db_Grp6[] = {
+ "sldt",
+ "str",
+ "lldt",
+ "ltr",
+ "verr",
+ "verw",
+ "",
+ ""
+};
+
+char * db_Grp7[] = {
+ "sgdt",
+ "sidt",
+ "lgdt",
+ "lidt",
+ "smsw",
+ "",
+ "lmsw",
+ "invlpg"
+};
+
+char * db_Grp8[] = {
+ "",
+ "",
+ "",
+ "",
+ "bt",
+ "bts",
+ "btr",
+ "btc"
+};
+
+struct inst db_inst_0f0x[] = {
+/*00*/ { "", TRUE, NONE, op1(Ew), (char *)db_Grp6 },
+/*01*/ { "", TRUE, NONE, op1(Ew), (char *)db_Grp7 },
+/*02*/ { "lar", TRUE, LONG, op2(E,R), 0 },
+/*03*/ { "lsl", TRUE, LONG, op2(E,R), 0 },
+/*04*/ { "", FALSE, NONE, 0, 0 },
+/*05*/ { "", FALSE, NONE, 0, 0 },
+/*06*/ { "clts", FALSE, NONE, 0, 0 },
+/*07*/ { "", FALSE, NONE, 0, 0 },
+
+/*08*/ { "invd", FALSE, NONE, 0, 0 },
+/*09*/ { "wbinvd",FALSE, NONE, 0, 0 },
+/*0a*/ { "", FALSE, NONE, 0, 0 },
+/*0b*/ { "", FALSE, NONE, 0, 0 },
+/*0c*/ { "", FALSE, NONE, 0, 0 },
+/*0d*/ { "", FALSE, NONE, 0, 0 },
+/*0e*/ { "", FALSE, NONE, 0, 0 },
+/*0f*/ { "", FALSE, NONE, 0, 0 },
+};
+
+struct inst db_inst_0f2x[] = {
+/*20*/ { "mov", TRUE, LONG, op2(CR,E), 0 }, /* use E for reg */
+/*21*/ { "mov", TRUE, LONG, op2(DR,E), 0 }, /* since mod == 11 */
+/*22*/ { "mov", TRUE, LONG, op2(E,CR), 0 },
+/*23*/ { "mov", TRUE, LONG, op2(E,DR), 0 },
+/*24*/ { "mov", TRUE, LONG, op2(TR,E), 0 },
+/*25*/ { "", FALSE, NONE, 0, 0 },
+/*26*/ { "mov", TRUE, LONG, op2(E,TR), 0 },
+/*27*/ { "", FALSE, NONE, 0, 0 },
+
+/*28*/ { "", FALSE, NONE, 0, 0 },
+/*29*/ { "", FALSE, NONE, 0, 0 },
+/*2a*/ { "", FALSE, NONE, 0, 0 },
+/*2b*/ { "", FALSE, NONE, 0, 0 },
+/*2c*/ { "", FALSE, NONE, 0, 0 },
+/*2d*/ { "", FALSE, NONE, 0, 0 },
+/*2e*/ { "", FALSE, NONE, 0, 0 },
+/*2f*/ { "", FALSE, NONE, 0, 0 },
+};
+
+struct inst db_inst_0f8x[] = {
+/*80*/ { "jo", FALSE, NONE, op1(Dl), 0 },
+/*81*/ { "jno", FALSE, NONE, op1(Dl), 0 },
+/*82*/ { "jb", FALSE, NONE, op1(Dl), 0 },
+/*83*/ { "jnb", FALSE, NONE, op1(Dl), 0 },
+/*84*/ { "jz", FALSE, NONE, op1(Dl), 0 },
+/*85*/ { "jnz", FALSE, NONE, op1(Dl), 0 },
+/*86*/ { "jbe", FALSE, NONE, op1(Dl), 0 },
+/*87*/ { "jnbe", FALSE, NONE, op1(Dl), 0 },
+
+/*88*/ { "js", FALSE, NONE, op1(Dl), 0 },
+/*89*/ { "jns", FALSE, NONE, op1(Dl), 0 },
+/*8a*/ { "jp", FALSE, NONE, op1(Dl), 0 },
+/*8b*/ { "jnp", FALSE, NONE, op1(Dl), 0 },
+/*8c*/ { "jl", FALSE, NONE, op1(Dl), 0 },
+/*8d*/ { "jnl", FALSE, NONE, op1(Dl), 0 },
+/*8e*/ { "jle", FALSE, NONE, op1(Dl), 0 },
+/*8f*/ { "jnle", FALSE, NONE, op1(Dl), 0 },
+};
+
+struct inst db_inst_0f9x[] = {
+/*90*/ { "seto", TRUE, NONE, op1(Eb), 0 },
+/*91*/ { "setno", TRUE, NONE, op1(Eb), 0 },
+/*92*/ { "setb", TRUE, NONE, op1(Eb), 0 },
+/*93*/ { "setnb", TRUE, NONE, op1(Eb), 0 },
+/*94*/ { "setz", TRUE, NONE, op1(Eb), 0 },
+/*95*/ { "setnz", TRUE, NONE, op1(Eb), 0 },
+/*96*/ { "setbe", TRUE, NONE, op1(Eb), 0 },
+/*97*/ { "setnbe",TRUE, NONE, op1(Eb), 0 },
+
+/*98*/ { "sets", TRUE, NONE, op1(Eb), 0 },
+/*99*/ { "setns", TRUE, NONE, op1(Eb), 0 },
+/*9a*/ { "setp", TRUE, NONE, op1(Eb), 0 },
+/*9b*/ { "setnp", TRUE, NONE, op1(Eb), 0 },
+/*9c*/ { "setl", TRUE, NONE, op1(Eb), 0 },
+/*9d*/ { "setnl", TRUE, NONE, op1(Eb), 0 },
+/*9e*/ { "setle", TRUE, NONE, op1(Eb), 0 },
+/*9f*/ { "setnle",TRUE, NONE, op1(Eb), 0 },
+};
+
+struct inst db_inst_0fax[] = {
+/*a0*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*a1*/ { "pop", FALSE, NONE, op1(Si), 0 },
+/*a2*/ { "", FALSE, NONE, 0, 0 },
+/*a3*/ { "bt", TRUE, LONG, op2(E,R), 0 },
+/*a4*/ { "shld", TRUE, LONG, op3(Ib,E,R), 0 },
+/*a5*/ { "shld", TRUE, LONG, op3(CL,E,R), 0 },
+/*a6*/ { "", FALSE, NONE, 0, 0 },
+/*a7*/ { "", FALSE, NONE, 0, 0 },
+
+/*a8*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*a9*/ { "pop", FALSE, NONE, op1(Si), 0 },
+/*aa*/ { "", FALSE, NONE, 0, 0 },
+/*ab*/ { "bts", TRUE, LONG, op2(E,R), 0 },
+/*ac*/ { "shrd", TRUE, LONG, op3(Ib,E,R), 0 },
+/*ad*/ { "shrd", TRUE, LONG, op3(CL,E,R), 0 },
+/*a6*/ { "", FALSE, NONE, 0, 0 },
+/*a7*/ { "imul", TRUE, LONG, op2(E,R), 0 },
+};
+
+struct inst db_inst_0fbx[] = {
+/*b0*/ { "", FALSE, NONE, 0, 0 },
+/*b1*/ { "", FALSE, NONE, 0, 0 },
+/*b2*/ { "lss", TRUE, LONG, op2(E, R), 0 },
+/*b3*/ { "bts", TRUE, LONG, op2(R, E), 0 },
+/*b4*/ { "lfs", TRUE, LONG, op2(E, R), 0 },
+/*b5*/ { "lgs", TRUE, LONG, op2(E, R), 0 },
+/*b6*/ { "movzb", TRUE, LONG, op2(E, R), 0 },
+/*b7*/ { "movzw", TRUE, LONG, op2(E, R), 0 },
+
+/*b8*/ { "", FALSE, NONE, 0, 0 },
+/*b9*/ { "", FALSE, NONE, 0, 0 },
+/*ba*/ { "", TRUE, LONG, op2(Is, E), (char *)db_Grp8 },
+/*bb*/ { "btc", TRUE, LONG, op2(R, E), 0 },
+/*bc*/ { "bsf", TRUE, LONG, op2(E, R), 0 },
+/*bd*/ { "bsr", TRUE, LONG, op2(E, R), 0 },
+/*be*/ { "movsb", TRUE, LONG, op2(E, R), 0 },
+/*bf*/ { "movsw", TRUE, LONG, op2(E, R), 0 },
+};
+
+struct inst db_inst_0fcx[] = {
+/*c0*/ { "xadd", TRUE, BYTE, op2(R, E), 0 },
+/*c1*/ { "xadd", TRUE, LONG, op2(R, E), 0 },
+/*c2*/ { "", FALSE, NONE, 0, 0 },
+/*c3*/ { "", FALSE, NONE, 0, 0 },
+/*c4*/ { "", FALSE, NONE, 0, 0 },
+/*c5*/ { "", FALSE, NONE, 0, 0 },
+/*c6*/ { "", FALSE, NONE, 0, 0 },
+/*c7*/ { "", FALSE, NONE, 0, 0 },
+/*c8*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*c9*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*ca*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*cb*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*cc*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*cd*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*ce*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*cf*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+};
+
+struct inst db_inst_0fdx[] = {
+/*c0*/ { "cmpxchg",TRUE, BYTE, op2(R, E), 0 },
+/*c1*/ { "cmpxchg",TRUE, LONG, op2(R, E), 0 },
+/*c2*/ { "", FALSE, NONE, 0, 0 },
+/*c3*/ { "", FALSE, NONE, 0, 0 },
+/*c4*/ { "", FALSE, NONE, 0, 0 },
+/*c5*/ { "", FALSE, NONE, 0, 0 },
+/*c6*/ { "", FALSE, NONE, 0, 0 },
+/*c7*/ { "", FALSE, NONE, 0, 0 },
+/*c8*/ { "", FALSE, NONE, 0, 0 },
+/*c9*/ { "", FALSE, NONE, 0, 0 },
+/*ca*/ { "", FALSE, NONE, 0, 0 },
+/*cb*/ { "", FALSE, NONE, 0, 0 },
+/*cc*/ { "", FALSE, NONE, 0, 0 },
+/*cd*/ { "", FALSE, NONE, 0, 0 },
+/*ce*/ { "", FALSE, NONE, 0, 0 },
+/*cf*/ { "", FALSE, NONE, 0, 0 },
+};
+
+struct inst *db_inst_0f[] = {
+ db_inst_0f0x,
+ 0,
+ db_inst_0f2x,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ db_inst_0f8x,
+ db_inst_0f9x,
+ db_inst_0fax,
+ db_inst_0fbx,
+ db_inst_0fcx,
+ db_inst_0fdx,
+ 0,
+ 0
+};
+
+char * db_Esc92[] = {
+ "fnop", "", "", "", "", "", "", ""
+};
+char * db_Esc93[] = {
+ "", "", "", "", "", "", "", ""
+};
+char * db_Esc94[] = {
+ "fchs", "fabs", "", "", "ftst", "fxam", "", ""
+};
+char * db_Esc95[] = {
+ "fld1", "fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz",""
+};
+char * db_Esc96[] = {
+ "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp",
+ "fincstp"
+};
+char * db_Esc97[] = {
+ "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos"
+};
+
+char * db_Esca4[] = {
+ "", "fucompp","", "", "", "", "", ""
+};
+
+char * db_Escb4[] = {
+ "", "", "fnclex","fninit","", "", "", ""
+};
+
+char * db_Esce3[] = {
+ "", "fcompp","", "", "", "", "", ""
+};
+
+char * db_Escf4[] = {
+ "fnstsw","", "", "", "", "", "", ""
+};
+
+struct finst db_Esc8[] = {
+/*0*/ { "fadd", SNGL, op2(STI,ST), 0 },
+/*1*/ { "fmul", SNGL, op2(STI,ST), 0 },
+/*2*/ { "fcom", SNGL, op2(STI,ST), 0 },
+/*3*/ { "fcomp", SNGL, op2(STI,ST), 0 },
+/*4*/ { "fsub", SNGL, op2(STI,ST), 0 },
+/*5*/ { "fsubr", SNGL, op2(STI,ST), 0 },
+/*6*/ { "fdiv", SNGL, op2(STI,ST), 0 },
+/*7*/ { "fdivr", SNGL, op2(STI,ST), 0 },
+};
+
+struct finst db_Esc9[] = {
+/*0*/ { "fld", SNGL, op1(STI), 0 },
+/*1*/ { "", NONE, op1(STI), "fxch" },
+/*2*/ { "fst", SNGL, op1(X), (char *)db_Esc92 },
+/*3*/ { "fstp", SNGL, op1(X), (char *)db_Esc93 },
+/*4*/ { "fldenv", NONE, op1(X), (char *)db_Esc94 },
+/*5*/ { "fldcw", NONE, op1(X), (char *)db_Esc95 },
+/*6*/ { "fnstenv",NONE, op1(X), (char *)db_Esc96 },
+/*7*/ { "fnstcw", NONE, op1(X), (char *)db_Esc97 },
+};
+
+struct finst db_Esca[] = {
+/*0*/ { "fiadd", WORD, 0, 0 },
+/*1*/ { "fimul", WORD, 0, 0 },
+/*2*/ { "ficom", WORD, 0, 0 },
+/*3*/ { "ficomp", WORD, 0, 0 },
+/*4*/ { "fisub", WORD, op1(X), (char *)db_Esca4 },
+/*5*/ { "fisubr", WORD, 0, 0 },
+/*6*/ { "fidiv", WORD, 0, 0 },
+/*7*/ { "fidivr", WORD, 0, 0 }
+};
+
+struct finst db_Escb[] = {
+/*0*/ { "fild", WORD, 0, 0 },
+/*1*/ { "", NONE, 0, 0 },
+/*2*/ { "fist", WORD, 0, 0 },
+/*3*/ { "fistp", WORD, 0, 0 },
+/*4*/ { "", WORD, op1(X), (char *)db_Escb4 },
+/*5*/ { "fld", EXTR, 0, 0 },
+/*6*/ { "", WORD, 0, 0 },
+/*7*/ { "fstp", EXTR, 0, 0 },
+};
+
+struct finst db_Escc[] = {
+/*0*/ { "fadd", DBLR, op2(ST,STI), 0 },
+/*1*/ { "fmul", DBLR, op2(ST,STI), 0 },
+/*2*/ { "fcom", DBLR, op2(ST,STI), 0 },
+/*3*/ { "fcomp", DBLR, op2(ST,STI), 0 },
+/*4*/ { "fsub", DBLR, op2(ST,STI), "fsubr" },
+/*5*/ { "fsubr", DBLR, op2(ST,STI), "fsub" },
+/*6*/ { "fdiv", DBLR, op2(ST,STI), "fdivr" },
+/*7*/ { "fdivr", DBLR, op2(ST,STI), "fdiv" },
+};
+
+struct finst db_Escd[] = {
+/*0*/ { "fld", DBLR, op1(STI), "ffree" },
+/*1*/ { "", NONE, 0, 0 },
+/*2*/ { "fst", DBLR, op1(STI), 0 },
+/*3*/ { "fstp", DBLR, op1(STI), 0 },
+/*4*/ { "frstor", NONE, op1(STI), "fucom" },
+/*5*/ { "", NONE, op1(STI), "fucomp" },
+/*6*/ { "fnsave", NONE, 0, 0 },
+/*7*/ { "fnstsw", NONE, 0, 0 },
+};
+
+struct finst db_Esce[] = {
+/*0*/ { "fiadd", LONG, op2(ST,STI), "faddp" },
+/*1*/ { "fimul", LONG, op2(ST,STI), "fmulp" },
+/*2*/ { "ficom", LONG, 0, 0 },
+/*3*/ { "ficomp", LONG, op1(X), (char *)db_Esce3 },
+/*4*/ { "fisub", LONG, op2(ST,STI), "fsubrp" },
+/*5*/ { "fisubr", LONG, op2(ST,STI), "fsubp" },
+/*6*/ { "fidiv", LONG, op2(ST,STI), "fdivrp" },
+/*7*/ { "fidivr", LONG, op2(ST,STI), "fdivp" },
+};
+
+struct finst db_Escf[] = {
+/*0*/ { "fild", LONG, 0, 0 },
+/*1*/ { "", LONG, 0, 0 },
+/*2*/ { "fist", LONG, 0, 0 },
+/*3*/ { "fistp", LONG, 0, 0 },
+/*4*/ { "fbld", NONE, op1(XA), (char *)db_Escf4 },
+/*5*/ { "fld", QUAD, 0, 0 },
+/*6*/ { "fbstp", NONE, 0, 0 },
+/*7*/ { "fstp", QUAD, 0, 0 },
+};
+
+struct finst *db_Esc_inst[] = {
+ db_Esc8, db_Esc9, db_Esca, db_Escb,
+ db_Escc, db_Escd, db_Esce, db_Escf
+};
+
+char * db_Grp1[] = {
+ "add",
+ "or",
+ "adc",
+ "sbb",
+ "and",
+ "sub",
+ "xor",
+ "cmp"
+};
+
+char * db_Grp2[] = {
+ "rol",
+ "ror",
+ "rcl",
+ "rcr",
+ "shl",
+ "shr",
+ "shl",
+ "sar"
+};
+
+struct inst db_Grp3[] = {
+ { "test", TRUE, NONE, op2(I,E), 0 },
+ { "test", TRUE, NONE, op2(I,E), 0 },
+ { "not", TRUE, NONE, op1(E), 0 },
+ { "neg", TRUE, NONE, op1(E), 0 },
+ { "mul", TRUE, NONE, op2(E,A), 0 },
+ { "imul", TRUE, NONE, op2(E,A), 0 },
+ { "div", TRUE, NONE, op2(E,A), 0 },
+ { "idiv", TRUE, NONE, op2(E,A), 0 },
+};
+
+struct inst db_Grp4[] = {
+ { "inc", TRUE, BYTE, op1(E), 0 },
+ { "dec", TRUE, BYTE, op1(E), 0 },
+ { "", TRUE, NONE, 0, 0 },
+ { "", TRUE, NONE, 0, 0 },
+ { "", TRUE, NONE, 0, 0 },
+ { "", TRUE, NONE, 0, 0 },
+ { "", TRUE, NONE, 0, 0 },
+ { "", TRUE, NONE, 0, 0 }
+};
+
+struct inst db_Grp5[] = {
+ { "inc", TRUE, LONG, op1(E), 0 },
+ { "dec", TRUE, LONG, op1(E), 0 },
+ { "call", TRUE, NONE, op1(Eind),0 },
+ { "lcall", TRUE, NONE, op1(Eind),0 },
+ { "jmp", TRUE, NONE, op1(Eind),0 },
+ { "ljmp", TRUE, NONE, op1(Eind),0 },
+ { "push", TRUE, LONG, op1(E), 0 },
+ { "", TRUE, NONE, 0, 0 }
+};
+
+struct inst db_inst_table[256] = {
+/*00*/ { "add", TRUE, BYTE, op2(R, E), 0 },
+/*01*/ { "add", TRUE, LONG, op2(R, E), 0 },
+/*02*/ { "add", TRUE, BYTE, op2(E, R), 0 },
+/*03*/ { "add", TRUE, LONG, op2(E, R), 0 },
+/*04*/ { "add", FALSE, BYTE, op2(Is, A), 0 },
+/*05*/ { "add", FALSE, LONG, op2(Is, A), 0 },
+/*06*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*07*/ { "pop", FALSE, NONE, op1(Si), 0 },
+
+/*08*/ { "or", TRUE, BYTE, op2(R, E), 0 },
+/*09*/ { "or", TRUE, LONG, op2(R, E), 0 },
+/*0a*/ { "or", TRUE, BYTE, op2(E, R), 0 },
+/*0b*/ { "or", TRUE, LONG, op2(E, R), 0 },
+/*0c*/ { "or", FALSE, BYTE, op2(I, A), 0 },
+/*0d*/ { "or", FALSE, LONG, op2(I, A), 0 },
+/*0e*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*0f*/ { "", FALSE, NONE, 0, 0 },
+
+/*10*/ { "adc", TRUE, BYTE, op2(R, E), 0 },
+/*11*/ { "adc", TRUE, LONG, op2(R, E), 0 },
+/*12*/ { "adc", TRUE, BYTE, op2(E, R), 0 },
+/*13*/ { "adc", TRUE, LONG, op2(E, R), 0 },
+/*14*/ { "adc", FALSE, BYTE, op2(Is, A), 0 },
+/*15*/ { "adc", FALSE, LONG, op2(Is, A), 0 },
+/*16*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*17*/ { "pop", FALSE, NONE, op1(Si), 0 },
+
+/*18*/ { "sbb", TRUE, BYTE, op2(R, E), 0 },
+/*19*/ { "sbb", TRUE, LONG, op2(R, E), 0 },
+/*1a*/ { "sbb", TRUE, BYTE, op2(E, R), 0 },
+/*1b*/ { "sbb", TRUE, LONG, op2(E, R), 0 },
+/*1c*/ { "sbb", FALSE, BYTE, op2(Is, A), 0 },
+/*1d*/ { "sbb", FALSE, LONG, op2(Is, A), 0 },
+/*1e*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*1f*/ { "pop", FALSE, NONE, op1(Si), 0 },
+
+/*20*/ { "and", TRUE, BYTE, op2(R, E), 0 },
+/*21*/ { "and", TRUE, LONG, op2(R, E), 0 },
+/*22*/ { "and", TRUE, BYTE, op2(E, R), 0 },
+/*23*/ { "and", TRUE, LONG, op2(E, R), 0 },
+/*24*/ { "and", FALSE, BYTE, op2(I, A), 0 },
+/*25*/ { "and", FALSE, LONG, op2(I, A), 0 },
+/*26*/ { "", FALSE, NONE, 0, 0 },
+/*27*/ { "aaa", FALSE, NONE, 0, 0 },
+
+/*28*/ { "sub", TRUE, BYTE, op2(R, E), 0 },
+/*29*/ { "sub", TRUE, LONG, op2(R, E), 0 },
+/*2a*/ { "sub", TRUE, BYTE, op2(E, R), 0 },
+/*2b*/ { "sub", TRUE, LONG, op2(E, R), 0 },
+/*2c*/ { "sub", FALSE, BYTE, op2(Is, A), 0 },
+/*2d*/ { "sub", FALSE, LONG, op2(Is, A), 0 },
+/*2e*/ { "", FALSE, NONE, 0, 0 },
+/*2f*/ { "das", FALSE, NONE, 0, 0 },
+
+/*30*/ { "xor", TRUE, BYTE, op2(R, E), 0 },
+/*31*/ { "xor", TRUE, LONG, op2(R, E), 0 },
+/*32*/ { "xor", TRUE, BYTE, op2(E, R), 0 },
+/*33*/ { "xor", TRUE, LONG, op2(E, R), 0 },
+/*34*/ { "xor", FALSE, BYTE, op2(I, A), 0 },
+/*35*/ { "xor", FALSE, LONG, op2(I, A), 0 },
+/*36*/ { "", FALSE, NONE, 0, 0 },
+/*37*/ { "daa", FALSE, NONE, 0, 0 },
+
+/*38*/ { "cmp", TRUE, BYTE, op2(R, E), 0 },
+/*39*/ { "cmp", TRUE, LONG, op2(R, E), 0 },
+/*3a*/ { "cmp", TRUE, BYTE, op2(E, R), 0 },
+/*3b*/ { "cmp", TRUE, LONG, op2(E, R), 0 },
+/*3c*/ { "cmp", FALSE, BYTE, op2(Is, A), 0 },
+/*3d*/ { "cmp", FALSE, LONG, op2(Is, A), 0 },
+/*3e*/ { "", FALSE, NONE, 0, 0 },
+/*3f*/ { "aas", FALSE, NONE, 0, 0 },
+
+/*40*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*41*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*42*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*43*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*44*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*45*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*46*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*47*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+
+/*48*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*49*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4a*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4b*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4c*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4d*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4e*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4f*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+
+/*50*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*51*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*52*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*53*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*54*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*55*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*56*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*57*/ { "push", FALSE, LONG, op1(Ri), 0 },
+
+/*58*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*59*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5a*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5b*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5c*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5d*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5e*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5f*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+
+/*60*/ { "pusha", FALSE, LONG, 0, 0 },
+/*61*/ { "popa", FALSE, LONG, 0, 0 },
+/*62*/ { "bound", TRUE, LONG, op2(E, R), 0 },
+/*63*/ { "arpl", TRUE, NONE, op2(Ew,Rw), 0 },
+
+/*64*/ { "", FALSE, NONE, 0, 0 },
+/*65*/ { "", FALSE, NONE, 0, 0 },
+/*66*/ { "", FALSE, NONE, 0, 0 },
+/*67*/ { "", FALSE, NONE, 0, 0 },
+
+/*68*/ { "push", FALSE, LONG, op1(I), 0 },
+/*69*/ { "imul", TRUE, LONG, op3(I,E,R), 0 },
+/*6a*/ { "push", FALSE, LONG, op1(Ib), 0 },
+/*6b*/ { "imul", TRUE, LONG, op3(Ibs,E,R),0 },
+/*6c*/ { "ins", FALSE, BYTE, op2(DX, DI), 0 },
+/*6d*/ { "ins", FALSE, LONG, op2(DX, DI), 0 },
+/*6e*/ { "outs", FALSE, BYTE, op2(SI, DX), 0 },
+/*6f*/ { "outs", FALSE, LONG, op2(SI, DX), 0 },
+
+/*70*/ { "jo", FALSE, NONE, op1(Db), 0 },
+/*71*/ { "jno", FALSE, NONE, op1(Db), 0 },
+/*72*/ { "jb", FALSE, NONE, op1(Db), 0 },
+/*73*/ { "jnb", FALSE, NONE, op1(Db), 0 },
+/*74*/ { "jz", FALSE, NONE, op1(Db), 0 },
+/*75*/ { "jnz", FALSE, NONE, op1(Db), 0 },
+/*76*/ { "jbe", FALSE, NONE, op1(Db), 0 },
+/*77*/ { "jnbe", FALSE, NONE, op1(Db), 0 },
+
+/*78*/ { "js", FALSE, NONE, op1(Db), 0 },
+/*79*/ { "jns", FALSE, NONE, op1(Db), 0 },
+/*7a*/ { "jp", FALSE, NONE, op1(Db), 0 },
+/*7b*/ { "jnp", FALSE, NONE, op1(Db), 0 },
+/*7c*/ { "jl", FALSE, NONE, op1(Db), 0 },
+/*7d*/ { "jnl", FALSE, NONE, op1(Db), 0 },
+/*7e*/ { "jle", FALSE, NONE, op1(Db), 0 },
+/*7f*/ { "jnle", FALSE, NONE, op1(Db), 0 },
+
+/*80*/ { "", TRUE, BYTE, op2(I, E), (char *)db_Grp1 },
+/*81*/ { "", TRUE, LONG, op2(I, E), (char *)db_Grp1 },
+/*82*/ { "", TRUE, BYTE, op2(Is,E), (char *)db_Grp1 },
+/*83*/ { "", TRUE, LONG, op2(Ibs,E), (char *)db_Grp1 },
+/*84*/ { "test", TRUE, BYTE, op2(R, E), 0 },
+/*85*/ { "test", TRUE, LONG, op2(R, E), 0 },
+/*86*/ { "xchg", TRUE, BYTE, op2(R, E), 0 },
+/*87*/ { "xchg", TRUE, LONG, op2(R, E), 0 },
+
+/*88*/ { "mov", TRUE, BYTE, op2(R, E), 0 },
+/*89*/ { "mov", TRUE, LONG, op2(R, E), 0 },
+/*8a*/ { "mov", TRUE, BYTE, op2(E, R), 0 },
+/*8b*/ { "mov", TRUE, LONG, op2(E, R), 0 },
+/*8c*/ { "mov", TRUE, NONE, op2(S, Ew), 0 },
+/*8d*/ { "lea", TRUE, LONG, op2(E, R), 0 },
+/*8e*/ { "mov", TRUE, NONE, op2(Ew, S), 0 },
+/*8f*/ { "pop", TRUE, LONG, op1(E), 0 },
+
+/*90*/ { "nop", FALSE, NONE, 0, 0 },
+/*91*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*92*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*93*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*94*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*95*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*96*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*97*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+
+/*98*/ { "cbw", FALSE, SDEP, 0, "cwde" }, /* cbw/cwde */
+/*99*/ { "cwd", FALSE, SDEP, 0, "cdq" }, /* cwd/cdq */
+/*9a*/ { "lcall", FALSE, NONE, op1(OS), 0 },
+/*9b*/ { "wait", FALSE, NONE, 0, 0 },
+/*9c*/ { "pushf", FALSE, LONG, 0, 0 },
+/*9d*/ { "popf", FALSE, LONG, 0, 0 },
+/*9e*/ { "sahf", FALSE, NONE, 0, 0 },
+/*9f*/ { "lahf", FALSE, NONE, 0, 0 },
+
+/*a0*/ { "mov", FALSE, BYTE, op2(O, A), 0 },
+/*a1*/ { "mov", FALSE, LONG, op2(O, A), 0 },
+/*a2*/ { "mov", FALSE, BYTE, op2(A, O), 0 },
+/*a3*/ { "mov", FALSE, LONG, op2(A, O), 0 },
+/*a4*/ { "movs", FALSE, BYTE, op2(SI,DI), 0 },
+/*a5*/ { "movs", FALSE, LONG, op2(SI,DI), 0 },
+/*a6*/ { "cmps", FALSE, BYTE, op2(SI,DI), 0 },
+/*a7*/ { "cmps", FALSE, LONG, op2(SI,DI), 0 },
+
+/*a8*/ { "test", FALSE, BYTE, op2(I, A), 0 },
+/*a9*/ { "test", FALSE, LONG, op2(I, A), 0 },
+/*aa*/ { "stos", FALSE, BYTE, op1(DI), 0 },
+/*ab*/ { "stos", FALSE, LONG, op1(DI), 0 },
+/*ac*/ { "lods", FALSE, BYTE, op1(SI), 0 },
+/*ad*/ { "lods", FALSE, LONG, op1(SI), 0 },
+/*ae*/ { "scas", FALSE, BYTE, op1(SI), 0 },
+/*af*/ { "scas", FALSE, LONG, op1(SI), 0 },
+
+/*b0*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b1*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b2*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b3*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b4*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b5*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b6*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b7*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+
+/*b8*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*b9*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*ba*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*bb*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*bc*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*bd*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*be*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*bf*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+
+/*c0*/ { "", TRUE, BYTE, op2(Ib, E), (char *)db_Grp2 },
+/*c1*/ { "", TRUE, LONG, op2(Ib, E), (char *)db_Grp2 },
+/*c2*/ { "ret", FALSE, NONE, op1(Iw), 0 },
+/*c3*/ { "ret", FALSE, NONE, 0, 0 },
+/*c4*/ { "les", TRUE, LONG, op2(E, R), 0 },
+/*c5*/ { "lds", TRUE, LONG, op2(E, R), 0 },
+/*c6*/ { "mov", TRUE, BYTE, op2(I, E), 0 },
+/*c7*/ { "mov", TRUE, LONG, op2(I, E), 0 },
+
+/*c8*/ { "enter", FALSE, NONE, op2(Ib, Iw), 0 },
+/*c9*/ { "leave", FALSE, NONE, 0, 0 },
+/*ca*/ { "lret", FALSE, NONE, op1(Iw), 0 },
+/*cb*/ { "lret", FALSE, NONE, 0, 0 },
+/*cc*/ { "int", FALSE, NONE, op1(o3), 0 },
+/*cd*/ { "int", FALSE, NONE, op1(Ib), 0 },
+/*ce*/ { "into", FALSE, NONE, 0, 0 },
+/*cf*/ { "iret", FALSE, NONE, 0, 0 },
+
+/*d0*/ { "", TRUE, BYTE, op2(o1, E), (char *)db_Grp2 },
+/*d1*/ { "", TRUE, LONG, op2(o1, E), (char *)db_Grp2 },
+/*d2*/ { "", TRUE, BYTE, op2(CL, E), (char *)db_Grp2 },
+/*d3*/ { "", TRUE, LONG, op2(CL, E), (char *)db_Grp2 },
+/*d4*/ { "aam", TRUE, NONE, 0, 0 },
+/*d5*/ { "aad", TRUE, NONE, 0, 0 },
+/*d6*/ { "", FALSE, NONE, 0, 0 },
+/*d7*/ { "xlat", FALSE, BYTE, op1(BX), 0 },
+
+/*d8*/ { "", TRUE, NONE, 0, (char *)db_Esc8 },
+/*d9*/ { "", TRUE, NONE, 0, (char *)db_Esc9 },
+/*da*/ { "", TRUE, NONE, 0, (char *)db_Esca },
+/*db*/ { "", TRUE, NONE, 0, (char *)db_Escb },
+/*dc*/ { "", TRUE, NONE, 0, (char *)db_Escc },
+/*dd*/ { "", TRUE, NONE, 0, (char *)db_Escd },
+/*de*/ { "", TRUE, NONE, 0, (char *)db_Esce },
+/*df*/ { "", TRUE, NONE, 0, (char *)db_Escf },
+
+/*e0*/ { "loopne",FALSE, NONE, op1(Db), 0 },
+/*e1*/ { "loope", FALSE, NONE, op1(Db), 0 },
+/*e2*/ { "loop", FALSE, NONE, op1(Db), 0 },
+/*e3*/ { "jcxz", FALSE, SDEP, op1(Db), "jecxz" },
+/*e4*/ { "in", FALSE, BYTE, op2(Ib, A), 0 },
+/*e5*/ { "in", FALSE, LONG, op2(Ib, A) , 0 },
+/*e6*/ { "out", FALSE, BYTE, op2(A, Ib), 0 },
+/*e7*/ { "out", FALSE, LONG, op2(A, Ib) , 0 },
+
+/*e8*/ { "call", FALSE, NONE, op1(Dl), 0 },
+/*e9*/ { "jmp", FALSE, NONE, op1(Dl), 0 },
+/*ea*/ { "ljmp", FALSE, NONE, op1(OS), 0 },
+/*eb*/ { "jmp", FALSE, NONE, op1(Db), 0 },
+/*ec*/ { "in", FALSE, BYTE, op2(DX, A), 0 },
+/*ed*/ { "in", FALSE, LONG, op2(DX, A) , 0 },
+/*ee*/ { "out", FALSE, BYTE, op2(A, DX), 0 },
+/*ef*/ { "out", FALSE, LONG, op2(A, DX) , 0 },
+
+/*f0*/ { "", FALSE, NONE, 0, 0 },
+/*f1*/ { "", FALSE, NONE, 0, 0 },
+/*f2*/ { "", FALSE, NONE, 0, 0 },
+/*f3*/ { "", FALSE, NONE, 0, 0 },
+/*f4*/ { "hlt", FALSE, NONE, 0, 0 },
+/*f5*/ { "cmc", FALSE, NONE, 0, 0 },
+/*f6*/ { "", TRUE, BYTE, 0, (char *)db_Grp3 },
+/*f7*/ { "", TRUE, LONG, 0, (char *)db_Grp3 },
+
+/*f8*/ { "clc", FALSE, NONE, 0, 0 },
+/*f9*/ { "stc", FALSE, NONE, 0, 0 },
+/*fa*/ { "cli", FALSE, NONE, 0, 0 },
+/*fb*/ { "sti", FALSE, NONE, 0, 0 },
+/*fc*/ { "cld", FALSE, NONE, 0, 0 },
+/*fd*/ { "std", FALSE, NONE, 0, 0 },
+/*fe*/ { "", TRUE, NONE, 0, (char *)db_Grp4 },
+/*ff*/ { "", TRUE, NONE, 0, (char *)db_Grp5 },
+};
+
+struct inst db_bad_inst =
+ { "???", FALSE, NONE, 0, 0 }
+;
+
+#define f_mod(byte) ((byte)>>6)
+#define f_reg(byte) (((byte)>>3)&0x7)
+#define f_rm(byte) ((byte)&0x7)
+
+#define sib_ss(byte) ((byte)>>6)
+#define sib_index(byte) (((byte)>>3)&0x7)
+#define sib_base(byte) ((byte)&0x7)
+
+struct i_addr {
+ int is_reg; /* if reg, reg number is in 'disp' */
+ int disp;
+ char * base;
+ char * index;
+ int ss;
+};
+
+char * db_index_reg_16[8] = {
+ "%bx,%si",
+ "%bx,%di",
+ "%bp,%si",
+ "%bp,%di",
+ "%si",
+ "%di",
+ "%bp",
+ "%bx"
+};
+
+char * db_reg[3][8] = {
+ "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh",
+ "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di",
+ "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi"
+};
+
+char * db_seg_reg[8] = {
+ "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "", ""
+};
+
+/*
+ * lengths for size attributes
+ */
+int db_lengths[] = {
+ 1, /* BYTE */
+ 2, /* WORD */
+ 4, /* LONG */
+ 8, /* QUAD */
+ 4, /* SNGL */
+ 8, /* DBLR */
+ 10, /* EXTR */
+};
+
+#define get_value_inc(result, loc, size, is_signed) \
+ result = db_get_value((loc), (size), (is_signed)); \
+ (loc) += (size);
+
+/*
+ * Read address at location and return updated location.
+ */
+db_addr_t
+db_read_address(loc, short_addr, regmodrm, addrp)
+ db_addr_t loc;
+ int short_addr;
+ int regmodrm;
+ struct i_addr *addrp; /* out */
+{
+ int mod, rm, sib, index, ss, disp;
+
+ mod = f_mod(regmodrm);
+ rm = f_rm(regmodrm);
+
+ if (mod == 3) {
+ addrp->is_reg = TRUE;
+ addrp->disp = rm;
+ return (loc);
+ }
+ addrp->is_reg = FALSE;
+ addrp->index = 0;
+
+ if (short_addr) {
+ addrp->index = 0;
+ addrp->ss = 0;
+ switch (mod) {
+ case 0:
+ if (rm == 6) {
+ get_value_inc(disp, loc, 2, TRUE);
+ addrp->disp = disp;
+ addrp->base = 0;
+ }
+ else {
+ addrp->disp = 0;
+ addrp->base = db_index_reg_16[rm];
+ }
+ break;
+ case 1:
+ get_value_inc(disp, loc, 1, TRUE);
+ addrp->disp = disp;
+ addrp->base = db_index_reg_16[rm];
+ break;
+ case 2:
+ get_value_inc(disp, loc, 2, TRUE);
+ addrp->disp = disp;
+ addrp->base = db_index_reg_16[rm];
+ break;
+ }
+ }
+ else {
+ if (mod != 3 && rm == 4) {
+ get_value_inc(sib, loc, 1, FALSE);
+ rm = sib_base(sib);
+ index = sib_index(sib);
+ if (index != 4)
+ addrp->index = db_reg[LONG][index];
+ addrp->ss = sib_ss(sib);
+ }
+
+ switch (mod) {
+ case 0:
+ if (rm == 5) {
+ get_value_inc(addrp->disp, loc, 4, FALSE);
+ addrp->base = 0;
+ }
+ else {
+ addrp->disp = 0;
+ addrp->base = db_reg[LONG][rm];
+ }
+ break;
+
+ case 1:
+ get_value_inc(disp, loc, 1, TRUE);
+ addrp->disp = disp;
+ addrp->base = db_reg[LONG][rm];
+ break;
+
+ case 2:
+ get_value_inc(disp, loc, 4, FALSE);
+ addrp->disp = disp;
+ addrp->base = db_reg[LONG][rm];
+ break;
+ }
+ }
+ return (loc);
+}
+
+void
+db_print_address(seg, size, addrp)
+ char * seg;
+ int size;
+ struct i_addr *addrp;
+{
+ if (addrp->is_reg) {
+ db_printf("%s", db_reg[size][addrp->disp]);
+ return;
+ }
+
+ if (seg) {
+ db_printf("%s:", seg);
+ }
+
+ db_printsym((db_addr_t)addrp->disp, DB_STGY_ANY);
+ if (addrp->base != 0 || addrp->index != 0) {
+ db_printf("(");
+ if (addrp->base)
+ db_printf("%s", addrp->base);
+ if (addrp->index)
+ db_printf(",%s,%d", addrp->index, 1<<addrp->ss);
+ db_printf(")");
+ }
+}
+
+/*
+ * Disassemble floating-point ("escape") instruction
+ * and return updated location.
+ */
+db_addr_t
+db_disasm_esc(loc, inst, short_addr, size, seg)
+ db_addr_t loc;
+ int inst;
+ int short_addr;
+ int size;
+ char * seg;
+{
+ int regmodrm;
+ struct finst *fp;
+ int mod;
+ struct i_addr address;
+ char * name;
+
+ get_value_inc(regmodrm, loc, 1, FALSE);
+ fp = &db_Esc_inst[inst - 0xd8][f_reg(regmodrm)];
+ mod = f_mod(regmodrm);
+ if (mod != 3) {
+ /*
+ * Normal address modes.
+ */
+ loc = db_read_address(loc, short_addr, regmodrm, &address);
+ db_printf(fp->f_name);
+ switch(fp->f_size) {
+ case SNGL:
+ db_printf("s");
+ break;
+ case DBLR:
+ db_printf("l");
+ break;
+ case EXTR:
+ db_printf("t");
+ break;
+ case WORD:
+ db_printf("s");
+ break;
+ case LONG:
+ db_printf("l");
+ break;
+ case QUAD:
+ db_printf("q");
+ break;
+ default:
+ break;
+ }
+ db_printf("\t");
+ db_print_address(seg, BYTE, &address);
+ }
+ else {
+ /*
+ * 'reg-reg' - special formats
+ */
+ switch (fp->f_rrmode) {
+ case op2(ST,STI):
+ name = (fp->f_rrname) ? fp->f_rrname : fp->f_name;
+ db_printf("%s\t%%st,%%st(%d)",name,f_rm(regmodrm));
+ break;
+ case op2(STI,ST):
+ name = (fp->f_rrname) ? fp->f_rrname : fp->f_name;
+ db_printf("%s\t%%st(%d),%%st",name, f_rm(regmodrm));
+ break;
+ case op1(STI):
+ name = (fp->f_rrname) ? fp->f_rrname : fp->f_name;
+ db_printf("%s\t%%st(%d)",name, f_rm(regmodrm));
+ break;
+ case op1(X):
+ db_printf("%s", ((char **)fp->f_rrname)[f_rm(regmodrm)]);
+ break;
+ case op1(XA):
+ db_printf("%s\t%%ax",
+ ((char **)fp->f_rrname)[f_rm(regmodrm)]);
+ break;
+ default:
+ db_printf("<bad instruction>");
+ break;
+ }
+ }
+
+ return (loc);
+}
+
+/*
+ * Disassemble instruction at 'loc'. 'altfmt' specifies an
+ * (optional) alternate format. Return address of start of
+ * next instruction.
+ */
+db_addr_t
+db_disasm(loc, altfmt)
+ db_addr_t loc;
+ boolean_t altfmt;
+{
+ int inst;
+ int size;
+ int short_addr;
+ char * seg;
+ struct inst * ip;
+ char * i_name;
+ int i_size;
+ int i_mode;
+ int regmodrm = 0;
+ boolean_t first;
+ int displ;
+ int prefix;
+ int imm;
+ int imm2;
+ int len;
+ struct i_addr address;
+
+ get_value_inc(inst, loc, 1, FALSE);
+ short_addr = FALSE;
+ size = LONG;
+ seg = 0;
+
+ /*
+ * Get prefixes
+ */
+ prefix = TRUE;
+ do {
+ switch (inst) {
+ case 0x66: /* data16 */
+ size = WORD;
+ break;
+ case 0x67:
+ short_addr = TRUE;
+ break;
+ case 0x26:
+ seg = "%es";
+ break;
+ case 0x36:
+ seg = "%ss";
+ break;
+ case 0x2e:
+ seg = "%cs";
+ break;
+ case 0x3e:
+ seg = "%ds";
+ break;
+ case 0x64:
+ seg = "%fs";
+ break;
+ case 0x65:
+ seg = "%gs";
+ break;
+ case 0xf0:
+ db_printf("lock ");
+ break;
+ case 0xf2:
+ db_printf("repne ");
+ break;
+ case 0xf3:
+ db_printf("repe "); /* XXX repe VS rep */
+ break;
+ default:
+ prefix = FALSE;
+ break;
+ }
+ if (prefix) {
+ get_value_inc(inst, loc, 1, FALSE);
+ }
+ } while (prefix);
+
+ if (inst >= 0xd8 && inst <= 0xdf) {
+ loc = db_disasm_esc(loc, inst, short_addr, size, seg);
+ db_printf("\n");
+ return (loc);
+ }
+
+ if (inst == 0x0f) {
+ get_value_inc(inst, loc, 1, FALSE);
+ ip = db_inst_0f[inst>>4];
+ if (ip == 0) {
+ ip = &db_bad_inst;
+ }
+ else {
+ ip = &ip[inst&0xf];
+ }
+ }
+ else
+ ip = &db_inst_table[inst];
+
+ if (ip->i_has_modrm) {
+ get_value_inc(regmodrm, loc, 1, FALSE);
+ loc = db_read_address(loc, short_addr, regmodrm, &address);
+ }
+
+ i_name = ip->i_name;
+ i_size = ip->i_size;
+ i_mode = ip->i_mode;
+
+ if (ip->i_extra == (char *)db_Grp1 ||
+ ip->i_extra == (char *)db_Grp2 ||
+ ip->i_extra == (char *)db_Grp6 ||
+ ip->i_extra == (char *)db_Grp7 ||
+ ip->i_extra == (char *)db_Grp8) {
+ i_name = ((char **)ip->i_extra)[f_reg(regmodrm)];
+ }
+ else if (ip->i_extra == (char *)db_Grp3) {
+ ip = (struct inst *)ip->i_extra;
+ ip = &ip[f_reg(regmodrm)];
+ i_name = ip->i_name;
+ i_mode = ip->i_mode;
+ }
+ else if (ip->i_extra == (char *)db_Grp4 ||
+ ip->i_extra == (char *)db_Grp5) {
+ ip = (struct inst *)ip->i_extra;
+ ip = &ip[f_reg(regmodrm)];
+ i_name = ip->i_name;
+ i_mode = ip->i_mode;
+ i_size = ip->i_size;
+ }
+
+ if (i_size == SDEP) {
+ if (size == WORD)
+ db_printf(i_name);
+ else
+ db_printf(ip->i_extra);
+ }
+ else {
+ db_printf(i_name);
+ if (i_size != NONE) {
+ if (i_size == BYTE) {
+ db_printf("b");
+ size = BYTE;
+ }
+ else if (i_size == WORD) {
+ db_printf("w");
+ size = WORD;
+ }
+ else if (size == WORD)
+ db_printf("w");
+ else
+ db_printf("l");
+ }
+ }
+ db_printf("\t");
+ for (first = TRUE;
+ i_mode != 0;
+ i_mode >>= 8, first = FALSE)
+ {
+ if (!first)
+ db_printf(",");
+
+ switch (i_mode & 0xFF) {
+
+ case E:
+ db_print_address(seg, size, &address);
+ break;
+
+ case Eind:
+ db_printf("*");
+ db_print_address(seg, size, &address);
+ break;
+
+ case Ew:
+ db_print_address(seg, WORD, &address);
+ break;
+
+ case Eb:
+ db_print_address(seg, BYTE, &address);
+ break;
+
+ case R:
+ db_printf("%s", db_reg[size][f_reg(regmodrm)]);
+ break;
+
+ case Rw:
+ db_printf("%s", db_reg[WORD][f_reg(regmodrm)]);
+ break;
+
+ case Ri:
+ db_printf("%s", db_reg[size][f_rm(inst)]);
+ break;
+
+ case S:
+ db_printf("%s", db_seg_reg[f_reg(regmodrm)]);
+ break;
+
+ case Si:
+ db_printf("%s", db_seg_reg[f_reg(inst)]);
+ break;
+
+ case A:
+ db_printf("%s", db_reg[size][0]); /* acc */
+ break;
+
+ case BX:
+ if (seg)
+ db_printf("%s:", seg);
+ db_printf("(%s)", short_addr ? "%bx" : "%ebx");
+ break;
+
+ case CL:
+ db_printf("%%cl");
+ break;
+
+ case DX:
+ db_printf("%%dx");
+ break;
+
+ case SI:
+ if (seg)
+ db_printf("%s:", seg);
+ db_printf("(%s)", short_addr ? "%si" : "%esi");
+ break;
+
+ case DI:
+ db_printf("%%es:(%s)", short_addr ? "%di" : "%edi");
+ break;
+
+ case CR:
+ db_printf("%%cr%d", f_reg(regmodrm));
+ break;
+
+ case DR:
+ db_printf("%%dr%d", f_reg(regmodrm));
+ break;
+
+ case TR:
+ db_printf("%%tr%d", f_reg(regmodrm));
+ break;
+
+ case I:
+ len = db_lengths[size];
+ get_value_inc(imm, loc, len, FALSE);/* unsigned */
+ db_printf("$%#n", imm);
+ break;
+
+ case Is:
+ len = db_lengths[size];
+ get_value_inc(imm, loc, len, TRUE); /* signed */
+ db_printf("$%#r", imm);
+ break;
+
+ case Ib:
+ get_value_inc(imm, loc, 1, FALSE); /* unsigned */
+ db_printf("$%#n", imm);
+ break;
+
+ case Ibs:
+ get_value_inc(imm, loc, 1, TRUE); /* signed */
+ db_printf("$%#r", imm);
+ break;
+
+ case Iw:
+ get_value_inc(imm, loc, 2, FALSE); /* unsigned */
+ db_printf("$%#n", imm);
+ break;
+
+ case Il:
+ get_value_inc(imm, loc, 4, FALSE);
+ db_printf("$%#n", imm);
+ break;
+
+ case O:
+ if (short_addr) {
+ get_value_inc(displ, loc, 2, TRUE);
+ }
+ else {
+ get_value_inc(displ, loc, 4, TRUE);
+ }
+ if (seg)
+ db_printf("%s:%#r",seg, displ);
+ else
+ db_printsym((db_addr_t)displ, DB_STGY_ANY);
+ break;
+
+ case Db:
+ get_value_inc(displ, loc, 1, TRUE);
+ db_printsym((db_addr_t)(displ + loc), DB_STGY_XTRN);
+ break;
+
+ case Dl:
+ get_value_inc(displ, loc, 4, TRUE);
+ db_printsym((db_addr_t)(displ + loc), DB_STGY_XTRN);
+ break;
+
+ case o1:
+ db_printf("$1");
+ break;
+
+ case o3:
+ db_printf("$3");
+ break;
+
+ case OS:
+ get_value_inc(imm, loc, 4, FALSE); /* offset */
+ get_value_inc(imm2, loc, 2, FALSE); /* segment */
+ db_printf("$%#n,%#n", imm2, imm);
+ break;
+ }
+ }
+
+ if (altfmt == 0) {
+ if (inst == 0xe9 || inst == 0xeb) {
+ /*
+ * GAS pads to longword boundary after unconditional jumps.
+ */
+ loc = (loc + (4-1)) & ~(4-1);
+ }
+ }
+ db_printf("\n");
+ return (loc);
+}
+
diff --git a/sys/amd64/amd64/db_interface.c b/sys/amd64/amd64/db_interface.c
new file mode 100644
index 0000000..5f7c9d5
--- /dev/null
+++ b/sys/amd64/amd64/db_interface.c
@@ -0,0 +1,240 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_interface.c,v 1.5 1993/12/19 00:50:00 wollman Exp $
+ */
+
+/*
+ * Interface to new debugger.
+ */
+#include "param.h"
+#include "systm.h"
+#include "kernel.h"
+#include "proc.h"
+#include "ddb/ddb.h"
+
+#include <sys/reboot.h>
+#include <vm/vm_statistics.h>
+#include <vm/pmap.h>
+
+#include <setjmp.h>
+
+int db_active = 0;
+
+db_regs_t ddb_regs;
+
+/*
+ * Received keyboard interrupt sequence.
+ */
+void
+kdb_kbd_trap(regs)
+ struct i386_saved_state *regs;
+{
+ if (db_active == 0 && (boothowto & RB_KDB)) {
+ printf("\n\nkernel: keyboard interrupt\n");
+ kdb_trap(-1, 0, regs);
+ }
+}
+
+/*
+ * kdb_trap - field a TRACE or BPT trap
+ */
+
+static jmp_buf *db_nofault = 0;
+
+int
+kdb_trap(type, code, regs)
+ int type, code;
+ register struct i386_saved_state *regs;
+{
+#if 0
+ if ((boothowto&RB_KDB) == 0)
+ return(0);
+#endif
+
+ switch (type) {
+ case T_BPTFLT /* T_INT3 */: /* breakpoint */
+ case T_KDBTRAP /* T_WATCHPOINT */: /* watchpoint */
+ case T_PRIVINFLT /* T_DEBUG */: /* single_step */
+
+ case -1: /* keyboard interrupt */
+ break;
+
+ default:
+ kdbprinttrap(type, code);
+
+ if (db_nofault) {
+ jmp_buf *no_fault = db_nofault;
+ db_nofault = 0;
+ longjmp(*no_fault, 1);
+ }
+ }
+
+ /* Should switch to kdb`s own stack here. */
+
+ ddb_regs = *regs;
+
+ if ((regs->tf_cs & 0x3) == 0) {
+ /*
+ * Kernel mode - esp and ss not saved
+ */
+ ddb_regs.tf_esp = (int)&regs->tf_esp; /* kernel stack pointer */
+#if 0
+ ddb_regs.ss = KERNEL_DS;
+#endif
+ asm(" movw %%ss,%%ax; movl %%eax,%0 "
+ : "=g" (ddb_regs.tf_ss)
+ :
+ : "ax");
+ }
+
+ db_active++;
+ cnpollc(TRUE);
+ db_trap(type, code);
+ cnpollc(FALSE);
+ db_active--;
+
+ regs->tf_eip = ddb_regs.tf_eip;
+ regs->tf_eflags = ddb_regs.tf_eflags;
+ regs->tf_eax = ddb_regs.tf_eax;
+ regs->tf_ecx = ddb_regs.tf_ecx;
+ regs->tf_edx = ddb_regs.tf_edx;
+ regs->tf_ebx = ddb_regs.tf_ebx;
+ if (regs->tf_cs & 0x3) {
+ /*
+ * user mode - saved esp and ss valid
+ */
+ regs->tf_esp = ddb_regs.tf_esp; /* user stack pointer */
+ regs->tf_ss = ddb_regs.tf_ss & 0xffff; /* user stack segment */
+ }
+ regs->tf_ebp = ddb_regs.tf_ebp;
+ regs->tf_esi = ddb_regs.tf_esi;
+ regs->tf_edi = ddb_regs.tf_edi;
+ regs->tf_es = ddb_regs.tf_es & 0xffff;
+ regs->tf_cs = ddb_regs.tf_cs & 0xffff;
+ regs->tf_ds = ddb_regs.tf_ds & 0xffff;
+#if 0
+ regs->tf_fs = ddb_regs.tf_fs & 0xffff;
+ regs->tf_gs = ddb_regs.tf_gs & 0xffff;
+#endif
+
+ return (1);
+}
+
+/*
+ * Print trap reason.
+ */
+void
+kdbprinttrap(type, code)
+ int type, code;
+{
+ printf("kernel: ");
+ printf("type %d", type);
+ printf(" trap, code=%x\n", code);
+}
+
+/*
+ * Read bytes from kernel address space for debugger.
+ */
+
+extern jmp_buf db_jmpbuf;
+
+void
+db_read_bytes(addr, size, data)
+ vm_offset_t addr;
+ register int size;
+ register char *data;
+{
+ register char *src;
+
+ db_nofault = &db_jmpbuf;
+
+ src = (char *)addr;
+ while (--size >= 0)
+ *data++ = *src++;
+
+ db_nofault = 0;
+}
+
+/*
+ * Write bytes to kernel address space for debugger.
+ */
+void
+db_write_bytes(addr, size, data)
+ vm_offset_t addr;
+ register int size;
+ register char *data;
+{
+ register char *dst;
+
+ register pt_entry_t *ptep0 = 0;
+ pt_entry_t oldmap0 = { 0 };
+ vm_offset_t addr1;
+ register pt_entry_t *ptep1 = 0;
+ pt_entry_t oldmap1 = { 0 };
+ extern char etext;
+
+ db_nofault = &db_jmpbuf;
+
+ if (addr >= VM_MIN_KERNEL_ADDRESS &&
+ addr <= (vm_offset_t)&etext)
+ {
+ ptep0 = pmap_pte(kernel_pmap, addr);
+ oldmap0 = *ptep0;
+ *(int *)ptep0 |= /* INTEL_PTE_WRITE */ PG_RW;
+
+ addr1 = i386_trunc_page(addr + size - 1);
+ if (i386_trunc_page(addr) != addr1) {
+ /* data crosses a page boundary */
+
+ ptep1 = pmap_pte(kernel_pmap, addr1);
+ oldmap1 = *ptep1;
+ *(int *)ptep1 |= /* INTEL_PTE_WRITE */ PG_RW;
+ }
+ tlbflush();
+ }
+
+ dst = (char *)addr;
+
+ while (--size >= 0)
+ *dst++ = *data++;
+
+ db_nofault = 0;
+
+ if (ptep0) {
+ *ptep0 = oldmap0;
+ if (ptep1) {
+ *ptep1 = oldmap1;
+ }
+ tlbflush();
+ }
+}
+
+void
+Debugger (msg)
+ const char *msg;
+{
+ asm ("int $3");
+}
diff --git a/sys/amd64/amd64/db_trace.c b/sys/amd64/amd64/db_trace.c
new file mode 100644
index 0000000..c7c2cd8
--- /dev/null
+++ b/sys/amd64/amd64/db_trace.c
@@ -0,0 +1,339 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_trace.c,v 1.4 1994/01/03 07:55:19 davidg Exp $
+ */
+
+#include "param.h"
+
+#include <vm/vm_param.h>
+#include <vm/lock.h>
+#include <vm/vm_statistics.h>
+#include <machine/pmap.h>
+#include "systm.h"
+#include "proc.h"
+#include "ddb/ddb.h"
+
+#include <ddb/db_access.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_variables.h>
+
+/*
+ * Machine register set.
+ */
+struct db_variable db_regs[] = {
+ "cs", (int *)&ddb_regs.tf_cs, FCN_NULL,
+ "ds", (int *)&ddb_regs.tf_ds, FCN_NULL,
+ "es", (int *)&ddb_regs.tf_es, FCN_NULL,
+#if 0
+ "fs", (int *)&ddb_regs.tf_fs, FCN_NULL,
+ "gs", (int *)&ddb_regs.tf_gs, FCN_NULL,
+#endif
+ "ss", (int *)&ddb_regs.tf_ss, FCN_NULL,
+ "eax", (int *)&ddb_regs.tf_eax, FCN_NULL,
+ "ecx", (int *)&ddb_regs.tf_ecx, FCN_NULL,
+ "edx", (int *)&ddb_regs.tf_edx, FCN_NULL,
+ "ebx", (int *)&ddb_regs.tf_ebx, FCN_NULL,
+ "esp", (int *)&ddb_regs.tf_esp,FCN_NULL,
+ "ebp", (int *)&ddb_regs.tf_ebp, FCN_NULL,
+ "esi", (int *)&ddb_regs.tf_esi, FCN_NULL,
+ "edi", (int *)&ddb_regs.tf_edi, FCN_NULL,
+ "eip", (int *)&ddb_regs.tf_eip, FCN_NULL,
+ "efl", (int *)&ddb_regs.tf_eflags, FCN_NULL,
+};
+struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
+
+/*
+ * Stack trace.
+ */
+#define INKERNEL(va) (((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
+
+struct i386_frame {
+ struct i386_frame *f_frame;
+ int f_retaddr;
+ int f_arg0;
+};
+
+#define TRAP 1
+#define INTERRUPT 2
+#define SYSCALL 3
+
+db_addr_t db_trap_symbol_value = 0;
+db_addr_t db_syscall_symbol_value = 0;
+db_addr_t db_kdintr_symbol_value = 0;
+boolean_t db_trace_symbols_found = FALSE;
+
+void
+db_find_trace_symbols()
+{
+ db_expr_t value;
+ if (db_value_of_name("_trap", &value))
+ db_trap_symbol_value = (db_addr_t) value;
+ if (db_value_of_name("_kdintr", &value))
+ db_kdintr_symbol_value = (db_addr_t) value;
+ if (db_value_of_name("_syscall", &value))
+ db_syscall_symbol_value = (db_addr_t) value;
+ db_trace_symbols_found = TRUE;
+}
+
+/*
+ * Figure out how many arguments were passed into the frame at "fp".
+ */
+int
+db_numargs(fp)
+ struct i386_frame *fp;
+{
+ int *argp;
+ int inst;
+ int args;
+ extern char etext[];
+
+ argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE);
+ if (argp < (int *)VM_MIN_KERNEL_ADDRESS || argp > (int *)etext)
+ args = 5;
+ else {
+ inst = db_get_value((int)argp, 4, FALSE);
+ if ((inst & 0xff) == 0x59) /* popl %ecx */
+ args = 1;
+ else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */
+ args = ((inst >> 16) & 0xff) / 4;
+ else
+ args = 5;
+ }
+ return (args);
+}
+
+/*
+ * Figure out the next frame up in the call stack.
+ * For trap(), we print the address of the faulting instruction and
+ * proceed with the calling frame. We return the ip that faulted.
+ * If the trap was caused by jumping through a bogus pointer, then
+ * the next line in the backtrace will list some random function as
+ * being called. It should get the argument list correct, though.
+ * It might be possible to dig out from the next frame up the name
+ * of the function that faulted, but that could get hairy.
+ */
+void
+db_nextframe(fp, ip, argp, is_trap)
+ struct i386_frame **fp; /* in/out */
+ db_addr_t *ip; /* out */
+ int *argp; /* in */
+ int is_trap; /* in */
+{
+ struct i386_saved_state *saved_regs;
+
+ switch (is_trap) {
+ case 0:
+ *ip = (db_addr_t)
+ db_get_value((int) &(*fp)->f_retaddr, 4, FALSE);
+ *fp = (struct i386_frame *)
+ db_get_value((int) &(*fp)->f_frame, 4, FALSE);
+ break;
+ case TRAP:
+ default:
+ /*
+ * We know that trap() has 1 argument and we know that
+ * it is an (int *).
+ */
+#if 0
+ saved_regs = (struct i386_saved_state *)
+ db_get_value((int)argp, 4, FALSE);
+#endif
+ saved_regs = (struct i386_saved_state *)argp;
+ db_printf("--- trap (number %d) ---\n",
+ saved_regs->tf_trapno & 0xffff);
+ db_printsym(saved_regs->tf_eip, DB_STGY_XTRN);
+ db_printf(":\n");
+ *fp = (struct i386_frame *)saved_regs->tf_ebp;
+ *ip = (db_addr_t)saved_regs->tf_eip;
+ break;
+
+ case SYSCALL: {
+ struct trapframe *saved_regs = (struct trapframe *)argp;
+
+ db_printf("--- syscall (number %d) ---\n", saved_regs->tf_eax);
+ db_printsym(saved_regs->tf_eip, DB_STGY_XTRN);
+ db_printf(":\n");
+ *fp = (struct i386_frame *)saved_regs->tf_ebp;
+ *ip = (db_addr_t)saved_regs->tf_eip;
+ }
+ break;
+ }
+}
+
+void
+db_stack_trace_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ boolean_t have_addr;
+ db_expr_t count;
+ char *modif;
+{
+ struct i386_frame *frame, *lastframe;
+ int *argp;
+ db_addr_t callpc;
+ int is_trap;
+ boolean_t kernel_only = TRUE;
+ boolean_t trace_thread = FALSE;
+
+#if 0
+ if (!db_trace_symbols_found)
+ db_find_trace_symbols();
+#endif
+
+ {
+ register char *cp = modif;
+ register char c;
+
+ while ((c = *cp++) != 0) {
+ if (c == 't')
+ trace_thread = TRUE;
+ if (c == 'u')
+ kernel_only = FALSE;
+ }
+ }
+
+ if (count == -1)
+ count = 65535;
+
+ if (!have_addr) {
+ frame = (struct i386_frame *)ddb_regs.tf_ebp;
+ callpc = (db_addr_t)ddb_regs.tf_eip;
+ }
+ else if (trace_thread) {
+ printf ("db_trace.c: can't trace thread\n");
+ }
+ else {
+ frame = (struct i386_frame *)addr;
+ callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE);
+ }
+
+ lastframe = 0;
+ while (count-- && frame != 0) {
+ int narg;
+ char * name;
+ db_expr_t offset;
+ db_sym_t sym;
+#define MAXNARG 16
+ char *argnames[MAXNARG], **argnp = NULL;
+
+ sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
+ db_symbol_values(sym, &name, NULL);
+
+ if (lastframe == 0 && sym == NULL) {
+ /* Symbol not found, peek at code */
+ int instr = db_get_value(callpc, 4, FALSE);
+
+ offset = 1;
+ if ((instr & 0x00ffffff) == 0x00e58955 ||
+ /* enter: pushl %ebp, movl %esp, %ebp */
+ (instr & 0x0000ffff) == 0x0000e589
+ /* enter+1: movl %esp, %ebp */ ) {
+ offset = 0;
+ }
+ }
+#define STRCMP(s1,s2) ((s1) && (s2) && strcmp((s1), (s2)) == 0)
+ if (INKERNEL((int)frame) && STRCMP(name, "_trap")) {
+ narg = 1;
+ is_trap = TRAP;
+ }
+ else
+ if (INKERNEL((int)frame) && STRCMP(name, "_kdintr")) {
+ is_trap = INTERRUPT;
+ narg = 0;
+ }
+ else
+ if (INKERNEL((int)frame) && STRCMP(name, "_syscall")) {
+ is_trap = SYSCALL;
+ narg = 0;
+ }
+#undef STRCMP
+ else {
+ is_trap = 0;
+ narg = MAXNARG;
+ if (db_sym_numargs(sym, &narg, argnames)) {
+ argnp = argnames;
+ } else {
+ narg = db_numargs(frame);
+ }
+ }
+
+ db_printf("%s(", name);
+
+ if (lastframe == 0 && offset == 0 && !have_addr) {
+ /*
+ * We have a breakpoint before the frame is set up
+ * Use %esp instead
+ */
+ argp = &((struct i386_frame *)(ddb_regs.tf_esp-4))->f_arg0;
+ } else
+ argp = &frame->f_arg0;
+
+ while (narg) {
+ if (argnp)
+ db_printf("%s=", *argnp++);
+ db_printf("%x", db_get_value((int)argp, 4, FALSE));
+ argp++;
+ if (--narg != 0)
+ db_printf(",");
+ }
+ db_printf(") at ");
+ db_printsym(callpc, DB_STGY_PROC);
+ db_printf("\n");
+
+ if (lastframe == 0 && offset == 0 && !have_addr) {
+ /* Frame really belongs to next callpc */
+ lastframe = (struct i386_frame *)(ddb_regs.tf_esp-4);
+ callpc = (db_addr_t)db_get_value((int)&lastframe->f_retaddr, 4, FALSE);
+ continue;
+ }
+
+ lastframe = frame;
+ db_nextframe(&frame, &callpc, &frame->f_arg0, is_trap);
+
+ if (frame == 0) {
+ /* end of chain */
+ break;
+ }
+ if (INKERNEL((int)frame)) {
+ /* staying in kernel */
+ if (frame <= lastframe) {
+ db_printf("Bad frame pointer: 0x%x\n", frame);
+ break;
+ }
+ }
+ else if (INKERNEL((int)lastframe)) {
+ /* switch from user to kernel */
+ if (kernel_only)
+ break; /* kernel stack only */
+ }
+ else {
+ /* in user */
+ if (frame <= lastframe) {
+ db_printf("Bad user frame pointer: 0x%x\n", frame);
+ break;
+ }
+ }
+ }
+}
diff --git a/sys/amd64/amd64/exception.S b/sys/amd64/amd64/exception.S
new file mode 100644
index 0000000..30bc164
--- /dev/null
+++ b/sys/amd64/amd64/exception.S
@@ -0,0 +1,275 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: exception.s,v 1.2 1994/01/03 07:55:20 davidg Exp $
+ */
+
+#include "npx.h" /* NNPX */
+
+#include "assym.s" /* system defines */
+
+#include "errno.h" /* error return codes */
+
+#include "machine/spl.h" /* SWI_AST_MASK ... */
+
+#include "machine/psl.h" /* PSL_I */
+
+#include "machine/trap.h" /* trap codes */
+#include "syscall.h" /* syscall numbers */
+
+#include "machine/asmacros.h" /* miscellaneous macros */
+
+#define KDSEL 0x10 /* kernel data selector */
+#define SEL_RPL_MASK 0x0003
+#define TRAPF_CS_OFF (13 * 4)
+
+ .text
+
+/*****************************************************************************/
+/* Trap handling */
+/*****************************************************************************/
+/*
+ * Trap and fault vector routines
+ */
+#define IDTVEC(name) ALIGN_TEXT ; .globl _X/**/name ; _X/**/name:
+#define TRAP(a) pushl $(a) ; jmp _alltraps
+
+/*
+ * XXX - debugger traps are now interrupt gates so at least bdb doesn't lose
+ * control. The sti's give the standard losing behaviour for ddb and kgdb.
+ */
+#ifdef BDE_DEBUGGER
+#define BDBTRAP(name) \
+ ss ; \
+ cmpb $0,_bdb_exists ; \
+ je 1f ; \
+ testb $SEL_RPL_MASK,4(%esp) ; \
+ jne 1f ; \
+ ss ; \
+ .globl bdb_/**/name/**/_ljmp ; \
+bdb_/**/name/**/_ljmp: ; \
+ ljmp $0,$0 ; \
+1:
+#else
+#define BDBTRAP(name)
+#endif
+
+#ifdef KGDB
+# define BPTTRAP(a) testl $PSL_I,4+8(%esp) ; je 1f ; sti ; 1: ; \
+ pushl $(a) ; jmp _bpttraps
+#else
+# define BPTTRAP(a) testl $PSL_I,4+8(%esp) ; je 1f ; sti ; 1: ; TRAP(a)
+#endif
+
+MCOUNT_LABEL(user)
+MCOUNT_LABEL(btrap)
+
+IDTVEC(div)
+ pushl $0; TRAP(T_DIVIDE)
+IDTVEC(dbg)
+ BDBTRAP(dbg)
+ pushl $0; BPTTRAP(T_TRCTRAP)
+IDTVEC(nmi)
+ pushl $0; TRAP(T_NMI)
+IDTVEC(bpt)
+ BDBTRAP(bpt)
+ pushl $0; BPTTRAP(T_BPTFLT)
+IDTVEC(ofl)
+ pushl $0; TRAP(T_OFLOW)
+IDTVEC(bnd)
+ pushl $0; TRAP(T_BOUND)
+IDTVEC(ill)
+ pushl $0; TRAP(T_PRIVINFLT)
+IDTVEC(dna)
+ pushl $0; TRAP(T_DNA)
+IDTVEC(dble)
+ TRAP(T_DOUBLEFLT)
+IDTVEC(fpusegm)
+ pushl $0; TRAP(T_FPOPFLT)
+IDTVEC(tss)
+ TRAP(T_TSSFLT)
+IDTVEC(missing)
+ TRAP(T_SEGNPFLT)
+IDTVEC(stk)
+ TRAP(T_STKFLT)
+IDTVEC(prot)
+ TRAP(T_PROTFLT)
+IDTVEC(page)
+ TRAP(T_PAGEFLT)
+IDTVEC(rsvd)
+ pushl $0; TRAP(T_RESERVED)
+IDTVEC(fpu)
+#if NNPX > 0
+ /*
+ * Handle like an interrupt so that we can call npxintr to clear the
+ * error. It would be better to handle npx interrupts as traps but
+ * this is difficult for nested interrupts.
+ */
+ pushl $0 /* dumby error code */
+ pushl $0 /* dumby trap type */
+ pushal
+ pushl %ds
+ pushl %es /* now the stack frame is a trap frame */
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+ FAKE_MCOUNT(12*4(%esp))
+ movl _cpl,%eax
+ pushl %eax
+ pushl $0 /* dummy unit to finish building intr frame */
+ incl _cnt+V_TRAP
+ orl $SWI_AST_MASK,%eax
+ movl %eax,_cpl
+ call _npxintr
+ MEXITCOUNT
+ jmp _doreti
+#else /* NNPX > 0 */
+ pushl $0; TRAP(T_ARITHTRAP)
+#endif /* NNPX > 0 */
+ /* 17 - 31 reserved for future exp */
+IDTVEC(rsvd0)
+ pushl $0; TRAP(17)
+IDTVEC(rsvd1)
+ pushl $0; TRAP(18)
+IDTVEC(rsvd2)
+ pushl $0; TRAP(19)
+IDTVEC(rsvd3)
+ pushl $0; TRAP(20)
+IDTVEC(rsvd4)
+ pushl $0; TRAP(21)
+IDTVEC(rsvd5)
+ pushl $0; TRAP(22)
+IDTVEC(rsvd6)
+ pushl $0; TRAP(23)
+IDTVEC(rsvd7)
+ pushl $0; TRAP(24)
+IDTVEC(rsvd8)
+ pushl $0; TRAP(25)
+IDTVEC(rsvd9)
+ pushl $0; TRAP(26)
+IDTVEC(rsvd10)
+ pushl $0; TRAP(27)
+IDTVEC(rsvd11)
+ pushl $0; TRAP(28)
+IDTVEC(rsvd12)
+ pushl $0; TRAP(29)
+IDTVEC(rsvd13)
+ pushl $0; TRAP(30)
+IDTVEC(rsvd14)
+ pushl $0; TRAP(31)
+
+ SUPERALIGN_TEXT
+_alltraps:
+ pushal
+ pushl %ds
+ pushl %es
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+ FAKE_MCOUNT(12*4(%esp))
+calltrap:
+ FAKE_MCOUNT(_btrap) /* init "from" _btrap -> calltrap */
+ incl _cnt+V_TRAP
+ orl $SWI_AST_MASK,_cpl
+ call _trap
+ /*
+ * There was no place to save the cpl so we have to recover it
+ * indirectly. For traps from user mode it was 0, and for traps
+ * from kernel mode Oring SWI_AST_MASK into it didn't change it.
+ */
+ subl %eax,%eax
+ testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp)
+ jne 1f
+ movl _cpl,%eax
+1:
+ /*
+ * Return via _doreti to handle ASTs. Have to change trap frame
+ * to interrupt frame.
+ */
+ pushl %eax
+ subl $4,%esp
+ MEXITCOUNT
+ jmp _doreti
+
+#ifdef KGDB
+/*
+ * This code checks for a kgdb trap, then falls through
+ * to the regular trap code.
+ */
+ SUPERALIGN_TEXT
+_bpttraps:
+ pushal
+ pushl %ds
+ pushl %es
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+ FAKE_MCOUNT(12*4(%esp))
+ testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp) /* non-kernel mode? */
+ jne calltrap /* yes */
+ call _kgdb_trap_glue
+ MEXITCOUNT
+ jmp calltrap
+#endif
+
+/*
+ * Call gate entry for syscall
+ */
+ SUPERALIGN_TEXT
+IDTVEC(syscall)
+ pushfl /* Room for tf_err */
+ pushfl /* Room for tf_trapno */
+ pushal
+ pushl %ds
+ pushl %es
+ movl $KDSEL,%eax /* switch to kernel segments */
+ movl %ax,%ds
+ movl %ax,%es
+ movl TF_ERR(%esp),%eax /* copy eflags from tf_err to fs_eflags */
+ movl %eax,TF_EFLAGS(%esp)
+ FAKE_MCOUNT(12*4(%esp))
+ incl _cnt+V_SYSCALL
+ movl $SWI_AST_MASK,_cpl
+ call _syscall
+ /*
+ * Return via _doreti to handle ASTs.
+ */
+ pushl $0 /* cpl to restore */
+ subl $4,%esp
+ MEXITCOUNT
+ jmp _doreti
+
+/*
+ * include generated interrupt vectors and ISA intr code
+ */
+#include "i386/isa/vector.s"
+#include "i386/isa/icu.s"
diff --git a/sys/amd64/amd64/exception.s b/sys/amd64/amd64/exception.s
new file mode 100644
index 0000000..30bc164
--- /dev/null
+++ b/sys/amd64/amd64/exception.s
@@ -0,0 +1,275 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: exception.s,v 1.2 1994/01/03 07:55:20 davidg Exp $
+ */
+
+#include "npx.h" /* NNPX */
+
+#include "assym.s" /* system defines */
+
+#include "errno.h" /* error return codes */
+
+#include "machine/spl.h" /* SWI_AST_MASK ... */
+
+#include "machine/psl.h" /* PSL_I */
+
+#include "machine/trap.h" /* trap codes */
+#include "syscall.h" /* syscall numbers */
+
+#include "machine/asmacros.h" /* miscellaneous macros */
+
+#define KDSEL 0x10 /* kernel data selector */
+#define SEL_RPL_MASK 0x0003
+#define TRAPF_CS_OFF (13 * 4)
+
+ .text
+
+/*****************************************************************************/
+/* Trap handling */
+/*****************************************************************************/
+/*
+ * Trap and fault vector routines
+ */
+#define IDTVEC(name) ALIGN_TEXT ; .globl _X/**/name ; _X/**/name:
+#define TRAP(a) pushl $(a) ; jmp _alltraps
+
+/*
+ * XXX - debugger traps are now interrupt gates so at least bdb doesn't lose
+ * control. The sti's give the standard losing behaviour for ddb and kgdb.
+ */
+#ifdef BDE_DEBUGGER
+#define BDBTRAP(name) \
+ ss ; \
+ cmpb $0,_bdb_exists ; \
+ je 1f ; \
+ testb $SEL_RPL_MASK,4(%esp) ; \
+ jne 1f ; \
+ ss ; \
+ .globl bdb_/**/name/**/_ljmp ; \
+bdb_/**/name/**/_ljmp: ; \
+ ljmp $0,$0 ; \
+1:
+#else
+#define BDBTRAP(name)
+#endif
+
+#ifdef KGDB
+# define BPTTRAP(a) testl $PSL_I,4+8(%esp) ; je 1f ; sti ; 1: ; \
+ pushl $(a) ; jmp _bpttraps
+#else
+# define BPTTRAP(a) testl $PSL_I,4+8(%esp) ; je 1f ; sti ; 1: ; TRAP(a)
+#endif
+
+MCOUNT_LABEL(user)
+MCOUNT_LABEL(btrap)
+
+IDTVEC(div)
+ pushl $0; TRAP(T_DIVIDE)
+IDTVEC(dbg)
+ BDBTRAP(dbg)
+ pushl $0; BPTTRAP(T_TRCTRAP)
+IDTVEC(nmi)
+ pushl $0; TRAP(T_NMI)
+IDTVEC(bpt)
+ BDBTRAP(bpt)
+ pushl $0; BPTTRAP(T_BPTFLT)
+IDTVEC(ofl)
+ pushl $0; TRAP(T_OFLOW)
+IDTVEC(bnd)
+ pushl $0; TRAP(T_BOUND)
+IDTVEC(ill)
+ pushl $0; TRAP(T_PRIVINFLT)
+IDTVEC(dna)
+ pushl $0; TRAP(T_DNA)
+IDTVEC(dble)
+ TRAP(T_DOUBLEFLT)
+IDTVEC(fpusegm)
+ pushl $0; TRAP(T_FPOPFLT)
+IDTVEC(tss)
+ TRAP(T_TSSFLT)
+IDTVEC(missing)
+ TRAP(T_SEGNPFLT)
+IDTVEC(stk)
+ TRAP(T_STKFLT)
+IDTVEC(prot)
+ TRAP(T_PROTFLT)
+IDTVEC(page)
+ TRAP(T_PAGEFLT)
+IDTVEC(rsvd)
+ pushl $0; TRAP(T_RESERVED)
+IDTVEC(fpu)
+#if NNPX > 0
+ /*
+ * Handle like an interrupt so that we can call npxintr to clear the
+ * error. It would be better to handle npx interrupts as traps but
+ * this is difficult for nested interrupts.
+ */
+ pushl $0 /* dumby error code */
+ pushl $0 /* dumby trap type */
+ pushal
+ pushl %ds
+ pushl %es /* now the stack frame is a trap frame */
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+ FAKE_MCOUNT(12*4(%esp))
+ movl _cpl,%eax
+ pushl %eax
+ pushl $0 /* dummy unit to finish building intr frame */
+ incl _cnt+V_TRAP
+ orl $SWI_AST_MASK,%eax
+ movl %eax,_cpl
+ call _npxintr
+ MEXITCOUNT
+ jmp _doreti
+#else /* NNPX > 0 */
+ pushl $0; TRAP(T_ARITHTRAP)
+#endif /* NNPX > 0 */
+ /* 17 - 31 reserved for future exp */
+IDTVEC(rsvd0)
+ pushl $0; TRAP(17)
+IDTVEC(rsvd1)
+ pushl $0; TRAP(18)
+IDTVEC(rsvd2)
+ pushl $0; TRAP(19)
+IDTVEC(rsvd3)
+ pushl $0; TRAP(20)
+IDTVEC(rsvd4)
+ pushl $0; TRAP(21)
+IDTVEC(rsvd5)
+ pushl $0; TRAP(22)
+IDTVEC(rsvd6)
+ pushl $0; TRAP(23)
+IDTVEC(rsvd7)
+ pushl $0; TRAP(24)
+IDTVEC(rsvd8)
+ pushl $0; TRAP(25)
+IDTVEC(rsvd9)
+ pushl $0; TRAP(26)
+IDTVEC(rsvd10)
+ pushl $0; TRAP(27)
+IDTVEC(rsvd11)
+ pushl $0; TRAP(28)
+IDTVEC(rsvd12)
+ pushl $0; TRAP(29)
+IDTVEC(rsvd13)
+ pushl $0; TRAP(30)
+IDTVEC(rsvd14)
+ pushl $0; TRAP(31)
+
+ SUPERALIGN_TEXT
+_alltraps:
+ pushal
+ pushl %ds
+ pushl %es
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+ FAKE_MCOUNT(12*4(%esp))
+calltrap:
+ FAKE_MCOUNT(_btrap) /* init "from" _btrap -> calltrap */
+ incl _cnt+V_TRAP
+ orl $SWI_AST_MASK,_cpl
+ call _trap
+ /*
+ * There was no place to save the cpl so we have to recover it
+ * indirectly. For traps from user mode it was 0, and for traps
+ * from kernel mode Oring SWI_AST_MASK into it didn't change it.
+ */
+ subl %eax,%eax
+ testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp)
+ jne 1f
+ movl _cpl,%eax
+1:
+ /*
+ * Return via _doreti to handle ASTs. Have to change trap frame
+ * to interrupt frame.
+ */
+ pushl %eax
+ subl $4,%esp
+ MEXITCOUNT
+ jmp _doreti
+
+#ifdef KGDB
+/*
+ * This code checks for a kgdb trap, then falls through
+ * to the regular trap code.
+ */
+ SUPERALIGN_TEXT
+_bpttraps:
+ pushal
+ pushl %ds
+ pushl %es
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+ FAKE_MCOUNT(12*4(%esp))
+ testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp) /* non-kernel mode? */
+ jne calltrap /* yes */
+ call _kgdb_trap_glue
+ MEXITCOUNT
+ jmp calltrap
+#endif
+
+/*
+ * Call gate entry for syscall
+ */
+ SUPERALIGN_TEXT
+IDTVEC(syscall)
+ pushfl /* Room for tf_err */
+ pushfl /* Room for tf_trapno */
+ pushal
+ pushl %ds
+ pushl %es
+ movl $KDSEL,%eax /* switch to kernel segments */
+ movl %ax,%ds
+ movl %ax,%es
+ movl TF_ERR(%esp),%eax /* copy eflags from tf_err to fs_eflags */
+ movl %eax,TF_EFLAGS(%esp)
+ FAKE_MCOUNT(12*4(%esp))
+ incl _cnt+V_SYSCALL
+ movl $SWI_AST_MASK,_cpl
+ call _syscall
+ /*
+ * Return via _doreti to handle ASTs.
+ */
+ pushl $0 /* cpl to restore */
+ subl $4,%esp
+ MEXITCOUNT
+ jmp _doreti
+
+/*
+ * include generated interrupt vectors and ISA intr code
+ */
+#include "i386/isa/vector.s"
+#include "i386/isa/icu.s"
diff --git a/sys/amd64/amd64/fpu.c b/sys/amd64/amd64/fpu.c
new file mode 100644
index 0000000..00424bf
--- /dev/null
+++ b/sys/amd64/amd64/fpu.c
@@ -0,0 +1,552 @@
+/*-
+ * Copyright (c) 1990 William Jolitz.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)npx.c 7.2 (Berkeley) 5/12/91
+ * $Id: npx.c,v 1.6 1994/01/03 07:55:43 davidg Exp $
+ */
+
+#include "npx.h"
+#if NNPX > 0
+
+#include "param.h"
+#include "systm.h"
+#include "conf.h"
+#include "file.h"
+#include "proc.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+#include "machine/trap.h"
+#include "ioctl.h"
+#include "machine/specialreg.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/isa.h"
+
+/*
+ * 387 and 287 Numeric Coprocessor Extension (NPX) Driver.
+ */
+
+#ifdef __GNUC__
+
+#define disable_intr() __asm("cli")
+#define enable_intr() __asm("sti")
+#define fldcw(addr) __asm("fldcw %0" : : "m" (*addr))
+#define fnclex() __asm("fnclex")
+#define fninit() __asm("fninit")
+#define fnsave(addr) __asm("fnsave %0" : "=m" (*addr) : "0" (*addr))
+#define fnstcw(addr) __asm("fnstcw %0" : "=m" (*addr) : "0" (*addr))
+#define fnstsw(addr) __asm("fnstsw %0" : "=m" (*addr) : "0" (*addr))
+#define fp_divide_by_0() __asm("fldz; fld1; fdiv %st,%st(1); fwait")
+#define frstor(addr) __asm("frstor %0" : : "m" (*addr))
+#define fwait() __asm("fwait")
+#define read_eflags() ({u_long ef; \
+ __asm("pushf; popl %0" : "=a" (ef)); \
+ ef; })
+#define start_emulating() __asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \
+ : : "n" (CR0_TS) : "ax")
+#define stop_emulating() __asm("clts")
+#define write_eflags(ef) __asm("pushl %0; popf" : : "a" ((u_long) ef))
+
+#else /* not __GNUC__ */
+
+void disable_intr __P((void));
+void enable_intr __P((void));
+void fldcw __P((caddr_t addr));
+void fnclex __P((void));
+void fninit __P((void));
+void fnsave __P((caddr_t addr));
+void fnstcw __P((caddr_t addr));
+void fnstsw __P((caddr_t addr));
+void fp_divide_by_0 __P((void));
+void frstor __P((caddr_t addr));
+void fwait __P((void));
+u_long read_eflags __P((void));
+void start_emulating __P((void));
+void stop_emulating __P((void));
+void write_eflags __P((u_long ef));
+
+#endif /* __GNUC__ */
+
+typedef u_char bool_t;
+
+extern struct gate_descriptor idt[];
+
+int npxdna __P((void));
+void npxexit __P((struct proc *p));
+void npxinit __P((u_int control));
+void npxintr __P((struct intrframe frame));
+void npxsave __P((struct save87 *addr));
+static int npxattach __P((struct isa_device *dvp));
+static int npxprobe __P((struct isa_device *dvp));
+static int npxprobe1 __P((struct isa_device *dvp));
+
+struct isa_driver npxdriver = {
+ npxprobe, npxattach, "npx",
+};
+
+u_int npx0_imask;
+struct proc *npxproc;
+
+static bool_t npx_ex16;
+static bool_t npx_exists;
+static struct gate_descriptor npx_idt_probeintr;
+static int npx_intrno;
+static volatile u_int npx_intrs_while_probing;
+static bool_t npx_irq13;
+static volatile u_int npx_traps_while_probing;
+
+/*
+ * Special interrupt handlers. Someday intr0-intr15 will be used to count
+ * interrupts. We'll still need a special exception 16 handler. The busy
+ * latch stuff in probintr() can be moved to npxprobe().
+ */
+void probeintr(void);
+asm
+("
+ .text
+_probeintr:
+ ss
+ incl _npx_intrs_while_probing
+ pushl %eax
+ movb $0x20,%al # EOI (asm in strings loses cpp features)
+ outb %al,$0xa0 # IO_ICU2
+ outb %al,$0x20 #IO_ICU1
+ movb $0,%al
+ outb %al,$0xf0 # clear BUSY# latch
+ popl %eax
+ iret
+");
+
+void probetrap(void);
+asm
+("
+ .text
+_probetrap:
+ ss
+ incl _npx_traps_while_probing
+ fnclex
+ iret
+");
+
+/*
+ * Probe routine. Initialize cr0 to give correct behaviour for [f]wait
+ * whether the device exists or not (XXX should be elsewhere). Set flags
+ * to tell npxattach() what to do. Modify device struct if npx doesn't
+ * need to use interrupts. Return 1 if device exists.
+ */
+static int
+npxprobe(dvp)
+ struct isa_device *dvp;
+{
+ int result;
+ u_long save_eflags;
+ u_char save_icu1_mask;
+ u_char save_icu2_mask;
+ struct gate_descriptor save_idt_npxintr;
+ struct gate_descriptor save_idt_npxtrap;
+ /*
+ * This routine is now just a wrapper for npxprobe1(), to install
+ * special npx interrupt and trap handlers, to enable npx interrupts
+ * and to disable other interrupts. Someday isa_configure() will
+ * install suitable handlers and run with interrupts enabled so we
+ * won't need to do so much here.
+ */
+ npx_intrno = NRSVIDT + ffs(dvp->id_irq) - 1;
+ save_eflags = read_eflags();
+ disable_intr();
+ save_icu1_mask = inb(IO_ICU1 + 1);
+ save_icu2_mask = inb(IO_ICU2 + 1);
+ save_idt_npxintr = idt[npx_intrno];
+ save_idt_npxtrap = idt[16];
+ outb(IO_ICU1 + 1, ~(IRQ_SLAVE | dvp->id_irq));
+ outb(IO_ICU2 + 1, ~(dvp->id_irq >> 8));
+ setidt(16, probetrap, SDT_SYS386TGT, SEL_KPL);
+ setidt(npx_intrno, probeintr, SDT_SYS386IGT, SEL_KPL);
+ npx_idt_probeintr = idt[npx_intrno];
+ enable_intr();
+ result = npxprobe1(dvp);
+ disable_intr();
+ outb(IO_ICU1 + 1, save_icu1_mask);
+ outb(IO_ICU2 + 1, save_icu2_mask);
+ idt[npx_intrno] = save_idt_npxintr;
+ idt[16] = save_idt_npxtrap;
+ write_eflags(save_eflags);
+ return (result);
+}
+
+static int
+npxprobe1(dvp)
+ struct isa_device *dvp;
+{
+ int control;
+ int status;
+#ifdef lint
+ npxintr();
+#endif
+ /*
+ * Partially reset the coprocessor, if any. Some BIOS's don't reset
+ * it after a warm boot.
+ */
+ outb(0xf1, 0); /* full reset on some systems, NOP on others */
+ outb(0xf0, 0); /* clear BUSY# latch */
+ /*
+ * Prepare to trap all ESC (i.e., NPX) instructions and all WAIT
+ * instructions. We must set the CR0_MP bit and use the CR0_TS
+ * bit to control the trap, because setting the CR0_EM bit does
+ * not cause WAIT instructions to trap. It's important to trap
+ * WAIT instructions - otherwise the "wait" variants of no-wait
+ * control instructions would degenerate to the "no-wait" variants
+ * after FP context switches but work correctly otherwise. It's
+ * particularly important to trap WAITs when there is no NPX -
+ * otherwise the "wait" variants would always degenerate.
+ *
+ * Try setting CR0_NE to get correct error reporting on 486DX's.
+ * Setting it should fail or do nothing on lesser processors.
+ */
+ load_cr0(rcr0() | CR0_MP | CR0_NE);
+ /*
+ * But don't trap while we're probing.
+ */
+ stop_emulating();
+ /*
+ * Finish resetting the coprocessor, if any. If there is an error
+ * pending, then we may get a bogus IRQ13, but probeintr() will handle
+ * it OK. Bogus halts have never been observed, but we enabled
+ * IRQ13 and cleared the BUSY# latch early to handle them anyway.
+ */
+ fninit();
+ DELAY(1000); /* wait for any IRQ13 (fwait might hang) */
+#ifdef DIAGNOSTIC
+ if (npx_intrs_while_probing != 0)
+ printf("fninit caused %u bogus npx interrupt(s)\n",
+ npx_intrs_while_probing);
+ if (npx_traps_while_probing != 0)
+ printf("fninit caused %u bogus npx trap(s)\n",
+ npx_traps_while_probing);
+#endif
+ /*
+ * Check for a status of mostly zero.
+ */
+ status = 0x5a5a;
+ fnstsw(&status);
+ if ((status & 0xb8ff) == 0) {
+ /*
+ * Good, now check for a proper control word.
+ */
+ control = 0x5a5a;
+ fnstcw(&control);
+ if ((control & 0x1f3f) == 0x033f) {
+ npx_exists = 1;
+ /*
+ * We have an npx, now divide by 0 to see if exception
+ * 16 works.
+ */
+ control &= ~(1 << 2); /* enable divide by 0 trap */
+ fldcw(&control);
+ npx_traps_while_probing = npx_intrs_while_probing = 0;
+ fp_divide_by_0();
+ if (npx_traps_while_probing != 0) {
+ /*
+ * Good, exception 16 works.
+ */
+ npx_ex16 = 1;
+ dvp->id_irq = 0; /* zap the interrupt */
+ /*
+ * special return value to flag that we do not
+ * actually use any I/O registers
+ */
+ return (-1);
+ }
+ if (npx_intrs_while_probing != 0) {
+ /*
+ * Bad, we are stuck with IRQ13.
+ */
+ npx_irq13 = 1;
+ npx0_imask = dvp->id_irq; /* npxattach too late */
+ return (IO_NPXSIZE);
+ }
+ /*
+ * Worse, even IRQ13 is broken. Use emulator.
+ */
+ }
+ }
+ /*
+ * Probe failed, but we want to get to npxattach to initialize the
+ * emulator and say that it has been installed. XXX handle devices
+ * that aren't really devices better.
+ */
+ dvp->id_irq = 0;
+ /*
+ * special return value to flag that we do not
+ * actually use any I/O registers
+ */
+ return (-1);
+}
+
+/*
+ * Attach routine - announce which it is, and wire into system
+ */
+int
+npxattach(dvp)
+ struct isa_device *dvp;
+{
+ if (!npx_ex16 && !npx_irq13) {
+ if (npx_exists)
+ printf("npx%d: Error reporting broken, using 387 emulator\n",dvp->id_unit);
+ else
+ printf("npx%d: 387 Emulator\n",dvp->id_unit);
+ }
+ npxinit(__INITIAL_NPXCW__);
+ return (1); /* XXX unused */
+}
+
+/*
+ * Initialize floating point unit.
+ */
+void
+npxinit(control)
+ u_int control;
+{
+ struct save87 dummy;
+
+ if (!npx_exists)
+ return;
+ /*
+ * fninit has the same h/w bugs as fnsave. Use the detoxified
+ * fnsave to throw away any junk in the fpu. fnsave initializes
+ * the fpu and sets npxproc = NULL as important side effects.
+ */
+ npxsave(&dummy);
+ stop_emulating();
+ fldcw(&control);
+ if (curpcb != NULL)
+ fnsave(&curpcb->pcb_savefpu);
+ start_emulating();
+}
+
+/*
+ * Free coprocessor (if we have it).
+ */
+void
+npxexit(p)
+ struct proc *p;
+{
+
+ if (p == npxproc) {
+ start_emulating();
+ npxproc = NULL;
+ }
+}
+
+/*
+ * Record the FPU state and reinitialize it all except for the control word.
+ * Then generate a SIGFPE.
+ *
+ * Reinitializing the state allows naive SIGFPE handlers to longjmp without
+ * doing any fixups.
+ *
+ * XXX there is currently no way to pass the full error state to signal
+ * handlers, and if this is a nested interrupt there is no way to pass even
+ * a status code! So there is no way to have a non-naive SIGFPE handler. At
+ * best a handler could do an fninit followed by an fldcw of a static value.
+ * fnclex would be of little use because it would leave junk on the FPU stack.
+ * Returning from the handler would be even less safe than usual because
+ * IRQ13 exception handling makes exceptions even less precise than usual.
+ */
+void
+npxintr(frame)
+ struct intrframe frame;
+{
+ int code;
+
+ if (npxproc == NULL || !npx_exists) {
+ /* XXX no %p in stand/printf.c. Cast to quiet gcc -Wall. */
+ printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n",
+ (u_long) npxproc, (u_long) curproc, npx_exists);
+ panic("npxintr from nowhere");
+ }
+ if (npxproc != curproc) {
+ printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n",
+ (u_long) npxproc, (u_long) curproc, npx_exists);
+ panic("npxintr from non-current process");
+ }
+ /*
+ * Save state. This does an implied fninit. It had better not halt
+ * the cpu or we'll hang.
+ */
+ outb(0xf0, 0);
+ fnsave(&curpcb->pcb_savefpu);
+ fwait();
+ /*
+ * Restore control word (was clobbered by fnsave).
+ */
+ fldcw(&curpcb->pcb_savefpu.sv_env.en_cw);
+ fwait();
+ /*
+ * Remember the exception status word and tag word. The current
+ * (almost fninit'ed) fpu state is in the fpu and the exception
+ * state just saved will soon be junk. However, the implied fninit
+ * doesn't change the error pointers or register contents, and we
+ * preserved the control word and will copy the status and tag
+ * words, so the complete exception state can be recovered.
+ */
+ curpcb->pcb_savefpu.sv_ex_sw = curpcb->pcb_savefpu.sv_env.en_sw;
+ curpcb->pcb_savefpu.sv_ex_tw = curpcb->pcb_savefpu.sv_env.en_tw;
+
+ /*
+ * Pass exception to process.
+ */
+ if (ISPL(frame.if_cs) == SEL_UPL) {
+ /*
+ * Interrupt is essentially a trap, so we can afford to call
+ * the SIGFPE handler (if any) as soon as the interrupt
+ * returns.
+ *
+ * XXX little or nothing is gained from this, and plenty is
+ * lost - the interrupt frame has to contain the trap frame
+ * (this is otherwise only necessary for the rescheduling trap
+ * in doreti, and the frame for that could easily be set up
+ * just before it is used).
+ */
+ curproc->p_regs = (int *)&frame.if_es;
+#ifdef notyet
+ /*
+ * Encode the appropriate code for detailed information on
+ * this exception.
+ */
+ code = XXX_ENCODE(curpcb->pcb_savefpu.sv_ex_sw);
+#else
+ code = 0; /* XXX */
+#endif
+ trapsignal(curproc, SIGFPE, code);
+ } else {
+ /*
+ * Nested interrupt. These losers occur when:
+ * o an IRQ13 is bogusly generated at a bogus time, e.g.:
+ * o immediately after an fnsave or frstor of an
+ * error state.
+ * o a couple of 386 instructions after
+ * "fstpl _memvar" causes a stack overflow.
+ * These are especially nasty when combined with a
+ * trace trap.
+ * o an IRQ13 occurs at the same time as another higher-
+ * priority interrupt.
+ *
+ * Treat them like a true async interrupt.
+ */
+ psignal(npxproc, SIGFPE);
+ }
+}
+
+/*
+ * Implement device not available (DNA) exception
+ *
+ * It would be better to switch FP context here (only). This would require
+ * saving the state in the proc table instead of in the pcb.
+ */
+int
+npxdna()
+{
+ if (!npx_exists)
+ return (0);
+ if (npxproc != NULL) {
+ printf("npxdna: npxproc = %lx, curproc = %lx\n",
+ (u_long) npxproc, (u_long) curproc);
+ panic("npxdna");
+ }
+ stop_emulating();
+ /*
+ * Record new context early in case frstor causes an IRQ13.
+ */
+ npxproc = curproc;
+ /*
+ * The following frstor may cause an IRQ13 when the state being
+ * restored has a pending error. The error will appear to have been
+ * triggered by the current (npx) user instruction even when that
+ * instruction is a no-wait instruction that should not trigger an
+ * error (e.g., fnclex). On at least one 486 system all of the
+ * no-wait instructions are broken the same as frstor, so our
+ * treatment does not amplify the breakage. On at least one
+ * 386/Cyrix 387 system, fnclex works correctly while frstor and
+ * fnsave are broken, so our treatment breaks fnclex if it is the
+ * first FPU instruction after a context switch.
+ */
+ frstor(&curpcb->pcb_savefpu);
+
+ return (1);
+}
+
+/*
+ * Wrapper for fnsave instruction to handle h/w bugs. If there is an error
+ * pending, then fnsave generates a bogus IRQ13 on some systems. Force
+ * any IRQ13 to be handled immediately, and then ignore it. This routine is
+ * often called at splhigh so it must not use many system services. In
+ * particular, it's much easier to install a special handler than to
+ * guarantee that it's safe to use npxintr() and its supporting code.
+ */
+void
+npxsave(addr)
+ struct save87 *addr;
+{
+ u_char icu1_mask;
+ u_char icu2_mask;
+ u_char old_icu1_mask;
+ u_char old_icu2_mask;
+ struct gate_descriptor save_idt_npxintr;
+
+ disable_intr();
+ old_icu1_mask = inb(IO_ICU1 + 1);
+ old_icu2_mask = inb(IO_ICU2 + 1);
+ save_idt_npxintr = idt[npx_intrno];
+ outb(IO_ICU1 + 1, old_icu1_mask & ~(IRQ_SLAVE | npx0_imask));
+ outb(IO_ICU2 + 1, old_icu2_mask & ~(npx0_imask >> 8));
+ idt[npx_intrno] = npx_idt_probeintr;
+ enable_intr();
+ stop_emulating();
+ fnsave(addr);
+ fwait();
+ start_emulating();
+ npxproc = NULL;
+ disable_intr();
+ icu1_mask = inb(IO_ICU1 + 1); /* masks may have changed */
+ icu2_mask = inb(IO_ICU2 + 1);
+ outb(IO_ICU1 + 1,
+ (icu1_mask & ~npx0_imask) | (old_icu1_mask & npx0_imask));
+ outb(IO_ICU2 + 1,
+ (icu2_mask & ~(npx0_imask >> 8))
+ | (old_icu2_mask & (npx0_imask >> 8)));
+ idt[npx_intrno] = save_idt_npxintr;
+ enable_intr(); /* back to usual state */
+}
+
+#endif /* NNPX > 0 */
diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c
new file mode 100644
index 0000000..b7847e8
--- /dev/null
+++ b/sys/amd64/amd64/genassym.c
@@ -0,0 +1,194 @@
+/*-
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)genassym.c 5.11 (Berkeley) 5/10/91
+ * $Id: genassym.c,v 1.6 1993/11/13 02:24:59 davidg Exp $
+ */
+
+#include "sys/param.h"
+#include "sys/buf.h"
+#include "sys/vmmeter.h"
+#include "sys/proc.h"
+#include "sys/user.h"
+#include "sys/mbuf.h"
+#include "sys/msgbuf.h"
+#include "sys/resourcevar.h"
+#include "machine/cpu.h"
+#include "machine/trap.h"
+#include "machine/psl.h"
+#include "sys/syscall.h"
+#include "vm/vm_param.h"
+#include "vm/vm_map.h"
+#include "machine/pmap.h"
+
+main()
+{
+ struct proc *p = (struct proc *)0;
+ struct vmmeter *vm = (struct vmmeter *)0;
+ struct user *up = (struct user *)0;
+ struct rusage *rup = (struct rusage *)0;
+ struct uprof *uprof = (struct uprof *)0;
+ struct vmspace *vms = (struct vmspace *)0;
+ vm_map_t map = (vm_map_t)0;
+ pmap_t pmap = (pmap_t)0;
+ struct pcb *pcb = (struct pcb *)0;
+ struct trapframe *tf = (struct trapframe *)0;
+ struct sigframe *sigf = (struct sigframe *)0;
+ register unsigned i;
+
+ printf("#define\tI386_CR3PAT %d\n", I386_CR3PAT);
+ printf("#define\tUDOT_SZ %d\n", sizeof(struct user));
+ printf("#define\tP_LINK %d\n", &p->p_link);
+ printf("#define\tP_RLINK %d\n", &p->p_rlink);
+ printf("#define\tP_VMSPACE %d\n", &p->p_vmspace);
+ printf("#define\tVM_PMAP %d\n", &vms->vm_pmap);
+ printf("#define\tP_ADDR %d\n", &p->p_addr);
+ printf("#define\tP_PRI %d\n", &p->p_pri);
+ printf("#define\tP_STAT %d\n", &p->p_stat);
+ printf("#define\tP_WCHAN %d\n", &p->p_wchan);
+ printf("#define\tP_FLAG %d\n", &p->p_flag);
+ printf("#define\tP_PID %d\n", &p->p_pid);
+ printf("#define\tSSLEEP %d\n", SSLEEP);
+ printf("#define\tSRUN %d\n", SRUN);
+ printf("#define\tV_SWTCH %d\n", &vm->v_swtch);
+ printf("#define\tV_TRAP %d\n", &vm->v_trap);
+ printf("#define\tV_SYSCALL %d\n", &vm->v_syscall);
+ printf("#define\tV_INTR %d\n", &vm->v_intr);
+ printf("#define\tV_SOFT %d\n", &vm->v_soft);
+ printf("#define\tV_PDMA %d\n", &vm->v_pdma);
+ printf("#define\tV_FAULTS %d\n", &vm->v_faults);
+ printf("#define\tV_PGREC %d\n", &vm->v_pgrec);
+ printf("#define\tV_FASTPGREC %d\n", &vm->v_fastpgrec);
+ printf("#define\tUPAGES %d\n", UPAGES);
+ printf("#define\tHIGHPAGES %d\n", HIGHPAGES);
+ printf("#define\tCLSIZE %d\n", CLSIZE);
+ printf("#define\tNBPG %d\n", NBPG);
+ printf("#define\tNPTEPG %d\n", NPTEPG);
+ printf("#define\tPDESIZE %d\n", PDESIZE);
+ printf("#define\tPTESIZE %d\n", PTESIZE);
+ printf("#define\tNKPDE %d\n", NKPDE);
+ printf("#define\tNKPT %d\n", NKPT);
+ printf("#define\tKPTDI 0x%x\n", KPTDI);
+ printf("#define\tKSTKPTDI 0x%x\n", KSTKPTDI);
+ printf("#define\tKSTKPTEOFF 0x%x\n", KSTKPTEOFF);
+ printf("#define\tPTDPTDI 0x%x\n", PTDPTDI);
+ printf("#define\tAPTDPTDI 0x%x\n", APTDPTDI);
+ printf("#define\tPGSHIFT %d\n", PGSHIFT);
+ printf("#define\tPDRSHIFT %d\n", PDRSHIFT);
+ printf("#define\tSYSPTSIZE %d\n", SYSPTSIZE);
+ printf("#define\tUSRPTSIZE %d\n", USRPTSIZE);
+ printf("#define\tUSRIOSIZE %d\n", USRIOSIZE);
+#ifdef SYSVSHM
+ printf("#define\tSHMMAXPGS %d\n", SHMMAXPGS);
+#endif
+ printf("#define\tUSRSTACK 0x%x\n", USRSTACK);
+ printf("#define\tVM_MAXUSER_ADDRESS 0x%x\n", VM_MAXUSER_ADDRESS);
+ printf("#define\tKERNBASE 0x%x\n", KERNBASE);
+ printf("#define\tMSGBUFPTECNT %d\n", btoc(sizeof (struct msgbuf)));
+ printf("#define\tNMBCLUSTERS %d\n", NMBCLUSTERS);
+ printf("#define\tMCLBYTES %d\n", MCLBYTES);
+ printf("#define\tPCB_LINK %d\n", &pcb->pcb_tss.tss_link);
+ printf("#define\tPCB_ESP0 %d\n", &pcb->pcb_tss.tss_esp0);
+ printf("#define\tPCB_SS0 %d\n", &pcb->pcb_tss.tss_ss0);
+ printf("#define\tPCB_ESP1 %d\n", &pcb->pcb_tss.tss_esp1);
+ printf("#define\tPCB_SS1 %d\n", &pcb->pcb_tss.tss_ss1);
+ printf("#define\tPCB_ESP2 %d\n", &pcb->pcb_tss.tss_esp2);
+ printf("#define\tPCB_SS2 %d\n", &pcb->pcb_tss.tss_ss2);
+ printf("#define\tPCB_CR3 %d\n", &pcb->pcb_tss.tss_cr3);
+ printf("#define\tPCB_EIP %d\n", &pcb->pcb_tss.tss_eip);
+ printf("#define\tPCB_EFLAGS %d\n", &pcb->pcb_tss.tss_eflags);
+ printf("#define\tPCB_EAX %d\n", &pcb->pcb_tss.tss_eax);
+ printf("#define\tPCB_ECX %d\n", &pcb->pcb_tss.tss_ecx);
+ printf("#define\tPCB_EDX %d\n", &pcb->pcb_tss.tss_edx);
+ printf("#define\tPCB_EBX %d\n", &pcb->pcb_tss.tss_ebx);
+ printf("#define\tPCB_ESP %d\n", &pcb->pcb_tss.tss_esp);
+ printf("#define\tPCB_EBP %d\n", &pcb->pcb_tss.tss_ebp);
+ printf("#define\tPCB_ESI %d\n", &pcb->pcb_tss.tss_esi);
+ printf("#define\tPCB_EDI %d\n", &pcb->pcb_tss.tss_edi);
+ printf("#define\tPCB_ES %d\n", &pcb->pcb_tss.tss_es);
+ printf("#define\tPCB_CS %d\n", &pcb->pcb_tss.tss_cs);
+ printf("#define\tPCB_SS %d\n", &pcb->pcb_tss.tss_ss);
+ printf("#define\tPCB_DS %d\n", &pcb->pcb_tss.tss_ds);
+ printf("#define\tPCB_FS %d\n", &pcb->pcb_tss.tss_fs);
+ printf("#define\tPCB_GS %d\n", &pcb->pcb_tss.tss_gs);
+ printf("#define\tPCB_LDT %d\n", &pcb->pcb_tss.tss_ldt);
+ printf("#define\tPCB_USERLDT %d\n", &pcb->pcb_ldt);
+ printf("#define\tPCB_IOOPT %d\n", &pcb->pcb_tss.tss_ioopt);
+ printf("#define\tU_PROF %d\n", &up->u_stats.p_prof);
+ printf("#define\tU_PROFSCALE %d\n", &up->u_stats.p_prof.pr_scale);
+ printf("#define\tPR_BASE %d\n", &uprof->pr_base);
+ printf("#define\tPR_SIZE %d\n", &uprof->pr_size);
+ printf("#define\tPR_OFF %d\n", &uprof->pr_off);
+ printf("#define\tPR_SCALE %d\n", &uprof->pr_scale);
+ printf("#define\tRU_MINFLT %d\n", &rup->ru_minflt);
+ printf("#define\tPCB_FLAGS %d\n", &pcb->pcb_flags);
+ printf("#define\tPCB_SAVEFPU %d\n", &pcb->pcb_savefpu);
+ printf("#define\tFP_USESEMC %d\n", FP_USESEMC);
+ printf("#define\tPCB_SAVEEMC %d\n", &pcb->pcb_saveemc);
+ printf("#define\tPCB_CMAP2 %d\n", &pcb->pcb_cmap2);
+ printf("#define\tPCB_IML %d\n", &pcb->pcb_iml);
+ printf("#define\tPCB_ONFAULT %d\n", &pcb->pcb_onfault);
+
+ printf("#define\tTF_ES %d\n", &tf->tf_es);
+ printf("#define\tTF_DS %d\n", &tf->tf_ds);
+ printf("#define\tTF_EDI %d\n", &tf->tf_edi);
+ printf("#define\tTF_ESI %d\n", &tf->tf_esi);
+ printf("#define\tTF_EBP %d\n", &tf->tf_ebp);
+ printf("#define\tTF_ISP %d\n", &tf->tf_isp);
+ printf("#define\tTF_EBX %d\n", &tf->tf_ebx);
+ printf("#define\tTF_EDX %d\n", &tf->tf_edx);
+ printf("#define\tTF_ECX %d\n", &tf->tf_ecx);
+ printf("#define\tTF_EAX %d\n", &tf->tf_eax);
+ printf("#define\tTF_TRAPNO %d\n", &tf->tf_trapno);
+ printf("#define\tTF_ERR %d\n", &tf->tf_err);
+ printf("#define\tTF_EIP %d\n", &tf->tf_eip);
+ printf("#define\tTF_CS %d\n", &tf->tf_cs);
+ printf("#define\tTF_EFLAGS %d\n", &tf->tf_eflags);
+ printf("#define\tTF_ESP %d\n", &tf->tf_esp);
+ printf("#define\tTF_SS %d\n", &tf->tf_ss);
+
+ printf("#define\tSIGF_SIGNUM %d\n", &sigf->sf_signum);
+ printf("#define\tSIGF_CODE %d\n", &sigf->sf_code);
+ printf("#define\tSIGF_SCP %d\n", &sigf->sf_scp);
+ printf("#define\tSIGF_HANDLER %d\n", &sigf->sf_handler);
+ printf("#define\tSIGF_SC %d\n", &sigf->sf_sc);
+
+ printf("#define\tB_READ %d\n", B_READ);
+ printf("#define\tENOENT %d\n", ENOENT);
+ printf("#define\tEFAULT %d\n", EFAULT);
+ printf("#define\tENAMETOOLONG %d\n", ENAMETOOLONG);
+ exit(0);
+}
+
diff --git a/sys/amd64/amd64/locore.S b/sys/amd64/amd64/locore.S
new file mode 100644
index 0000000..8da8438
--- /dev/null
+++ b/sys/amd64/amd64/locore.S
@@ -0,0 +1,552 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)locore.s 7.3 (Berkeley) 5/13/91
+ * $Id: locore.s,v 1.15 1994/02/01 04:08:54 davidg Exp $
+ */
+
+/*
+ * locore.s: FreeBSD machine support for the Intel 386
+ * originally from: locore.s, by William F. Jolitz
+ *
+ * Substantially rewritten by David Greenman, Rod Grimes,
+ * Bruce Evans, Wolfgang Solfrank, and many others.
+ */
+
+#include "npx.h" /* for NNPX */
+#include "assym.s" /* system definitions */
+#include "machine/psl.h" /* processor status longword defs */
+#include "machine/pte.h" /* page table entry definitions */
+#include "errno.h" /* error return codes */
+#include "machine/specialreg.h" /* x86 special registers */
+#include "machine/cputypes.h" /* x86 cpu type definitions */
+#include "syscall.h" /* system call numbers */
+#include "machine/asmacros.h" /* miscellaneous asm macros */
+
+/*
+ * XXX
+ *
+ * Note: This version greatly munged to avoid various assembler errors
+ * that may be fixed in newer versions of gas. Perhaps newer versions
+ * will have more pleasant appearance.
+ */
+
+/*
+ * PTmap is recursive pagemap at top of virtual address space.
+ * Within PTmap, the page directory can be found (third indirection).
+ */
+ .globl _PTmap,_PTD,_PTDpde,_Sysmap
+ .set _PTmap,PTDPTDI << PDRSHIFT
+ .set _PTD,_PTmap + (PTDPTDI * NBPG)
+ .set _PTDpde,_PTD + (PTDPTDI * PDESIZE)
+
+/* Sysmap is the base address of the kernel page tables */
+ .set _Sysmap,_PTmap + (KPTDI * NBPG)
+
+/*
+ * APTmap, APTD is the alternate recursive pagemap.
+ * It's used when modifying another process's page tables.
+ */
+ .globl _APTmap,_APTD,_APTDpde
+ .set _APTmap,APTDPTDI << PDRSHIFT
+ .set _APTD,_APTmap + (APTDPTDI * NBPG)
+ .set _APTDpde,_PTD + (APTDPTDI * PDESIZE)
+
+/*
+ * Access to each processes kernel stack is via a region of
+ * per-process address space (at the beginning), immediatly above
+ * the user process stack.
+ */
+ .set _kstack,USRSTACK
+ .globl _kstack
+
+/*
+ * Globals
+ */
+ .data
+ .globl _esym
+_esym: .long 0 /* ptr to end of syms */
+
+ .globl _boothowto,_bootdev,_curpcb
+
+ .globl _cpu,_cold,_atdevbase
+_cpu: .long 0 /* are we 386, 386sx, or 486 */
+_cold: .long 1 /* cold till we are not */
+_atdevbase: .long 0 /* location of start of iomem in virtual */
+_atdevphys: .long 0 /* location of device mapping ptes (phys) */
+
+ .globl _KERNend
+_KERNend: .long 0 /* phys addr end of kernel (just after bss) */
+
+ .globl _IdlePTD,_KPTphys
+_IdlePTD: .long 0 /* phys addr of kernel PTD */
+_KPTphys: .long 0 /* phys addr of kernel page tables */
+
+ .globl _cyloffset
+_cyloffset: .long 0 /* cylinder offset from boot blocks */
+
+ .globl _proc0paddr
+_proc0paddr: .long 0 /* address of proc 0 address space */
+
+#ifdef BDE_DEBUGGER
+ .globl _bdb_exists /* flag to indicate BDE debugger is available */
+_bdb_exists: .long 0
+#endif
+
+ .globl tmpstk
+ .space 0x1000
+tmpstk:
+
+
+/*
+ * System Initialization
+ */
+ .text
+
+/*
+ * btext: beginning of text section.
+ * Also the entry point (jumped to directly from the boot blocks).
+ */
+NON_GPROF_ENTRY(btext)
+ movw $0x1234,0x472 /* warm boot */
+ jmp 1f
+ .org 0x500 /* space for BIOS variables */
+
+ /*
+ * pass parameters on stack (howto, bootdev, unit, cyloffset, esym)
+ * note: (%esp) is return address of boot
+ * ( if we want to hold onto /boot, it's physical %esp up to _end)
+ */
+
+ 1: movl 4(%esp),%eax
+ movl %eax,_boothowto-KERNBASE
+ movl 8(%esp),%eax
+ movl %eax,_bootdev-KERNBASE
+ movl 12(%esp),%eax
+ movl %eax,_cyloffset-KERNBASE
+ movl 16(%esp),%eax
+ addl $KERNBASE,%eax
+ movl %eax,_esym-KERNBASE
+#ifdef DISKLESS /* Copy diskless structure */
+ movl _nfs_diskless_size-KERNBASE,%ecx
+ movl 20(%esp),%esi
+ movl $(_nfs_diskless-KERNBASE),%edi
+ rep
+ movsb
+#endif
+
+ /* find out our CPU type. */
+ pushfl
+ popl %eax
+ movl %eax,%ecx
+ xorl $0x40000,%eax
+ pushl %eax
+ popfl
+ pushfl
+ popl %eax
+ xorl %ecx,%eax
+ shrl $18,%eax
+ andl $1,%eax
+ push %ecx
+ popfl
+
+ cmpl $0,%eax
+ jne 1f
+ movl $CPU_386,_cpu-KERNBASE
+ jmp 2f
+1: movl $CPU_486,_cpu-KERNBASE
+2:
+
+ /*
+ * Finished with old stack; load new %esp now instead of later so
+ * we can trace this code without having to worry about the trace
+ * trap clobbering the memory test or the zeroing of the bss+bootstrap
+ * page tables.
+ *
+ * XXX - wdboot clears the bss after testing that this is safe.
+ * This is too wasteful - memory below 640K is scarce. The boot
+ * program should check:
+ * text+data <= &stack_variable - more_space_for_stack
+ * text+data+bss+pad+space_for_page_tables <= end_of_memory
+ * Oops, the gdt is in the carcass of the boot program so clearing
+ * the rest of memory is still not possible.
+ */
+ movl $tmpstk-KERNBASE,%esp /* bootstrap stack end location */
+
+/*
+ * Virtual address space of kernel:
+ *
+ * text | data | bss | [syms] | page dir | proc0 kernel stack | usr stk map | Sysmap
+ * pages: 1 UPAGES (2) 1 NKPT (7)
+ */
+
+/* find end of kernel image */
+ movl $_end-KERNBASE,%ecx
+ addl $NBPG-1,%ecx /* page align up */
+ andl $~(NBPG-1),%ecx
+ movl %ecx,%esi /* esi = start of free memory */
+ movl %ecx,_KERNend-KERNBASE /* save end of kernel */
+
+/* clear bss */
+ movl $_edata-KERNBASE,%edi
+ subl %edi,%ecx /* get amount to clear */
+ xorl %eax,%eax /* specify zero fill */
+ cld
+ rep
+ stosb
+
+/*
+ * The value in esi is both the end of the kernel bss and a pointer to
+ * the kernel page directory, and is used by the rest of locore to build
+ * the tables.
+ * esi + 1(page dir) + 2(UPAGES) + 1(p0stack) + NKPT(number of kernel
+ * page table pages) is then passed on the stack to init386(first) as
+ * the value first. esi should ALWAYS be page aligned!!
+ */
+ movl %esi,%ecx /* Get current first availiable address */
+
+/* clear pagetables, page directory, stack, etc... */
+ movl %esi,%edi /* base (page directory) */
+ movl $((1+UPAGES+1+NKPT)*NBPG),%ecx /* amount to clear */
+ xorl %eax,%eax /* specify zero fill */
+ cld
+ rep
+ stosb
+
+/* physical address of Idle proc/kernel page directory */
+ movl %esi,_IdlePTD-KERNBASE
+
+/*
+ * fillkpt
+ * eax = (page frame address | control | status) == pte
+ * ebx = address of page table
+ * ecx = how many pages to map
+ */
+#define fillkpt \
+1: movl %eax,(%ebx) ; \
+ addl $NBPG,%eax ; /* increment physical address */ \
+ addl $4,%ebx ; /* next pte */ \
+ loop 1b ;
+
+/*
+ * Map Kernel
+ *
+ * First step - build page tables
+ */
+#if defined (KGDB) || defined (BDE_DEBUGGER)
+ movl _KERNend-KERNBASE,%ecx /* this much memory, */
+ shrl $PGSHIFT,%ecx /* for this many PTEs */
+#ifdef BDE_DEBUGGER
+ cmpl $0xa0,%ecx /* XXX - cover debugger pages */
+ jae 1f
+ movl $0xa0,%ecx
+1:
+#endif /* BDE_DEBUGGER */
+ movl $PG_V|PG_KW,%eax /* having these bits set, */
+ lea ((1+UPAGES+1)*NBPG)(%esi),%ebx /* phys addr of kernel PT base */
+ movl %ebx,_KPTphys-KERNBASE /* save in global */
+ fillkpt
+
+#else /* !KGDB && !BDE_DEBUGGER */
+ /* write protect kernel text (doesn't do a thing for 386's - only 486's) */
+ movl $_etext-KERNBASE,%ecx /* get size of text */
+ shrl $PGSHIFT,%ecx /* for this many PTEs */
+ movl $PG_V|PG_KR,%eax /* specify read only */
+ lea ((1+UPAGES+1)*NBPG)(%esi),%ebx /* phys addr of kernel PT base */
+ movl %ebx,_KPTphys-KERNBASE /* save in global */
+ fillkpt
+
+ /* data and bss are r/w */
+ andl $PG_FRAME,%eax /* strip to just addr of bss */
+ movl _KERNend-KERNBASE,%ecx /* calculate size */
+ subl %eax,%ecx
+ shrl $PGSHIFT,%ecx
+ orl $PG_V|PG_KW,%eax /* valid, kernel read/write */
+ fillkpt
+#endif /* KGDB || BDE_DEBUGGER */
+
+/* now initialize the page dir, upages, p0stack PT, and page tables */
+
+ movl $(1+UPAGES+1+NKPT),%ecx /* number of PTEs */
+ movl %esi,%eax /* phys address of PTD */
+ andl $PG_FRAME,%eax /* convert to PFN, should be a NOP */
+ orl $PG_V|PG_KW,%eax /* valid, kernel read/write */
+ movl %esi,%ebx /* calculate pte offset to ptd */
+ shrl $PGSHIFT-2,%ebx
+ addl %esi,%ebx /* address of page directory */
+ addl $((1+UPAGES+1)*NBPG),%ebx /* offset to kernel page tables */
+ fillkpt
+
+/* map I/O memory map */
+
+ movl _KPTphys-KERNBASE,%ebx /* base of kernel page tables */
+ lea (0xa0 * PTESIZE)(%ebx),%ebx /* hardwire ISA hole at KERNBASE + 0xa0000 */
+ movl $0x100-0xa0,%ecx /* for this many pte s, */
+ movl $(0xa0000|PG_V|PG_KW|PG_N),%eax /* valid, kernel read/write, non-cacheable */
+ movl %ebx,_atdevphys-KERNBASE /* save phys addr of ptes */
+ fillkpt
+
+ /* map proc 0's kernel stack into user page table page */
+
+ movl $UPAGES,%ecx /* for this many pte s, */
+ lea (1*NBPG)(%esi),%eax /* physical address in proc 0 */
+ lea (KERNBASE)(%eax),%edx /* change into virtual addr */
+ movl %edx,_proc0paddr-KERNBASE /* save VA for proc 0 init */
+ orl $PG_V|PG_KW,%eax /* valid, kernel read/write */
+ lea ((1+UPAGES)*NBPG)(%esi),%ebx /* addr of stack page table in proc 0 */
+ addl $(KSTKPTEOFF * PTESIZE),%ebx /* offset to kernel stack PTE */
+ fillkpt
+
+/*
+ * Initialize kernel page table directory
+ */
+ /* install a pde for temporary double map of bottom of VA */
+ movl _KPTphys-KERNBASE,%eax
+ orl $PG_V|PG_KW,%eax /* valid, kernel read/write */
+ movl %eax,(%esi) /* which is where temp maps! */
+
+ /* initialize kernel pde's */
+ movl $(NKPT),%ecx /* for this many PDEs */
+ lea (KPTDI*PDESIZE)(%esi),%ebx /* offset of pde for kernel */
+ fillkpt
+
+ /* install a pde recursively mapping page directory as a page table! */
+ movl %esi,%eax /* phys address of ptd in proc 0 */
+ orl $PG_V|PG_KW,%eax /* pde entry is valid */
+ movl %eax,PTDPTDI*PDESIZE(%esi) /* which is where PTmap maps! */
+
+ /* install a pde to map kernel stack for proc 0 */
+ lea ((1+UPAGES)*NBPG)(%esi),%eax /* physical address of pt in proc 0 */
+ orl $PG_V|PG_KW,%eax /* pde entry is valid */
+ movl %eax,KSTKPTDI*PDESIZE(%esi) /* which is where kernel stack maps! */
+
+#ifdef BDE_DEBUGGER
+ /* copy and convert stuff from old gdt and idt for debugger */
+
+ cmpl $0x0375c339,0x96104 /* XXX - debugger signature */
+ jne 1f
+ movb $1,_bdb_exists-KERNBASE
+1:
+ pushal
+ subl $2*6,%esp
+
+ sgdt (%esp)
+ movl 2(%esp),%esi /* base address of current gdt */
+ movl $_gdt-KERNBASE,%edi
+ movl %edi,2(%esp)
+ movl $8*18/4,%ecx
+ rep /* copy gdt */
+ movsl
+ movl $_gdt-KERNBASE,-8+2(%edi) /* adjust gdt self-ptr */
+ movb $0x92,-8+5(%edi)
+
+ sidt 6(%esp)
+ movl 6+2(%esp),%esi /* base address of current idt */
+ movl 8+4(%esi),%eax /* convert dbg descriptor to ... */
+ movw 8(%esi),%ax
+ movl %eax,bdb_dbg_ljmp+1-KERNBASE /* ... immediate offset ... */
+ movl 8+2(%esi),%eax
+ movw %ax,bdb_dbg_ljmp+5-KERNBASE /* ... and selector for ljmp */
+ movl 24+4(%esi),%eax /* same for bpt descriptor */
+ movw 24(%esi),%ax
+ movl %eax,bdb_bpt_ljmp+1-KERNBASE
+ movl 24+2(%esi),%eax
+ movw %ax,bdb_bpt_ljmp+5-KERNBASE
+
+ movl $_idt-KERNBASE,%edi
+ movl %edi,6+2(%esp)
+ movl $8*4/4,%ecx
+ rep /* copy idt */
+ movsl
+
+ lgdt (%esp)
+ lidt 6(%esp)
+
+ addl $2*6,%esp
+ popal
+#endif /* BDE_DEBUGGER */
+
+ /* load base of page directory and enable mapping */
+ movl %esi,%eax /* phys address of ptd in proc 0 */
+ orl $I386_CR3PAT,%eax
+ movl %eax,%cr3 /* load ptd addr into mmu */
+ movl %cr0,%eax /* get control word */
+ orl $CR0_PE|CR0_PG,%eax /* enable paging */
+ movl %eax,%cr0 /* and let's page NOW! */
+
+ pushl $begin /* jump to high mem */
+ ret
+
+begin: /* now running relocated at KERNBASE where the system is linked to run */
+
+ .globl _Crtat /* XXX - locore should not know about */
+ movl _Crtat,%eax /* variables of device drivers (pccons)! */
+ subl $(KERNBASE+0xA0000),%eax
+ movl _atdevphys,%edx /* get pte PA */
+ subl _KPTphys,%edx /* remove base of ptes, now have phys offset */
+ shll $PGSHIFT-2,%edx /* corresponding to virt offset */
+ addl $KERNBASE,%edx /* add virtual base */
+ movl %edx,_atdevbase
+ addl %eax,%edx
+ movl %edx,_Crtat
+
+ /* set up bootstrap stack - 48 bytes */
+ movl $_kstack+UPAGES*NBPG-4*12,%esp /* bootstrap stack end location */
+ xorl %eax,%eax /* mark end of frames */
+ movl %eax,%ebp
+ movl _proc0paddr,%eax
+ movl %esi,PCB_CR3(%eax)
+
+#ifdef BDE_DEBUGGER
+ /* relocate debugger gdt entries */
+
+ movl $_gdt+8*9,%eax /* adjust slots 9-17 */
+ movl $9,%ecx
+reloc_gdt:
+ movb $KERNBASE>>24,7(%eax) /* top byte of base addresses, was 0, */
+ addl $8,%eax /* now KERNBASE>>24 */
+ loop reloc_gdt
+
+ cmpl $0,_bdb_exists
+ je 1f
+ int $3
+1:
+#endif /* BDE_DEBUGGER */
+
+ /*
+ * Skip over the page tables and the kernel stack
+ */
+ lea ((1+UPAGES+1+NKPT)*NBPG)(%esi),%esi
+
+ pushl %esi /* value of first for init386(first) */
+ call _init386 /* wire 386 chip for unix operation */
+
+ movl $0,_PTD
+ call _main /* autoconfiguration, mountroot etc */
+ popl %esi
+
+ /*
+ * now we've run main() and determined what cpu-type we are, we can
+ * enable WP mode on i486 cpus and above.
+ */
+#if defined(I486_CPU) || defined(I586_CPU)
+ cmpl $CPUCLASS_386,_cpu_class
+ je 1f
+ movl %cr0,%eax /* get control word */
+ orl $CR0_WP,%eax /* enable write protect for all modes */
+ movl %eax,%cr0 /* and do it */
+#endif
+ /*
+ * on return from main(), we are process 1
+ * set up address space and stack so that we can 'return' to user mode
+ */
+1:
+ .globl __ucodesel,__udatasel
+ movl __ucodesel,%eax
+ movl __udatasel,%ecx
+ /* build outer stack frame */
+ pushl %ecx /* user ss */
+ pushl $USRSTACK /* user esp */
+ pushl %eax /* user cs */
+ pushl $0 /* user ip */
+ movl %cx,%ds
+ movl %cx,%es
+ movl %ax,%fs /* double map cs to fs */
+ movl %cx,%gs /* and ds to gs */
+ lret /* goto user! */
+
+ pushl $lretmsg1 /* "should never get here!" */
+ call _panic
+lretmsg1:
+ .asciz "lret: toinit\n"
+
+
+#define LCALL(x,y) .byte 0x9a ; .long y ; .word x
+/*
+ * Icode is copied out to process 1 and executed in user mode:
+ * execve("/sbin/init", argv, envp); exit(0);
+ * If the execve fails, process 1 exits and the system panics.
+ */
+NON_GPROF_ENTRY(icode)
+ pushl $0 /* envp for execve() */
+
+# pushl $argv-_icode /* can't do this 'cos gas 1.38 is broken */
+ movl $argv,%eax
+ subl $_icode,%eax
+ pushl %eax /* argp for execve() */
+
+# pushl $init-_icode
+ movl $init,%eax
+ subl $_icode,%eax
+ pushl %eax /* fname for execve() */
+
+ pushl %eax /* dummy return address */
+
+ movl $SYS_execve,%eax
+ LCALL(0x7,0x0)
+
+ /* exit if something botches up in the above execve() */
+ pushl %eax /* execve failed, the errno will do for an */
+ /* exit code because errnos are < 128 */
+ pushl %eax /* dummy return address */
+ movl $SYS_exit,%eax
+ LCALL(0x7,0x0)
+
+init:
+ .asciz "/sbin/init"
+ ALIGN_DATA
+argv:
+ .long init+6-_icode /* argv[0] = "init" ("/sbin/init" + 6) */
+ .long eicode-_icode /* argv[1] follows icode after copyout */
+ .long 0
+eicode:
+
+ .globl _szicode
+_szicode:
+ .long _szicode-_icode
+
+NON_GPROF_ENTRY(sigcode)
+ call SIGF_HANDLER(%esp)
+ lea SIGF_SC(%esp),%eax /* scp (the call may have clobbered the */
+ /* copy at 8(%esp)) */
+ pushl %eax
+ pushl %eax /* junk to fake return address */
+ movl $103,%eax /* XXX sigreturn() */
+ LCALL(0x7,0) /* enter kernel with args on stack */
+ hlt /* never gets here */
+
+ .globl _szsigcode
+_szsigcode:
+ .long _szsigcode-_sigcode
diff --git a/sys/amd64/amd64/locore.s b/sys/amd64/amd64/locore.s
new file mode 100644
index 0000000..8da8438
--- /dev/null
+++ b/sys/amd64/amd64/locore.s
@@ -0,0 +1,552 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)locore.s 7.3 (Berkeley) 5/13/91
+ * $Id: locore.s,v 1.15 1994/02/01 04:08:54 davidg Exp $
+ */
+
+/*
+ * locore.s: FreeBSD machine support for the Intel 386
+ * originally from: locore.s, by William F. Jolitz
+ *
+ * Substantially rewritten by David Greenman, Rod Grimes,
+ * Bruce Evans, Wolfgang Solfrank, and many others.
+ */
+
+#include "npx.h" /* for NNPX */
+#include "assym.s" /* system definitions */
+#include "machine/psl.h" /* processor status longword defs */
+#include "machine/pte.h" /* page table entry definitions */
+#include "errno.h" /* error return codes */
+#include "machine/specialreg.h" /* x86 special registers */
+#include "machine/cputypes.h" /* x86 cpu type definitions */
+#include "syscall.h" /* system call numbers */
+#include "machine/asmacros.h" /* miscellaneous asm macros */
+
+/*
+ * XXX
+ *
+ * Note: This version greatly munged to avoid various assembler errors
+ * that may be fixed in newer versions of gas. Perhaps newer versions
+ * will have more pleasant appearance.
+ */
+
+/*
+ * PTmap is recursive pagemap at top of virtual address space.
+ * Within PTmap, the page directory can be found (third indirection).
+ */
+ .globl _PTmap,_PTD,_PTDpde,_Sysmap
+ .set _PTmap,PTDPTDI << PDRSHIFT
+ .set _PTD,_PTmap + (PTDPTDI * NBPG)
+ .set _PTDpde,_PTD + (PTDPTDI * PDESIZE)
+
+/* Sysmap is the base address of the kernel page tables */
+ .set _Sysmap,_PTmap + (KPTDI * NBPG)
+
+/*
+ * APTmap, APTD is the alternate recursive pagemap.
+ * It's used when modifying another process's page tables.
+ */
+ .globl _APTmap,_APTD,_APTDpde
+ .set _APTmap,APTDPTDI << PDRSHIFT
+ .set _APTD,_APTmap + (APTDPTDI * NBPG)
+ .set _APTDpde,_PTD + (APTDPTDI * PDESIZE)
+
+/*
+ * Access to each processes kernel stack is via a region of
+ * per-process address space (at the beginning), immediatly above
+ * the user process stack.
+ */
+ .set _kstack,USRSTACK
+ .globl _kstack
+
+/*
+ * Globals
+ */
+ .data
+ .globl _esym
+_esym: .long 0 /* ptr to end of syms */
+
+ .globl _boothowto,_bootdev,_curpcb
+
+ .globl _cpu,_cold,_atdevbase
+_cpu: .long 0 /* are we 386, 386sx, or 486 */
+_cold: .long 1 /* cold till we are not */
+_atdevbase: .long 0 /* location of start of iomem in virtual */
+_atdevphys: .long 0 /* location of device mapping ptes (phys) */
+
+ .globl _KERNend
+_KERNend: .long 0 /* phys addr end of kernel (just after bss) */
+
+ .globl _IdlePTD,_KPTphys
+_IdlePTD: .long 0 /* phys addr of kernel PTD */
+_KPTphys: .long 0 /* phys addr of kernel page tables */
+
+ .globl _cyloffset
+_cyloffset: .long 0 /* cylinder offset from boot blocks */
+
+ .globl _proc0paddr
+_proc0paddr: .long 0 /* address of proc 0 address space */
+
+#ifdef BDE_DEBUGGER
+ .globl _bdb_exists /* flag to indicate BDE debugger is available */
+_bdb_exists: .long 0
+#endif
+
+ .globl tmpstk
+ .space 0x1000
+tmpstk:
+
+
+/*
+ * System Initialization
+ */
+ .text
+
+/*
+ * btext: beginning of text section.
+ * Also the entry point (jumped to directly from the boot blocks).
+ */
+NON_GPROF_ENTRY(btext)
+ movw $0x1234,0x472 /* warm boot */
+ jmp 1f
+ .org 0x500 /* space for BIOS variables */
+
+ /*
+ * pass parameters on stack (howto, bootdev, unit, cyloffset, esym)
+ * note: (%esp) is return address of boot
+ * ( if we want to hold onto /boot, it's physical %esp up to _end)
+ */
+
+ 1: movl 4(%esp),%eax
+ movl %eax,_boothowto-KERNBASE
+ movl 8(%esp),%eax
+ movl %eax,_bootdev-KERNBASE
+ movl 12(%esp),%eax
+ movl %eax,_cyloffset-KERNBASE
+ movl 16(%esp),%eax
+ addl $KERNBASE,%eax
+ movl %eax,_esym-KERNBASE
+#ifdef DISKLESS /* Copy diskless structure */
+ movl _nfs_diskless_size-KERNBASE,%ecx
+ movl 20(%esp),%esi
+ movl $(_nfs_diskless-KERNBASE),%edi
+ rep
+ movsb
+#endif
+
+ /* find out our CPU type. */
+ pushfl
+ popl %eax
+ movl %eax,%ecx
+ xorl $0x40000,%eax
+ pushl %eax
+ popfl
+ pushfl
+ popl %eax
+ xorl %ecx,%eax
+ shrl $18,%eax
+ andl $1,%eax
+ push %ecx
+ popfl
+
+ cmpl $0,%eax
+ jne 1f
+ movl $CPU_386,_cpu-KERNBASE
+ jmp 2f
+1: movl $CPU_486,_cpu-KERNBASE
+2:
+
+ /*
+ * Finished with old stack; load new %esp now instead of later so
+ * we can trace this code without having to worry about the trace
+ * trap clobbering the memory test or the zeroing of the bss+bootstrap
+ * page tables.
+ *
+ * XXX - wdboot clears the bss after testing that this is safe.
+ * This is too wasteful - memory below 640K is scarce. The boot
+ * program should check:
+ * text+data <= &stack_variable - more_space_for_stack
+ * text+data+bss+pad+space_for_page_tables <= end_of_memory
+ * Oops, the gdt is in the carcass of the boot program so clearing
+ * the rest of memory is still not possible.
+ */
+ movl $tmpstk-KERNBASE,%esp /* bootstrap stack end location */
+
+/*
+ * Virtual address space of kernel:
+ *
+ * text | data | bss | [syms] | page dir | proc0 kernel stack | usr stk map | Sysmap
+ * pages: 1 UPAGES (2) 1 NKPT (7)
+ */
+
+/* find end of kernel image */
+ movl $_end-KERNBASE,%ecx
+ addl $NBPG-1,%ecx /* page align up */
+ andl $~(NBPG-1),%ecx
+ movl %ecx,%esi /* esi = start of free memory */
+ movl %ecx,_KERNend-KERNBASE /* save end of kernel */
+
+/* clear bss */
+ movl $_edata-KERNBASE,%edi
+ subl %edi,%ecx /* get amount to clear */
+ xorl %eax,%eax /* specify zero fill */
+ cld
+ rep
+ stosb
+
+/*
+ * The value in esi is both the end of the kernel bss and a pointer to
+ * the kernel page directory, and is used by the rest of locore to build
+ * the tables.
+ * esi + 1(page dir) + 2(UPAGES) + 1(p0stack) + NKPT(number of kernel
+ * page table pages) is then passed on the stack to init386(first) as
+ * the value first. esi should ALWAYS be page aligned!!
+ */
+ movl %esi,%ecx /* Get current first availiable address */
+
+/* clear pagetables, page directory, stack, etc... */
+ movl %esi,%edi /* base (page directory) */
+ movl $((1+UPAGES+1+NKPT)*NBPG),%ecx /* amount to clear */
+ xorl %eax,%eax /* specify zero fill */
+ cld
+ rep
+ stosb
+
+/* physical address of Idle proc/kernel page directory */
+ movl %esi,_IdlePTD-KERNBASE
+
+/*
+ * fillkpt
+ * eax = (page frame address | control | status) == pte
+ * ebx = address of page table
+ * ecx = how many pages to map
+ */
+#define fillkpt \
+1: movl %eax,(%ebx) ; \
+ addl $NBPG,%eax ; /* increment physical address */ \
+ addl $4,%ebx ; /* next pte */ \
+ loop 1b ;
+
+/*
+ * Map Kernel
+ *
+ * First step - build page tables
+ */
+#if defined (KGDB) || defined (BDE_DEBUGGER)
+ movl _KERNend-KERNBASE,%ecx /* this much memory, */
+ shrl $PGSHIFT,%ecx /* for this many PTEs */
+#ifdef BDE_DEBUGGER
+ cmpl $0xa0,%ecx /* XXX - cover debugger pages */
+ jae 1f
+ movl $0xa0,%ecx
+1:
+#endif /* BDE_DEBUGGER */
+ movl $PG_V|PG_KW,%eax /* having these bits set, */
+ lea ((1+UPAGES+1)*NBPG)(%esi),%ebx /* phys addr of kernel PT base */
+ movl %ebx,_KPTphys-KERNBASE /* save in global */
+ fillkpt
+
+#else /* !KGDB && !BDE_DEBUGGER */
+ /* write protect kernel text (doesn't do a thing for 386's - only 486's) */
+ movl $_etext-KERNBASE,%ecx /* get size of text */
+ shrl $PGSHIFT,%ecx /* for this many PTEs */
+ movl $PG_V|PG_KR,%eax /* specify read only */
+ lea ((1+UPAGES+1)*NBPG)(%esi),%ebx /* phys addr of kernel PT base */
+ movl %ebx,_KPTphys-KERNBASE /* save in global */
+ fillkpt
+
+ /* data and bss are r/w */
+ andl $PG_FRAME,%eax /* strip to just addr of bss */
+ movl _KERNend-KERNBASE,%ecx /* calculate size */
+ subl %eax,%ecx
+ shrl $PGSHIFT,%ecx
+ orl $PG_V|PG_KW,%eax /* valid, kernel read/write */
+ fillkpt
+#endif /* KGDB || BDE_DEBUGGER */
+
+/* now initialize the page dir, upages, p0stack PT, and page tables */
+
+ movl $(1+UPAGES+1+NKPT),%ecx /* number of PTEs */
+ movl %esi,%eax /* phys address of PTD */
+ andl $PG_FRAME,%eax /* convert to PFN, should be a NOP */
+ orl $PG_V|PG_KW,%eax /* valid, kernel read/write */
+ movl %esi,%ebx /* calculate pte offset to ptd */
+ shrl $PGSHIFT-2,%ebx
+ addl %esi,%ebx /* address of page directory */
+ addl $((1+UPAGES+1)*NBPG),%ebx /* offset to kernel page tables */
+ fillkpt
+
+/* map I/O memory map */
+
+ movl _KPTphys-KERNBASE,%ebx /* base of kernel page tables */
+ lea (0xa0 * PTESIZE)(%ebx),%ebx /* hardwire ISA hole at KERNBASE + 0xa0000 */
+ movl $0x100-0xa0,%ecx /* for this many pte s, */
+ movl $(0xa0000|PG_V|PG_KW|PG_N),%eax /* valid, kernel read/write, non-cacheable */
+ movl %ebx,_atdevphys-KERNBASE /* save phys addr of ptes */
+ fillkpt
+
+ /* map proc 0's kernel stack into user page table page */
+
+ movl $UPAGES,%ecx /* for this many pte s, */
+ lea (1*NBPG)(%esi),%eax /* physical address in proc 0 */
+ lea (KERNBASE)(%eax),%edx /* change into virtual addr */
+ movl %edx,_proc0paddr-KERNBASE /* save VA for proc 0 init */
+ orl $PG_V|PG_KW,%eax /* valid, kernel read/write */
+ lea ((1+UPAGES)*NBPG)(%esi),%ebx /* addr of stack page table in proc 0 */
+ addl $(KSTKPTEOFF * PTESIZE),%ebx /* offset to kernel stack PTE */
+ fillkpt
+
+/*
+ * Initialize kernel page table directory
+ */
+ /* install a pde for temporary double map of bottom of VA */
+ movl _KPTphys-KERNBASE,%eax
+ orl $PG_V|PG_KW,%eax /* valid, kernel read/write */
+ movl %eax,(%esi) /* which is where temp maps! */
+
+ /* initialize kernel pde's */
+ movl $(NKPT),%ecx /* for this many PDEs */
+ lea (KPTDI*PDESIZE)(%esi),%ebx /* offset of pde for kernel */
+ fillkpt
+
+ /* install a pde recursively mapping page directory as a page table! */
+ movl %esi,%eax /* phys address of ptd in proc 0 */
+ orl $PG_V|PG_KW,%eax /* pde entry is valid */
+ movl %eax,PTDPTDI*PDESIZE(%esi) /* which is where PTmap maps! */
+
+ /* install a pde to map kernel stack for proc 0 */
+ lea ((1+UPAGES)*NBPG)(%esi),%eax /* physical address of pt in proc 0 */
+ orl $PG_V|PG_KW,%eax /* pde entry is valid */
+ movl %eax,KSTKPTDI*PDESIZE(%esi) /* which is where kernel stack maps! */
+
+#ifdef BDE_DEBUGGER
+ /* copy and convert stuff from old gdt and idt for debugger */
+
+ cmpl $0x0375c339,0x96104 /* XXX - debugger signature */
+ jne 1f
+ movb $1,_bdb_exists-KERNBASE
+1:
+ pushal
+ subl $2*6,%esp
+
+ sgdt (%esp)
+ movl 2(%esp),%esi /* base address of current gdt */
+ movl $_gdt-KERNBASE,%edi
+ movl %edi,2(%esp)
+ movl $8*18/4,%ecx
+ rep /* copy gdt */
+ movsl
+ movl $_gdt-KERNBASE,-8+2(%edi) /* adjust gdt self-ptr */
+ movb $0x92,-8+5(%edi)
+
+ sidt 6(%esp)
+ movl 6+2(%esp),%esi /* base address of current idt */
+ movl 8+4(%esi),%eax /* convert dbg descriptor to ... */
+ movw 8(%esi),%ax
+ movl %eax,bdb_dbg_ljmp+1-KERNBASE /* ... immediate offset ... */
+ movl 8+2(%esi),%eax
+ movw %ax,bdb_dbg_ljmp+5-KERNBASE /* ... and selector for ljmp */
+ movl 24+4(%esi),%eax /* same for bpt descriptor */
+ movw 24(%esi),%ax
+ movl %eax,bdb_bpt_ljmp+1-KERNBASE
+ movl 24+2(%esi),%eax
+ movw %ax,bdb_bpt_ljmp+5-KERNBASE
+
+ movl $_idt-KERNBASE,%edi
+ movl %edi,6+2(%esp)
+ movl $8*4/4,%ecx
+ rep /* copy idt */
+ movsl
+
+ lgdt (%esp)
+ lidt 6(%esp)
+
+ addl $2*6,%esp
+ popal
+#endif /* BDE_DEBUGGER */
+
+ /* load base of page directory and enable mapping */
+ movl %esi,%eax /* phys address of ptd in proc 0 */
+ orl $I386_CR3PAT,%eax
+ movl %eax,%cr3 /* load ptd addr into mmu */
+ movl %cr0,%eax /* get control word */
+ orl $CR0_PE|CR0_PG,%eax /* enable paging */
+ movl %eax,%cr0 /* and let's page NOW! */
+
+ pushl $begin /* jump to high mem */
+ ret
+
+begin: /* now running relocated at KERNBASE where the system is linked to run */
+
+ .globl _Crtat /* XXX - locore should not know about */
+ movl _Crtat,%eax /* variables of device drivers (pccons)! */
+ subl $(KERNBASE+0xA0000),%eax
+ movl _atdevphys,%edx /* get pte PA */
+ subl _KPTphys,%edx /* remove base of ptes, now have phys offset */
+ shll $PGSHIFT-2,%edx /* corresponding to virt offset */
+ addl $KERNBASE,%edx /* add virtual base */
+ movl %edx,_atdevbase
+ addl %eax,%edx
+ movl %edx,_Crtat
+
+ /* set up bootstrap stack - 48 bytes */
+ movl $_kstack+UPAGES*NBPG-4*12,%esp /* bootstrap stack end location */
+ xorl %eax,%eax /* mark end of frames */
+ movl %eax,%ebp
+ movl _proc0paddr,%eax
+ movl %esi,PCB_CR3(%eax)
+
+#ifdef BDE_DEBUGGER
+ /* relocate debugger gdt entries */
+
+ movl $_gdt+8*9,%eax /* adjust slots 9-17 */
+ movl $9,%ecx
+reloc_gdt:
+ movb $KERNBASE>>24,7(%eax) /* top byte of base addresses, was 0, */
+ addl $8,%eax /* now KERNBASE>>24 */
+ loop reloc_gdt
+
+ cmpl $0,_bdb_exists
+ je 1f
+ int $3
+1:
+#endif /* BDE_DEBUGGER */
+
+ /*
+ * Skip over the page tables and the kernel stack
+ */
+ lea ((1+UPAGES+1+NKPT)*NBPG)(%esi),%esi
+
+ pushl %esi /* value of first for init386(first) */
+ call _init386 /* wire 386 chip for unix operation */
+
+ movl $0,_PTD
+ call _main /* autoconfiguration, mountroot etc */
+ popl %esi
+
+ /*
+ * now we've run main() and determined what cpu-type we are, we can
+ * enable WP mode on i486 cpus and above.
+ */
+#if defined(I486_CPU) || defined(I586_CPU)
+ cmpl $CPUCLASS_386,_cpu_class
+ je 1f
+ movl %cr0,%eax /* get control word */
+ orl $CR0_WP,%eax /* enable write protect for all modes */
+ movl %eax,%cr0 /* and do it */
+#endif
+ /*
+ * on return from main(), we are process 1
+ * set up address space and stack so that we can 'return' to user mode
+ */
+1:
+ .globl __ucodesel,__udatasel
+ movl __ucodesel,%eax
+ movl __udatasel,%ecx
+ /* build outer stack frame */
+ pushl %ecx /* user ss */
+ pushl $USRSTACK /* user esp */
+ pushl %eax /* user cs */
+ pushl $0 /* user ip */
+ movl %cx,%ds
+ movl %cx,%es
+ movl %ax,%fs /* double map cs to fs */
+ movl %cx,%gs /* and ds to gs */
+ lret /* goto user! */
+
+ pushl $lretmsg1 /* "should never get here!" */
+ call _panic
+lretmsg1:
+ .asciz "lret: toinit\n"
+
+
+#define LCALL(x,y) .byte 0x9a ; .long y ; .word x
+/*
+ * Icode is copied out to process 1 and executed in user mode:
+ * execve("/sbin/init", argv, envp); exit(0);
+ * If the execve fails, process 1 exits and the system panics.
+ */
+NON_GPROF_ENTRY(icode)
+ pushl $0 /* envp for execve() */
+
+# pushl $argv-_icode /* can't do this 'cos gas 1.38 is broken */
+ movl $argv,%eax
+ subl $_icode,%eax
+ pushl %eax /* argp for execve() */
+
+# pushl $init-_icode
+ movl $init,%eax
+ subl $_icode,%eax
+ pushl %eax /* fname for execve() */
+
+ pushl %eax /* dummy return address */
+
+ movl $SYS_execve,%eax
+ LCALL(0x7,0x0)
+
+ /* exit if something botches up in the above execve() */
+ pushl %eax /* execve failed, the errno will do for an */
+ /* exit code because errnos are < 128 */
+ pushl %eax /* dummy return address */
+ movl $SYS_exit,%eax
+ LCALL(0x7,0x0)
+
+init:
+ .asciz "/sbin/init"
+ ALIGN_DATA
+argv:
+ .long init+6-_icode /* argv[0] = "init" ("/sbin/init" + 6) */
+ .long eicode-_icode /* argv[1] follows icode after copyout */
+ .long 0
+eicode:
+
+ .globl _szicode
+_szicode:
+ .long _szicode-_icode
+
+NON_GPROF_ENTRY(sigcode)
+ call SIGF_HANDLER(%esp)
+ lea SIGF_SC(%esp),%eax /* scp (the call may have clobbered the */
+ /* copy at 8(%esp)) */
+ pushl %eax
+ pushl %eax /* junk to fake return address */
+ movl $103,%eax /* XXX sigreturn() */
+ LCALL(0x7,0) /* enter kernel with args on stack */
+ hlt /* never gets here */
+
+ .globl _szsigcode
+_szsigcode:
+ .long _szsigcode-_sigcode
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
new file mode 100644
index 0000000..eab1075
--- /dev/null
+++ b/sys/amd64/amd64/machdep.c
@@ -0,0 +1,1449 @@
+/*-
+ * Copyright (c) 1992 Terrence R. Lambert.
+ * Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91
+ * $Id: machdep.c,v 1.41 1994/03/30 02:31:11 davidg Exp $
+ */
+
+#include "npx.h"
+#include "isa.h"
+
+#include <stddef.h>
+#include "param.h"
+#include "systm.h"
+#include "signalvar.h"
+#include "kernel.h"
+#include "map.h"
+#include "proc.h"
+#include "user.h"
+#include "exec.h" /* for PS_STRINGS */
+#include "buf.h"
+#include "reboot.h"
+#include "conf.h"
+#include "file.h"
+#include "callout.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "msgbuf.h"
+
+#ifdef SYSVSHM
+#include "sys/shm.h"
+#endif
+
+#ifdef SYSVMSG
+#include "msg.h"
+#endif
+
+#ifdef SYSVSEM
+#include "sem.h"
+#endif
+
+#include "vm/vm.h"
+#include "vm/vm_kern.h"
+#include "vm/vm_page.h"
+
+#include "sys/exec.h"
+#include "sys/vnode.h"
+
+extern vm_offset_t avail_start, avail_end;
+
+#include "machine/cpu.h"
+#include "machine/reg.h"
+#include "machine/psl.h"
+#include "machine/specialreg.h"
+#include "machine/sysarch.h"
+#include "machine/cons.h"
+
+#include "i386/isa/isa.h"
+#include "i386/isa/rtc.h"
+
+static void identifycpu(void);
+static void initcpu(void);
+static int test_page(int *, int);
+
+extern int grow(struct proc *,int);
+const char machine[] = "PC-Class";
+const char *cpu_model;
+
+#ifndef PANIC_REBOOT_WAIT_TIME
+#define PANIC_REBOOT_WAIT_TIME 15 /* default to 15 seconds */
+#endif
+
+/*
+ * Declare these as initialized data so we can patch them.
+ */
+int nswbuf = 0;
+#ifdef NBUF
+int nbuf = NBUF;
+#else
+int nbuf = 0;
+#endif
+#ifdef BUFPAGES
+int bufpages = BUFPAGES;
+#else
+int bufpages = 0;
+#endif
+#ifdef BOUNCEPAGES
+int bouncepages = BOUNCEPAGES;
+#else
+int bouncepages = 0;
+#endif
+extern int freebufspace;
+extern char *bouncememory;
+
+int _udatasel, _ucodesel;
+
+/*
+ * Machine-dependent startup code
+ */
+int boothowto = 0, Maxmem = 0, badpages = 0, physmem = 0;
+long dumplo;
+extern int bootdev;
+int biosmem;
+
+vm_offset_t phys_avail[6];
+
+extern cyloffset;
+
+int cpu_class;
+
+void dumpsys __P((void));
+
+void
+cpu_startup()
+{
+ register int unixsize;
+ register unsigned i;
+ register struct pte *pte;
+ int mapaddr, j;
+ register caddr_t v;
+ int maxbufs, base, residual;
+ extern long Usrptsize;
+ vm_offset_t minaddr, maxaddr;
+ vm_size_t size = 0;
+ int firstaddr;
+
+ /*
+ * Initialize error message buffer (at end of core).
+ */
+
+ /* avail_end was pre-decremented in init_386() to compensate */
+ for (i = 0; i < btoc(sizeof (struct msgbuf)); i++)
+ pmap_enter(pmap_kernel(), (vm_offset_t)msgbufp,
+ avail_end + i * NBPG,
+ VM_PROT_ALL, TRUE);
+ msgbufmapped = 1;
+
+ /*
+ * Good {morning,afternoon,evening,night}.
+ */
+ printf(version);
+ identifycpu();
+ printf("real memory = %d (%d pages)\n", ptoa(physmem), physmem);
+ if (badpages)
+ printf("bad memory = %d (%d pages)\n", ptoa(badpages), badpages);
+
+ /*
+ * Allocate space for system data structures.
+ * The first available kernel virtual address is in "v".
+ * As pages of kernel virtual memory are allocated, "v" is incremented.
+ * As pages of memory are allocated and cleared,
+ * "firstaddr" is incremented.
+ * An index into the kernel page table corresponding to the
+ * virtual memory address maintained in "v" is kept in "mapaddr".
+ */
+
+ /*
+ * Make two passes. The first pass calculates how much memory is
+ * needed and allocates it. The second pass assigns virtual
+ * addresses to the various data structures.
+ */
+ firstaddr = 0;
+again:
+ v = (caddr_t)firstaddr;
+
+#define valloc(name, type, num) \
+ (name) = (type *)v; v = (caddr_t)((name)+(num))
+#define valloclim(name, type, num, lim) \
+ (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num)))
+ valloc(callout, struct callout, ncallout);
+#ifdef SYSVSHM
+ valloc(shmsegs, struct shmid_ds, shminfo.shmmni);
+#endif
+#ifdef SYSVSEM
+ valloc(sema, struct semid_ds, seminfo.semmni);
+ valloc(sem, struct sem, seminfo.semmns);
+ /* This is pretty disgusting! */
+ valloc(semu, int, (seminfo.semmnu * seminfo.semusz) / sizeof(int));
+#endif
+#ifdef SYSVMSG
+ valloc(msgpool, char, msginfo.msgmax);
+ valloc(msgmaps, struct msgmap, msginfo.msgseg);
+ valloc(msghdrs, struct msg, msginfo.msgtql);
+ valloc(msqids, struct msqid_ds, msginfo.msgmni);
+#endif
+ /*
+ * Determine how many buffers to allocate.
+ * Use 20% of memory of memory beyond the first 2MB
+ * Insure a minimum of 16 fs buffers.
+ * We allocate 1/2 as many swap buffer headers as file i/o buffers.
+ */
+ if (bufpages == 0)
+ bufpages = ((physmem << PGSHIFT) - 2048*1024) / NBPG / 5;
+ if (bufpages < 64)
+ bufpages = 64;
+
+ /*
+ * We must still limit the maximum number of buffers to be no
+ * more than 2/5's of the size of the kernal malloc region, this
+ * will only take effect for machines with lots of memory
+ */
+ bufpages = min(bufpages, (VM_KMEM_SIZE / NBPG) * 2 / 5);
+ if (nbuf == 0) {
+ nbuf = bufpages / 2;
+ if (nbuf < 32)
+ nbuf = 32;
+ }
+ freebufspace = bufpages * NBPG;
+ if (nswbuf == 0) {
+ nswbuf = (nbuf / 2) &~ 1; /* force even */
+ if (nswbuf > 256)
+ nswbuf = 256; /* sanity */
+ }
+ valloc(swbuf, struct buf, nswbuf);
+ valloc(buf, struct buf, nbuf);
+
+#ifndef NOBOUNCE
+ /*
+ * If there is more than 16MB of memory, allocate some bounce buffers
+ */
+ if (Maxmem > 4096) {
+ if (bouncepages == 0)
+ bouncepages = 96; /* largest physio size + extra */
+ v = (caddr_t)((vm_offset_t)((vm_offset_t)v + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1));
+ valloc(bouncememory, char, bouncepages * PAGE_SIZE);
+ }
+#endif
+
+ /*
+ * End of first pass, size has been calculated so allocate memory
+ */
+ if (firstaddr == 0) {
+ size = (vm_size_t)(v - firstaddr);
+ firstaddr = (int)kmem_alloc(kernel_map, round_page(size));
+ if (firstaddr == 0)
+ panic("startup: no room for tables");
+ goto again;
+ }
+
+ /*
+ * End of second pass, addresses have been assigned
+ */
+ if ((vm_size_t)(v - firstaddr) != size)
+ panic("startup: table size inconsistency");
+
+ /*
+ * Allocate a submap for buffer space allocations.
+ * XXX we are NOT using buffer_map, but due to
+ * the references to it we will just allocate 1 page of
+ * vm (not real memory) to make things happy...
+ */
+ buffer_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr,
+ /* bufpages * */NBPG, TRUE);
+ /*
+ * Allocate a submap for physio
+ */
+ phys_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr,
+ VM_PHYS_SIZE, TRUE);
+
+ /*
+ * Finally, allocate mbuf pool. Since mclrefcnt is an off-size
+ * we use the more space efficient malloc in place of kmem_alloc.
+ */
+ mclrefcnt = (char *)malloc(NMBCLUSTERS+CLBYTES/MCLBYTES,
+ M_MBUF, M_NOWAIT);
+ bzero(mclrefcnt, NMBCLUSTERS+CLBYTES/MCLBYTES);
+ mb_map = kmem_suballoc(kmem_map, (vm_offset_t)&mbutl, &maxaddr,
+ VM_MBUF_SIZE, FALSE);
+ /*
+ * Initialize callouts
+ */
+ callfree = callout;
+ for (i = 1; i < ncallout; i++)
+ callout[i-1].c_next = &callout[i];
+
+ printf("avail memory = %d (%d pages)\n", ptoa(vm_page_free_count), vm_page_free_count);
+ printf("using %d buffers containing %d bytes of memory\n",
+ nbuf, bufpages * CLBYTES);
+
+#ifndef NOBOUNCE
+ /*
+ * init bounce buffers
+ */
+ vm_bounce_init();
+#endif
+
+ /*
+ * Set up CPU-specific registers, cache, etc.
+ */
+ initcpu();
+
+ /*
+ * Set up buffers, so they can be used to read disk labels.
+ */
+ bufinit();
+
+ /*
+ * Configure the system.
+ */
+ configure();
+}
+
+
+struct cpu_nameclass i386_cpus[] = {
+ { "Intel 80286", CPUCLASS_286 }, /* CPU_286 */
+ { "i386SX", CPUCLASS_386 }, /* CPU_386SX */
+ { "i386DX", CPUCLASS_386 }, /* CPU_386 */
+ { "i486SX", CPUCLASS_486 }, /* CPU_486SX */
+ { "i486DX", CPUCLASS_486 }, /* CPU_486 */
+ { "i586", CPUCLASS_586 }, /* CPU_586 */
+};
+
+static void
+identifycpu()
+{
+ printf("CPU: ");
+ if (cpu >= 0 && cpu < (sizeof i386_cpus/sizeof(struct cpu_nameclass))) {
+ printf("%s", i386_cpus[cpu].cpu_name);
+ cpu_class = i386_cpus[cpu].cpu_class;
+ cpu_model = i386_cpus[cpu].cpu_name;
+ } else {
+ printf("unknown cpu type %d\n", cpu);
+ panic("startup: bad cpu id");
+ }
+ printf(" (");
+ switch(cpu_class) {
+ case CPUCLASS_286:
+ printf("286");
+ break;
+ case CPUCLASS_386:
+ printf("386");
+ break;
+ case CPUCLASS_486:
+ printf("486");
+ break;
+ case CPUCLASS_586:
+ printf("586");
+ break;
+ default:
+ printf("unknown"); /* will panic below... */
+ }
+ printf("-class CPU)");
+ printf("\n"); /* cpu speed would be nice, but how? */
+
+ /*
+ * Now that we have told the user what they have,
+ * let them know if that machine type isn't configured.
+ */
+ switch (cpu_class) {
+ case CPUCLASS_286: /* a 286 should not make it this far, anyway */
+#if !defined(I386_CPU) && !defined(I486_CPU) && !defined(I586_CPU)
+#error This kernel is not configured for one of the supported CPUs
+#endif
+#if !defined(I386_CPU)
+ case CPUCLASS_386:
+#endif
+#if !defined(I486_CPU)
+ case CPUCLASS_486:
+#endif
+#if !defined(I586_CPU)
+ case CPUCLASS_586:
+#endif
+ panic("CPU class not configured");
+ default:
+ break;
+ }
+}
+
+#ifdef PGINPROF
+/*
+ * Return the difference (in microseconds)
+ * between the current time and a previous
+ * time as represented by the arguments.
+ * If there is a pending clock interrupt
+ * which has not been serviced due to high
+ * ipl, return error code.
+ */
+/*ARGSUSED*/
+vmtime(otime, olbolt, oicr)
+ register int otime, olbolt, oicr;
+{
+
+ return (((time.tv_sec-otime)*60 + lbolt-olbolt)*16667);
+}
+#endif
+
+extern int kstack[];
+
+/*
+ * Send an interrupt to process.
+ *
+ * Stack is set up to allow sigcode stored
+ * in u. to call routine, followed by kcall
+ * to sigreturn routine below. After sigreturn
+ * resets the signal mask, the stack, and the
+ * frame pointer, it returns to the user
+ * specified pc, psl.
+ */
+void
+sendsig(catcher, sig, mask, code)
+ sig_t catcher;
+ int sig, mask;
+ unsigned code;
+{
+ register struct proc *p = curproc;
+ register int *regs;
+ register struct sigframe *fp;
+ struct sigacts *ps = p->p_sigacts;
+ int oonstack, frmtrap;
+
+ regs = p->p_regs;
+ oonstack = ps->ps_onstack;
+ /*
+ * Allocate and validate space for the signal handler
+ * context. Note that if the stack is in P0 space, the
+ * call to grow() is a nop, and the useracc() check
+ * will fail if the process has not already allocated
+ * the space with a `brk'.
+ */
+ if (!ps->ps_onstack && (ps->ps_sigonstack & sigmask(sig))) {
+ fp = (struct sigframe *)(ps->ps_sigsp
+ - sizeof(struct sigframe));
+ ps->ps_onstack = 1;
+ } else {
+ fp = (struct sigframe *)(regs[tESP]
+ - sizeof(struct sigframe));
+ }
+
+ /*
+ * grow() will return FALSE if the fp will not fit inside the stack
+ * and the stack can not be grown. useracc will return FALSE
+ * if access is denied.
+ */
+ if ((grow(p, (int)fp) == FALSE) ||
+ (useracc((caddr_t)fp, sizeof (struct sigframe), B_WRITE) == FALSE)) {
+ /*
+ * Process has trashed its stack; give it an illegal
+ * instruction to halt it in its tracks.
+ */
+ SIGACTION(p, SIGILL) = SIG_DFL;
+ sig = sigmask(SIGILL);
+ p->p_sigignore &= ~sig;
+ p->p_sigcatch &= ~sig;
+ p->p_sigmask &= ~sig;
+ psignal(p, SIGILL);
+ return;
+ }
+
+ /*
+ * Build the argument list for the signal handler.
+ */
+ fp->sf_signum = sig;
+ fp->sf_code = code;
+ fp->sf_scp = &fp->sf_sc;
+ fp->sf_addr = (char *) regs[tERR];
+ fp->sf_handler = catcher;
+
+ /* save scratch registers */
+ fp->sf_sc.sc_eax = regs[tEAX];
+ fp->sf_sc.sc_ebx = regs[tEBX];
+ fp->sf_sc.sc_ecx = regs[tECX];
+ fp->sf_sc.sc_edx = regs[tEDX];
+ fp->sf_sc.sc_esi = regs[tESI];
+ fp->sf_sc.sc_edi = regs[tEDI];
+ fp->sf_sc.sc_cs = regs[tCS];
+ fp->sf_sc.sc_ds = regs[tDS];
+ fp->sf_sc.sc_ss = regs[tSS];
+ fp->sf_sc.sc_es = regs[tES];
+ fp->sf_sc.sc_isp = regs[tISP];
+
+ /*
+ * Build the signal context to be used by sigreturn.
+ */
+ fp->sf_sc.sc_onstack = oonstack;
+ fp->sf_sc.sc_mask = mask;
+ fp->sf_sc.sc_sp = regs[tESP];
+ fp->sf_sc.sc_fp = regs[tEBP];
+ fp->sf_sc.sc_pc = regs[tEIP];
+ fp->sf_sc.sc_ps = regs[tEFLAGS];
+ regs[tESP] = (int)fp;
+ regs[tEIP] = (int)((struct pcb *)kstack)->pcb_sigc;
+ regs[tEFLAGS] &= ~PSL_VM;
+ regs[tCS] = _ucodesel;
+ regs[tDS] = _udatasel;
+ regs[tES] = _udatasel;
+ regs[tSS] = _udatasel;
+}
+
+/*
+ * System call to cleanup state after a signal
+ * has been taken. Reset signal mask and
+ * stack state from context left by sendsig (above).
+ * Return to previous pc and psl as specified by
+ * context left by sendsig. Check carefully to
+ * make sure that the user has not modified the
+ * psl to gain improper privileges or to cause
+ * a machine fault.
+ */
+struct sigreturn_args {
+ struct sigcontext *sigcntxp;
+};
+
+int
+sigreturn(p, uap, retval)
+ struct proc *p;
+ struct sigreturn_args *uap;
+ int *retval;
+{
+ register struct sigcontext *scp;
+ register struct sigframe *fp;
+ register int *regs = p->p_regs;
+ int eflags;
+
+ /*
+ * (XXX old comment) regs[tESP] points to the return address.
+ * The user scp pointer is above that.
+ * The return address is faked in the signal trampoline code
+ * for consistency.
+ */
+ scp = uap->sigcntxp;
+ fp = (struct sigframe *)
+ ((caddr_t)scp - offsetof(struct sigframe, sf_sc));
+
+ if (useracc((caddr_t)fp, sizeof (*fp), 0) == 0)
+ return(EINVAL);
+
+ eflags = scp->sc_ps;
+ if ((eflags & PSL_USERCLR) != 0 ||
+ (eflags & PSL_USERSET) != PSL_USERSET ||
+ (eflags & PSL_IOPL) < (regs[tEFLAGS] & PSL_IOPL)) {
+#ifdef DEBUG
+ printf("sigreturn: eflags=0x%x\n", eflags);
+#endif
+ return(EINVAL);
+ }
+
+ /*
+ * Sanity check the user's selectors and error if they
+ * are suspect.
+ */
+#define max_ldt_sel(pcb) \
+ ((pcb)->pcb_ldt ? (pcb)->pcb_ldt_len : (sizeof(ldt) / sizeof(ldt[0])))
+
+#define valid_ldt_sel(sel) \
+ (ISLDT(sel) && ISPL(sel) == SEL_UPL && \
+ IDXSEL(sel) < max_ldt_sel(&p->p_addr->u_pcb))
+
+#define null_sel(sel) \
+ (!ISLDT(sel) && IDXSEL(sel) == 0)
+
+ if ((scp->sc_cs&0xffff != _ucodesel && !valid_ldt_sel(scp->sc_cs)) ||
+ (scp->sc_ss&0xffff != _udatasel && !valid_ldt_sel(scp->sc_ss)) ||
+ (scp->sc_ds&0xffff != _udatasel && !valid_ldt_sel(scp->sc_ds) &&
+ !null_sel(scp->sc_ds)) ||
+ (scp->sc_es&0xffff != _udatasel && !valid_ldt_sel(scp->sc_es) &&
+ !null_sel(scp->sc_es))) {
+#ifdef DEBUG
+ printf("sigreturn: cs=0x%x ss=0x%x ds=0x%x es=0x%x\n",
+ scp->sc_cs, scp->sc_ss, scp->sc_ds, scp->sc_es);
+#endif
+ trapsignal(p, SIGBUS, T_PROTFLT);
+ return(EINVAL);
+ }
+
+#undef max_ldt_sel
+#undef valid_ldt_sel
+#undef null_sel
+
+ /* restore scratch registers */
+ regs[tEAX] = scp->sc_eax;
+ regs[tEBX] = scp->sc_ebx;
+ regs[tECX] = scp->sc_ecx;
+ regs[tEDX] = scp->sc_edx;
+ regs[tESI] = scp->sc_esi;
+ regs[tEDI] = scp->sc_edi;
+ regs[tCS] = scp->sc_cs;
+ regs[tDS] = scp->sc_ds;
+ regs[tES] = scp->sc_es;
+ regs[tSS] = scp->sc_ss;
+ regs[tISP] = scp->sc_isp;
+
+ if (useracc((caddr_t)scp, sizeof (*scp), 0) == 0)
+ return(EINVAL);
+
+ p->p_sigacts->ps_onstack = scp->sc_onstack & 01;
+ p->p_sigmask = scp->sc_mask &~
+ (sigmask(SIGKILL)|sigmask(SIGCONT)|sigmask(SIGSTOP));
+ regs[tEBP] = scp->sc_fp;
+ regs[tESP] = scp->sc_sp;
+ regs[tEIP] = scp->sc_pc;
+ regs[tEFLAGS] = eflags;
+ return(EJUSTRETURN);
+}
+
+/*
+ * a simple function to make the system panic (and dump a vmcore)
+ * in a predictable fashion
+ */
+void diediedie()
+{
+ panic("because you said to!");
+}
+
+int waittime = -1;
+struct pcb dumppcb;
+
+void
+boot(arghowto)
+ int arghowto;
+{
+ register long dummy; /* r12 is reserved */
+ register int howto; /* r11 == how to boot */
+ register int devtype; /* r10 == major of root dev */
+ extern int cold;
+ int nomsg = 1;
+
+ if (cold) {
+ printf("hit reset please");
+ for(;;);
+ }
+ howto = arghowto;
+ if ((howto&RB_NOSYNC) == 0 && waittime < 0 && bfreelist[0].b_forw) {
+ register struct buf *bp;
+ int iter, nbusy;
+
+ waittime = 0;
+ (void) splnet();
+ printf("syncing disks... ");
+ /*
+ * Release inodes held by texts before update.
+ */
+ if (panicstr == 0)
+ vnode_pager_umount(NULL);
+ sync(curproc, NULL, NULL);
+ /*
+ * Unmount filesystems
+ */
+#if 0
+ if (panicstr == 0)
+ vfs_unmountall();
+#endif
+
+ for (iter = 0; iter < 20; iter++) {
+ nbusy = 0;
+ for (bp = &buf[nbuf]; --bp >= buf; )
+ if ((bp->b_flags & (B_BUSY|B_INVAL)) == B_BUSY)
+ nbusy++;
+ if (nbusy == 0)
+ break;
+ if (nomsg) {
+ printf("updating disks before rebooting... ");
+ nomsg = 0;
+ }
+ printf("%d ", nbusy);
+ DELAY(40000 * iter);
+ }
+ if (nbusy)
+ printf("giving up\n");
+ else
+ printf("done\n");
+ DELAY(10000); /* wait for printf to finish */
+ }
+ splhigh();
+ devtype = major(rootdev);
+ if (howto&RB_HALT) {
+ printf("\n");
+ printf("The operating system has halted.\n");
+ printf("Please press any key to reboot.\n\n");
+ cngetc();
+ } else {
+ if (howto & RB_DUMP) {
+ savectx(&dumppcb, 0);
+ dumppcb.pcb_ptd = rcr3();
+ dumpsys();
+
+ if (PANIC_REBOOT_WAIT_TIME != 0) {
+ if (PANIC_REBOOT_WAIT_TIME != -1) {
+ int loop;
+ printf("Automatic reboot in %d seconds - press a key on the console to abort\n",
+ PANIC_REBOOT_WAIT_TIME);
+ for (loop = PANIC_REBOOT_WAIT_TIME; loop > 0; --loop) {
+ DELAY(1000 * 1000); /* one second */
+ if (sgetc(1)) /* Did user type a key? */
+ break;
+ }
+ if (!loop)
+ goto die;
+ }
+ } else { /* zero time specified - reboot NOW */
+ goto die;
+ }
+ printf("--> Press a key on the console to reboot <--\n");
+ cngetc();
+ }
+ }
+#ifdef lint
+ dummy = 0; dummy = dummy;
+ printf("howto %d, devtype %d\n", arghowto, devtype);
+#endif
+die:
+ printf("Rebooting...\n");
+ DELAY(1000000); /* wait 1 sec for printf's to complete and be read */
+ cpu_reset();
+ for(;;) ;
+ /* NOTREACHED */
+}
+
+unsigned long dumpmag = 0x8fca0101UL; /* magic number for savecore */
+int dumpsize = 0; /* also for savecore */
+/*
+ * Doadump comes here after turning off memory management and
+ * getting on the dump stack, either when called above, or by
+ * the auto-restart code.
+ */
+void
+dumpsys()
+{
+
+ if (dumpdev == NODEV)
+ return;
+ if ((minor(dumpdev)&07) != 1)
+ return;
+ dumpsize = Maxmem;
+ printf("\ndumping to dev %x, offset %d\n", dumpdev, dumplo);
+ printf("dump ");
+ switch ((*bdevsw[major(dumpdev)].d_dump)(dumpdev)) {
+
+ case ENXIO:
+ printf("device bad\n");
+ break;
+
+ case EFAULT:
+ printf("device not ready\n");
+ break;
+
+ case EINVAL:
+ printf("area improper\n");
+ break;
+
+ case EIO:
+ printf("i/o error\n");
+ break;
+
+ case EINTR:
+ printf("aborted from console\n");
+ break;
+
+ default:
+ printf("succeeded\n");
+ break;
+ }
+}
+
+#ifdef HZ
+/*
+ * If HZ is defined we use this code, otherwise the code in
+ * /sys/i386/i386/microtime.s is used. The othercode only works
+ * for HZ=100.
+ */
+microtime(tvp)
+ register struct timeval *tvp;
+{
+ int s = splhigh();
+
+ *tvp = time;
+ tvp->tv_usec += tick;
+ while (tvp->tv_usec > 1000000) {
+ tvp->tv_sec++;
+ tvp->tv_usec -= 1000000;
+ }
+ splx(s);
+}
+#endif /* HZ */
+
+static void
+initcpu()
+{
+}
+
+/*
+ * Clear registers on exec
+ */
+void
+setregs(p, entry, stack)
+ struct proc *p;
+ u_long entry;
+ u_long stack;
+{
+ p->p_regs[tEBP] = 0; /* bottom of the fp chain */
+ p->p_regs[tEIP] = entry;
+ p->p_regs[tESP] = stack;
+ p->p_regs[tSS] = _udatasel;
+ p->p_regs[tDS] = _udatasel;
+ p->p_regs[tES] = _udatasel;
+ p->p_regs[tCS] = _ucodesel;
+
+ p->p_addr->u_pcb.pcb_flags = 0; /* no fp at all */
+ load_cr0(rcr0() | CR0_TS); /* start emulating */
+#if NNPX > 0
+ npxinit(__INITIAL_NPXCW__);
+#endif /* NNPX > 0 */
+}
+
+/*
+ * Initialize 386 and configure to run kernel
+ */
+
+/*
+ * Initialize segments & interrupt table
+ */
+
+union descriptor gdt[NGDT];
+union descriptor ldt[NLDT]; /* local descriptor table */
+struct gate_descriptor idt[NIDT]; /* interrupt descriptor table */
+
+int _default_ldt, currentldt;
+
+struct i386tss tss, panic_tss;
+
+extern struct user *proc0paddr;
+
+/* software prototypes -- in more palatable form */
+struct soft_segment_descriptor gdt_segs[] = {
+ /* Null Descriptor */
+{ 0x0, /* segment base address */
+ 0x0, /* length */
+ 0, /* segment type */
+ 0, /* segment descriptor priority level */
+ 0, /* segment descriptor present */
+ 0, 0,
+ 0, /* default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Code Descriptor for kernel */
+{ 0x0, /* segment base address */
+ 0xfffff, /* length - all address space */
+ SDT_MEMERA, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0, 0,
+ 1, /* default 32 vs 16 bit size */
+ 1 /* limit granularity (byte/page units)*/ },
+ /* Data Descriptor for kernel */
+{ 0x0, /* segment base address */
+ 0xfffff, /* length - all address space */
+ SDT_MEMRWA, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0, 0,
+ 1, /* default 32 vs 16 bit size */
+ 1 /* limit granularity (byte/page units)*/ },
+ /* LDT Descriptor */
+{ (int) ldt, /* segment base address */
+ sizeof(ldt)-1, /* length - all address space */
+ SDT_SYSLDT, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0, 0,
+ 0, /* unused - default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Null Descriptor - Placeholder */
+{ 0x0, /* segment base address */
+ 0x0, /* length - all address space */
+ 0, /* segment type */
+ 0, /* segment descriptor priority level */
+ 0, /* segment descriptor present */
+ 0, 0,
+ 0, /* default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Panic Tss Descriptor */
+{ (int) &panic_tss, /* segment base address */
+ sizeof(tss)-1, /* length - all address space */
+ SDT_SYS386TSS, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0, 0,
+ 0, /* unused - default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Proc 0 Tss Descriptor */
+{ (int) kstack, /* segment base address */
+ sizeof(tss)-1, /* length - all address space */
+ SDT_SYS386TSS, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0, 0,
+ 0, /* unused - default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* User LDT Descriptor per process */
+{ (int) ldt, /* segment base address */
+ (512 * sizeof(union descriptor)-1), /* length */
+ SDT_SYSLDT, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0, 0,
+ 0, /* unused - default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+};
+
+struct soft_segment_descriptor ldt_segs[] = {
+ /* Null Descriptor - overwritten by call gate */
+{ 0x0, /* segment base address */
+ 0x0, /* length - all address space */
+ 0, /* segment type */
+ 0, /* segment descriptor priority level */
+ 0, /* segment descriptor present */
+ 0, 0,
+ 0, /* default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Null Descriptor - overwritten by call gate */
+{ 0x0, /* segment base address */
+ 0x0, /* length - all address space */
+ 0, /* segment type */
+ 0, /* segment descriptor priority level */
+ 0, /* segment descriptor present */
+ 0, 0,
+ 0, /* default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Null Descriptor - overwritten by call gate */
+{ 0x0, /* segment base address */
+ 0x0, /* length - all address space */
+ 0, /* segment type */
+ 0, /* segment descriptor priority level */
+ 0, /* segment descriptor present */
+ 0, 0,
+ 0, /* default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Code Descriptor for user */
+{ 0x0, /* segment base address */
+ 0xfffff, /* length - all address space */
+ SDT_MEMERA, /* segment type */
+ SEL_UPL, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0, 0,
+ 1, /* default 32 vs 16 bit size */
+ 1 /* limit granularity (byte/page units)*/ },
+ /* Data Descriptor for user */
+{ 0x0, /* segment base address */
+ 0xfffff, /* length - all address space */
+ SDT_MEMRWA, /* segment type */
+ SEL_UPL, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0, 0,
+ 1, /* default 32 vs 16 bit size */
+ 1 /* limit granularity (byte/page units)*/ } };
+
+void
+setidt(idx, func, typ, dpl)
+ int idx;
+ void (*func)();
+ int typ;
+ int dpl;
+{
+ struct gate_descriptor *ip = idt + idx;
+
+ ip->gd_looffset = (int)func;
+ ip->gd_selector = 8;
+ ip->gd_stkcpy = 0;
+ ip->gd_xx = 0;
+ ip->gd_type = typ;
+ ip->gd_dpl = dpl;
+ ip->gd_p = 1;
+ ip->gd_hioffset = ((int)func)>>16 ;
+}
+
+#define IDTVEC(name) __CONCAT(X,name)
+typedef void idtvec_t();
+
+extern idtvec_t
+ IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl),
+ IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(dble), IDTVEC(fpusegm),
+ IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot),
+ IDTVEC(page), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(rsvd0),
+ IDTVEC(rsvd1), IDTVEC(rsvd2), IDTVEC(rsvd3), IDTVEC(rsvd4),
+ IDTVEC(rsvd5), IDTVEC(rsvd6), IDTVEC(rsvd7), IDTVEC(rsvd8),
+ IDTVEC(rsvd9), IDTVEC(rsvd10), IDTVEC(rsvd11), IDTVEC(rsvd12),
+ IDTVEC(rsvd13), IDTVEC(rsvd14), IDTVEC(rsvd14), IDTVEC(syscall);
+
+int _gsel_tss;
+
+void
+init386(first)
+ int first;
+{
+ extern ssdtosd(), lgdt(), lidt(), lldt(), etext;
+ int x, *pi;
+ unsigned biosbasemem, biosextmem;
+ struct gate_descriptor *gdp;
+ extern int sigcode,szsigcode;
+ /* table descriptors - used to load tables by microp */
+ struct region_descriptor r_gdt, r_idt;
+ int pagesinbase, pagesinext;
+ int target_page;
+
+ proc0.p_addr = proc0paddr;
+
+ /*
+ * Initialize the console before we print anything out.
+ */
+
+ cninit ();
+
+ /*
+ * make gdt memory segments, the code segment goes up to end of the
+ * page with etext in it, the data segment goes to the end of
+ * the address space
+ */
+ gdt_segs[GCODE_SEL].ssd_limit = i386_btop(i386_round_page(&etext)) - 1;
+ gdt_segs[GDATA_SEL].ssd_limit = i386_btop(0) - 1;
+ for (x=0; x < NGDT; x++) ssdtosd(gdt_segs+x, gdt+x);
+
+ /* make ldt memory segments */
+ /*
+ * The data segment limit must not cover the user area because we
+ * don't want the user area to be writable in copyout() etc. (page
+ * level protection is lost in kernel mode on 386's). Also, we
+ * don't want the user area to be writable directly (page level
+ * protection of the user area is not available on 486's with
+ * CR0_WP set, because there is no user-read/kernel-write mode).
+ *
+ * XXX - VM_MAXUSER_ADDRESS is an end address, not a max. And it
+ * should be spelled ...MAX_USER...
+ */
+#define VM_END_USER_RW_ADDRESS VM_MAXUSER_ADDRESS
+ /*
+ * The code segment limit has to cover the user area until we move
+ * the signal trampoline out of the user area. This is safe because
+ * the code segment cannot be written to directly.
+ */
+#define VM_END_USER_R_ADDRESS (VM_END_USER_RW_ADDRESS + UPAGES * NBPG)
+ ldt_segs[LUCODE_SEL].ssd_limit = i386_btop(VM_END_USER_R_ADDRESS) - 1;
+ ldt_segs[LUDATA_SEL].ssd_limit = i386_btop(VM_END_USER_RW_ADDRESS) - 1;
+ /* Note. eventually want private ldts per process */
+ for (x=0; x < 5; x++) ssdtosd(ldt_segs+x, ldt+x);
+
+ /* exceptions */
+ setidt(0, &IDTVEC(div), SDT_SYS386TGT, SEL_KPL);
+ setidt(1, &IDTVEC(dbg), SDT_SYS386TGT, SEL_KPL);
+ setidt(2, &IDTVEC(nmi), SDT_SYS386TGT, SEL_KPL);
+ setidt(3, &IDTVEC(bpt), SDT_SYS386TGT, SEL_UPL);
+ setidt(4, &IDTVEC(ofl), SDT_SYS386TGT, SEL_UPL);
+ setidt(5, &IDTVEC(bnd), SDT_SYS386TGT, SEL_KPL);
+ setidt(6, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL);
+ setidt(7, &IDTVEC(dna), SDT_SYS386TGT, SEL_KPL);
+ setidt(8, &IDTVEC(dble), SDT_SYS386TGT, SEL_KPL);
+ setidt(9, &IDTVEC(fpusegm), SDT_SYS386TGT, SEL_KPL);
+ setidt(10, &IDTVEC(tss), SDT_SYS386TGT, SEL_KPL);
+ setidt(11, &IDTVEC(missing), SDT_SYS386TGT, SEL_KPL);
+ setidt(12, &IDTVEC(stk), SDT_SYS386TGT, SEL_KPL);
+ setidt(13, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL);
+ setidt(14, &IDTVEC(page), SDT_SYS386TGT, SEL_KPL);
+ setidt(15, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL);
+ setidt(16, &IDTVEC(fpu), SDT_SYS386TGT, SEL_KPL);
+ setidt(17, &IDTVEC(rsvd0), SDT_SYS386TGT, SEL_KPL);
+ setidt(18, &IDTVEC(rsvd1), SDT_SYS386TGT, SEL_KPL);
+ setidt(19, &IDTVEC(rsvd2), SDT_SYS386TGT, SEL_KPL);
+ setidt(20, &IDTVEC(rsvd3), SDT_SYS386TGT, SEL_KPL);
+ setidt(21, &IDTVEC(rsvd4), SDT_SYS386TGT, SEL_KPL);
+ setidt(22, &IDTVEC(rsvd5), SDT_SYS386TGT, SEL_KPL);
+ setidt(23, &IDTVEC(rsvd6), SDT_SYS386TGT, SEL_KPL);
+ setidt(24, &IDTVEC(rsvd7), SDT_SYS386TGT, SEL_KPL);
+ setidt(25, &IDTVEC(rsvd8), SDT_SYS386TGT, SEL_KPL);
+ setidt(26, &IDTVEC(rsvd9), SDT_SYS386TGT, SEL_KPL);
+ setidt(27, &IDTVEC(rsvd10), SDT_SYS386TGT, SEL_KPL);
+ setidt(28, &IDTVEC(rsvd11), SDT_SYS386TGT, SEL_KPL);
+ setidt(29, &IDTVEC(rsvd12), SDT_SYS386TGT, SEL_KPL);
+ setidt(30, &IDTVEC(rsvd13), SDT_SYS386TGT, SEL_KPL);
+ setidt(31, &IDTVEC(rsvd14), SDT_SYS386TGT, SEL_KPL);
+
+#include "isa.h"
+#if NISA >0
+ isa_defaultirq();
+#endif
+
+ r_gdt.rd_limit = sizeof(gdt) - 1;
+ r_gdt.rd_base = (int) gdt;
+ lgdt(&r_gdt);
+ r_idt.rd_limit = sizeof(idt) - 1;
+ r_idt.rd_base = (int) idt;
+ lidt(&r_idt);
+ _default_ldt = GSEL(GLDT_SEL, SEL_KPL);
+ lldt(_default_ldt);
+ currentldt = _default_ldt;
+
+#include "ddb.h"
+#if NDDB > 0
+ kdb_init();
+ if (boothowto & RB_KDB)
+ Debugger("Boot flags requested debugger");
+#endif
+
+ /* Use BIOS values stored in RTC CMOS RAM, since probing
+ * breaks certain 386 AT relics.
+ */
+ biosbasemem = rtcin(RTC_BASELO)+ (rtcin(RTC_BASEHI)<<8);
+ biosextmem = rtcin(RTC_EXTLO)+ (rtcin(RTC_EXTHI)<<8);
+
+ /*
+ * If BIOS tells us that it has more than 640k in the basemem,
+ * don't believe it - set it to 640k.
+ */
+ if (biosbasemem > 640)
+ biosbasemem = 640;
+
+ /*
+ * Some 386 machines might give us a bogus number for extended
+ * mem. If this happens, stop now.
+ */
+#ifndef LARGEMEM
+ if (biosextmem > 65536) {
+ panic("extended memory beyond limit of 64MB");
+ /* NOTREACHED */
+ }
+#endif
+
+ pagesinbase = biosbasemem * 1024 / NBPG;
+ pagesinext = biosextmem * 1024 / NBPG;
+
+ /*
+ * Special hack for chipsets that still remap the 384k hole when
+ * there's 16MB of memory - this really confuses people that
+ * are trying to use bus mastering ISA controllers with the
+ * "16MB limit"; they only have 16MB, but the remapping puts
+ * them beyond the limit.
+ * XXX - this should be removed when bounce buffers are
+ * implemented.
+ */
+ /*
+ * If extended memory is between 15-16MB (16-17MB phys address range),
+ * chop it to 15MB.
+ */
+ if ((pagesinext > 3840) && (pagesinext < 4096))
+ pagesinext = 3840;
+
+ /*
+ * Maxmem isn't the "maximum memory", it's the highest page of
+ * of the physical address space. It should be "Maxphyspage".
+ */
+ Maxmem = pagesinext + 0x100000/PAGE_SIZE;
+
+#ifdef MAXMEM
+ if (MAXMEM/4 < Maxmem)
+ Maxmem = MAXMEM/4;
+#endif
+ /*
+ * Calculate number of physical pages, but account for Maxmem
+ * limitation above.
+ */
+ physmem = pagesinbase +
+ (min(pagesinext + 0x100000/PAGE_SIZE, Maxmem) - 0x100000/PAGE_SIZE);
+
+ /* call pmap initialization to make new kernel address space */
+ pmap_bootstrap (first, 0);
+
+ /*
+ * Do simple memory test over range of extended memory that BIOS
+ * indicates exists. Adjust Maxmem to the highest page of
+ * good memory.
+ */
+ printf("Testing memory (%dMB)...", ptoa(Maxmem)/1024/1024);
+
+ for (target_page = Maxmem - 1; target_page >= atop(first); target_page--) {
+ extern struct pte *CMAP1;
+ extern caddr_t CADDR1;
+
+ /*
+ * map page into kernel: valid, read/write, non-cacheable
+ */
+ *(int *)CMAP1 = PG_V | PG_KW | PG_N | ptoa(target_page);
+ tlbflush();
+
+ /*
+ * Test for alternating 1's and 0's
+ */
+ filli(0xaaaaaaaa, CADDR1, PAGE_SIZE/sizeof(int));
+ if (test_page((int *)CADDR1, 0xaaaaaaaa)) {
+ Maxmem = target_page;
+ badpages++;
+ continue;
+ }
+ /*
+ * Test for alternating 0's and 1's
+ */
+ filli(0x55555555, CADDR1, PAGE_SIZE/sizeof(int));
+ if (test_page((int *)CADDR1, 0x55555555)) {
+ Maxmem = target_page;
+ badpages++;
+ continue;
+ }
+ /*
+ * Test for all 1's
+ */
+ filli(0xffffffff, CADDR1, PAGE_SIZE/sizeof(int));
+ if (test_page((int *)CADDR1, 0xffffffff)) {
+ Maxmem = target_page;
+ badpages++;
+ continue;
+ }
+ /*
+ * Test zeroing of page
+ */
+ bzero(CADDR1, PAGE_SIZE);
+ if (test_page((int *)CADDR1, 0)) {
+ /*
+ * test of page failed
+ */
+ Maxmem = target_page;
+ badpages++;
+ continue;
+ }
+ }
+ printf("done.\n");
+
+ avail_end = (Maxmem << PAGE_SHIFT)
+ - i386_round_page(sizeof(struct msgbuf));
+
+ /*
+ * Initialize pointers to the two chunks of memory; for use
+ * later in vm_page_startup.
+ */
+ /* avail_start is initialized in pmap_bootstrap */
+ x = 0;
+ if (pagesinbase > 1) {
+ phys_avail[x++] = NBPG; /* skip first page of memory */
+ phys_avail[x++] = pagesinbase * NBPG; /* memory up to the ISA hole */
+ }
+ phys_avail[x++] = avail_start; /* memory up to the end */
+ phys_avail[x++] = avail_end;
+ phys_avail[x++] = 0; /* no more chunks */
+ phys_avail[x++] = 0;
+
+ /* now running on new page tables, configured,and u/iom is accessible */
+
+ /* make a initial tss so microp can get interrupt stack on syscall! */
+ proc0.p_addr->u_pcb.pcb_tss.tss_esp0 = (int) kstack + UPAGES*NBPG;
+ proc0.p_addr->u_pcb.pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ;
+ _gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
+
+ ((struct i386tss *)gdt_segs[GPROC0_SEL].ssd_base)->tss_ioopt =
+ (sizeof(tss))<<16;
+
+ ltr(_gsel_tss);
+
+ /* make a call gate to reenter kernel with */
+ gdp = &ldt[LSYS5CALLS_SEL].gd;
+
+ x = (int) &IDTVEC(syscall);
+ gdp->gd_looffset = x++;
+ gdp->gd_selector = GSEL(GCODE_SEL,SEL_KPL);
+ gdp->gd_stkcpy = 1;
+ gdp->gd_type = SDT_SYS386CGT;
+ gdp->gd_dpl = SEL_UPL;
+ gdp->gd_p = 1;
+ gdp->gd_hioffset = ((int) &IDTVEC(syscall)) >>16;
+
+ /* transfer to user mode */
+
+ _ucodesel = LSEL(LUCODE_SEL, SEL_UPL);
+ _udatasel = LSEL(LUDATA_SEL, SEL_UPL);
+
+ /* setup proc 0's pcb */
+ bcopy(&sigcode, proc0.p_addr->u_pcb.pcb_sigc, szsigcode);
+ proc0.p_addr->u_pcb.pcb_flags = 0;
+ proc0.p_addr->u_pcb.pcb_ptd = IdlePTD;
+}
+
+int
+test_page(address, pattern)
+ int *address;
+ int pattern;
+{
+ int *x;
+
+ for (x = address; x < (int *)((char *)address + PAGE_SIZE); x++) {
+ if (*x != pattern)
+ return (1);
+ }
+ return(0);
+}
+
+/*
+ * insert an element into a queue
+ */
+#undef insque
+void /* XXX replace with inline FIXME! */
+_insque(element, head)
+ register struct prochd *element, *head;
+{
+ element->ph_link = head->ph_link;
+ head->ph_link = (struct proc *)element;
+ element->ph_rlink = (struct proc *)head;
+ ((struct prochd *)(element->ph_link))->ph_rlink=(struct proc *)element;
+}
+
+/*
+ * remove an element from a queue
+ */
+#undef remque
+void /* XXX replace with inline FIXME! */
+_remque(element)
+ register struct prochd *element;
+{
+ ((struct prochd *)(element->ph_link))->ph_rlink = element->ph_rlink;
+ ((struct prochd *)(element->ph_rlink))->ph_link = element->ph_link;
+ element->ph_rlink = (struct proc *)0;
+}
+
+/*
+ * The registers are in the frame; the frame is in the user area of
+ * the process in question; when the process is active, the registers
+ * are in "the kernel stack"; when it's not, they're still there, but
+ * things get flipped around. So, since p->p_regs is the whole address
+ * of the register set, take its offset from the kernel stack, and
+ * index into the user block. Don't you just *love* virtual memory?
+ * (I'm starting to think seymour is right...)
+ */
+
+int
+ptrace_set_pc (struct proc *p, unsigned int addr) {
+ void *regs = (char*)p->p_addr +
+ ((char*) p->p_regs - (char*) kstack);
+
+ ((struct trapframe *)regs)->tf_eip = addr;
+ return 0;
+}
+
+int
+ptrace_single_step (struct proc *p) {
+ void *regs = (char*)p->p_addr +
+ ((char*) p->p_regs - (char*) kstack);
+
+ ((struct trapframe *)regs)->tf_eflags |= PSL_T;
+ return 0;
+}
+
+/*
+ * Copy the registers to user-space.
+ */
+
+int
+ptrace_getregs (struct proc *p, unsigned int *addr) {
+ int error;
+ struct regs regs = {0};
+
+ if (error = fill_regs (p, &regs))
+ return error;
+
+ return copyout (&regs, addr, sizeof (regs));
+}
+
+int
+ptrace_setregs (struct proc *p, unsigned int *addr) {
+ int error;
+ struct regs regs = {0};
+
+ if (error = copyin (addr, &regs, sizeof(regs)))
+ return error;
+
+ return set_regs (p, &regs);
+}
+
+int
+fill_regs(struct proc *p, struct regs *regs) {
+ int error;
+ struct trapframe *tp;
+ void *ptr = (char*)p->p_addr +
+ ((char*) p->p_regs - (char*) kstack);
+
+ tp = ptr;
+ regs->r_es = tp->tf_es;
+ regs->r_ds = tp->tf_ds;
+ regs->r_edi = tp->tf_edi;
+ regs->r_esi = tp->tf_esi;
+ regs->r_ebp = tp->tf_ebp;
+ regs->r_ebx = tp->tf_ebx;
+ regs->r_edx = tp->tf_edx;
+ regs->r_ecx = tp->tf_ecx;
+ regs->r_eax = tp->tf_eax;
+ regs->r_eip = tp->tf_eip;
+ regs->r_cs = tp->tf_cs;
+ regs->r_eflags = tp->tf_eflags;
+ regs->r_esp = tp->tf_esp;
+ regs->r_ss = tp->tf_ss;
+ return 0;
+}
+
+int
+set_regs (struct proc *p, struct regs *regs) {
+ int error;
+ struct trapframe *tp;
+ void *ptr = (char*)p->p_addr +
+ ((char*) p->p_regs - (char*) kstack);
+
+ tp = ptr;
+ tp->tf_es = regs->r_es;
+ tp->tf_ds = regs->r_ds;
+ tp->tf_edi = regs->r_edi;
+ tp->tf_esi = regs->r_esi;
+ tp->tf_ebp = regs->r_ebp;
+ tp->tf_ebx = regs->r_ebx;
+ tp->tf_edx = regs->r_edx;
+ tp->tf_ecx = regs->r_ecx;
+ tp->tf_eax = regs->r_eax;
+ tp->tf_eip = regs->r_eip;
+ tp->tf_cs = regs->r_cs;
+ tp->tf_eflags = regs->r_eflags;
+ tp->tf_esp = regs->r_esp;
+ tp->tf_ss = regs->r_ss;
+ return 0;
+}
+
+#include "ddb.h"
+#if NDDB <= 0
+void
+Debugger(const char *msg)
+{
+ printf("Debugger(\"%s\") called.", msg);
+}
+#endif /* no DDB */
diff --git a/sys/amd64/amd64/mem.c b/sys/amd64/amd64/mem.c
new file mode 100644
index 0000000..c3899a1
--- /dev/null
+++ b/sys/amd64/amd64/mem.c
@@ -0,0 +1,260 @@
+/*-
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department, and code derived from software contributed to
+ * Berkeley by William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Utah $Hdr: mem.c 1.13 89/10/08$
+ * from: @(#)mem.c 7.2 (Berkeley) 5/9/91
+ * $Id: mem.c,v 1.6 1993/12/19 00:50:06 wollman Exp $
+ */
+
+/*
+ * Memory special file
+ */
+
+#include "param.h"
+#include "conf.h"
+#include "buf.h"
+#include "systm.h"
+#include "uio.h"
+#include "malloc.h"
+#include "proc.h"
+
+#include "machine/cpu.h"
+#include "machine/psl.h"
+
+#include "vm/vm_param.h"
+#include "vm/lock.h"
+#include "vm/vm_statistics.h"
+#include "vm/vm_prot.h"
+#include "vm/pmap.h"
+
+extern char *vmmap; /* poor name! */
+/*ARGSUSED*/
+int
+mmclose(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ struct trapframe *fp;
+
+ switch (minor(dev)) {
+ case 14:
+ fp = (struct trapframe *)curproc->p_regs;
+ fp->tf_eflags &= ~PSL_IOPL;
+ break;
+ default:
+ break;
+ }
+ return(0);
+}
+/*ARGSUSED*/
+int
+mmopen(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ struct trapframe *fp;
+
+ switch (minor(dev)) {
+ case 14:
+ fp = (struct trapframe *)curproc->p_regs;
+ fp->tf_eflags |= PSL_IOPL;
+ break;
+ default:
+ break;
+ }
+ return(0);
+}
+/*ARGSUSED*/
+int
+mmrw(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ register int o;
+ register u_int c, v;
+ register struct iovec *iov;
+ int error = 0;
+ caddr_t zbuf = NULL;
+
+ while (uio->uio_resid > 0 && error == 0) {
+ iov = uio->uio_iov;
+ if (iov->iov_len == 0) {
+ uio->uio_iov++;
+ uio->uio_iovcnt--;
+ if (uio->uio_iovcnt < 0)
+ panic("mmrw");
+ continue;
+ }
+ switch (minor(dev)) {
+
+/* minor device 0 is physical memory */
+ case 0:
+ v = uio->uio_offset;
+ pmap_enter(pmap_kernel(), (vm_offset_t)vmmap, v,
+ uio->uio_rw == UIO_READ ? VM_PROT_READ : VM_PROT_WRITE,
+ TRUE);
+ o = (int)uio->uio_offset & PGOFSET;
+ c = (u_int)(NBPG - ((int)iov->iov_base & PGOFSET));
+ c = MIN(c, (u_int)(NBPG - o));
+ c = MIN(c, (u_int)iov->iov_len);
+ error = uiomove((caddr_t)&vmmap[o], (int)c, uio);
+ pmap_remove(pmap_kernel(), (vm_offset_t)vmmap,
+ (vm_offset_t)&vmmap[NBPG]);
+ continue;
+
+/* minor device 1 is kernel memory */
+ case 1:
+ c = iov->iov_len;
+ if (!kernacc((caddr_t)uio->uio_offset, c,
+ uio->uio_rw == UIO_READ ? B_READ : B_WRITE))
+ return(EFAULT);
+ error = uiomove((caddr_t)uio->uio_offset, (int)c, uio);
+ continue;
+
+/* minor device 2 is EOF/RATHOLE */
+ case 2:
+ if (uio->uio_rw == UIO_READ)
+ return (0);
+ c = iov->iov_len;
+ break;
+
+/* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */
+ case 12:
+ if (uio->uio_rw == UIO_WRITE) {
+ c = iov->iov_len;
+ break;
+ }
+ if (zbuf == NULL) {
+ zbuf = (caddr_t)
+ malloc(CLBYTES, M_TEMP, M_WAITOK);
+ bzero(zbuf, CLBYTES);
+ }
+ c = MIN(iov->iov_len, CLBYTES);
+ error = uiomove(zbuf, (int)c, uio);
+ continue;
+
+#ifdef notyet
+/* 386 I/O address space (/dev/ioport[bwl]) is a read/write access to seperate
+ i/o device address bus, different than memory bus. Semantics here are
+ very different than ordinary read/write, as if iov_len is a multiple
+ an implied string move from a single port will be done. Note that lseek
+ must be used to set the port number reliably. */
+ case 14:
+ if (iov->iov_len == 1) {
+ u_char tmp;
+ tmp = inb(uio->uio_offset);
+ error = uiomove (&tmp, iov->iov_len, uio);
+ } else {
+ if (!useracc((caddr_t)iov->iov_base,
+ iov->iov_len, uio->uio_rw))
+ return (EFAULT);
+ insb(uio->uio_offset, iov->iov_base,
+ iov->iov_len);
+ }
+ break;
+ case 15:
+ if (iov->iov_len == sizeof (short)) {
+ u_short tmp;
+ tmp = inw(uio->uio_offset);
+ error = uiomove (&tmp, iov->iov_len, uio);
+ } else {
+ if (!useracc((caddr_t)iov->iov_base,
+ iov->iov_len, uio->uio_rw))
+ return (EFAULT);
+ insw(uio->uio_offset, iov->iov_base,
+ iov->iov_len/ sizeof (short));
+ }
+ break;
+ case 16:
+ if (iov->iov_len == sizeof (long)) {
+ u_long tmp;
+ tmp = inl(uio->uio_offset);
+ error = uiomove (&tmp, iov->iov_len, uio);
+ } else {
+ if (!useracc((caddr_t)iov->iov_base,
+ iov->iov_len, uio->uio_rw))
+ return (EFAULT);
+ insl(uio->uio_offset, iov->iov_base,
+ iov->iov_len/ sizeof (long));
+ }
+ break;
+#endif
+
+ default:
+ return (ENXIO);
+ }
+ if (error)
+ break;
+ iov->iov_base += c;
+ iov->iov_len -= c;
+ uio->uio_offset += c;
+ uio->uio_resid -= c;
+ }
+ if (zbuf)
+ free(zbuf, M_TEMP);
+ return (error);
+}
+
+
+
+
+/*******************************************************\
+* allow user processes to MMAP some memory sections *
+* instead of going through read/write *
+\*******************************************************/
+int memmmap(dev_t dev, int offset, int nprot)
+{
+ switch (minor(dev))
+ {
+
+/* minor device 0 is physical memory */
+ case 0:
+ return i386_btop(offset);
+
+/* minor device 1 is kernel memory */
+ case 1:
+ return i386_btop(vtophys(offset));
+
+ default:
+ return -1;
+ }
+}
+
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c
new file mode 100644
index 0000000..d5b556f
--- /dev/null
+++ b/sys/amd64/amd64/pmap.c
@@ -0,0 +1,1938 @@
+/*
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ * Copyright (c) 1994 John S. Dyson
+ * All rights reserved.
+ * Copyright (c) 1994 David Greenman
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department and William Jolitz of UUNET Technologies Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)pmap.c 7.7 (Berkeley) 5/12/91
+ * $Id: pmap.c,v 1.24 1994/04/20 07:06:14 davidg Exp $
+ */
+
+/*
+ * Derived from hp300 version by Mike Hibler, this version by William
+ * Jolitz uses a recursive map [a pde points to the page directory] to
+ * map the page tables using the pagetables themselves. This is done to
+ * reduce the impact on kernel virtual memory for lots of sparse address
+ * space, and to reduce the cost of memory to each process.
+ *
+ * Derived from: hp300/@(#)pmap.c 7.1 (Berkeley) 12/5/90
+ */
+/*
+ * Major modifications by John S. Dyson primarily to support
+ * pageable page tables, eliminating pmap_attributes,
+ * discontiguous memory pages, and using more efficient string
+ * instructions. Jan 13, 1994. Further modifications on Mar 2, 1994,
+ * general clean-up and efficiency mods.
+ */
+
+/*
+ * Manages physical address maps.
+ *
+ * In addition to hardware address maps, this
+ * module is called upon to provide software-use-only
+ * maps which may or may not be stored in the same
+ * form as hardware maps. These pseudo-maps are
+ * used to store intermediate results from copy
+ * operations to and from address spaces.
+ *
+ * Since the information managed by this module is
+ * also stored by the logical address mapping module,
+ * this module may throw away valid virtual-to-physical
+ * mappings at almost any time. However, invalidations
+ * of virtual-to-physical mappings must be done as
+ * requested.
+ *
+ * In order to cope with hardware architectures which
+ * make virtual-to-physical map invalidates expensive,
+ * this module may delay invalidate or reduced protection
+ * operations until such time as they are actually
+ * necessary. This module is given full information as
+ * to which processors are currently using which maps,
+ * and to when physical maps must be made correct.
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "malloc.h"
+#include "user.h"
+#include "i386/include/cpufunc.h"
+#include "i386/include/cputypes.h"
+
+#include "vm/vm.h"
+#include "vm/vm_kern.h"
+#include "vm/vm_page.h"
+
+#include "i386/isa/isa.h"
+
+/*
+ * Allocate various and sundry SYSMAPs used in the days of old VM
+ * and not yet converted. XXX.
+ */
+#define BSDVM_COMPAT 1
+
+/*
+ * Get PDEs and PTEs for user/kernel address space
+ */
+#define pmap_pde(m, v) (&((m)->pm_pdir[((vm_offset_t)(v) >> PD_SHIFT)&1023]))
+#define pdir_pde(m, v) (m[((vm_offset_t)(v) >> PD_SHIFT)&1023])
+
+#define pmap_pte_pa(pte) (*(int *)(pte) & PG_FRAME)
+
+#define pmap_pde_v(pte) ((*(int *)pte & PG_V) != 0)
+#define pmap_pte_w(pte) ((*(int *)pte & PG_W) != 0)
+#define pmap_pte_m(pte) ((*(int *)pte & PG_M) != 0)
+#define pmap_pte_u(pte) ((*(int *)pte & PG_U) != 0)
+#define pmap_pte_v(pte) ((*(int *)pte & PG_V) != 0)
+
+#define pmap_pte_set_w(pte, v) ((v)?(*(int *)pte |= PG_W):(*(int *)pte &= ~PG_W))
+#define pmap_pte_set_prot(pte, v) ((*(int *)pte &= ~PG_PROT), (*(int *)pte |= (v)))
+
+/*
+ * Given a map and a machine independent protection code,
+ * convert to a vax protection code.
+ */
+#define pte_prot(m, p) (protection_codes[p])
+int protection_codes[8];
+
+struct pmap kernel_pmap_store;
+pmap_t kernel_pmap;
+
+vm_offset_t phys_avail[6]; /* 2 entries + 1 null */
+vm_offset_t avail_start; /* PA of first available physical page */
+vm_offset_t avail_end; /* PA of last available physical page */
+vm_size_t mem_size; /* memory size in bytes */
+vm_offset_t virtual_avail; /* VA of first avail page (after kernel bss)*/
+vm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */
+int i386pagesperpage; /* PAGE_SIZE / I386_PAGE_SIZE */
+boolean_t pmap_initialized = FALSE; /* Has pmap_init completed? */
+vm_offset_t vm_first_phys, vm_last_phys;
+
+static inline boolean_t pmap_testbit();
+static inline void pmap_changebit();
+static inline int pmap_is_managed();
+static inline void *vm_get_pmap();
+static inline void vm_put_pmap();
+inline void pmap_use_pt();
+inline void pmap_unuse_pt();
+inline pt_entry_t * const pmap_pte();
+static inline pv_entry_t get_pv_entry();
+void pmap_alloc_pv_entry();
+void pmap_clear_modify();
+void i386_protection_init();
+extern vm_offset_t pager_sva, pager_eva;
+extern int cpu_class;
+
+#if BSDVM_COMPAT
+#include "msgbuf.h"
+
+/*
+ * All those kernel PT submaps that BSD is so fond of
+ */
+pt_entry_t *CMAP1, *CMAP2, *mmap;
+caddr_t CADDR1, CADDR2, vmmap;
+pt_entry_t *msgbufmap;
+struct msgbuf *msgbufp;
+#endif
+
+void init_pv_entries(int) ;
+
+/*
+ * Routine: pmap_pte
+ * Function:
+ * Extract the page table entry associated
+ * with the given map/virtual_address pair.
+ * [ what about induced faults -wfj]
+ */
+
+inline pt_entry_t *
+const pmap_pte(pmap, va)
+ register pmap_t pmap;
+ vm_offset_t va;
+{
+
+ if (pmap && *pmap_pde(pmap, va)) {
+ vm_offset_t frame = (int) pmap->pm_pdir[PTDPTDI] & PG_FRAME;
+ /* are we current address space or kernel? */
+ if ( (pmap == kernel_pmap) || (frame == ((int) PTDpde & PG_FRAME)))
+ return ((pt_entry_t *) vtopte(va));
+ /* otherwise, we are alternate address space */
+ else {
+ if ( frame != ((int) APTDpde & PG_FRAME) ) {
+ APTDpde = pmap->pm_pdir[PTDPTDI];
+ tlbflush();
+ }
+ return((pt_entry_t *) avtopte(va));
+ }
+ }
+ return(0);
+}
+
+/*
+ * Routine: pmap_extract
+ * Function:
+ * Extract the physical page address associated
+ * with the given map/virtual_address pair.
+ */
+
+vm_offset_t
+pmap_extract(pmap, va)
+ register pmap_t pmap;
+ vm_offset_t va;
+{
+ pd_entry_t save;
+ vm_offset_t pa;
+ int s;
+
+ if (pmap && *pmap_pde(pmap, va)) {
+ vm_offset_t frame = (int) pmap->pm_pdir[PTDPTDI] & PG_FRAME;
+ /* are we current address space or kernel? */
+ if ( (pmap == kernel_pmap)
+ || (frame == ((int) PTDpde & PG_FRAME)) ) {
+ pa = *(int *) vtopte(va);
+ /* otherwise, we are alternate address space */
+ } else {
+ if ( frame != ((int) APTDpde & PG_FRAME)) {
+ APTDpde = pmap->pm_pdir[PTDPTDI];
+ tlbflush();
+ }
+ pa = *(int *) avtopte(va);
+ }
+ pa = (pa & PG_FRAME) | (va & ~PG_FRAME);
+ return pa;
+ }
+ return 0;
+
+}
+
+/*
+ * determine if a page is managed (memory vs. device)
+ */
+static inline int
+pmap_is_managed(pa)
+ vm_offset_t pa;
+{
+ int i;
+
+ if (!pmap_initialized)
+ return 0;
+
+ for (i = 0; phys_avail[i + 1]; i += 2) {
+ if (pa >= phys_avail[i] && pa < phys_avail[i + 1])
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * find the vm_page_t of a pte (only) given va of pte and pmap
+ */
+inline vm_page_t
+pmap_pte_vm_page(pmap, pt)
+ pmap_t pmap;
+ vm_offset_t pt;
+{
+ pt = i386_trunc_page( pt);
+ pt = (pt - UPT_MIN_ADDRESS) / NBPG;
+ pt = ((vm_offset_t) pmap->pm_pdir[pt]) & PG_FRAME;
+ return PHYS_TO_VM_PAGE(pt);
+}
+
+/*
+ * Wire a page table page
+ */
+inline void
+pmap_use_pt(pmap, va)
+ pmap_t pmap;
+ vm_offset_t va;
+{
+ vm_offset_t pt;
+
+ if (va >= VM_MAX_ADDRESS || !pmap_initialized)
+ return;
+
+ pt = (vm_offset_t) vtopte(va);
+ vm_page_hold( pmap_pte_vm_page(pmap, pt));
+}
+
+/*
+ * Unwire a page table page
+ */
+inline void
+pmap_unuse_pt(pmap, va)
+ pmap_t pmap;
+ vm_offset_t va;
+{
+ vm_offset_t pt;
+
+ if (va >= VM_MAX_ADDRESS || !pmap_initialized)
+ return;
+
+ pt = (vm_offset_t) vtopte(va);
+ vm_page_unhold( pmap_pte_vm_page(pmap, pt));
+}
+
+/* [ macro again?, should I force kstack into user map here? -wfj ] */
+void
+pmap_activate(pmap, pcbp)
+ register pmap_t pmap;
+ struct pcb *pcbp;
+{
+ PMAP_ACTIVATE(pmap, pcbp);
+}
+
+/*
+ * Bootstrap the system enough to run with virtual memory.
+ * Map the kernel's code and data, and allocate the system page table.
+ *
+ * On the I386 this is called after mapping has already been enabled
+ * and just syncs the pmap module with what has already been done.
+ * [We can't call it easily with mapping off since the kernel is not
+ * mapped with PA == VA, hence we would have to relocate every address
+ * from the linked base (virtual) address "KERNBASE" to the actual
+ * (physical) address starting relative to 0]
+ */
+
+#define DMAPAGES 8
+void
+pmap_bootstrap(firstaddr, loadaddr)
+ vm_offset_t firstaddr;
+ vm_offset_t loadaddr;
+{
+#if BSDVM_COMPAT
+ vm_offset_t va;
+ pt_entry_t *pte;
+#endif
+ extern int IdlePTD;
+
+ avail_start = firstaddr + DMAPAGES*NBPG;
+
+ virtual_avail = (vm_offset_t) KERNBASE + avail_start;
+ virtual_end = VM_MAX_KERNEL_ADDRESS;
+ i386pagesperpage = PAGE_SIZE / NBPG;
+
+ /*
+ * Initialize protection array.
+ */
+ i386_protection_init();
+
+ /*
+ * The kernel's pmap is statically allocated so we don't
+ * have to use pmap_create, which is unlikely to work
+ * correctly at this part of the boot sequence.
+ */
+ kernel_pmap = &kernel_pmap_store;
+
+ kernel_pmap->pm_pdir = (pd_entry_t *)(KERNBASE + IdlePTD);
+
+ simple_lock_init(&kernel_pmap->pm_lock);
+ kernel_pmap->pm_count = 1;
+
+#if BSDVM_COMPAT
+ /*
+ * Allocate all the submaps we need
+ */
+#define SYSMAP(c, p, v, n) \
+ v = (c)va; va += ((n)*NBPG); p = pte; pte += (n);
+
+ va = virtual_avail;
+ pte = pmap_pte(kernel_pmap, va);
+
+ SYSMAP(caddr_t ,CMAP1 ,CADDR1 ,1 )
+ SYSMAP(caddr_t ,CMAP2 ,CADDR2 ,1 )
+ SYSMAP(caddr_t ,mmap ,vmmap ,1 )
+ SYSMAP(struct msgbuf * ,msgbufmap ,msgbufp ,1 )
+ virtual_avail = va;
+#endif
+ /*
+ * reserve special hunk of memory for use by bus dma as a bounce
+ * buffer (contiguous virtual *and* physical memory). for now,
+ * assume vm does not use memory beneath hole, and we know that
+ * the bootstrap uses top 32k of base memory. -wfj
+ */
+ {
+ extern vm_offset_t isaphysmem;
+ isaphysmem = va;
+
+ virtual_avail = pmap_map(va, firstaddr,
+ firstaddr + DMAPAGES*NBPG, VM_PROT_ALL);
+ }
+
+ *(int *)PTD = 0;
+ tlbflush();
+
+}
+
+/*
+ * Initialize the pmap module.
+ * Called by vm_init, to initialize any structures that the pmap
+ * system needs to map virtual memory.
+ * pmap_init has been enhanced to support in a fairly consistant
+ * way, discontiguous physical memory.
+ */
+void
+pmap_init(phys_start, phys_end)
+ vm_offset_t phys_start, phys_end;
+{
+ vm_offset_t addr, addr2;
+ vm_size_t npg, s;
+ int rv;
+ int i;
+ extern int KPTphys;
+ extern int IdlePTD;
+
+ /*
+ * Now that kernel map has been allocated, we can mark as
+ * unavailable regions which we have mapped in locore.
+ */
+ addr = atdevbase;
+ (void) vm_map_find(kernel_map, NULL, (vm_offset_t) 0,
+ &addr, (0x100000-0xa0000), FALSE);
+
+ addr = (vm_offset_t) KERNBASE + IdlePTD;
+ vm_object_reference(kernel_object);
+ (void) vm_map_find(kernel_map, kernel_object, addr,
+ &addr, (4 + NKPT) * NBPG, FALSE);
+
+
+ /*
+ * calculate the number of pv_entries needed
+ */
+ vm_first_phys = phys_avail[0];
+ for (i = 0; phys_avail[i + 1]; i += 2) ;
+ npg = (phys_avail[(i - 2) + 1] - vm_first_phys) / NBPG;
+
+ /*
+ * Allocate memory for random pmap data structures. Includes the
+ * pv_head_table.
+ */
+ s = (vm_size_t) (sizeof(struct pv_entry) * npg);
+ s = i386_round_page(s);
+ addr = (vm_offset_t) kmem_alloc(kernel_map, s);
+ pv_table = (pv_entry_t) addr;
+
+ /*
+ * init the pv free list
+ */
+ init_pv_entries(npg);
+ /*
+ * Now it is safe to enable pv_table recording.
+ */
+ pmap_initialized = TRUE;
+}
+
+/*
+ * Used to map a range of physical addresses into kernel
+ * virtual address space.
+ *
+ * For now, VM is already on, we only need to map the
+ * specified memory.
+ */
+vm_offset_t
+pmap_map(virt, start, end, prot)
+ vm_offset_t virt;
+ vm_offset_t start;
+ vm_offset_t end;
+ int prot;
+{
+ while (start < end) {
+ pmap_enter(kernel_pmap, virt, start, prot, FALSE);
+ virt += PAGE_SIZE;
+ start += PAGE_SIZE;
+ }
+ return(virt);
+}
+
+/*
+ * Create and return a physical map.
+ *
+ * If the size specified for the map
+ * is zero, the map is an actual physical
+ * map, and may be referenced by the
+ * hardware.
+ *
+ * If the size specified is non-zero,
+ * the map will be used in software only, and
+ * is bounded by that size.
+ *
+ * [ just allocate a ptd and mark it uninitialize -- should we track
+ * with a table which process has which ptd? -wfj ]
+ */
+
+pmap_t
+pmap_create(size)
+ vm_size_t size;
+{
+ register pmap_t pmap;
+
+ /*
+ * Software use map does not need a pmap
+ */
+ if (size)
+ return(NULL);
+
+ pmap = (pmap_t) malloc(sizeof *pmap, M_VMPMAP, M_WAITOK);
+ bzero(pmap, sizeof(*pmap));
+ pmap_pinit(pmap);
+ return (pmap);
+}
+
+
+struct pmaplist {
+ struct pmaplist *next;
+};
+
+static inline void *
+vm_get_pmap()
+{
+ struct pmaplist *rtval;
+
+ rtval = (struct pmaplist *)kmem_alloc(kernel_map, ctob(1));
+ bzero(rtval, ctob(1));
+ return rtval;
+}
+
+static inline void
+vm_put_pmap(up)
+ struct pmaplist *up;
+{
+ kmem_free(kernel_map, up, ctob(1));
+}
+
+/*
+ * Initialize a preallocated and zeroed pmap structure,
+ * such as one in a vmspace structure.
+ */
+void
+pmap_pinit(pmap)
+ register struct pmap *pmap;
+{
+ /*
+ * No need to allocate page table space yet but we do need a
+ * valid page directory table.
+ */
+ pmap->pm_pdir = (pd_entry_t *) vm_get_pmap();
+
+ /* wire in kernel global address entries */
+ bcopy(PTD+KPTDI, pmap->pm_pdir+KPTDI, NKPT*PTESIZE);
+
+ /* install self-referential address mapping entry */
+ *(int *)(pmap->pm_pdir+PTDPTDI) =
+ ((int)pmap_kextract((vm_offset_t)pmap->pm_pdir)) | PG_V | PG_KW;
+
+ pmap->pm_count = 1;
+ simple_lock_init(&pmap->pm_lock);
+}
+
+/*
+ * Retire the given physical map from service.
+ * Should only be called if the map contains
+ * no valid mappings.
+ */
+void
+pmap_destroy(pmap)
+ register pmap_t pmap;
+{
+ int count;
+
+ if (pmap == NULL)
+ return;
+
+ simple_lock(&pmap->pm_lock);
+ count = --pmap->pm_count;
+ simple_unlock(&pmap->pm_lock);
+ if (count == 0) {
+ pmap_release(pmap);
+ free((caddr_t)pmap, M_VMPMAP);
+ }
+}
+
+/*
+ * Release any resources held by the given physical map.
+ * Called when a pmap initialized by pmap_pinit is being released.
+ * Should only be called if the map contains no valid mappings.
+ */
+void
+pmap_release(pmap)
+ register struct pmap *pmap;
+{
+ vm_put_pmap((struct pmaplist *) pmap->pm_pdir);
+}
+
+/*
+ * Add a reference to the specified pmap.
+ */
+void
+pmap_reference(pmap)
+ pmap_t pmap;
+{
+ if (pmap != NULL) {
+ simple_lock(&pmap->pm_lock);
+ pmap->pm_count++;
+ simple_unlock(&pmap->pm_lock);
+ }
+}
+
+#define PV_FREELIST_MIN ((NBPG / sizeof (struct pv_entry)) / 2)
+
+/*
+ * Data for the pv entry allocation mechanism
+ */
+int pv_freelistcnt;
+pv_entry_t pv_freelist;
+vm_offset_t pvva;
+int npvvapg;
+
+/*
+ * free the pv_entry back to the free list
+ */
+inline static void
+free_pv_entry(pv)
+ pv_entry_t pv;
+{
+ if (!pv) return;
+ ++pv_freelistcnt;
+ pv->pv_next = pv_freelist;
+ pv_freelist = pv;
+}
+
+/*
+ * get a new pv_entry, allocating a block from the system
+ * when needed.
+ * the memory allocation is performed bypassing the malloc code
+ * because of the possibility of allocations at interrupt time.
+ */
+static inline pv_entry_t
+get_pv_entry()
+{
+ pv_entry_t tmp;
+
+ /*
+ * get more pv_entry pages if needed
+ */
+ while (pv_freelistcnt < PV_FREELIST_MIN || pv_freelist == 0) {
+ pmap_alloc_pv_entry();
+ }
+
+ /*
+ * get a pv_entry off of the free list
+ */
+ --pv_freelistcnt;
+ tmp = pv_freelist;
+ pv_freelist = tmp->pv_next;
+ tmp->pv_pmap = 0;
+ tmp->pv_va = 0;
+ tmp->pv_next = 0;
+ return tmp;
+}
+
+/*
+ * this *strange* allocation routine *statistically* eliminates the
+ * *possibility* of a malloc failure (*FATAL*) for a pv_entry_t data structure.
+ * also -- this code is MUCH MUCH faster than the malloc equiv...
+ */
+void
+pmap_alloc_pv_entry()
+{
+ /*
+ * do we have any pre-allocated map-pages left?
+ */
+ if (npvvapg) {
+ vm_page_t m;
+ /*
+ * we do this to keep recursion away
+ */
+ pv_freelistcnt += PV_FREELIST_MIN;
+ /*
+ * allocate a physical page out of the vm system
+ */
+ if (m = vm_page_alloc(kernel_object, pvva-vm_map_min(kernel_map))) {
+ int newentries;
+ int i;
+ pv_entry_t entry;
+ newentries = (NBPG/sizeof (struct pv_entry));
+ /*
+ * wire the page
+ */
+ vm_page_wire(m);
+ m->flags &= ~PG_BUSY;
+ /*
+ * let the kernel see it
+ */
+ pmap_enter(vm_map_pmap(kernel_map), pvva,
+ VM_PAGE_TO_PHYS(m), VM_PROT_DEFAULT,1);
+
+ entry = (pv_entry_t) pvva;
+ /*
+ * update the allocation pointers
+ */
+ pvva += NBPG;
+ --npvvapg;
+
+ /*
+ * free the entries into the free list
+ */
+ for (i = 0; i < newentries; i++) {
+ free_pv_entry(entry);
+ entry++;
+ }
+ }
+ pv_freelistcnt -= PV_FREELIST_MIN;
+ }
+ if (!pv_freelist)
+ panic("get_pv_entry: cannot get a pv_entry_t");
+}
+
+
+
+/*
+ * init the pv_entry allocation system
+ */
+#define PVSPERPAGE 64
+void
+init_pv_entries(npg)
+ int npg;
+{
+ /*
+ * allocate enough kvm space for PVSPERPAGE entries per page (lots)
+ * kvm space is fairly cheap, be generous!!! (the system can panic
+ * if this is too small.)
+ */
+ npvvapg = ((npg*PVSPERPAGE) * sizeof(struct pv_entry) + NBPG - 1)/NBPG;
+ pvva = kmem_alloc_pageable(kernel_map, npvvapg * NBPG);
+ /*
+ * get the first batch of entries
+ */
+ free_pv_entry(get_pv_entry());
+}
+
+static pt_entry_t *
+get_pt_entry(pmap)
+ pmap_t pmap;
+{
+ pt_entry_t *ptp;
+ vm_offset_t frame = (int) pmap->pm_pdir[PTDPTDI] & PG_FRAME;
+ /* are we current address space or kernel? */
+ if (pmap == kernel_pmap || frame == ((int) PTDpde & PG_FRAME)) {
+ ptp=PTmap;
+ /* otherwise, we are alternate address space */
+ } else {
+ if ( frame != ((int) APTDpde & PG_FRAME)) {
+ APTDpde = pmap->pm_pdir[PTDPTDI];
+ tlbflush();
+ }
+ ptp=APTmap;
+ }
+ return ptp;
+}
+
+/*
+ * If it is the first entry on the list, it is actually
+ * in the header and we must copy the following entry up
+ * to the header. Otherwise we must search the list for
+ * the entry. In either case we free the now unused entry.
+ */
+void
+pmap_remove_entry(pmap, pv, va)
+ struct pmap *pmap;
+ pv_entry_t pv;
+ vm_offset_t va;
+{
+ pv_entry_t npv;
+ int wired;
+ int s;
+ s = splimp();
+ if (pmap == pv->pv_pmap && va == pv->pv_va) {
+ npv = pv->pv_next;
+ if (npv) {
+ *pv = *npv;
+ free_pv_entry(npv);
+ } else {
+ pv->pv_pmap = NULL;
+ }
+ } else {
+ for (npv = pv->pv_next; npv; npv = npv->pv_next) {
+ if (pmap == npv->pv_pmap && va == npv->pv_va) {
+ break;
+ }
+ pv = npv;
+ }
+ if (npv) {
+ pv->pv_next = npv->pv_next;
+ free_pv_entry(npv);
+ }
+ }
+ splx(s);
+}
+
+/*
+ * Remove the given range of addresses from the specified map.
+ *
+ * It is assumed that the start and end are properly
+ * rounded to the page size.
+ */
+void
+pmap_remove(pmap, sva, eva)
+ struct pmap *pmap;
+ register vm_offset_t sva;
+ register vm_offset_t eva;
+{
+ register pt_entry_t *ptp,*ptq;
+ vm_offset_t pa;
+ register pv_entry_t pv;
+ vm_offset_t va;
+ vm_page_t m;
+ pt_entry_t oldpte;
+
+ if (pmap == NULL)
+ return;
+
+ ptp = get_pt_entry(pmap);
+
+/*
+ * special handling of removing one page. a very
+ * common operation and easy to short circuit some
+ * code.
+ */
+ if( (sva + NBPG) == eva) {
+
+ if( *pmap_pde( pmap, sva) == 0)
+ return;
+
+ ptq = ptp + i386_btop(sva);
+
+ if( !*ptq)
+ return;
+ /*
+ * Update statistics
+ */
+ if (pmap_pte_w(ptq))
+ pmap->pm_stats.wired_count--;
+ pmap->pm_stats.resident_count--;
+
+ pa = pmap_pte_pa(ptq);
+ oldpte = *ptq;
+ *ptq = 0;
+
+ if (pmap_is_managed(pa)) {
+ if ((((int) oldpte & PG_M) && (sva < USRSTACK || sva > UPT_MAX_ADDRESS))
+ || (sva >= USRSTACK && sva < USRSTACK+(UPAGES*NBPG))) {
+ if (sva < pager_sva || sva >= pager_eva) {
+ m = PHYS_TO_VM_PAGE(pa);
+ m->flags &= ~PG_CLEAN;
+ }
+ }
+
+ pv = pa_to_pvh(pa);
+ pmap_remove_entry(pmap, pv, sva);
+ pmap_unuse_pt(pmap, sva);
+ }
+ tlbflush();
+ return;
+ }
+
+ sva = i386_btop(sva);
+ eva = i386_btop(eva);
+
+ while (sva < eva) {
+ /*
+ * Weed out invalid mappings.
+ * Note: we assume that the page directory table is
+ * always allocated, and in kernel virtual.
+ */
+
+ if ( *pmap_pde(pmap, i386_ptob(sva)) == 0 ) {
+ /* We can race ahead here, straight to next pde.. */
+ nextpde:
+ sva = ((sva + NPTEPG) & ~(NPTEPG - 1));
+ continue;
+ }
+
+ ptq = ptp + sva;
+
+ /*
+ * search for page table entries, use string operations
+ * that are much faster than
+ * explicitly scanning when page tables are not fully
+ * populated.
+ */
+ if ( *ptq == 0) {
+ vm_offset_t pdnxt = ((sva + NPTEPG) & ~(NPTEPG - 1));
+ vm_offset_t nscan = pdnxt - sva;
+ int found = 0;
+
+ if ((nscan + sva) > eva)
+ nscan = eva - sva;
+
+ asm("xorl %%eax,%%eax;cld;repe;scasl;jz 1f;incl %%eax;1:;"
+ :"=D"(ptq),"=a"(found)
+ :"c"(nscan),"0"(ptq)
+ :"cx");
+
+ if( !found) {
+ sva = pdnxt;
+ continue;
+ }
+ ptq -= 1;
+
+ sva = ptq - ptp;
+ }
+
+ /*
+ * Update statistics
+ */
+ oldpte = *ptq;
+ if (((int)oldpte) & PG_W)
+ pmap->pm_stats.wired_count--;
+ pmap->pm_stats.resident_count--;
+
+ /*
+ * Invalidate the PTEs.
+ * XXX: should cluster them up and invalidate as many
+ * as possible at once.
+ */
+ *ptq = 0;
+
+ va = i386_ptob(sva);
+
+ /*
+ * Remove from the PV table (raise IPL since we
+ * may be called at interrupt time).
+ */
+ pa = ((int)oldpte) & PG_FRAME;
+ if (!pmap_is_managed(pa)) {
+ ++sva;
+ continue;
+ }
+
+ if ((((int) oldpte & PG_M) && (va < USRSTACK || va > UPT_MAX_ADDRESS))
+ || (va >= USRSTACK && va < USRSTACK+(UPAGES*NBPG))) {
+ if (va < pager_sva || va >= pager_eva) {
+ m = PHYS_TO_VM_PAGE(pa);
+ m->flags &= ~PG_CLEAN;
+ }
+ }
+
+ pv = pa_to_pvh(pa);
+ pmap_remove_entry(pmap, pv, va);
+ pmap_unuse_pt(pmap, va);
+ ++sva;
+ }
+ tlbflush();
+}
+
+/*
+ * Routine: pmap_remove_all
+ * Function:
+ * Removes this physical page from
+ * all physical maps in which it resides.
+ * Reflects back modify bits to the pager.
+ *
+ * Notes:
+ * Original versions of this routine were very
+ * inefficient because they iteratively called
+ * pmap_remove (slow...)
+ */
+void
+pmap_remove_all(pa)
+ vm_offset_t pa;
+{
+ register pv_entry_t pv, npv;
+ register pt_entry_t *pte, *ptp;
+ vm_offset_t va;
+ struct pmap *pmap;
+ struct map *map;
+ vm_page_t m;
+ int s;
+
+ /*
+ * Not one of ours
+ */
+ if (!pmap_is_managed(pa))
+ return;
+
+ pa = i386_trunc_page(pa);
+ pv = pa_to_pvh(pa);
+ m = PHYS_TO_VM_PAGE(pa);
+
+ s = splimp();
+ while (pv->pv_pmap != NULL) {
+ pmap = pv->pv_pmap;
+ ptp = get_pt_entry(pmap);
+ va = i386_btop(pv->pv_va);
+ pte = ptp + va;
+ if (pmap_pte_w(pte))
+ pmap->pm_stats.wired_count--;
+ if ( *pte)
+ pmap->pm_stats.resident_count--;
+
+ /*
+ * update the vm_page_t clean bit
+ */
+ if ( (m->flags & PG_CLEAN) &&
+ ((((int) *pte) & PG_M) && (pv->pv_va < USRSTACK || pv->pv_va > UPT_MAX_ADDRESS))
+ || (pv->pv_va >= USRSTACK && pv->pv_va < USRSTACK+(UPAGES*NBPG))) {
+ if (pv->pv_va < pager_sva || pv->pv_va >= pager_eva) {
+ m->flags &= ~PG_CLEAN;
+ }
+ }
+
+ *pte = 0;
+ pmap_unuse_pt(pmap, pv->pv_va);
+
+ npv = pv->pv_next;
+ if (npv) {
+ *pv = *npv;
+ free_pv_entry(npv);
+ } else {
+ pv->pv_pmap = NULL;
+ }
+ }
+ splx(s);
+ tlbflush();
+}
+
+
+/*
+ * Set the physical protection on the
+ * specified range of this map as requested.
+ */
+void
+pmap_protect(pmap, sva, eva, prot)
+ register pmap_t pmap;
+ vm_offset_t sva, eva;
+ vm_prot_t prot;
+{
+ register pt_entry_t *pte;
+ register vm_offset_t va;
+ int i386prot;
+ register pt_entry_t *ptp;
+ int evap = i386_btop(eva);
+ int s;
+
+ if (pmap == NULL)
+ return;
+
+ if ((prot & VM_PROT_READ) == VM_PROT_NONE) {
+ pmap_remove(pmap, sva, eva);
+ return;
+ }
+ if (prot & VM_PROT_WRITE)
+ return;
+
+ ptp = get_pt_entry(pmap);
+
+ va = sva;
+ while (va < eva) {
+ int found=0;
+ int svap;
+ vm_offset_t nscan;
+ /*
+ * Page table page is not allocated.
+ * Skip it, we don't want to force allocation
+ * of unnecessary PTE pages just to set the protection.
+ */
+ if (! *pmap_pde(pmap, va)) {
+ /* XXX: avoid address wrap around */
+nextpde:
+ if (va >= i386_trunc_pdr((vm_offset_t)-1))
+ break;
+ va = i386_round_pdr(va + PAGE_SIZE);
+ continue;
+ }
+
+ pte = ptp + i386_btop(va);
+
+ if( *pte == 0) {
+ /*
+ * scan for a non-empty pte
+ */
+ svap = pte - ptp;
+ nscan = ((svap + NPTEPG) & ~(NPTEPG - 1)) - svap;
+
+ if (nscan + svap > evap)
+ nscan = evap - svap;
+
+ found = 0;
+ if (nscan)
+ asm("xorl %%eax,%%eax;cld;repe;scasl;jz 1f;incl %%eax;1:;"
+ :"=D"(pte),"=a"(found)
+ :"c"(nscan),"0"(pte):"cx");
+
+ if( !found)
+ goto nextpde;
+
+ pte -= 1;
+ svap = pte - ptp;
+
+ va = i386_ptob(svap);
+ }
+
+ i386prot = pte_prot(pmap, prot);
+ if (va < UPT_MAX_ADDRESS) {
+ i386prot |= PG_u;
+ if( va >= UPT_MIN_ADDRESS)
+ i386prot |= PG_RW;
+ }
+ pmap_pte_set_prot(pte, i386prot);
+ va += PAGE_SIZE;
+ }
+ tlbflush();
+}
+
+/*
+ * Insert the given physical page (p) at
+ * the specified virtual address (v) in the
+ * target physical map with the protection requested.
+ *
+ * If specified, the page will be wired down, meaning
+ * that the related pte can not be reclaimed.
+ *
+ * NB: This is the only routine which MAY NOT lazy-evaluate
+ * or lose information. That is, this routine must actually
+ * insert this page into the given map NOW.
+ */
+void
+pmap_enter(pmap, va, pa, prot, wired)
+ register pmap_t pmap;
+ vm_offset_t va;
+ register vm_offset_t pa;
+ vm_prot_t prot;
+ boolean_t wired;
+{
+ register pt_entry_t *pte;
+ register pt_entry_t npte;
+ vm_offset_t opa;
+ int cacheable=1;
+
+ if (pmap == NULL)
+ return;
+
+ va = i386_trunc_page(va);
+ pa = i386_trunc_page(pa);
+ if (va > VM_MAX_KERNEL_ADDRESS)panic("pmap_enter: toobig");
+
+ /*
+ * Page Directory table entry not valid, we need a new PT page
+ */
+ if ( *pmap_pde(pmap, va) == 0) {
+ pg("ptdi %x, va %x", pmap->pm_pdir[PTDPTDI], va);
+ }
+
+ pte = pmap_pte(pmap, va);
+ opa = pmap_pte_pa(pte);
+
+ /*
+ * Mapping has not changed, must be protection or wiring change.
+ */
+ if (opa == pa) {
+ /*
+ * Wiring change, just update stats.
+ * We don't worry about wiring PT pages as they remain
+ * resident as long as there are valid mappings in them.
+ * Hence, if a user page is wired, the PT page will be also.
+ */
+ if (wired && !pmap_pte_w(pte) || !wired && pmap_pte_w(pte)) {
+ if (wired)
+ pmap->pm_stats.wired_count++;
+ else
+ pmap->pm_stats.wired_count--;
+ }
+ goto validate;
+ }
+
+ /*
+ * Mapping has changed, invalidate old range and fall through to
+ * handle validating new mapping.
+ */
+ if (opa) {
+ pmap_remove(pmap, va, va + PAGE_SIZE);
+ }
+
+ /*
+ * Enter on the PV list if part of our managed memory
+ * Note that we raise IPL while manipulating pv_table
+ * since pmap_enter can be called at interrupt time.
+ */
+ if (pmap_is_managed(pa)) {
+ register pv_entry_t pv, npv;
+ int s;
+
+ pv = pa_to_pvh(pa);
+ s = splimp();
+ /*
+ * No entries yet, use header as the first entry
+ */
+ if (pv->pv_pmap == NULL) {
+ pv->pv_va = va;
+ pv->pv_pmap = pmap;
+ pv->pv_next = NULL;
+ }
+ /*
+ * There is at least one other VA mapping this page.
+ * Place this entry after the header.
+ */
+ else {
+ npv = get_pv_entry();
+ npv->pv_va = va;
+ npv->pv_pmap = pmap;
+ npv->pv_next = pv->pv_next;
+ pv->pv_next = npv;
+ }
+ splx(s);
+ cacheable = 1;
+ } else {
+ cacheable = 0;
+ }
+
+ pmap_use_pt(pmap, va);
+
+ /*
+ * Increment counters
+ */
+ pmap->pm_stats.resident_count++;
+ if (wired)
+ pmap->pm_stats.wired_count++;
+
+validate:
+ /*
+ * Now validate mapping with desired protection/wiring.
+ */
+ npte = (pt_entry_t) ( (int) (pa | pte_prot(pmap, prot) | PG_V));
+ /*
+ * for correctness:
+ */
+ if( !cacheable)
+ (int) npte |= PG_N;
+
+ /*
+ * When forking (copy-on-write, etc):
+ * A process will turn off write permissions for any of its writable
+ * pages. If the data (object) is only referred to by one process, the
+ * processes map is modified directly as opposed to using the
+ * object manipulation routine. When using pmap_protect, the
+ * modified bits are not kept in the vm_page_t data structure.
+ * Therefore, when using pmap_enter in vm_fault to bring back
+ * writability of a page, there has been no memory of the
+ * modified or referenced bits except at the pte level.
+ * this clause supports the carryover of the modified and
+ * used (referenced) bits.
+ */
+ if (pa == opa)
+ (int) npte |= (int) *pte & (PG_M|PG_U);
+
+
+ if (wired)
+ (int) npte |= PG_W;
+ if (va < UPT_MIN_ADDRESS)
+ (int) npte |= PG_u;
+ else if (va < UPT_MAX_ADDRESS)
+ (int) npte |= PG_u | PG_RW;
+
+ if( *pte != npte) {
+ *pte = npte;
+ tlbflush();
+ }
+}
+
+/*
+ * add a wired page to the kva
+ */
+void
+pmap_kenter(va, pa)
+ vm_offset_t va;
+ register vm_offset_t pa;
+{
+ register pt_entry_t *pte;
+ register pv_entry_t pv, npv;
+ vm_offset_t opa;
+ int s;
+
+ /*
+ * Enter on the PV list if part of our managed memory
+ * Note that we raise IPL while manipulating pv_table
+ * since pmap_enter can be called at interrupt time.
+ */
+
+ pte = vtopte(va);
+
+ opa = pmap_pte_pa(pte);
+ /*
+ * Mapping has not changed, must be protection or wiring change.
+ */
+ if (opa == pa) {
+ /*
+ * Wiring change, just update stats.
+ * We don't worry about wiring PT pages as they remain
+ * resident as long as there are valid mappings in them.
+ * Hence, if a user page is wired, the PT page will be also.
+ */
+ if (!pmap_pte_w(pte)) {
+ kernel_pmap->pm_stats.wired_count++;
+ }
+ goto validate;
+ }
+
+ if (opa) {
+ pmap_remove(kernel_pmap, va, va + PAGE_SIZE);
+ }
+
+ pv = pa_to_pvh(pa);
+ s = splimp();
+ /*
+ * No entries yet, use header as the first entry
+ */
+ if (pv->pv_pmap == NULL) {
+ pv->pv_va = va;
+ pv->pv_pmap = kernel_pmap;
+ pv->pv_next = NULL;
+ }
+ /*
+ * There is at least one other VA mapping this page.
+ * Place this entry after the header.
+ */
+ else {
+ npv = get_pv_entry();
+ npv->pv_va = va;
+ npv->pv_pmap = kernel_pmap;
+ npv->pv_next = pv->pv_next;
+ pv->pv_next = npv;
+ }
+ splx(s);
+
+ /*
+ * Increment counters
+ */
+ kernel_pmap->pm_stats.resident_count++;
+
+validate:
+
+ /*
+ * Now validate mapping with desired protection/wiring.
+ */
+ *pte = (pt_entry_t) ( (int) (pa | PG_RW | PG_V | PG_W));
+}
+
+/*
+ * this code makes some *MAJOR* assumptions:
+ * 1. Current pmap & pmap exists.
+ * 2. Not wired.
+ * 3. Read access.
+ * 4. No page table pages.
+ * 5. Tlbflush is deferred to calling procedure.
+ * 6. Page IS managed.
+ * but is *MUCH* faster than pmap_enter...
+ */
+
+static inline void
+pmap_enter_quick(pmap, va, pa)
+ register pmap_t pmap;
+ vm_offset_t va;
+ register vm_offset_t pa;
+{
+ register pt_entry_t *pte;
+ register pv_entry_t pv, npv;
+ int s;
+
+ /*
+ * Enter on the PV list if part of our managed memory
+ * Note that we raise IPL while manipulating pv_table
+ * since pmap_enter can be called at interrupt time.
+ */
+
+ pte = vtopte(va);
+ if (pmap_pte_pa(pte)) {
+ pmap_remove(pmap, va, va + PAGE_SIZE);
+ }
+
+ pv = pa_to_pvh(pa);
+ s = splimp();
+ /*
+ * No entries yet, use header as the first entry
+ */
+ if (pv->pv_pmap == NULL) {
+ pv->pv_va = va;
+ pv->pv_pmap = pmap;
+ pv->pv_next = NULL;
+ }
+ /*
+ * There is at least one other VA mapping this page.
+ * Place this entry after the header.
+ */
+ else {
+ npv = get_pv_entry();
+ npv->pv_va = va;
+ npv->pv_pmap = pmap;
+ npv->pv_next = pv->pv_next;
+ pv->pv_next = npv;
+ }
+ splx(s);
+
+ pmap_use_pt(pmap, va);
+
+ /*
+ * Increment counters
+ */
+ pmap->pm_stats.resident_count++;
+
+validate:
+
+ /*
+ * Now validate mapping with desired protection/wiring.
+ */
+ *pte = (pt_entry_t) ( (int) (pa | PG_RO | PG_V | PG_u));
+}
+
+/*
+ * pmap_object_init_pt preloads the ptes for a given object
+ * into the specified pmap. This eliminates the blast of soft
+ * faults on process startup and immediately after an mmap.
+ */
+void
+pmap_object_init_pt(pmap, addr, object, offset, size)
+ pmap_t pmap;
+ vm_offset_t addr;
+ vm_object_t object;
+ vm_offset_t offset;
+ vm_offset_t size;
+{
+
+ vm_offset_t tmpoff;
+ vm_page_t p;
+ int s;
+ vm_offset_t v, lastv=0;
+ pt_entry_t pte;
+ extern vm_map_t kernel_map;
+ vm_offset_t objbytes;
+
+ if (!pmap)
+ return;
+
+ /*
+ * if we are processing a major portion of the object, then
+ * scan the entire thing.
+ */
+ if( size > object->size / 2) {
+ objbytes = size;
+ p = (vm_page_t) queue_first(&object->memq);
+ while (!queue_end(&object->memq, (queue_entry_t) p) && objbytes != 0) {
+ tmpoff = p->offset;
+ if( tmpoff < offset) {
+ p = (vm_page_t) queue_next(&p->listq);
+ continue;
+ }
+ tmpoff -= offset;
+ if( tmpoff >= size) {
+ p = (vm_page_t) queue_next(&p->listq);
+ continue;
+ }
+
+ if ((p->flags & (PG_BUSY|PG_FICTITIOUS)) == 0 ) {
+ vm_page_hold(p);
+ v = i386_trunc_page(((vm_offset_t)vtopte( addr+tmpoff)));
+ /* a fault might occur here */
+ *(volatile char *)v += 0;
+ vm_page_unhold(p);
+ pmap_enter_quick(pmap, addr+tmpoff, VM_PAGE_TO_PHYS(p));
+ }
+ p = (vm_page_t) queue_next(&p->listq);
+ objbytes -= NBPG;
+ }
+ } else {
+ /*
+ * else lookup the pages one-by-one.
+ */
+ for(tmpoff = 0; tmpoff < size; tmpoff += NBPG) {
+ if( p = vm_page_lookup(object, tmpoff + offset)) {
+ if( (p->flags & (PG_BUSY|PG_FICTITIOUS)) == 0) {
+ vm_page_hold(p);
+ v = i386_trunc_page(((vm_offset_t)vtopte( addr+tmpoff)));
+ /* a fault might occur here */
+ *(volatile char *)v += 0;
+ vm_page_unhold(p);
+ pmap_enter_quick(pmap, addr+tmpoff, VM_PAGE_TO_PHYS(p));
+ }
+ }
+ }
+ }
+
+ tlbflush();
+}
+
+/*
+ * Routine: pmap_change_wiring
+ * Function: Change the wiring attribute for a map/virtual-address
+ * pair.
+ * In/out conditions:
+ * The mapping must already exist in the pmap.
+ */
+void
+pmap_change_wiring(pmap, va, wired)
+ register pmap_t pmap;
+ vm_offset_t va;
+ boolean_t wired;
+{
+ register pt_entry_t *pte;
+
+ if (pmap == NULL)
+ return;
+
+ pte = pmap_pte(pmap, va);
+ if (wired && !pmap_pte_w(pte) || !wired && pmap_pte_w(pte)) {
+ if (wired)
+ pmap->pm_stats.wired_count++;
+ else
+ pmap->pm_stats.wired_count--;
+ }
+ /*
+ * Wiring is not a hardware characteristic so there is no need
+ * to invalidate TLB.
+ */
+ pmap_pte_set_w(pte, wired);
+ /*
+ * When unwiring, set the modified bit in the pte -- could have
+ * been changed by the kernel
+ */
+ if (!wired)
+ (int) *pte |= PG_M;
+}
+
+
+
+/*
+ * Copy the range specified by src_addr/len
+ * from the source map to the range dst_addr/len
+ * in the destination map.
+ *
+ * This routine is only advisory and need not do anything.
+ */
+void
+pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr)
+ pmap_t dst_pmap, src_pmap;
+ vm_offset_t dst_addr;
+ vm_size_t len;
+ vm_offset_t src_addr;
+{
+}
+/*
+ * Require that all active physical maps contain no
+ * incorrect entries NOW. [This update includes
+ * forcing updates of any address map caching.]
+ *
+ * Generally used to insure that a thread about
+ * to run will see a semantically correct world.
+ */
+void
+pmap_update()
+{
+ tlbflush();
+}
+
+/*
+ * Routine: pmap_kernel
+ * Function:
+ * Returns the physical map handle for the kernel.
+ */
+pmap_t
+pmap_kernel()
+{
+ return (kernel_pmap);
+}
+
+/*
+ * pmap_zero_page zeros the specified (machine independent)
+ * page by mapping the page into virtual memory and using
+ * bzero to clear its contents, one machine dependent page
+ * at a time.
+ */
+void
+pmap_zero_page(phys)
+ vm_offset_t phys;
+{
+ *(int *)CMAP2 = PG_V | PG_KW | i386_trunc_page(phys);
+ tlbflush();
+ bzero(CADDR2,NBPG);
+}
+
+/*
+ * pmap_copy_page copies the specified (machine independent)
+ * page by mapping the page into virtual memory and using
+ * bcopy to copy the page, one machine dependent page at a
+ * time.
+ */
+void
+pmap_copy_page(src, dst)
+ vm_offset_t src;
+ vm_offset_t dst;
+{
+ *(int *)CMAP1 = PG_V | PG_KW | i386_trunc_page(src);
+ *(int *)CMAP2 = PG_V | PG_KW | i386_trunc_page(dst);
+ tlbflush();
+
+#if __GNUC__ > 1
+ memcpy(CADDR2, CADDR1, NBPG);
+#else
+ bcopy(CADDR1, CADDR2, NBPG);
+#endif
+}
+
+
+/*
+ * Routine: pmap_pageable
+ * Function:
+ * Make the specified pages (by pmap, offset)
+ * pageable (or not) as requested.
+ *
+ * A page which is not pageable may not take
+ * a fault; therefore, its page table entry
+ * must remain valid for the duration.
+ *
+ * This routine is merely advisory; pmap_enter
+ * will specify that these pages are to be wired
+ * down (or not) as appropriate.
+ */
+void
+pmap_pageable(pmap, sva, eva, pageable)
+ pmap_t pmap;
+ vm_offset_t sva, eva;
+ boolean_t pageable;
+{
+}
+
+/*
+ * this routine returns true if a physical page resides
+ * in the given pmap.
+ */
+boolean_t
+pmap_page_exists(pmap, pa)
+ pmap_t pmap;
+ vm_offset_t pa;
+{
+ register pv_entry_t pv;
+ int s;
+
+ if (!pmap_is_managed(pa))
+ return FALSE;
+
+ pv = pa_to_pvh(pa);
+ s = splimp();
+
+ /*
+ * Not found, check current mappings returning
+ * immediately if found.
+ */
+ if (pv->pv_pmap != NULL) {
+ for (; pv; pv = pv->pv_next) {
+ if (pv->pv_pmap == pmap) {
+ splx(s);
+ return TRUE;
+ }
+ }
+ }
+ splx(s);
+ return(FALSE);
+}
+
+/*
+ * pmap_testbit tests bits in pte's
+ * note that the testbit/changebit routines are inline,
+ * and a lot of things compile-time evaluate.
+ */
+static inline boolean_t
+pmap_testbit(pa, bit)
+ register vm_offset_t pa;
+ int bit;
+{
+ register pv_entry_t pv;
+ pt_entry_t *pte;
+ int s;
+
+ if (!pmap_is_managed(pa))
+ return FALSE;
+
+ pv = pa_to_pvh(pa);
+ s = splimp();
+
+ /*
+ * Not found, check current mappings returning
+ * immediately if found.
+ */
+ if (pv->pv_pmap != NULL) {
+ for (; pv; pv = pv->pv_next) {
+ /*
+ * if the bit being tested is the modified bit,
+ * then mark UPAGES as always modified, and
+ * ptes as never modified.
+ */
+ if (bit & PG_U ) {
+ if ((pv->pv_va >= pager_sva) && (pv->pv_va < pager_eva)) {
+ continue;
+ }
+ }
+ if (bit & PG_M ) {
+ if (pv->pv_va >= USRSTACK) {
+ if (pv->pv_va >= pager_sva && pv->pv_va < pager_eva) {
+ continue;
+ }
+ if (pv->pv_va < USRSTACK+(UPAGES*NBPG)) {
+ splx(s);
+ return TRUE;
+ }
+ else if (pv->pv_va < UPT_MAX_ADDRESS) {
+ splx(s);
+ return FALSE;
+ }
+ }
+ }
+ pte = pmap_pte(pv->pv_pmap, pv->pv_va);
+ if ((int) *pte & bit) {
+ splx(s);
+ return TRUE;
+ }
+ }
+ }
+ splx(s);
+ return(FALSE);
+}
+
+/*
+ * this routine is used to modify bits in ptes
+ */
+static inline void
+pmap_changebit(pa, bit, setem)
+ vm_offset_t pa;
+ int bit;
+ boolean_t setem;
+{
+ register pv_entry_t pv;
+ register pt_entry_t *pte, npte;
+ vm_offset_t va;
+ int s;
+
+ if (!pmap_is_managed(pa))
+ return;
+
+ pv = pa_to_pvh(pa);
+ s = splimp();
+
+ /*
+ * Loop over all current mappings setting/clearing as appropos
+ * If setting RO do we need to clear the VAC?
+ */
+ if (pv->pv_pmap != NULL) {
+ for (; pv; pv = pv->pv_next) {
+ va = pv->pv_va;
+
+ /*
+ * don't write protect pager mappings
+ */
+ if (!setem && (bit == PG_RW)) {
+ if (va >= pager_sva && va < pager_eva)
+ continue;
+ }
+
+ pte = pmap_pte(pv->pv_pmap, va);
+ if (setem)
+ (int) npte = (int) *pte | bit;
+ else
+ (int) npte = (int) *pte & ~bit;
+ *pte = npte;
+ }
+ }
+ splx(s);
+ tlbflush();
+}
+
+/*
+ * pmap_page_protect:
+ *
+ * Lower the permission for all mappings to a given page.
+ */
+void
+pmap_page_protect(phys, prot)
+ vm_offset_t phys;
+ vm_prot_t prot;
+{
+ if ((prot & VM_PROT_WRITE) == 0) {
+ if (prot & (VM_PROT_READ | VM_PROT_EXECUTE))
+ pmap_changebit(phys, PG_RW, FALSE);
+ else
+ pmap_remove_all(phys);
+ }
+}
+
+/*
+ * Clear the modify bits on the specified physical page.
+ */
+void
+pmap_clear_modify(pa)
+ vm_offset_t pa;
+{
+ pmap_changebit(pa, PG_M, FALSE);
+}
+
+/*
+ * pmap_clear_reference:
+ *
+ * Clear the reference bit on the specified physical page.
+ */
+void
+pmap_clear_reference(pa)
+ vm_offset_t pa;
+{
+ pmap_changebit(pa, PG_U, FALSE);
+}
+
+/*
+ * pmap_is_referenced:
+ *
+ * Return whether or not the specified physical page is referenced
+ * by any physical maps.
+ */
+
+boolean_t
+pmap_is_referenced(pa)
+ vm_offset_t pa;
+{
+ return(pmap_testbit(pa, PG_U));
+}
+
+/*
+ * pmap_is_modified:
+ *
+ * Return whether or not the specified physical page is modified
+ * by any physical maps.
+ */
+
+boolean_t
+pmap_is_modified(pa)
+ vm_offset_t pa;
+{
+ return(pmap_testbit(pa, PG_M));
+}
+
+/*
+ * Routine: pmap_copy_on_write
+ * Function:
+ * Remove write privileges from all
+ * physical maps for this physical page.
+ */
+void
+pmap_copy_on_write(pa)
+ vm_offset_t pa;
+{
+ pmap_changebit(pa, PG_RW, FALSE);
+}
+
+
+vm_offset_t
+pmap_phys_address(ppn)
+ int ppn;
+{
+ return(i386_ptob(ppn));
+}
+
+/*
+ * Miscellaneous support routines follow
+ */
+
+void
+i386_protection_init()
+{
+ register int *kp, prot;
+
+ kp = protection_codes;
+ for (prot = 0; prot < 8; prot++) {
+ switch (prot) {
+ case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE:
+ *kp++ = 0;
+ break;
+ case VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE:
+ case VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE:
+ case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE:
+ *kp++ = PG_RO;
+ break;
+ case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE:
+ case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE:
+ case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE:
+ case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE:
+ *kp++ = PG_RW;
+ break;
+ }
+ }
+}
+
+#ifdef DEBUG
+void
+pmap_pvdump(pa)
+ vm_offset_t pa;
+{
+ register pv_entry_t pv;
+
+ printf("pa %x", pa);
+ for (pv = pa_to_pvh(pa); pv; pv = pv->pv_next) {
+ printf(" -> pmap %x, va %x, flags %x",
+ pv->pv_pmap, pv->pv_va, pv->pv_flags);
+ pads(pv->pv_pmap);
+ }
+ printf(" ");
+}
+
+/* print address space of pmap*/
+void
+pads(pm)
+ pmap_t pm;
+{
+ unsigned va, i, j;
+ pt_entry_t *ptep;
+
+ if (pm == kernel_pmap) return;
+ for (i = 0; i < 1024; i++)
+ if (pm->pm_pdir[i])
+ for (j = 0; j < 1024 ; j++) {
+ va = (i<<PD_SHIFT)+(j<<PG_SHIFT);
+ if (pm == kernel_pmap && va < KERNBASE)
+ continue;
+ if (pm != kernel_pmap && va > UPT_MAX_ADDRESS)
+ continue;
+ ptep = pmap_pte(pm, va);
+ if (pmap_pte_v(ptep))
+ printf("%x:%x ", va, *(int *)ptep);
+ } ;
+
+}
+#endif
diff --git a/sys/amd64/amd64/support.S b/sys/amd64/amd64/support.S
new file mode 100644
index 0000000..e808222
--- /dev/null
+++ b/sys/amd64/amd64/support.S
@@ -0,0 +1,1153 @@
+/*-
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: support.s,v 1.6 1994/04/02 07:00:29 davidg Exp $
+ */
+
+#include "assym.s" /* system definitions */
+#include "errno.h" /* error return codes */
+#include "machine/asmacros.h" /* miscellaneous asm macros */
+#include "machine/cputypes.h" /* types of CPUs */
+
+#define KDSEL 0x10 /* kernel data selector */
+#define IDXSHIFT 10
+
+/*
+ * Support routines for GCC, general C-callable functions
+ */
+ENTRY(__udivsi3)
+ movl 4(%esp),%eax
+ xorl %edx,%edx
+ divl 8(%esp)
+ ret
+
+ENTRY(__divsi3)
+ movl 4(%esp),%eax
+ cltd
+ idivl 8(%esp)
+ ret
+
+ /*
+ * I/O bus instructions via C
+ */
+ENTRY(inb) /* val = inb(port) */
+ movl 4(%esp),%edx
+ subl %eax,%eax
+ inb %dx,%al
+ NOP
+ ret
+
+ENTRY(inw) /* val = inw(port) */
+ movl 4(%esp),%edx
+ subl %eax,%eax
+ inw %dx,%ax
+ NOP
+ ret
+
+ENTRY(insb) /* insb(port, addr, cnt) */
+ pushl %edi
+ movw 8(%esp),%dx
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ insb
+ NOP
+ movl %edi,%eax
+ popl %edi
+ ret
+
+ENTRY(insw) /* insw(port, addr, cnt) */
+ pushl %edi
+ movw 8(%esp),%dx
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ insw
+ NOP
+ movl %edi,%eax
+ popl %edi
+ ret
+
+ENTRY(insl) /* insl(port, addr, cnt) */
+ pushl %edi
+ movw 8(%esp),%dx
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ insl
+ NOP
+ movl %edi,%eax
+ popl %edi
+ ret
+
+ENTRY(rtcin) /* rtcin(val) */
+ movl 4(%esp),%eax
+ outb %al,$0x70
+ NOP
+ xorl %eax,%eax
+ inb $0x71,%al
+ NOP
+ ret
+
+ENTRY(outb) /* outb(port, val) */
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+ outb %al,%dx
+ NOP
+ ret
+
+ENTRY(outw) /* outw(port, val) */
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+ outw %ax,%dx
+ NOP
+ ret
+
+ENTRY(outsb) /* outsb(port, addr, cnt) */
+ pushl %esi
+ movw 8(%esp),%dx
+ movl 12(%esp),%esi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ outsb
+ NOP
+ movl %esi,%eax
+ popl %esi
+ ret
+
+ENTRY(outsw) /* outsw(port, addr, cnt) */
+ pushl %esi
+ movw 8(%esp),%dx
+ movl 12(%esp),%esi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ outsw
+ NOP
+ movl %esi,%eax
+ popl %esi
+ ret
+
+ENTRY(outsl) /* outsl(port, addr, cnt) */
+ pushl %esi
+ movw 8(%esp),%dx
+ movl 12(%esp),%esi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ outsl
+ NOP
+ movl %esi,%eax
+ popl %esi
+ ret
+
+/*
+ * bcopy family
+ */
+/*
+ * void bzero(void *base, u_int cnt)
+ * Special code for I486 because stosl uses lots
+ * of clocks. Makes little or no difference on DX2 type
+ * machines, but about stosl is about 1/2 as fast as
+ * memory moves on standard DX !!!!!
+ */
+
+ENTRY(bzero)
+#if defined(I486_CPU) && (defined(I386_CPU) || defined(I586_CPU))
+ cmpl $CPUCLASS_486,_cpu_class
+ jz 1f
+#endif
+#if defined(I386_CPU) || defined(I586_CPU)
+ pushl %edi
+ movl 8(%esp),%edi
+ movl 12(%esp),%ecx
+ xorl %eax,%eax
+ shrl $2,%ecx
+ cld
+ rep
+ stosl
+ movl 12(%esp),%ecx
+ andl $3,%ecx
+ rep
+ stosb
+ popl %edi
+ ret
+ .align 4
+#endif
+#if defined(I486_CPU)
+1:
+ movl 4(%esp),%edx
+ movl 8(%esp),%ecx
+ xorl %eax,%eax
+/
+/ do 64 byte chunks first
+/
+2:
+ cmpl $64,%ecx
+ jb 3f
+ movl %eax,(%edx)
+ movl %eax,4(%edx)
+ movl %eax,8(%edx)
+ movl %eax,12(%edx)
+ movl %eax,16(%edx)
+ movl %eax,20(%edx)
+ movl %eax,24(%edx)
+ movl %eax,28(%edx)
+ movl %eax,32(%edx)
+ movl %eax,36(%edx)
+ movl %eax,40(%edx)
+ movl %eax,44(%edx)
+ movl %eax,48(%edx)
+ movl %eax,52(%edx)
+ movl %eax,56(%edx)
+ movl %eax,60(%edx)
+ addl $64,%edx
+ subl $64,%ecx
+ jnz 2b
+ ret
+ .align 4
+/
+/ do 16 byte chunks
+/
+3:
+ cmpl $16,%ecx
+ jb 4f
+ movl %eax,(%edx)
+ movl %eax,4(%edx)
+ movl %eax,8(%edx)
+ movl %eax,12(%edx)
+ addl $16,%edx
+ subl $16,%ecx
+ jnz 3b
+ ret
+ .align 4
+/
+/ do 4 byte chunks
+/
+4: cmpl $4,%ecx
+ jb 5f
+ movl %eax,(%edx)
+ addl $4,%edx
+ subl $4,%ecx
+ jnz 4b
+ ret
+/
+/ do 1 byte chunks -- this appears to be faster than a loop
+/
+ .align 4
+jtab: .long do0
+ .long do1
+ .long do2
+ .long do3
+
+ .align 4
+5: jmp jtab(,%ecx,4)
+
+ .align 2
+do3: movb $0,(%edx)
+ incl %edx
+ movw $0,(%edx)
+ ret
+ .align 2
+do2: movw $0,(%edx)
+ ret
+ .align 2
+do1: movb $0,(%edx)
+do0: ret
+
+#endif
+
+/* fillw(pat, base, cnt) */
+ENTRY(fillw)
+ pushl %edi
+ movl 8(%esp),%eax
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ stosw
+ popl %edi
+ ret
+
+/* filli(pat, base, cnt) */
+ENTRY(filli)
+ pushl %edi
+ movl 8(%esp),%eax
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ stosl
+ popl %edi
+ ret
+
+ENTRY(bcopyb)
+bcopyb:
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ cmpl %esi,%edi /* potentially overlapping? */
+ jnb 1f
+ cld /* nope, copy forwards */
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ ret
+
+ ALIGN_TEXT
+1:
+ addl %ecx,%edi /* copy backwards. */
+ addl %ecx,%esi
+ std
+ decl %edi
+ decl %esi
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ cld
+ ret
+
+ENTRY(bcopyw)
+bcopyw:
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ cmpl %esi,%edi /* potentially overlapping? */
+ jnb 1f
+ cld /* nope, copy forwards */
+ shrl $1,%ecx /* copy by 16-bit words */
+ rep
+ movsw
+ adc %ecx,%ecx /* any bytes left? */
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ ret
+
+ ALIGN_TEXT
+1:
+ addl %ecx,%edi /* copy backwards */
+ addl %ecx,%esi
+ std
+ andl $1,%ecx /* any fractional bytes? */
+ decl %edi
+ decl %esi
+ rep
+ movsb
+ movl 20(%esp),%ecx /* copy remainder by 16-bit words */
+ shrl $1,%ecx
+ decl %esi
+ decl %edi
+ rep
+ movsw
+ popl %edi
+ popl %esi
+ cld
+ ret
+
+ENTRY(bcopyx)
+ movl 16(%esp),%eax
+ cmpl $2,%eax
+ je bcopyw /* not _bcopyw, to avoid multiple mcounts */
+ cmpl $4,%eax
+ je bcopy /* XXX the shared ret's break mexitcount */
+ jmp bcopyb
+
+/*
+ * (ov)bcopy(src, dst, cnt)
+ * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
+ */
+ALTENTRY(ovbcopy)
+ENTRY(bcopy)
+bcopy:
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ cmpl %esi,%edi /* potentially overlapping? */
+ jnb 1f
+ cld /* nope, copy forwards */
+ shrl $2,%ecx /* copy by 32-bit words */
+ rep
+ movsl
+ movl 20(%esp),%ecx
+ andl $3,%ecx /* any bytes left? */
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ ret
+
+ ALIGN_TEXT
+1:
+ addl %ecx,%edi /* copy backwards */
+ addl %ecx,%esi
+ std
+ andl $3,%ecx /* any fractional bytes? */
+ decl %edi
+ decl %esi
+ rep
+ movsb
+ movl 20(%esp),%ecx /* copy remainder by 32-bit words */
+ shrl $2,%ecx
+ subl $3,%esi
+ subl $3,%edi
+ rep
+ movsl
+ popl %edi
+ popl %esi
+ cld
+ ret
+
+ALTENTRY(ntohl)
+ENTRY(htonl)
+ movl 4(%esp),%eax
+#ifdef i486
+/* XXX */
+/* Since Gas 1.38 does not grok bswap this has been coded as the
+ * equivalent bytes. This can be changed back to bswap when we
+ * upgrade to a newer version of Gas
+ */
+ /* bswap %eax */
+ .byte 0x0f
+ .byte 0xc8
+#else
+ xchgb %al,%ah
+ roll $16,%eax
+ xchgb %al,%ah
+#endif
+ ret
+
+ALTENTRY(ntohs)
+ENTRY(htons)
+ movzwl 4(%esp),%eax
+ xchgb %al,%ah
+ ret
+
+/*****************************************************************************/
+/* copyout and fubyte family */
+/*****************************************************************************/
+/*
+ * Access user memory from inside the kernel. These routines and possibly
+ * the math- and DOS emulators should be the only places that do this.
+ *
+ * We have to access the memory with user's permissions, so use a segment
+ * selector with RPL 3. For writes to user space we have to additionally
+ * check the PTE for write permission, because the 386 does not check
+ * write permissions when we are executing with EPL 0. The 486 does check
+ * this if the WP bit is set in CR0, so we can use a simpler version here.
+ *
+ * These routines set curpcb->onfault for the time they execute. When a
+ * protection violation occurs inside the functions, the trap handler
+ * returns to *curpcb->onfault instead of the function.
+ */
+
+
+ENTRY(copyout) /* copyout(from_kernel, to_user, len) */
+ movl _curpcb,%eax
+ movl $copyout_fault,PCB_ONFAULT(%eax)
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+ movl 16(%esp),%esi
+ movl 20(%esp),%edi
+ movl 24(%esp),%ebx
+ orl %ebx,%ebx /* anything to do? */
+ jz done_copyout
+
+ /*
+ * Check explicitly for non-user addresses. If 486 write protection
+ * is being used, this check is essential because we are in kernel
+ * mode so the h/w does not provide any protection against writing
+ * kernel addresses.
+ *
+ * Otherwise, it saves having to load and restore %es to get the
+ * usual segment-based protection (the destination segment for movs
+ * is always %es). The other explicit checks for user-writablility
+ * are not quite sufficient. They fail for the user area because
+ * we mapped the user area read/write to avoid having an #ifdef in
+ * vm_machdep.c. They fail for user PTEs and/or PTDs! (107
+ * addresses including 0xff800000 and 0xfc000000). I'm not sure if
+ * this can be fixed. Marking the PTEs supervisor mode and the
+ * PDE's user mode would almost work, but there may be a problem
+ * with the self-referential PDE.
+ */
+ movl %edi,%eax
+ addl %ebx,%eax
+ jc copyout_fault
+/*
+ * XXX STOP USING VM_MAXUSER_ADDRESS.
+ * It is an end address, not a max, so every time it is used correctly it
+ * looks like there is an off by one error, and of course it caused an off
+ * by one error in several places.
+ */
+ cmpl $VM_MAXUSER_ADDRESS,%eax
+ ja copyout_fault
+
+#if defined(I386_CPU)
+
+#if defined(I486_CPU) || defined(I586_CPU)
+ cmpl $CPUCLASS_386,_cpu_class
+ jne 3f
+#endif
+/*
+ * We have to check each PTE for user write permission.
+ * The checking may cause a page fault, so it is important to set
+ * up everything for return via copyout_fault before here.
+ */
+ /* compute number of pages */
+ movl %edi,%ecx
+ andl $NBPG-1,%ecx
+ addl %ebx,%ecx
+ decl %ecx
+ shrl $IDXSHIFT+2,%ecx
+ incl %ecx
+
+ /* compute PTE offset for start address */
+ movl %edi,%edx
+ shrl $IDXSHIFT,%edx
+ andb $0xfc,%dl
+
+1: /* check PTE for each page */
+ movb _PTmap(%edx),%al
+ andb $0x07,%al /* Pages must be VALID + USERACC + WRITABLE */
+ cmpb $0x07,%al
+ je 2f
+
+ /* simulate a trap */
+ pushl %edx
+ pushl %ecx
+ shll $IDXSHIFT,%edx
+ pushl %edx
+ call _trapwrite /* trapwrite(addr) */
+ popl %edx
+ popl %ecx
+ popl %edx
+
+ orl %eax,%eax /* if not ok, return EFAULT */
+ jnz copyout_fault
+
+2:
+ addl $4,%edx
+ decl %ecx
+ jnz 1b /* check next page */
+#endif /* I386_CPU */
+
+ /* bcopy(%esi, %edi, %ebx) */
+3:
+ cld
+ movl %ebx,%ecx
+ shrl $2,%ecx
+ rep
+ movsl
+ movb %bl,%cl
+ andb $3,%cl
+ rep
+ movsb
+
+done_copyout:
+ popl %ebx
+ popl %edi
+ popl %esi
+ xorl %eax,%eax
+ movl _curpcb,%edx
+ movl %eax,PCB_ONFAULT(%edx)
+ ret
+
+ ALIGN_TEXT
+copyout_fault:
+ popl %ebx
+ popl %edi
+ popl %esi
+ movl _curpcb,%edx
+ movl $0,PCB_ONFAULT(%edx)
+ movl $EFAULT,%eax
+ ret
+
+/* copyin(from_user, to_kernel, len) */
+ENTRY(copyin)
+ movl _curpcb,%eax
+ movl $copyin_fault,PCB_ONFAULT(%eax)
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi /* caddr_t from */
+ movl 16(%esp),%edi /* caddr_t to */
+ movl 20(%esp),%ecx /* size_t len */
+
+ movb %cl,%al
+ shrl $2,%ecx /* copy longword-wise */
+ cld
+ gs
+ rep
+ movsl
+ movb %al,%cl
+ andb $3,%cl /* copy remaining bytes */
+ gs
+ rep
+ movsb
+
+ popl %edi
+ popl %esi
+ xorl %eax,%eax
+ movl _curpcb,%edx
+ movl %eax,PCB_ONFAULT(%edx)
+ ret
+
+ ALIGN_TEXT
+copyin_fault:
+ popl %edi
+ popl %esi
+ movl _curpcb,%edx
+ movl $0,PCB_ONFAULT(%edx)
+ movl $EFAULT,%eax
+ ret
+
+/*
+ * fu{byte,sword,word} : fetch a byte (sword, word) from user memory
+ */
+ALTENTRY(fuiword)
+ENTRY(fuword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx)
+ movl 4(%esp),%edx
+ gs
+ movl (%edx),%eax
+ movl $0,PCB_ONFAULT(%ecx)
+ ret
+
+ENTRY(fusword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx)
+ movl 4(%esp),%edx
+ gs
+ movzwl (%edx),%eax
+ movl $0,PCB_ONFAULT(%ecx)
+ ret
+
+ALTENTRY(fuibyte)
+ENTRY(fubyte)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx)
+ movl 4(%esp),%edx
+ gs
+ movzbl (%edx),%eax
+ movl $0,PCB_ONFAULT(%ecx)
+ ret
+
+ ALIGN_TEXT
+fusufault:
+ movl _curpcb,%ecx
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx)
+ decl %eax
+ ret
+
+/*
+ * su{byte,sword,word}: write a byte (word, longword) to user memory
+ */
+ALTENTRY(suiword)
+ENTRY(suword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx)
+ movl 4(%esp),%edx
+
+#if defined(I386_CPU)
+
+#if defined(I486_CPU) || defined(I586_CPU)
+ cmpl $CPUCLASS_386,_cpu_class
+ jne 2f /* we only have to set the right segment selector */
+#endif /* I486_CPU || I586_CPU */
+
+ /* XXX - page boundary crossing is still not handled */
+ movl %edx,%eax
+ shrl $IDXSHIFT,%edx
+ andb $0xfc,%dl
+ movb _PTmap(%edx),%dl
+ andb $0x7,%dl /* must be VALID + USERACC + WRITE */
+ cmpb $0x7,%dl
+ je 1f
+
+ /* simulate a trap */
+ pushl %eax
+ call _trapwrite
+ popl %edx /* remove junk parameter from stack */
+ movl _curpcb,%ecx /* restore trashed register */
+ orl %eax,%eax
+ jnz fusufault
+1:
+ movl 4(%esp),%edx
+#endif
+
+2:
+ movl 8(%esp),%eax
+ gs
+ movl %eax,(%edx)
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx)
+ ret
+
+ENTRY(susword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx)
+ movl 4(%esp),%edx
+
+#if defined(I386_CPU)
+
+#if defined(I486_CPU) || defined(I586_CPU)
+ cmpl $CPUCLASS_386,_cpu_class
+ jne 2f
+#endif /* I486_CPU || I586_CPU */
+
+ /* XXX - page boundary crossing is still not handled */
+ movl %edx,%eax
+ shrl $IDXSHIFT,%edx
+ andb $0xfc,%dl
+ movb _PTmap(%edx),%dl
+ andb $0x7,%dl /* must be VALID + USERACC + WRITE */
+ cmpb $0x7,%dl
+ je 1f
+
+ /* simulate a trap */
+ pushl %eax
+ call _trapwrite
+ popl %edx /* remove junk parameter from stack */
+ movl _curpcb,%ecx /* restore trashed register */
+ orl %eax,%eax
+ jnz fusufault
+1:
+ movl 4(%esp),%edx
+#endif
+
+2:
+ movw 8(%esp),%ax
+ gs
+ movw %ax,(%edx)
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx)
+ ret
+
+ALTENTRY(suibyte)
+ENTRY(subyte)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx)
+ movl 4(%esp),%edx
+
+#if defined(I386_CPU)
+
+#if defined(I486_CPU) || defined(I586_CPU)
+ cmpl $CPUCLASS_386,_cpu_class
+ jne 2f
+#endif /* I486_CPU || I586_CPU */
+
+ movl %edx,%eax
+ shrl $IDXSHIFT,%edx
+ andb $0xfc,%dl
+ movb _PTmap(%edx),%dl
+ andb $0x7,%dl /* must be VALID + USERACC + WRITE */
+ cmpb $0x7,%dl
+ je 1f
+
+ /* simulate a trap */
+ pushl %eax
+ call _trapwrite
+ popl %edx /* remove junk parameter from stack */
+ movl _curpcb,%ecx /* restore trashed register */
+ orl %eax,%eax
+ jnz fusufault
+1:
+ movl 4(%esp),%edx
+#endif
+
+2:
+ movb 8(%esp),%al
+ gs
+ movb %al,(%edx)
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx)
+ ret
+
+/*
+ * copyoutstr(from, to, maxlen, int *lencopied)
+ * copy a string from from to to, stop when a 0 character is reached.
+ * return ENAMETOOLONG if string is longer than maxlen, and
+ * EFAULT on protection violations. If lencopied is non-zero,
+ * return the actual length in *lencopied.
+ */
+ENTRY(copyoutstr)
+ pushl %esi
+ pushl %edi
+ movl _curpcb,%ecx
+ movl $cpystrflt,PCB_ONFAULT(%ecx)
+
+ movl 12(%esp),%esi /* %esi = from */
+ movl 16(%esp),%edi /* %edi = to */
+ movl 20(%esp),%edx /* %edx = maxlen */
+
+#if defined(I386_CPU)
+
+#if defined(I486_CPU) || defined(I586_CPU)
+ cmpl $CPUCLASS_386,_cpu_class
+ jne 5f
+#endif /* I486_CPU || I586_CPU */
+
+1:
+ /*
+ * It suffices to check that the first byte is in user space, because
+ * we look at a page at a time and the end address is on a page
+ * boundary.
+ */
+ cmpl $VM_MAXUSER_ADDRESS,%edi
+ jae cpystrflt
+
+ movl %edi,%eax
+ shrl $IDXSHIFT,%eax
+ andb $0xfc,%al
+ movb _PTmap(%eax),%al
+ andb $7,%al
+ cmpb $7,%al
+ je 2f
+
+ /* simulate trap */
+ pushl %edx
+ pushl %edi
+ call _trapwrite
+ popl %edi
+ popl %edx
+ orl %eax,%eax
+ jnz cpystrflt
+
+2: /* copy up to end of this page */
+ movl %edi,%eax
+ andl $NBPG-1,%eax
+ movl $NBPG,%ecx
+ subl %eax,%ecx /* ecx = NBPG - (src % NBPG) */
+ cmpl %ecx,%edx
+ jae 3f
+ movl %edx,%ecx /* ecx = min(ecx, edx) */
+3:
+ orl %ecx,%ecx
+ jz 4f
+ decl %ecx
+ decl %edx
+ lodsb
+ stosb
+ orb %al,%al
+ jnz 3b
+
+ /* Success -- 0 byte reached */
+ decl %edx
+ xorl %eax,%eax
+ jmp 6f
+
+4: /* next page */
+ orl %edx,%edx
+ jnz 1b
+
+ /* edx is zero -- return ENAMETOOLONG */
+ movl $ENAMETOOLONG,%eax
+ jmp cpystrflt_x
+#endif /* I386_CPU */
+
+#if defined(I486_CPU) || defined(I586_CPU)
+5:
+ incl %edx
+1:
+ decl %edx
+ jz 2f
+ /*
+ * gs override doesn't work for stosb. Use the same explicit check
+ * as in copyout(). It's much slower now because it is per-char.
+ * XXX - however, it would be faster to rewrite this function to use
+ * strlen() and copyout().
+ */
+ cmpl $VM_MAXUSER_ADDRESS,%edi
+ jae cpystrflt
+
+ lodsb
+ stosb
+ orb %al,%al
+ jnz 1b
+
+ /* Success -- 0 byte reached */
+ decl %edx
+ xorl %eax,%eax
+ jmp cpystrflt_x
+2:
+ /* edx is zero -- return ENAMETOOLONG */
+ movl $ENAMETOOLONG,%eax
+ jmp cpystrflt_x
+
+#endif /* I486_CPU || I586_CPU */
+
+/*
+ * copyinstr(from, to, maxlen, int *lencopied)
+ * copy a string from from to to, stop when a 0 character is reached.
+ * return ENAMETOOLONG if string is longer than maxlen, and
+ * EFAULT on protection violations. If lencopied is non-zero,
+ * return the actual length in *lencopied.
+ */
+ENTRY(copyinstr)
+ pushl %esi
+ pushl %edi
+ movl _curpcb,%ecx
+ movl $cpystrflt,PCB_ONFAULT(%ecx)
+
+ movl 12(%esp),%esi /* %esi = from */
+ movl 16(%esp),%edi /* %edi = to */
+ movl 20(%esp),%edx /* %edx = maxlen */
+ incl %edx
+
+1:
+ decl %edx
+ jz 4f
+ gs
+ lodsb
+ stosb
+ orb %al,%al
+ jnz 1b
+
+ /* Success -- 0 byte reached */
+ decl %edx
+ xorl %eax,%eax
+ jmp 6f
+4:
+ /* edx is zero -- return ENAMETOOLONG */
+ movl $ENAMETOOLONG,%eax
+ jmp 6f
+
+cpystrflt:
+ movl $EFAULT,%eax
+cpystrflt_x:
+6:
+ /* set *lencopied and return %eax */
+ movl _curpcb,%ecx
+ movl $0,PCB_ONFAULT(%ecx)
+ movl 20(%esp),%ecx
+ subl %edx,%ecx
+ movl 24(%esp),%edx
+ orl %edx,%edx
+ jz 7f
+ movl %ecx,(%edx)
+7:
+ popl %edi
+ popl %esi
+ ret
+
+
+/*
+ * copystr(from, to, maxlen, int *lencopied)
+ */
+ENTRY(copystr)
+ pushl %esi
+ pushl %edi
+
+ movl 12(%esp),%esi /* %esi = from */
+ movl 16(%esp),%edi /* %edi = to */
+ movl 20(%esp),%edx /* %edx = maxlen */
+ incl %edx
+
+1:
+ decl %edx
+ jz 4f
+ lodsb
+ stosb
+ orb %al,%al
+ jnz 1b
+
+ /* Success -- 0 byte reached */
+ decl %edx
+ xorl %eax,%eax
+ jmp 6f
+4:
+ /* edx is zero -- return ENAMETOOLONG */
+ movl $ENAMETOOLONG,%eax
+
+6:
+ /* set *lencopied and return %eax */
+ movl 20(%esp),%ecx
+ subl %edx,%ecx
+ movl 24(%esp),%edx
+ orl %edx,%edx
+ jz 7f
+ movl %ecx,(%edx)
+7:
+ popl %edi
+ popl %esi
+ ret
+
+/*
+ * Handling of special 386 registers and descriptor tables etc
+ */
+/* void lgdt(struct region_descriptor *rdp); */
+ENTRY(lgdt)
+ /* reload the descriptor table */
+ movl 4(%esp),%eax
+ lgdt (%eax)
+
+ /* flush the prefetch q */
+ jmp 1f
+ nop
+1:
+ /* reload "stale" selectors */
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+ movl %ax,%ss
+
+ /* reload code selector by turning return into intersegmental return */
+ movl (%esp),%eax
+ pushl %eax
+# movl $KCSEL,4(%esp)
+ movl $8,4(%esp)
+ lret
+
+/*
+ * void lidt(struct region_descriptor *rdp);
+ */
+ENTRY(lidt)
+ movl 4(%esp),%eax
+ lidt (%eax)
+ ret
+
+/*
+ * void lldt(u_short sel)
+ */
+ENTRY(lldt)
+ lldt 4(%esp)
+ ret
+
+/*
+ * void ltr(u_short sel)
+ */
+ENTRY(ltr)
+ ltr 4(%esp)
+ ret
+
+/* ssdtosd(*ssdp,*sdp) */
+ENTRY(ssdtosd)
+ pushl %ebx
+ movl 8(%esp),%ecx
+ movl 8(%ecx),%ebx
+ shll $16,%ebx
+ movl (%ecx),%edx
+ roll $16,%edx
+ movb %dh,%bl
+ movb %dl,%bh
+ rorl $8,%ebx
+ movl 4(%ecx),%eax
+ movw %ax,%dx
+ andl $0xf0000,%eax
+ orl %eax,%ebx
+ movl 12(%esp),%ecx
+ movl %edx,(%ecx)
+ movl %ebx,4(%ecx)
+ popl %ebx
+ ret
+
+#if 0
+/* tlbflush() */
+ENTRY(tlbflush)
+ movl %cr3,%eax
+ orl $I386_CR3PAT,%eax
+ movl %eax,%cr3
+ ret
+#endif
+
+/* load_cr0(cr0) */
+ENTRY(load_cr0)
+ movl 4(%esp),%eax
+ movl %eax,%cr0
+ ret
+
+/* rcr0() */
+ENTRY(rcr0)
+ movl %cr0,%eax
+ ret
+
+/* rcr2() */
+ENTRY(rcr2)
+ movl %cr2,%eax
+ ret
+
+/* rcr3() */
+ENTRY(rcr3)
+ movl %cr3,%eax
+ ret
+
+/* void load_cr3(caddr_t cr3) */
+ENTRY(load_cr3)
+ movl 4(%esp),%eax
+ orl $I386_CR3PAT,%eax
+ movl %eax,%cr3
+ ret
+
+
+/*****************************************************************************/
+/* setjump, longjump */
+/*****************************************************************************/
+
+ENTRY(setjmp)
+ movl 4(%esp),%eax
+ movl %ebx,(%eax) /* save ebx */
+ movl %esp,4(%eax) /* save esp */
+ movl %ebp,8(%eax) /* save ebp */
+ movl %esi,12(%eax) /* save esi */
+ movl %edi,16(%eax) /* save edi */
+ movl (%esp),%edx /* get rta */
+ movl %edx,20(%eax) /* save eip */
+ xorl %eax,%eax /* return(0); */
+ ret
+
+ENTRY(longjmp)
+ movl 4(%esp),%eax
+ movl (%eax),%ebx /* restore ebx */
+ movl 4(%eax),%esp /* restore esp */
+ movl 8(%eax),%ebp /* restore ebp */
+ movl 12(%eax),%esi /* restore esi */
+ movl 16(%eax),%edi /* restore edi */
+ movl 20(%eax),%edx /* get rta */
+ movl %edx,(%esp) /* put in return frame */
+ xorl %eax,%eax /* return(1); */
+ incl %eax
+ ret
diff --git a/sys/amd64/amd64/support.s b/sys/amd64/amd64/support.s
new file mode 100644
index 0000000..e808222
--- /dev/null
+++ b/sys/amd64/amd64/support.s
@@ -0,0 +1,1153 @@
+/*-
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: support.s,v 1.6 1994/04/02 07:00:29 davidg Exp $
+ */
+
+#include "assym.s" /* system definitions */
+#include "errno.h" /* error return codes */
+#include "machine/asmacros.h" /* miscellaneous asm macros */
+#include "machine/cputypes.h" /* types of CPUs */
+
+#define KDSEL 0x10 /* kernel data selector */
+#define IDXSHIFT 10
+
+/*
+ * Support routines for GCC, general C-callable functions
+ */
+ENTRY(__udivsi3)
+ movl 4(%esp),%eax
+ xorl %edx,%edx
+ divl 8(%esp)
+ ret
+
+ENTRY(__divsi3)
+ movl 4(%esp),%eax
+ cltd
+ idivl 8(%esp)
+ ret
+
+ /*
+ * I/O bus instructions via C
+ */
+ENTRY(inb) /* val = inb(port) */
+ movl 4(%esp),%edx
+ subl %eax,%eax
+ inb %dx,%al
+ NOP
+ ret
+
+ENTRY(inw) /* val = inw(port) */
+ movl 4(%esp),%edx
+ subl %eax,%eax
+ inw %dx,%ax
+ NOP
+ ret
+
+ENTRY(insb) /* insb(port, addr, cnt) */
+ pushl %edi
+ movw 8(%esp),%dx
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ insb
+ NOP
+ movl %edi,%eax
+ popl %edi
+ ret
+
+ENTRY(insw) /* insw(port, addr, cnt) */
+ pushl %edi
+ movw 8(%esp),%dx
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ insw
+ NOP
+ movl %edi,%eax
+ popl %edi
+ ret
+
+ENTRY(insl) /* insl(port, addr, cnt) */
+ pushl %edi
+ movw 8(%esp),%dx
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ insl
+ NOP
+ movl %edi,%eax
+ popl %edi
+ ret
+
+ENTRY(rtcin) /* rtcin(val) */
+ movl 4(%esp),%eax
+ outb %al,$0x70
+ NOP
+ xorl %eax,%eax
+ inb $0x71,%al
+ NOP
+ ret
+
+ENTRY(outb) /* outb(port, val) */
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+ outb %al,%dx
+ NOP
+ ret
+
+ENTRY(outw) /* outw(port, val) */
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+ outw %ax,%dx
+ NOP
+ ret
+
+ENTRY(outsb) /* outsb(port, addr, cnt) */
+ pushl %esi
+ movw 8(%esp),%dx
+ movl 12(%esp),%esi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ outsb
+ NOP
+ movl %esi,%eax
+ popl %esi
+ ret
+
+ENTRY(outsw) /* outsw(port, addr, cnt) */
+ pushl %esi
+ movw 8(%esp),%dx
+ movl 12(%esp),%esi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ outsw
+ NOP
+ movl %esi,%eax
+ popl %esi
+ ret
+
+ENTRY(outsl) /* outsl(port, addr, cnt) */
+ pushl %esi
+ movw 8(%esp),%dx
+ movl 12(%esp),%esi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ outsl
+ NOP
+ movl %esi,%eax
+ popl %esi
+ ret
+
+/*
+ * bcopy family
+ */
+/*
+ * void bzero(void *base, u_int cnt)
+ * Special code for I486 because stosl uses lots
+ * of clocks. Makes little or no difference on DX2 type
+ * machines, but about stosl is about 1/2 as fast as
+ * memory moves on standard DX !!!!!
+ */
+
+ENTRY(bzero)
+#if defined(I486_CPU) && (defined(I386_CPU) || defined(I586_CPU))
+ cmpl $CPUCLASS_486,_cpu_class
+ jz 1f
+#endif
+#if defined(I386_CPU) || defined(I586_CPU)
+ pushl %edi
+ movl 8(%esp),%edi
+ movl 12(%esp),%ecx
+ xorl %eax,%eax
+ shrl $2,%ecx
+ cld
+ rep
+ stosl
+ movl 12(%esp),%ecx
+ andl $3,%ecx
+ rep
+ stosb
+ popl %edi
+ ret
+ .align 4
+#endif
+#if defined(I486_CPU)
+1:
+ movl 4(%esp),%edx
+ movl 8(%esp),%ecx
+ xorl %eax,%eax
+/
+/ do 64 byte chunks first
+/
+2:
+ cmpl $64,%ecx
+ jb 3f
+ movl %eax,(%edx)
+ movl %eax,4(%edx)
+ movl %eax,8(%edx)
+ movl %eax,12(%edx)
+ movl %eax,16(%edx)
+ movl %eax,20(%edx)
+ movl %eax,24(%edx)
+ movl %eax,28(%edx)
+ movl %eax,32(%edx)
+ movl %eax,36(%edx)
+ movl %eax,40(%edx)
+ movl %eax,44(%edx)
+ movl %eax,48(%edx)
+ movl %eax,52(%edx)
+ movl %eax,56(%edx)
+ movl %eax,60(%edx)
+ addl $64,%edx
+ subl $64,%ecx
+ jnz 2b
+ ret
+ .align 4
+/
+/ do 16 byte chunks
+/
+3:
+ cmpl $16,%ecx
+ jb 4f
+ movl %eax,(%edx)
+ movl %eax,4(%edx)
+ movl %eax,8(%edx)
+ movl %eax,12(%edx)
+ addl $16,%edx
+ subl $16,%ecx
+ jnz 3b
+ ret
+ .align 4
+/
+/ do 4 byte chunks
+/
+4: cmpl $4,%ecx
+ jb 5f
+ movl %eax,(%edx)
+ addl $4,%edx
+ subl $4,%ecx
+ jnz 4b
+ ret
+/
+/ do 1 byte chunks -- this appears to be faster than a loop
+/
+ .align 4
+jtab: .long do0
+ .long do1
+ .long do2
+ .long do3
+
+ .align 4
+5: jmp jtab(,%ecx,4)
+
+ .align 2
+do3: movb $0,(%edx)
+ incl %edx
+ movw $0,(%edx)
+ ret
+ .align 2
+do2: movw $0,(%edx)
+ ret
+ .align 2
+do1: movb $0,(%edx)
+do0: ret
+
+#endif
+
+/* fillw(pat, base, cnt) */
+ENTRY(fillw)
+ pushl %edi
+ movl 8(%esp),%eax
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ stosw
+ popl %edi
+ ret
+
+/* filli(pat, base, cnt) */
+ENTRY(filli)
+ pushl %edi
+ movl 8(%esp),%eax
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ stosl
+ popl %edi
+ ret
+
+ENTRY(bcopyb)
+bcopyb:
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ cmpl %esi,%edi /* potentially overlapping? */
+ jnb 1f
+ cld /* nope, copy forwards */
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ ret
+
+ ALIGN_TEXT
+1:
+ addl %ecx,%edi /* copy backwards. */
+ addl %ecx,%esi
+ std
+ decl %edi
+ decl %esi
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ cld
+ ret
+
+ENTRY(bcopyw)
+bcopyw:
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ cmpl %esi,%edi /* potentially overlapping? */
+ jnb 1f
+ cld /* nope, copy forwards */
+ shrl $1,%ecx /* copy by 16-bit words */
+ rep
+ movsw
+ adc %ecx,%ecx /* any bytes left? */
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ ret
+
+ ALIGN_TEXT
+1:
+ addl %ecx,%edi /* copy backwards */
+ addl %ecx,%esi
+ std
+ andl $1,%ecx /* any fractional bytes? */
+ decl %edi
+ decl %esi
+ rep
+ movsb
+ movl 20(%esp),%ecx /* copy remainder by 16-bit words */
+ shrl $1,%ecx
+ decl %esi
+ decl %edi
+ rep
+ movsw
+ popl %edi
+ popl %esi
+ cld
+ ret
+
+ENTRY(bcopyx)
+ movl 16(%esp),%eax
+ cmpl $2,%eax
+ je bcopyw /* not _bcopyw, to avoid multiple mcounts */
+ cmpl $4,%eax
+ je bcopy /* XXX the shared ret's break mexitcount */
+ jmp bcopyb
+
+/*
+ * (ov)bcopy(src, dst, cnt)
+ * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
+ */
+ALTENTRY(ovbcopy)
+ENTRY(bcopy)
+bcopy:
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ cmpl %esi,%edi /* potentially overlapping? */
+ jnb 1f
+ cld /* nope, copy forwards */
+ shrl $2,%ecx /* copy by 32-bit words */
+ rep
+ movsl
+ movl 20(%esp),%ecx
+ andl $3,%ecx /* any bytes left? */
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ ret
+
+ ALIGN_TEXT
+1:
+ addl %ecx,%edi /* copy backwards */
+ addl %ecx,%esi
+ std
+ andl $3,%ecx /* any fractional bytes? */
+ decl %edi
+ decl %esi
+ rep
+ movsb
+ movl 20(%esp),%ecx /* copy remainder by 32-bit words */
+ shrl $2,%ecx
+ subl $3,%esi
+ subl $3,%edi
+ rep
+ movsl
+ popl %edi
+ popl %esi
+ cld
+ ret
+
+ALTENTRY(ntohl)
+ENTRY(htonl)
+ movl 4(%esp),%eax
+#ifdef i486
+/* XXX */
+/* Since Gas 1.38 does not grok bswap this has been coded as the
+ * equivalent bytes. This can be changed back to bswap when we
+ * upgrade to a newer version of Gas
+ */
+ /* bswap %eax */
+ .byte 0x0f
+ .byte 0xc8
+#else
+ xchgb %al,%ah
+ roll $16,%eax
+ xchgb %al,%ah
+#endif
+ ret
+
+ALTENTRY(ntohs)
+ENTRY(htons)
+ movzwl 4(%esp),%eax
+ xchgb %al,%ah
+ ret
+
+/*****************************************************************************/
+/* copyout and fubyte family */
+/*****************************************************************************/
+/*
+ * Access user memory from inside the kernel. These routines and possibly
+ * the math- and DOS emulators should be the only places that do this.
+ *
+ * We have to access the memory with user's permissions, so use a segment
+ * selector with RPL 3. For writes to user space we have to additionally
+ * check the PTE for write permission, because the 386 does not check
+ * write permissions when we are executing with EPL 0. The 486 does check
+ * this if the WP bit is set in CR0, so we can use a simpler version here.
+ *
+ * These routines set curpcb->onfault for the time they execute. When a
+ * protection violation occurs inside the functions, the trap handler
+ * returns to *curpcb->onfault instead of the function.
+ */
+
+
+ENTRY(copyout) /* copyout(from_kernel, to_user, len) */
+ movl _curpcb,%eax
+ movl $copyout_fault,PCB_ONFAULT(%eax)
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+ movl 16(%esp),%esi
+ movl 20(%esp),%edi
+ movl 24(%esp),%ebx
+ orl %ebx,%ebx /* anything to do? */
+ jz done_copyout
+
+ /*
+ * Check explicitly for non-user addresses. If 486 write protection
+ * is being used, this check is essential because we are in kernel
+ * mode so the h/w does not provide any protection against writing
+ * kernel addresses.
+ *
+ * Otherwise, it saves having to load and restore %es to get the
+ * usual segment-based protection (the destination segment for movs
+ * is always %es). The other explicit checks for user-writablility
+ * are not quite sufficient. They fail for the user area because
+ * we mapped the user area read/write to avoid having an #ifdef in
+ * vm_machdep.c. They fail for user PTEs and/or PTDs! (107
+ * addresses including 0xff800000 and 0xfc000000). I'm not sure if
+ * this can be fixed. Marking the PTEs supervisor mode and the
+ * PDE's user mode would almost work, but there may be a problem
+ * with the self-referential PDE.
+ */
+ movl %edi,%eax
+ addl %ebx,%eax
+ jc copyout_fault
+/*
+ * XXX STOP USING VM_MAXUSER_ADDRESS.
+ * It is an end address, not a max, so every time it is used correctly it
+ * looks like there is an off by one error, and of course it caused an off
+ * by one error in several places.
+ */
+ cmpl $VM_MAXUSER_ADDRESS,%eax
+ ja copyout_fault
+
+#if defined(I386_CPU)
+
+#if defined(I486_CPU) || defined(I586_CPU)
+ cmpl $CPUCLASS_386,_cpu_class
+ jne 3f
+#endif
+/*
+ * We have to check each PTE for user write permission.
+ * The checking may cause a page fault, so it is important to set
+ * up everything for return via copyout_fault before here.
+ */
+ /* compute number of pages */
+ movl %edi,%ecx
+ andl $NBPG-1,%ecx
+ addl %ebx,%ecx
+ decl %ecx
+ shrl $IDXSHIFT+2,%ecx
+ incl %ecx
+
+ /* compute PTE offset for start address */
+ movl %edi,%edx
+ shrl $IDXSHIFT,%edx
+ andb $0xfc,%dl
+
+1: /* check PTE for each page */
+ movb _PTmap(%edx),%al
+ andb $0x07,%al /* Pages must be VALID + USERACC + WRITABLE */
+ cmpb $0x07,%al
+ je 2f
+
+ /* simulate a trap */
+ pushl %edx
+ pushl %ecx
+ shll $IDXSHIFT,%edx
+ pushl %edx
+ call _trapwrite /* trapwrite(addr) */
+ popl %edx
+ popl %ecx
+ popl %edx
+
+ orl %eax,%eax /* if not ok, return EFAULT */
+ jnz copyout_fault
+
+2:
+ addl $4,%edx
+ decl %ecx
+ jnz 1b /* check next page */
+#endif /* I386_CPU */
+
+ /* bcopy(%esi, %edi, %ebx) */
+3:
+ cld
+ movl %ebx,%ecx
+ shrl $2,%ecx
+ rep
+ movsl
+ movb %bl,%cl
+ andb $3,%cl
+ rep
+ movsb
+
+done_copyout:
+ popl %ebx
+ popl %edi
+ popl %esi
+ xorl %eax,%eax
+ movl _curpcb,%edx
+ movl %eax,PCB_ONFAULT(%edx)
+ ret
+
+ ALIGN_TEXT
+copyout_fault:
+ popl %ebx
+ popl %edi
+ popl %esi
+ movl _curpcb,%edx
+ movl $0,PCB_ONFAULT(%edx)
+ movl $EFAULT,%eax
+ ret
+
+/* copyin(from_user, to_kernel, len) */
+ENTRY(copyin)
+ movl _curpcb,%eax
+ movl $copyin_fault,PCB_ONFAULT(%eax)
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi /* caddr_t from */
+ movl 16(%esp),%edi /* caddr_t to */
+ movl 20(%esp),%ecx /* size_t len */
+
+ movb %cl,%al
+ shrl $2,%ecx /* copy longword-wise */
+ cld
+ gs
+ rep
+ movsl
+ movb %al,%cl
+ andb $3,%cl /* copy remaining bytes */
+ gs
+ rep
+ movsb
+
+ popl %edi
+ popl %esi
+ xorl %eax,%eax
+ movl _curpcb,%edx
+ movl %eax,PCB_ONFAULT(%edx)
+ ret
+
+ ALIGN_TEXT
+copyin_fault:
+ popl %edi
+ popl %esi
+ movl _curpcb,%edx
+ movl $0,PCB_ONFAULT(%edx)
+ movl $EFAULT,%eax
+ ret
+
+/*
+ * fu{byte,sword,word} : fetch a byte (sword, word) from user memory
+ */
+ALTENTRY(fuiword)
+ENTRY(fuword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx)
+ movl 4(%esp),%edx
+ gs
+ movl (%edx),%eax
+ movl $0,PCB_ONFAULT(%ecx)
+ ret
+
+ENTRY(fusword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx)
+ movl 4(%esp),%edx
+ gs
+ movzwl (%edx),%eax
+ movl $0,PCB_ONFAULT(%ecx)
+ ret
+
+ALTENTRY(fuibyte)
+ENTRY(fubyte)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx)
+ movl 4(%esp),%edx
+ gs
+ movzbl (%edx),%eax
+ movl $0,PCB_ONFAULT(%ecx)
+ ret
+
+ ALIGN_TEXT
+fusufault:
+ movl _curpcb,%ecx
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx)
+ decl %eax
+ ret
+
+/*
+ * su{byte,sword,word}: write a byte (word, longword) to user memory
+ */
+ALTENTRY(suiword)
+ENTRY(suword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx)
+ movl 4(%esp),%edx
+
+#if defined(I386_CPU)
+
+#if defined(I486_CPU) || defined(I586_CPU)
+ cmpl $CPUCLASS_386,_cpu_class
+ jne 2f /* we only have to set the right segment selector */
+#endif /* I486_CPU || I586_CPU */
+
+ /* XXX - page boundary crossing is still not handled */
+ movl %edx,%eax
+ shrl $IDXSHIFT,%edx
+ andb $0xfc,%dl
+ movb _PTmap(%edx),%dl
+ andb $0x7,%dl /* must be VALID + USERACC + WRITE */
+ cmpb $0x7,%dl
+ je 1f
+
+ /* simulate a trap */
+ pushl %eax
+ call _trapwrite
+ popl %edx /* remove junk parameter from stack */
+ movl _curpcb,%ecx /* restore trashed register */
+ orl %eax,%eax
+ jnz fusufault
+1:
+ movl 4(%esp),%edx
+#endif
+
+2:
+ movl 8(%esp),%eax
+ gs
+ movl %eax,(%edx)
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx)
+ ret
+
+ENTRY(susword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx)
+ movl 4(%esp),%edx
+
+#if defined(I386_CPU)
+
+#if defined(I486_CPU) || defined(I586_CPU)
+ cmpl $CPUCLASS_386,_cpu_class
+ jne 2f
+#endif /* I486_CPU || I586_CPU */
+
+ /* XXX - page boundary crossing is still not handled */
+ movl %edx,%eax
+ shrl $IDXSHIFT,%edx
+ andb $0xfc,%dl
+ movb _PTmap(%edx),%dl
+ andb $0x7,%dl /* must be VALID + USERACC + WRITE */
+ cmpb $0x7,%dl
+ je 1f
+
+ /* simulate a trap */
+ pushl %eax
+ call _trapwrite
+ popl %edx /* remove junk parameter from stack */
+ movl _curpcb,%ecx /* restore trashed register */
+ orl %eax,%eax
+ jnz fusufault
+1:
+ movl 4(%esp),%edx
+#endif
+
+2:
+ movw 8(%esp),%ax
+ gs
+ movw %ax,(%edx)
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx)
+ ret
+
+ALTENTRY(suibyte)
+ENTRY(subyte)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx)
+ movl 4(%esp),%edx
+
+#if defined(I386_CPU)
+
+#if defined(I486_CPU) || defined(I586_CPU)
+ cmpl $CPUCLASS_386,_cpu_class
+ jne 2f
+#endif /* I486_CPU || I586_CPU */
+
+ movl %edx,%eax
+ shrl $IDXSHIFT,%edx
+ andb $0xfc,%dl
+ movb _PTmap(%edx),%dl
+ andb $0x7,%dl /* must be VALID + USERACC + WRITE */
+ cmpb $0x7,%dl
+ je 1f
+
+ /* simulate a trap */
+ pushl %eax
+ call _trapwrite
+ popl %edx /* remove junk parameter from stack */
+ movl _curpcb,%ecx /* restore trashed register */
+ orl %eax,%eax
+ jnz fusufault
+1:
+ movl 4(%esp),%edx
+#endif
+
+2:
+ movb 8(%esp),%al
+ gs
+ movb %al,(%edx)
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx)
+ ret
+
+/*
+ * copyoutstr(from, to, maxlen, int *lencopied)
+ * copy a string from from to to, stop when a 0 character is reached.
+ * return ENAMETOOLONG if string is longer than maxlen, and
+ * EFAULT on protection violations. If lencopied is non-zero,
+ * return the actual length in *lencopied.
+ */
+ENTRY(copyoutstr)
+ pushl %esi
+ pushl %edi
+ movl _curpcb,%ecx
+ movl $cpystrflt,PCB_ONFAULT(%ecx)
+
+ movl 12(%esp),%esi /* %esi = from */
+ movl 16(%esp),%edi /* %edi = to */
+ movl 20(%esp),%edx /* %edx = maxlen */
+
+#if defined(I386_CPU)
+
+#if defined(I486_CPU) || defined(I586_CPU)
+ cmpl $CPUCLASS_386,_cpu_class
+ jne 5f
+#endif /* I486_CPU || I586_CPU */
+
+1:
+ /*
+ * It suffices to check that the first byte is in user space, because
+ * we look at a page at a time and the end address is on a page
+ * boundary.
+ */
+ cmpl $VM_MAXUSER_ADDRESS,%edi
+ jae cpystrflt
+
+ movl %edi,%eax
+ shrl $IDXSHIFT,%eax
+ andb $0xfc,%al
+ movb _PTmap(%eax),%al
+ andb $7,%al
+ cmpb $7,%al
+ je 2f
+
+ /* simulate trap */
+ pushl %edx
+ pushl %edi
+ call _trapwrite
+ popl %edi
+ popl %edx
+ orl %eax,%eax
+ jnz cpystrflt
+
+2: /* copy up to end of this page */
+ movl %edi,%eax
+ andl $NBPG-1,%eax
+ movl $NBPG,%ecx
+ subl %eax,%ecx /* ecx = NBPG - (src % NBPG) */
+ cmpl %ecx,%edx
+ jae 3f
+ movl %edx,%ecx /* ecx = min(ecx, edx) */
+3:
+ orl %ecx,%ecx
+ jz 4f
+ decl %ecx
+ decl %edx
+ lodsb
+ stosb
+ orb %al,%al
+ jnz 3b
+
+ /* Success -- 0 byte reached */
+ decl %edx
+ xorl %eax,%eax
+ jmp 6f
+
+4: /* next page */
+ orl %edx,%edx
+ jnz 1b
+
+ /* edx is zero -- return ENAMETOOLONG */
+ movl $ENAMETOOLONG,%eax
+ jmp cpystrflt_x
+#endif /* I386_CPU */
+
+#if defined(I486_CPU) || defined(I586_CPU)
+5:
+ incl %edx
+1:
+ decl %edx
+ jz 2f
+ /*
+ * gs override doesn't work for stosb. Use the same explicit check
+ * as in copyout(). It's much slower now because it is per-char.
+ * XXX - however, it would be faster to rewrite this function to use
+ * strlen() and copyout().
+ */
+ cmpl $VM_MAXUSER_ADDRESS,%edi
+ jae cpystrflt
+
+ lodsb
+ stosb
+ orb %al,%al
+ jnz 1b
+
+ /* Success -- 0 byte reached */
+ decl %edx
+ xorl %eax,%eax
+ jmp cpystrflt_x
+2:
+ /* edx is zero -- return ENAMETOOLONG */
+ movl $ENAMETOOLONG,%eax
+ jmp cpystrflt_x
+
+#endif /* I486_CPU || I586_CPU */
+
+/*
+ * copyinstr(from, to, maxlen, int *lencopied)
+ * copy a string from from to to, stop when a 0 character is reached.
+ * return ENAMETOOLONG if string is longer than maxlen, and
+ * EFAULT on protection violations. If lencopied is non-zero,
+ * return the actual length in *lencopied.
+ */
+ENTRY(copyinstr)
+ pushl %esi
+ pushl %edi
+ movl _curpcb,%ecx
+ movl $cpystrflt,PCB_ONFAULT(%ecx)
+
+ movl 12(%esp),%esi /* %esi = from */
+ movl 16(%esp),%edi /* %edi = to */
+ movl 20(%esp),%edx /* %edx = maxlen */
+ incl %edx
+
+1:
+ decl %edx
+ jz 4f
+ gs
+ lodsb
+ stosb
+ orb %al,%al
+ jnz 1b
+
+ /* Success -- 0 byte reached */
+ decl %edx
+ xorl %eax,%eax
+ jmp 6f
+4:
+ /* edx is zero -- return ENAMETOOLONG */
+ movl $ENAMETOOLONG,%eax
+ jmp 6f
+
+cpystrflt:
+ movl $EFAULT,%eax
+cpystrflt_x:
+6:
+ /* set *lencopied and return %eax */
+ movl _curpcb,%ecx
+ movl $0,PCB_ONFAULT(%ecx)
+ movl 20(%esp),%ecx
+ subl %edx,%ecx
+ movl 24(%esp),%edx
+ orl %edx,%edx
+ jz 7f
+ movl %ecx,(%edx)
+7:
+ popl %edi
+ popl %esi
+ ret
+
+
+/*
+ * copystr(from, to, maxlen, int *lencopied)
+ */
+ENTRY(copystr)
+ pushl %esi
+ pushl %edi
+
+ movl 12(%esp),%esi /* %esi = from */
+ movl 16(%esp),%edi /* %edi = to */
+ movl 20(%esp),%edx /* %edx = maxlen */
+ incl %edx
+
+1:
+ decl %edx
+ jz 4f
+ lodsb
+ stosb
+ orb %al,%al
+ jnz 1b
+
+ /* Success -- 0 byte reached */
+ decl %edx
+ xorl %eax,%eax
+ jmp 6f
+4:
+ /* edx is zero -- return ENAMETOOLONG */
+ movl $ENAMETOOLONG,%eax
+
+6:
+ /* set *lencopied and return %eax */
+ movl 20(%esp),%ecx
+ subl %edx,%ecx
+ movl 24(%esp),%edx
+ orl %edx,%edx
+ jz 7f
+ movl %ecx,(%edx)
+7:
+ popl %edi
+ popl %esi
+ ret
+
+/*
+ * Handling of special 386 registers and descriptor tables etc
+ */
+/* void lgdt(struct region_descriptor *rdp); */
+ENTRY(lgdt)
+ /* reload the descriptor table */
+ movl 4(%esp),%eax
+ lgdt (%eax)
+
+ /* flush the prefetch q */
+ jmp 1f
+ nop
+1:
+ /* reload "stale" selectors */
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+ movl %ax,%ss
+
+ /* reload code selector by turning return into intersegmental return */
+ movl (%esp),%eax
+ pushl %eax
+# movl $KCSEL,4(%esp)
+ movl $8,4(%esp)
+ lret
+
+/*
+ * void lidt(struct region_descriptor *rdp);
+ */
+ENTRY(lidt)
+ movl 4(%esp),%eax
+ lidt (%eax)
+ ret
+
+/*
+ * void lldt(u_short sel)
+ */
+ENTRY(lldt)
+ lldt 4(%esp)
+ ret
+
+/*
+ * void ltr(u_short sel)
+ */
+ENTRY(ltr)
+ ltr 4(%esp)
+ ret
+
+/* ssdtosd(*ssdp,*sdp) */
+ENTRY(ssdtosd)
+ pushl %ebx
+ movl 8(%esp),%ecx
+ movl 8(%ecx),%ebx
+ shll $16,%ebx
+ movl (%ecx),%edx
+ roll $16,%edx
+ movb %dh,%bl
+ movb %dl,%bh
+ rorl $8,%ebx
+ movl 4(%ecx),%eax
+ movw %ax,%dx
+ andl $0xf0000,%eax
+ orl %eax,%ebx
+ movl 12(%esp),%ecx
+ movl %edx,(%ecx)
+ movl %ebx,4(%ecx)
+ popl %ebx
+ ret
+
+#if 0
+/* tlbflush() */
+ENTRY(tlbflush)
+ movl %cr3,%eax
+ orl $I386_CR3PAT,%eax
+ movl %eax,%cr3
+ ret
+#endif
+
+/* load_cr0(cr0) */
+ENTRY(load_cr0)
+ movl 4(%esp),%eax
+ movl %eax,%cr0
+ ret
+
+/* rcr0() */
+ENTRY(rcr0)
+ movl %cr0,%eax
+ ret
+
+/* rcr2() */
+ENTRY(rcr2)
+ movl %cr2,%eax
+ ret
+
+/* rcr3() */
+ENTRY(rcr3)
+ movl %cr3,%eax
+ ret
+
+/* void load_cr3(caddr_t cr3) */
+ENTRY(load_cr3)
+ movl 4(%esp),%eax
+ orl $I386_CR3PAT,%eax
+ movl %eax,%cr3
+ ret
+
+
+/*****************************************************************************/
+/* setjump, longjump */
+/*****************************************************************************/
+
+ENTRY(setjmp)
+ movl 4(%esp),%eax
+ movl %ebx,(%eax) /* save ebx */
+ movl %esp,4(%eax) /* save esp */
+ movl %ebp,8(%eax) /* save ebp */
+ movl %esi,12(%eax) /* save esi */
+ movl %edi,16(%eax) /* save edi */
+ movl (%esp),%edx /* get rta */
+ movl %edx,20(%eax) /* save eip */
+ xorl %eax,%eax /* return(0); */
+ ret
+
+ENTRY(longjmp)
+ movl 4(%esp),%eax
+ movl (%eax),%ebx /* restore ebx */
+ movl 4(%eax),%esp /* restore esp */
+ movl 8(%eax),%ebp /* restore ebp */
+ movl 12(%eax),%esi /* restore esi */
+ movl 16(%eax),%edi /* restore edi */
+ movl 20(%eax),%edx /* get rta */
+ movl %edx,(%esp) /* put in return frame */
+ xorl %eax,%eax /* return(1); */
+ incl %eax
+ ret
diff --git a/sys/amd64/amd64/swtch.s b/sys/amd64/amd64/swtch.s
new file mode 100644
index 0000000..4dbc672
--- /dev/null
+++ b/sys/amd64/amd64/swtch.s
@@ -0,0 +1,458 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: swtch.s,v 1.5 1994/04/02 07:00:30 davidg Exp $
+ */
+
+#include "npx.h" /* for NNPX */
+#include "assym.s" /* for preprocessor defines */
+#include "errno.h" /* for error codes */
+
+#include "machine/asmacros.h" /* for miscellaneous assembly macros */
+#define LOCORE /* XXX inhibit C declarations */
+#include "machine/spl.h" /* for SWI_AST_MASK ... */
+
+
+/*****************************************************************************/
+/* Scheduling */
+/*****************************************************************************/
+
+/*
+ * The following primitives manipulate the run queues.
+ * _whichqs tells which of the 32 queues _qs
+ * have processes in them. Setrq puts processes into queues, Remrq
+ * removes them from queues. The running process is on no queue,
+ * other processes are on a queue related to p->p_pri, divided by 4
+ * actually to shrink the 0-127 range of priorities into the 32 available
+ * queues.
+ */
+ .data
+ .globl _curpcb, _whichqs
+_curpcb: .long 0 /* pointer to curproc's PCB area */
+_whichqs: .long 0 /* which run queues have data */
+
+ .globl _qs,_cnt,_panic
+ .comm _noproc,4
+ .comm _runrun,4
+
+ .globl _want_resched
+_want_resched: .long 0 /* we need to re-run the scheduler */
+
+ .text
+/*
+ * Setrq(p)
+ *
+ * Call should be made at spl6(), and p->p_stat should be SRUN
+ */
+ENTRY(setrq)
+ movl 4(%esp),%eax
+ cmpl $0,P_RLINK(%eax) /* should not be on q already */
+ je set1
+ pushl $set2
+ call _panic
+set1:
+ movzbl P_PRI(%eax),%edx
+ shrl $2,%edx
+ btsl %edx,_whichqs /* set q full bit */
+ shll $3,%edx
+ addl $_qs,%edx /* locate q hdr */
+ movl %edx,P_LINK(%eax) /* link process on tail of q */
+ movl P_RLINK(%edx),%ecx
+ movl %ecx,P_RLINK(%eax)
+ movl %eax,P_RLINK(%edx)
+ movl %eax,P_LINK(%ecx)
+ ret
+
+set2: .asciz "setrq"
+
+/*
+ * Remrq(p)
+ *
+ * Call should be made at spl6().
+ */
+ENTRY(remrq)
+ movl 4(%esp),%eax
+ movzbl P_PRI(%eax),%edx
+ shrl $2,%edx
+ btrl %edx,_whichqs /* clear full bit, panic if clear already */
+ jb rem1
+ pushl $rem3
+ call _panic
+rem1:
+ pushl %edx
+ movl P_LINK(%eax),%ecx /* unlink process */
+ movl P_RLINK(%eax),%edx
+ movl %edx,P_RLINK(%ecx)
+ movl P_RLINK(%eax),%ecx
+ movl P_LINK(%eax),%edx
+ movl %edx,P_LINK(%ecx)
+ popl %edx
+ movl $_qs,%ecx
+ shll $3,%edx
+ addl %edx,%ecx
+ cmpl P_LINK(%ecx),%ecx /* q still has something? */
+ je rem2
+ shrl $3,%edx /* yes, set bit as still full */
+ btsl %edx,_whichqs
+rem2:
+ movl $0,P_RLINK(%eax) /* zap reverse link to indicate off list */
+ ret
+
+rem3: .asciz "remrq"
+sw0: .asciz "swtch"
+
+/*
+ * When no processes are on the runq, swtch() branches to _idle
+ * to wait for something to come ready.
+ */
+ ALIGN_TEXT
+_idle:
+ MCOUNT
+ movl _IdlePTD,%ecx
+ movl %ecx,%cr3
+ movl $tmpstk-4,%esp
+ sti
+
+ /*
+ * XXX callers of swtch() do a bogus splclock(). Locking should
+ * be left to swtch().
+ */
+ movl $SWI_AST_MASK,_cpl
+ testl $~SWI_AST_MASK,_ipending
+ je idle_loop
+ call _splz
+
+ ALIGN_TEXT
+idle_loop:
+ cli
+ cmpl $0,_whichqs
+ jne sw1a
+ sti
+ hlt /* wait for interrupt */
+ jmp idle_loop
+
+badsw:
+ pushl $sw0
+ call _panic
+ /*NOTREACHED*/
+
+/*
+ * Swtch()
+ */
+ENTRY(swtch)
+ incl _cnt+V_SWTCH
+
+ /* switch to new process. first, save context as needed */
+
+ movl _curproc,%ecx
+
+ /* if no process to save, don't bother */
+ testl %ecx,%ecx
+ je sw1
+
+ movl P_ADDR(%ecx),%ecx
+
+ movl (%esp),%eax /* Hardware registers */
+ movl %eax,PCB_EIP(%ecx)
+ movl %ebx,PCB_EBX(%ecx)
+ movl %esp,PCB_ESP(%ecx)
+ movl %ebp,PCB_EBP(%ecx)
+ movl %esi,PCB_ESI(%ecx)
+ movl %edi,PCB_EDI(%ecx)
+
+#if NNPX > 0
+ /* have we used fp, and need a save? */
+ mov _curproc,%eax
+ cmp %eax,_npxproc
+ jne 1f
+ pushl %ecx /* h/w bugs make saving complicated */
+ leal PCB_SAVEFPU(%ecx),%eax
+ pushl %eax
+ call _npxsave /* do it in a big C function */
+ popl %eax
+ popl %ecx
+1:
+#endif /* NNPX > 0 */
+
+ movl _CMAP2,%eax /* save temporary map PTE */
+ movl %eax,PCB_CMAP2(%ecx) /* in our context */
+ movl $0,_curproc /* out of process */
+
+# movw _cpl,%ax
+# movw %ax,PCB_IML(%ecx) /* save ipl */
+
+ /* save is done, now choose a new process or idle */
+sw1:
+ cli
+sw1a:
+ movl _whichqs,%edi
+2:
+ /* XXX - bsf is sloow */
+ bsfl %edi,%eax /* find a full q */
+ je _idle /* if none, idle */
+
+ /* XX update whichqs? */
+ btrl %eax,%edi /* clear q full status */
+ jnb 2b /* if it was clear, look for another */
+ movl %eax,%ebx /* save which one we are using */
+
+ shll $3,%eax
+ addl $_qs,%eax /* select q */
+ movl %eax,%esi
+
+#ifdef DIAGNOSTIC
+ cmpl P_LINK(%eax),%eax /* linked to self? (e.g. not on list) */
+ je badsw /* not possible */
+#endif
+
+ movl P_LINK(%eax),%ecx /* unlink from front of process q */
+ movl P_LINK(%ecx),%edx
+ movl %edx,P_LINK(%eax)
+ movl P_RLINK(%ecx),%eax
+ movl %eax,P_RLINK(%edx)
+
+ cmpl P_LINK(%ecx),%esi /* q empty */
+ je 3f
+ btsl %ebx,%edi /* nope, set to indicate full */
+3:
+ movl %edi,_whichqs /* update q status */
+
+ movl $0,%eax
+ movl %eax,_want_resched
+
+#ifdef DIAGNOSTIC
+ cmpl %eax,P_WCHAN(%ecx)
+ jne badsw
+ cmpb $SRUN,P_STAT(%ecx)
+ jne badsw
+#endif
+
+ movl %eax,P_RLINK(%ecx) /* isolate process to run */
+ movl P_ADDR(%ecx),%edx
+ movl PCB_CR3(%edx),%ebx
+
+ /* switch address space */
+ movl %ebx,%cr3
+
+ /* restore context */
+ movl PCB_EBX(%edx),%ebx
+ movl PCB_ESP(%edx),%esp
+ movl PCB_EBP(%edx),%ebp
+ movl PCB_ESI(%edx),%esi
+ movl PCB_EDI(%edx),%edi
+ movl PCB_EIP(%edx),%eax
+ movl %eax,(%esp)
+
+ movl PCB_CMAP2(%edx),%eax /* get temporary map */
+ movl %eax,_CMAP2 /* reload temporary map PTE */
+
+ movl %ecx,_curproc /* into next process */
+ movl %edx,_curpcb
+
+#ifdef USER_LDT
+ cmpl $0, PCB_USERLDT(%edx)
+ jnz 1f
+ movl __default_ldt,%eax
+ cmpl _currentldt,%eax
+ je 2f
+ lldt __default_ldt
+ movl %eax,_currentldt
+ jmp 2f
+1: pushl %edx
+ call _set_user_ldt
+ popl %edx
+2:
+#endif
+
+ pushl %edx /* save p to return */
+/*
+ * XXX - 0.0 forgot to save it - is that why this was commented out in 0.1?
+ * I think restoring the cpl is unnecessary, but we must turn off the cli
+ * now that spl*() don't do it as a side affect.
+ */
+ pushl PCB_IML(%edx)
+ sti
+#if 0
+ call _splx
+#endif
+ addl $4,%esp
+/*
+ * XXX - 0.0 gets here via swtch_to_inactive(). I think 0.1 gets here in the
+ * same way. Better return a value.
+ */
+ popl %eax /* return(p); */
+ ret
+
+ENTRY(mvesp)
+ movl %esp,%eax
+ ret
+/*
+ * struct proc *swtch_to_inactive(struct proc *p);
+ *
+ * At exit of a process, move off the address space of the
+ * process and onto a "safe" one. Then, on a temporary stack
+ * return and run code that disposes of the old state.
+ * Since this code requires a parameter from the "old" stack,
+ * pass it back as a return value.
+ */
+ENTRY(swtch_to_inactive)
+ popl %edx /* old pc */
+ popl %eax /* arg, our return value */
+ movl _IdlePTD,%ecx
+ movl %ecx,%cr3 /* good bye address space */
+ #write buffer?
+ movl $tmpstk-4,%esp /* temporary stack, compensated for call */
+ MEXITCOUNT
+ jmp %edx /* return, execute remainder of cleanup */
+
+/*
+ * savectx(pcb, altreturn)
+ * Update pcb, saving current processor state and arranging
+ * for alternate return ala longjmp in swtch if altreturn is true.
+ */
+ENTRY(savectx)
+ movl 4(%esp),%ecx
+ movw _cpl,%ax
+ movw %ax,PCB_IML(%ecx)
+ movl (%esp),%eax
+ movl %eax,PCB_EIP(%ecx)
+ movl %ebx,PCB_EBX(%ecx)
+ movl %esp,PCB_ESP(%ecx)
+ movl %ebp,PCB_EBP(%ecx)
+ movl %esi,PCB_ESI(%ecx)
+ movl %edi,PCB_EDI(%ecx)
+
+#if NNPX > 0
+ /*
+ * If npxproc == NULL, then the npx h/w state is irrelevant and the
+ * state had better already be in the pcb. This is true for forks
+ * but not for dumps (the old book-keeping with FP flags in the pcb
+ * always lost for dumps because the dump pcb has 0 flags).
+ *
+ * If npxproc != NULL, then we have to save the npx h/w state to
+ * npxproc's pcb and copy it to the requested pcb, or save to the
+ * requested pcb and reload. Copying is easier because we would
+ * have to handle h/w bugs for reloading. We used to lose the
+ * parent's npx state for forks by forgetting to reload.
+ */
+ mov _npxproc,%eax
+ testl %eax,%eax
+ je 1f
+
+ pushl %ecx
+ movl P_ADDR(%eax),%eax
+ leal PCB_SAVEFPU(%eax),%eax
+ pushl %eax
+ pushl %eax
+ call _npxsave
+ popl %eax
+ popl %eax
+ popl %ecx
+
+ pushl %ecx
+ pushl $108+8*2 /* XXX h/w state size + padding */
+ leal PCB_SAVEFPU(%ecx),%ecx
+ pushl %ecx
+ pushl %eax
+ call _bcopy
+ addl $12,%esp
+ popl %ecx
+1:
+#endif /* NNPX > 0 */
+
+ movl _CMAP2,%edx /* save temporary map PTE */
+ movl %edx,PCB_CMAP2(%ecx) /* in our context */
+
+ cmpl $0,8(%esp)
+ je 1f
+ movl %esp,%edx /* relocate current sp relative to pcb */
+ subl $_kstack,%edx /* (sp is relative to kstack): */
+ addl %edx,%ecx /* pcb += sp - kstack; */
+ movl %eax,(%ecx) /* write return pc at (relocated) sp@ */
+
+/* this mess deals with replicating register state gcc hides */
+ movl 12(%esp),%eax
+ movl %eax,12(%ecx)
+ movl 16(%esp),%eax
+ movl %eax,16(%ecx)
+ movl 20(%esp),%eax
+ movl %eax,20(%ecx)
+ movl 24(%esp),%eax
+ movl %eax,24(%ecx)
+1:
+ xorl %eax,%eax /* return 0 */
+ ret
+
+/*
+ * addupc(int pc, struct uprof *up, int ticks):
+ * update profiling information for the user process.
+ */
+ENTRY(addupc)
+ pushl %ebp
+ movl %esp,%ebp
+ movl 12(%ebp),%edx /* up */
+ movl 8(%ebp),%eax /* pc */
+
+ subl PR_OFF(%edx),%eax /* pc -= up->pr_off */
+ jb L1 /* if (pc was < off) return */
+
+ shrl $1,%eax /* praddr = pc >> 1 */
+ imull PR_SCALE(%edx),%eax /* praddr *= up->pr_scale */
+ shrl $15,%eax /* praddr = praddr << 15 */
+ andl $-2,%eax /* praddr &= ~1 */
+
+ cmpl PR_SIZE(%edx),%eax /* if (praddr > up->pr_size) return */
+ ja L1
+
+/* addl %eax,%eax /* praddr -> word offset */
+ addl PR_BASE(%edx),%eax /* praddr += up-> pr_base */
+ movl 16(%ebp),%ecx /* ticks */
+
+ movl _curpcb,%edx
+ movl $proffault,PCB_ONFAULT(%edx)
+ addl %ecx,(%eax) /* storage location += ticks */
+ movl $0,PCB_ONFAULT(%edx)
+L1:
+ leave
+ ret
+
+ ALIGN_TEXT
+proffault:
+ /* if we get a fault, then kill profiling all together */
+ movl $0,PCB_ONFAULT(%edx) /* squish the fault handler */
+ movl 12(%ebp),%ecx
+ movl $0,PR_SCALE(%ecx) /* up->pr_scale = 0 */
+ leave
+ ret
diff --git a/sys/amd64/amd64/sys_machdep.c b/sys/amd64/amd64/sys_machdep.c
new file mode 100644
index 0000000..92758ad
--- /dev/null
+++ b/sys/amd64/amd64/sys_machdep.c
@@ -0,0 +1,328 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)sys_machdep.c 5.5 (Berkeley) 1/19/91
+ * $Id: sys_machdep.c,v 1.3 1993/10/16 14:15:10 rgrimes Exp $
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "ioctl.h"
+#include "file.h"
+#include "time.h"
+#include "proc.h"
+#include "uio.h"
+#include "kernel.h"
+#include "mtio.h"
+#include "buf.h"
+#include "trace.h"
+
+#ifdef USER_LDT
+#include "user.h"
+#include "machine/cpu.h"
+#include "machine/sysarch.h"
+#include "vm/vm_kern.h" /* for kernel_map */
+#endif
+
+#ifdef TRACE
+int nvualarm;
+
+struct vtrace_args {
+ int request;
+ int value;
+};
+
+vtrace(p, uap, retval)
+ struct proc *p;
+ register struct vtrace_args *uap;
+ int *retval;
+{
+ int vdoualarm();
+
+ switch (uap->request) {
+
+ case VTR_DISABLE: /* disable a trace point */
+ case VTR_ENABLE: /* enable a trace point */
+ if (uap->value < 0 || uap->value >= TR_NFLAGS)
+ return (EINVAL);
+ *retval = traceflags[uap->value];
+ traceflags[uap->value] = uap->request;
+ break;
+
+ case VTR_VALUE: /* return a trace point setting */
+ if (uap->value < 0 || uap->value >= TR_NFLAGS)
+ return (EINVAL);
+ *retval = traceflags[uap->value];
+ break;
+
+ case VTR_UALARM: /* set a real-time ualarm, less than 1 min */
+ if (uap->value <= 0 || uap->value > 60 * hz || nvualarm > 5)
+ return (EINVAL);
+ nvualarm++;
+ timeout(vdoualarm, (caddr_t)p->p_pid, uap->value);
+ break;
+
+ case VTR_STAMP:
+ trace(TR_STAMP, uap->value, p->p_pid);
+ break;
+ }
+ return (0);
+}
+
+vdoualarm(arg)
+ int arg;
+{
+ register struct proc *p;
+
+ p = pfind(arg);
+ if (p)
+ psignal(p, 16);
+ nvualarm--;
+}
+#endif
+
+#ifdef USER_LDT
+void
+set_user_ldt(struct pcb *pcb)
+{
+ gdt_segs[GUSERLDT_SEL].ssd_base = (unsigned)pcb->pcb_ldt;
+ gdt_segs[GUSERLDT_SEL].ssd_limit = (pcb->pcb_ldt_len * sizeof(union descriptor)) - 1;
+ ssdtosd(gdt_segs+GUSERLDT_SEL, gdt+GUSERLDT_SEL);
+ lldt(GSEL(GUSERLDT_SEL, SEL_KPL));
+ currentldt = GSEL(GUSERLDT_SEL, SEL_KPL);
+}
+
+struct i386_get_ldt_args {
+ int start;
+ union descriptor *desc;
+ int num;
+};
+
+int
+i386_get_ldt(p, args, retval)
+ struct proc *p;
+ char *args;
+ int *retval;
+{
+ int error = 0;
+ struct pcb *pcb = &p->p_addr->u_pcb;
+ int nldt, num;
+ union descriptor *lp;
+ int s;
+ struct i386_get_ldt_args ua, *uap;
+
+ if ((error = copyin(args, &ua, sizeof(struct i386_get_ldt_args))) < 0)
+ return(error);
+
+ uap = &ua;
+#ifdef DEBUG
+ printf("i386_get_ldt: start=%d num=%d descs=%x\n", uap->start, uap->num, uap->desc);
+#endif
+
+ if (uap->start < 0 || uap->num < 0)
+ return(EINVAL);
+
+ s = splhigh();
+
+ if (pcb->pcb_ldt) {
+ nldt = pcb->pcb_ldt_len;
+ num = min(uap->num, nldt);
+ lp = &((union descriptor *)(pcb->pcb_ldt))[uap->start];
+ } else {
+ nldt = sizeof(ldt)/sizeof(ldt[0]);
+ num = min(uap->num, nldt);
+ lp = &ldt[uap->start];
+ }
+ if (uap->start > nldt) {
+ splx(s);
+ return(EINVAL);
+ }
+
+ error = copyout(lp, uap->desc, num * sizeof(union descriptor));
+ if (!error)
+ *retval = num;
+
+ splx(s);
+ return(error);
+}
+
+struct i386_set_ldt_args {
+ int start;
+ union descriptor *desc;
+ int num;
+};
+
+int
+i386_set_ldt(p, args, retval)
+ struct proc *p;
+ char *args;
+ int *retval;
+{
+ int error = 0, i, n;
+ struct pcb *pcb = &p->p_addr->u_pcb;
+ union descriptor *lp;
+ int s;
+ struct i386_set_ldt_args ua, *uap;
+
+ if ((error = copyin(args, &ua, sizeof(struct i386_set_ldt_args))) < 0)
+ return(error);
+
+ uap = &ua;
+
+#ifdef DEBUG
+ printf("i386_set_ldt: start=%d num=%d descs=%x\n", uap->start, uap->num, uap->desc);
+#endif
+
+ if (uap->start < 0 || uap->num < 0)
+ return(EINVAL);
+
+ /* XXX Should be 8192 ! */
+ if (uap->start > 512 ||
+ (uap->start + uap->num) > 512)
+ return(EINVAL);
+
+ /* allocate user ldt */
+ if (!pcb->pcb_ldt) {
+ union descriptor *new_ldt =
+ (union descriptor *)kmem_alloc(kernel_map, 512*sizeof(union descriptor));
+ bzero(new_ldt, 512*sizeof(union descriptor));
+ bcopy(ldt, new_ldt, sizeof(ldt));
+ pcb->pcb_ldt = (caddr_t)new_ldt;
+ pcb->pcb_ldt_len = 512; /* XXX need to grow */
+#ifdef DEBUG
+ printf("i386_set_ldt(%d): new_ldt=%x\n", p->p_pid, new_ldt);
+#endif
+ }
+
+ /* Check descriptors for access violations */
+ for (i = 0, n = uap->start; i < uap->num; i++, n++) {
+ union descriptor desc, *dp;
+ dp = &uap->desc[i];
+ error = copyin(dp, &desc, sizeof(union descriptor));
+ if (error)
+ return(error);
+
+ /* Only user (ring-3) descriptors */
+ if (desc.sd.sd_dpl != SEL_UPL)
+ return(EACCES);
+
+ /* Must be "present" */
+ if (desc.sd.sd_p == 0)
+ return(EACCES);
+
+ switch (desc.sd.sd_type) {
+ case SDT_SYSNULL:
+ case SDT_SYS286CGT:
+ case SDT_SYS386CGT:
+ break;
+ case SDT_MEMRO:
+ case SDT_MEMROA:
+ case SDT_MEMRW:
+ case SDT_MEMRWA:
+ case SDT_MEMROD:
+ case SDT_MEMRODA:
+ case SDT_MEME:
+ case SDT_MEMEA:
+ case SDT_MEMER:
+ case SDT_MEMERA:
+ case SDT_MEMEC:
+ case SDT_MEMEAC:
+ case SDT_MEMERC:
+ case SDT_MEMERAC: {
+#if 0
+ unsigned long base = (desc.sd.sd_hibase << 24)&0xFF000000;
+ base |= (desc.sd.sd_lobase&0x00FFFFFF);
+ if (base >= KERNBASE)
+ return(EACCES);
+#endif
+ break;
+ }
+ default:
+ return(EACCES);
+ /*NOTREACHED*/
+ }
+ }
+
+ s = splhigh();
+
+ /* Fill in range */
+ for (i = 0, n = uap->start; i < uap->num && !error; i++, n++) {
+ union descriptor desc, *dp;
+ dp = &uap->desc[i];
+ lp = &((union descriptor *)(pcb->pcb_ldt))[n];
+#ifdef DEBUG
+ printf("i386_set_ldt(%d): ldtp=%x\n", p->p_pid, lp);
+#endif
+ error = copyin(dp, lp, sizeof(union descriptor));
+ }
+ if (!error) {
+ *retval = uap->start;
+/* need_resched(); */
+ }
+
+ splx(s);
+ return(error);
+}
+#endif /* USER_LDT */
+
+struct sysarch_args {
+ int op;
+ char *parms;
+};
+
+int
+sysarch(p, uap, retval)
+ struct proc *p;
+ register struct sysarch_args *uap;
+ int *retval;
+{
+ int error = 0;
+
+ switch(uap->op) {
+#ifdef USER_LDT
+ case I386_GET_LDT:
+ error = i386_get_ldt(p, uap->parms, retval);
+ break;
+
+ case I386_SET_LDT:
+ error = i386_set_ldt(p, uap->parms, retval);
+ break;
+#endif
+ default:
+ error = EINVAL;
+ break;
+ }
+ return(error);
+}
diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
new file mode 100644
index 0000000..9bb38e1
--- /dev/null
+++ b/sys/amd64/amd64/trap.c
@@ -0,0 +1,728 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the University of Utah, and William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)trap.c 7.4 (Berkeley) 5/13/91
+ * $Id: trap.c,v 1.22 1994/04/07 10:51:00 davidg Exp $
+ */
+
+/*
+ * 386 Trap and System call handleing
+ */
+
+#include "isa.h"
+#include "npx.h"
+#include "ddb.h"
+#include "machine/cpu.h"
+#include "machine/psl.h"
+#include "machine/reg.h"
+#include "machine/eflags.h"
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "user.h"
+#include "acct.h"
+#include "kernel.h"
+#ifdef KTRACE
+#include "ktrace.h"
+#endif
+
+#include "vm/vm_param.h"
+#include "vm/pmap.h"
+#include "vm/vm_map.h"
+#include "vm/vm_user.h"
+#include "vm/vm_page.h"
+#include "sys/vmmeter.h"
+
+#include "machine/trap.h"
+
+#ifdef __GNUC__
+
+/*
+ * The "r" contraint could be "rm" except for fatal bugs in gas. As usual,
+ * we omit the size from the mov instruction to avoid nonfatal bugs in gas.
+ */
+#define read_gs() ({ u_short gs; __asm("mov %%gs,%0" : "=r" (gs)); gs; })
+#define write_gs(newgs) __asm("mov %0,%%gs" : : "r" ((u_short) newgs))
+
+#else /* not __GNUC__ */
+
+u_short read_gs __P((void));
+void write_gs __P((/* promoted u_short */ int gs));
+
+#endif /* __GNUC__ */
+
+extern int grow(struct proc *,int);
+
+struct sysent sysent[];
+int nsysent;
+
+#define MAX_TRAP_MSG 27
+char *trap_msg[] = {
+ "reserved addressing fault", /* 0 T_RESADFLT */
+ "privileged instruction fault", /* 1 T_PRIVINFLT */
+ "reserved operand fault", /* 2 T_RESOPFLT */
+ "breakpoint instruction fault", /* 3 T_BPTFLT */
+ "", /* 4 unused */
+ "system call trap", /* 5 T_SYSCALL */
+ "arithmetic trap", /* 6 T_ARITHTRAP */
+ "system forced exception", /* 7 T_ASTFLT */
+ "segmentation (limit) fault", /* 8 T_SEGFLT */
+ "protection fault", /* 9 T_PROTFLT */
+ "trace trap", /* 10 T_TRCTRAP */
+ "", /* 11 unused */
+ "page fault", /* 12 T_PAGEFLT */
+ "page table fault", /* 13 T_TABLEFLT */
+ "alignment fault", /* 14 T_ALIGNFLT */
+ "kernel stack pointer not valid", /* 15 T_KSPNOTVAL */
+ "bus error", /* 16 T_BUSERR */
+ "kernel debugger fault", /* 17 T_KDBTRAP */
+ "integer divide fault", /* 18 T_DIVIDE */
+ "non-maskable interrupt trap", /* 19 T_NMI */
+ "overflow trap", /* 20 T_OFLOW */
+ "FPU bounds check fault", /* 21 T_BOUND */
+ "FPU device not available", /* 22 T_DNA */
+ "double fault", /* 23 T_DOUBLEFLT */
+ "FPU operand fetch fault", /* 24 T_FPOPFLT */
+ "invalid TSS fault", /* 25 T_TSSFLT */
+ "segment not present fault", /* 26 T_SEGNPFLT */
+ "stack fault", /* 27 T_STKFLT */
+};
+
+#define pde_v(v) (PTD[((v)>>PD_SHIFT)&1023].pd_v)
+
+/*
+ * trap(frame):
+ * Exception, fault, and trap interface to BSD kernel. This
+ * common code is called from assembly language IDT gate entry
+ * routines that prepare a suitable stack frame, and restore this
+ * frame after the exception has been processed. Note that the
+ * effect is as if the arguments were passed call by reference.
+ */
+
+/*ARGSUSED*/
+void
+trap(frame)
+ struct trapframe frame;
+{
+ register int i;
+ register struct proc *p = curproc;
+ struct timeval syst;
+ int ucode, type, code, eva, fault_type;
+
+ frame.tf_eflags &= ~PSL_NT; /* clear nested trap XXX */
+ type = frame.tf_trapno;
+#if NDDB > 0
+ if (curpcb && curpcb->pcb_onfault) {
+ if (frame.tf_trapno == T_BPTFLT
+ || frame.tf_trapno == T_TRCTRAP)
+ if (kdb_trap (type, 0, &frame))
+ return;
+ }
+#endif
+
+ if (curpcb == 0 || curproc == 0)
+ goto skiptoswitch;
+ if (curpcb->pcb_onfault && frame.tf_trapno != T_PAGEFLT) {
+ extern int _udatasel;
+
+ if (read_gs() != (u_short) _udatasel)
+ /*
+ * Some user has corrupted %gs but we depend on it in
+ * copyout() etc. Fix it up and retry.
+ *
+ * (We don't preserve %fs or %gs, so users can change
+ * them to either _ucodesel, _udatasel or a not-present
+ * selector, possibly ORed with 0 to 3, making them
+ * volatile for other users. Not preserving them saves
+ * time and doesn't lose functionality or open security
+ * holes.)
+ */
+ write_gs(_udatasel);
+ else
+copyfault:
+ frame.tf_eip = (int)curpcb->pcb_onfault;
+ return;
+ }
+
+ syst = p->p_stime;
+ if (ISPL(frame.tf_cs) == SEL_UPL) {
+ type |= T_USER;
+ p->p_regs = (int *)&frame;
+ }
+
+skiptoswitch:
+ ucode=0;
+ eva = rcr2();
+ code = frame.tf_err;
+
+ if ((type & ~T_USER) == T_PAGEFLT)
+ goto pfault;
+
+ switch (type) {
+ case T_SEGNPFLT|T_USER:
+ case T_STKFLT|T_USER:
+ case T_PROTFLT|T_USER: /* protection fault */
+ ucode = code + BUS_SEGM_FAULT ;
+ i = SIGBUS;
+ break;
+
+ case T_PRIVINFLT|T_USER: /* privileged instruction fault */
+ case T_RESADFLT|T_USER: /* reserved addressing fault */
+ case T_RESOPFLT|T_USER: /* reserved operand fault */
+ case T_FPOPFLT|T_USER: /* coprocessor operand fault */
+ ucode = type &~ T_USER;
+ i = SIGILL;
+ break;
+
+ case T_ASTFLT|T_USER: /* Allow process switch */
+ astoff();
+ cnt.v_soft++;
+ if ((p->p_flag & SOWEUPC) && p->p_stats->p_prof.pr_scale) {
+ addupc(frame.tf_eip, &p->p_stats->p_prof, 1);
+ p->p_flag &= ~SOWEUPC;
+ }
+ goto out;
+
+ case T_DNA|T_USER:
+#if NNPX > 0
+ /* if a transparent fault (due to context switch "late") */
+ if (npxdna()) return;
+#endif /* NNPX > 0 */
+#if defined(MATH_EMULATE) || defined(GPL_MATH_EMULATE)
+ i = math_emulate(&frame);
+ if (i == 0) return;
+#else /* MATH_EMULATE || GPL_MATH_EMULATE */
+ panic("trap: math emulation necessary!");
+#endif /* MATH_EMULATE || GPL_MATH_EMULATE */
+ ucode = FPE_FPU_NP_TRAP;
+ break;
+
+ case T_BOUND|T_USER:
+ ucode = FPE_SUBRNG_TRAP;
+ i = SIGFPE;
+ break;
+
+ case T_OFLOW|T_USER:
+ ucode = FPE_INTOVF_TRAP;
+ i = SIGFPE;
+ break;
+
+ case T_DIVIDE|T_USER:
+ ucode = FPE_INTDIV_TRAP;
+ i = SIGFPE;
+ break;
+
+ case T_ARITHTRAP|T_USER:
+ ucode = code;
+ i = SIGFPE;
+ break;
+
+ pfault:
+ case T_PAGEFLT: /* allow page faults in kernel mode */
+ case T_PAGEFLT|T_USER: /* page fault */
+ {
+ vm_offset_t va;
+ struct vmspace *vm;
+ vm_map_t map = 0;
+ int rv = 0, oldflags;
+ vm_prot_t ftype;
+ unsigned v;
+ extern vm_map_t kernel_map;
+
+ va = trunc_page((vm_offset_t)eva);
+
+ /*
+ * Don't allow user-mode faults in kernel address space
+ */
+ if ((type == (T_PAGEFLT|T_USER)) && (va >= KERNBASE)) {
+ goto nogo;
+ }
+
+ if ((p == 0) || (type == T_PAGEFLT && va >= KERNBASE)) {
+ vm = 0;
+ map = kernel_map;
+ } else {
+ vm = p->p_vmspace;
+ map = &vm->vm_map;
+ }
+
+ if (code & PGEX_W)
+ ftype = VM_PROT_READ | VM_PROT_WRITE;
+ else
+ ftype = VM_PROT_READ;
+
+ oldflags = p->p_flag;
+ if (map != kernel_map) {
+ vm_offset_t pa;
+ vm_offset_t v = (vm_offset_t) vtopte(va);
+ vm_page_t ptepg;
+
+ /*
+ * Keep swapout from messing with us during this
+ * critical time.
+ */
+ p->p_flag |= SLOCK;
+
+ /*
+ * Grow the stack if necessary
+ */
+ if ((caddr_t)va > vm->vm_maxsaddr
+ && (caddr_t)va < (caddr_t)USRSTACK) {
+ if (!grow(p, va)) {
+ rv = KERN_FAILURE;
+ p->p_flag &= ~SLOCK;
+ p->p_flag |= (oldflags & SLOCK);
+ goto nogo;
+ }
+ }
+
+ /*
+ * Check if page table is mapped, if not,
+ * fault it first
+ */
+
+ /* Fault the pte only if needed: */
+ *(volatile char *)v += 0;
+
+ ptepg = (vm_page_t) pmap_pte_vm_page(vm_map_pmap(map), v);
+ vm_page_hold(ptepg);
+
+ /* Fault in the user page: */
+ rv = vm_fault(map, va, ftype, FALSE);
+
+ vm_page_unhold(ptepg);
+
+ /*
+ * page table pages don't need to be kept if they
+ * are not held
+ */
+ if( ptepg->hold_count == 0 && ptepg->wire_count == 0) {
+ pmap_page_protect( VM_PAGE_TO_PHYS(ptepg),
+ VM_PROT_NONE);
+ if( ptepg->flags & PG_CLEAN)
+ vm_page_free(ptepg);
+ }
+
+
+ p->p_flag &= ~SLOCK;
+ p->p_flag |= (oldflags & SLOCK);
+ } else {
+ /*
+ * Since we know that kernel virtual address addresses
+ * always have pte pages mapped, we just have to fault
+ * the page.
+ */
+ rv = vm_fault(map, va, ftype, FALSE);
+ }
+
+ if (rv == KERN_SUCCESS) {
+ if (type == T_PAGEFLT)
+ return;
+ goto out;
+ }
+nogo:
+ if (type == T_PAGEFLT) {
+ if (curpcb->pcb_onfault)
+ goto copyfault;
+
+ goto we_re_toast;
+ }
+ i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV;
+
+ /* kludge to pass faulting virtual address to sendsig */
+ ucode = type &~ T_USER;
+ frame.tf_err = eva;
+
+ break;
+ }
+
+#if NDDB == 0
+ case T_TRCTRAP: /* trace trap -- someone single stepping lcall's */
+ frame.tf_eflags &= ~PSL_T;
+
+ /* Q: how do we turn it on again? */
+ return;
+#endif
+
+ case T_BPTFLT|T_USER: /* bpt instruction fault */
+ case T_TRCTRAP|T_USER: /* trace trap */
+ frame.tf_eflags &= ~PSL_T;
+ i = SIGTRAP;
+ break;
+
+#if NISA > 0
+ case T_NMI:
+ case T_NMI|T_USER:
+#if NDDB > 0
+ /* NMI can be hooked up to a pushbutton for debugging */
+ printf ("NMI ... going to debugger\n");
+ if (kdb_trap (type, 0, &frame))
+ return;
+#endif
+ /* machine/parity/power fail/"kitchen sink" faults */
+ if (isa_nmi(code) == 0) return;
+ /* FALL THROUGH */
+#endif
+ default:
+ we_re_toast:
+
+ fault_type = type & ~T_USER;
+#if NDDB > 0
+ if ((fault_type == T_BPTFLT) || (fault_type == T_TRCTRAP)) {
+ if (kdb_trap (type, 0, &frame))
+ return;
+ }
+#endif
+ if (fault_type <= MAX_TRAP_MSG)
+ printf("\n\nFatal trap %d: %s while in %s mode\n",
+ fault_type, trap_msg[fault_type],
+ ISPL(frame.tf_cs) == SEL_UPL ? "user" : "kernel");
+ if (fault_type == T_PAGEFLT) {
+ printf("fault virtual address = 0x%x\n", eva);
+ printf("fault code = %s %s, %s\n",
+ code & PGEX_U ? "user" : "supervisor",
+ code & PGEX_W ? "write" : "read",
+ code & PGEX_P ? "protection violation" : "page not present");
+ }
+ printf("instruction pointer = 0x%x\n", frame.tf_eip);
+ printf("processor eflags = ");
+ if (frame.tf_eflags & EFL_TF)
+ printf("trace/trap, ");
+ if (frame.tf_eflags & EFL_IF)
+ printf("interrupt enabled, ");
+ if (frame.tf_eflags & EFL_NT)
+ printf("nested task, ");
+ if (frame.tf_eflags & EFL_RF)
+ printf("resume, ");
+ if (frame.tf_eflags & EFL_VM)
+ printf("vm86, ");
+ printf("IOPL = %d\n", (frame.tf_eflags & EFL_IOPL) >> 12);
+ printf("current process = ");
+ if (curproc) {
+ printf("%d (%s)\n",
+ curproc->p_pid, curproc->p_comm ?
+ curproc->p_comm : "");
+ } else {
+ printf("Idle\n");
+ }
+ printf("interrupt mask = ");
+ if ((cpl & net_imask) == net_imask)
+ printf("net ");
+ if ((cpl & tty_imask) == tty_imask)
+ printf("tty ");
+ if ((cpl & bio_imask) == bio_imask)
+ printf("bio ");
+ if (cpl == 0)
+ printf("none");
+ printf("\n");
+
+#ifdef KDB
+ if (kdb_trap(&psl))
+ return;
+#endif
+#if NDDB > 0
+ if (kdb_trap (type, 0, &frame))
+ return;
+#endif
+ if (fault_type <= MAX_TRAP_MSG)
+ panic(trap_msg[fault_type]);
+ else
+ panic("unknown/reserved trap");
+
+ /* NOTREACHED */
+ }
+
+ trapsignal(p, i, ucode);
+ if ((type & T_USER) == 0)
+ return;
+
+#ifdef DIAGNOSTIC
+ fault_type = type & ~T_USER;
+ if (fault_type <= MAX_TRAP_MSG) {
+ uprintf("fatal process exception: %s",
+ trap_msg[fault_type]);
+ if ((fault_type == T_PAGEFLT) || (fault_type == T_PROTFLT))
+ uprintf(", fault VA = 0x%x", eva);
+ uprintf("\n");
+ }
+#endif
+
+out:
+ while (i = CURSIG(p))
+ psig(i);
+ p->p_pri = p->p_usrpri;
+ if (want_resched) {
+ int s;
+ /*
+ * Since we are curproc, clock will normally just change
+ * our priority without moving us from one queue to another
+ * (since the running process is not on a queue.)
+ * If that happened after we setrq ourselves but before we
+ * swtch()'ed, we might not be on the queue indicated by
+ * our priority.
+ */
+ s = splclock();
+ setrq(p);
+ p->p_stats->p_ru.ru_nivcsw++;
+ swtch();
+ splx(s);
+ while (i = CURSIG(p))
+ psig(i);
+ }
+ if (p->p_stats->p_prof.pr_scale) {
+ int ticks;
+ struct timeval *tv = &p->p_stime;
+
+ ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
+ (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
+ if (ticks) {
+#ifdef PROFTIMER
+ extern int profscale;
+ addupc(frame.tf_eip, &p->p_stats->p_prof,
+ ticks * profscale);
+#else
+ addupc(frame.tf_eip, &p->p_stats->p_prof, ticks);
+#endif
+ }
+ }
+ curpri = p->p_pri;
+}
+
+/*
+ * Compensate for 386 brain damage (missing URKR).
+ * This is a little simpler than the pagefault handler in trap() because
+ * it the page tables have already been faulted in and high addresses
+ * are thrown out early for other reasons.
+ */
+int trapwrite(addr)
+ unsigned addr;
+{
+ struct proc *p;
+ vm_offset_t va, v;
+ struct vmspace *vm;
+ int oldflags;
+ int rv;
+
+ va = trunc_page((vm_offset_t)addr);
+ /*
+ * XXX - MAX is END. Changed > to >= for temp. fix.
+ */
+ if (va >= VM_MAXUSER_ADDRESS)
+ return (1);
+
+ p = curproc;
+ vm = p->p_vmspace;
+
+ oldflags = p->p_flag;
+ p->p_flag |= SLOCK;
+
+ if ((caddr_t)va >= vm->vm_maxsaddr
+ && (caddr_t)va < (caddr_t)USRSTACK) {
+ if (!grow(p, va)) {
+ p->p_flag &= ~SLOCK;
+ p->p_flag |= (oldflags & SLOCK);
+ return (1);
+ }
+ }
+
+ v = trunc_page(vtopte(va));
+
+ /*
+ * wire the pte page
+ */
+ if (va < USRSTACK) {
+ vm_map_pageable(&vm->vm_map, v, round_page(v+1), FALSE);
+ }
+
+ /*
+ * fault the data page
+ */
+ rv = vm_fault(&vm->vm_map, va, VM_PROT_READ|VM_PROT_WRITE, FALSE);
+
+ /*
+ * unwire the pte page
+ */
+ if (va < USRSTACK) {
+ vm_map_pageable(&vm->vm_map, v, round_page(v+1), TRUE);
+ }
+
+ p->p_flag &= ~SLOCK;
+ p->p_flag |= (oldflags & SLOCK);
+
+ if (rv != KERN_SUCCESS)
+ return 1;
+
+ return (0);
+}
+
+/*
+ * syscall(frame):
+ * System call request from POSIX system call gate interface to kernel.
+ * Like trap(), argument is call by reference.
+ */
+/*ARGSUSED*/
+void
+syscall(frame)
+ volatile struct trapframe frame;
+{
+ register int *locr0 = ((int *)&frame);
+ register caddr_t params;
+ register int i;
+ register struct sysent *callp;
+ register struct proc *p = curproc;
+ struct timeval syst;
+ int error, opc;
+ int args[8], rval[2];
+ int code;
+
+#ifdef lint
+ r0 = 0; r0 = r0; r1 = 0; r1 = r1;
+#endif
+ syst = p->p_stime;
+ if (ISPL(frame.tf_cs) != SEL_UPL)
+ panic("syscall");
+
+ code = frame.tf_eax;
+ p->p_regs = (int *)&frame;
+ params = (caddr_t)frame.tf_esp + sizeof (int) ;
+
+ /*
+ * Reconstruct pc, assuming lcall $X,y is 7 bytes, as it is always.
+ */
+ opc = frame.tf_eip - 7;
+ if (code == 0) {
+ code = fuword(params);
+ params += sizeof (int);
+ }
+ if (code < 0 || code >= nsysent)
+ callp = &sysent[0];
+ else
+ callp = &sysent[code];
+
+ if ((i = callp->sy_narg * sizeof (int)) &&
+ (error = copyin(params, (caddr_t)args, (u_int)i))) {
+ frame.tf_eax = error;
+ frame.tf_eflags |= PSL_C; /* carry bit */
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSCALL))
+ ktrsyscall(p->p_tracep, code, callp->sy_narg, args);
+#endif
+ goto done;
+ }
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSCALL))
+ ktrsyscall(p->p_tracep, code, callp->sy_narg, args);
+#endif
+ rval[0] = 0;
+ rval[1] = frame.tf_edx;
+/*pg("%d. s %d\n", p->p_pid, code);*/
+ error = (*callp->sy_call)(p, args, rval);
+ if (error == ERESTART)
+ frame.tf_eip = opc;
+ else if (error != EJUSTRETURN) {
+ if (error) {
+/*pg("error %d", error);*/
+ frame.tf_eax = error;
+ frame.tf_eflags |= PSL_C; /* carry bit */
+ } else {
+ frame.tf_eax = rval[0];
+ frame.tf_edx = rval[1];
+ frame.tf_eflags &= ~PSL_C; /* carry bit */
+ }
+ }
+ /* else if (error == EJUSTRETURN) */
+ /* nothing to do */
+done:
+ /*
+ * Reinitialize proc pointer `p' as it may be different
+ * if this is a child returning from fork syscall.
+ */
+ p = curproc;
+ while (i = CURSIG(p))
+ psig(i);
+ p->p_pri = p->p_usrpri;
+ if (want_resched) {
+ int s;
+ /*
+ * Since we are curproc, clock will normally just change
+ * our priority without moving us from one queue to another
+ * (since the running process is not on a queue.)
+ * If that happened after we setrq ourselves but before we
+ * swtch()'ed, we might not be on the queue indicated by
+ * our priority.
+ */
+ s = splclock();
+ setrq(p);
+ p->p_stats->p_ru.ru_nivcsw++;
+ swtch();
+ splx(s);
+ while (i = CURSIG(p))
+ psig(i);
+ }
+ if (p->p_stats->p_prof.pr_scale) {
+ int ticks;
+ struct timeval *tv = &p->p_stime;
+
+ ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
+ (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
+ if (ticks) {
+#ifdef PROFTIMER
+ extern int profscale;
+ addupc(frame.tf_eip, &p->p_stats->p_prof,
+ ticks * profscale);
+#else
+ addupc(frame.tf_eip, &p->p_stats->p_prof, ticks);
+#endif
+ }
+ }
+ curpri = p->p_pri;
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSRET))
+ ktrsysret(p->p_tracep, code, error, rval[0]);
+#endif
+#ifdef DIAGNOSTICx
+{ extern int _udatasel, _ucodesel;
+ if (frame.tf_ss != _udatasel)
+ printf("ss %x call %d\n", frame.tf_ss, code);
+ if ((frame.tf_cs&0xffff) != _ucodesel)
+ printf("cs %x call %d\n", frame.tf_cs, code);
+ if (frame.tf_eip > VM_MAXUSER_ADDRESS) {
+ printf("eip %x call %d\n", frame.tf_eip, code);
+ frame.tf_eip = 0;
+ }
+}
+#endif
+}
diff --git a/sys/amd64/amd64/tsc.c b/sys/amd64/amd64/tsc.c
new file mode 100644
index 0000000..d338cd5
--- /dev/null
+++ b/sys/amd64/amd64/tsc.c
@@ -0,0 +1,430 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz and Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)clock.c 7.2 (Berkeley) 5/12/91
+ * $Id: clock.c,v 1.6 1994/02/06 22:48:13 davidg Exp $
+ */
+
+/*
+ * Primitive clock interrupt routines.
+ */
+#include "param.h"
+#include "systm.h"
+#include "time.h"
+#include "kernel.h"
+#include "machine/segments.h"
+#include "machine/frame.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/rtc.h"
+#include "i386/isa/timerreg.h"
+
+/* X-tals being what they are, it's nice to be able to fudge this one... */
+/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */
+#ifndef TIMER_FREQ
+#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
+#endif
+#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
+
+void hardclock();
+static int beeping;
+int timer0_divisor = TIMER_DIV(100); /* XXX should be hz */
+u_int timer0_prescale;
+static char timer0_state = 0, timer2_state = 0;
+static char timer0_reprogram = 0;
+static void (*timer_func)() = hardclock;
+static void (*new_function)();
+static u_int new_rate;
+static u_int hardclock_divisor;
+
+
+void
+timerintr(struct intrframe frame)
+{
+ timer_func(frame);
+ switch (timer0_state) {
+ case 0:
+ break;
+ case 1:
+ if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
+ hardclock(frame);
+ timer0_prescale = 0;
+ }
+ break;
+ case 2:
+ disable_intr();
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+ outb(TIMER_CNTR0, TIMER_DIV(new_rate)%256);
+ outb(TIMER_CNTR0, TIMER_DIV(new_rate)/256);
+ enable_intr();
+ timer0_divisor = TIMER_DIV(new_rate);
+ timer0_prescale = 0;
+ timer_func = new_function;
+ timer0_state = 1;
+ break;
+ case 3:
+ if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
+ hardclock(frame);
+ disable_intr();
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+ outb(TIMER_CNTR0, TIMER_DIV(hz)%256);
+ outb(TIMER_CNTR0, TIMER_DIV(hz)/256);
+ enable_intr();
+ timer0_divisor = TIMER_DIV(hz);
+ timer0_prescale = 0;
+ timer_func = hardclock;;
+ timer0_state = 0;
+ }
+ break;
+ }
+}
+
+
+int
+acquire_timer0(int rate, void (*function)() )
+{
+ if (timer0_state || !function)
+ return -1;
+
+ new_function = function;
+ new_rate = rate;
+ timer0_state = 2;
+ return 0;
+}
+
+
+int
+acquire_timer2(int mode)
+{
+ if (timer2_state)
+ return -1;
+ timer2_state = 1;
+ outb(TIMER_MODE, TIMER_SEL2 | (mode &0x3f));
+ return 0;
+}
+
+
+int
+release_timer0()
+{
+ if (!timer0_state)
+ return -1;
+ timer0_state = 3;
+ return 0;
+}
+
+
+int
+release_timer2()
+{
+ if (!timer2_state)
+ return -1;
+ timer2_state = 0;
+ outb(TIMER_MODE, TIMER_SEL2|TIMER_SQWAVE|TIMER_16BIT);
+ return 0;
+}
+
+
+static int
+getit()
+{
+ int high, low;
+
+ disable_intr();
+ /* select timer0 and latch counter value */
+ outb(TIMER_MODE, TIMER_SEL0);
+ low = inb(TIMER_CNTR0);
+ high = inb(TIMER_CNTR0);
+ enable_intr();
+ return ((high << 8) | low);
+}
+
+
+/*
+ * Wait "n" microseconds.
+ * Relies on timer 1 counting down from (TIMER_FREQ / hz)
+ * Note: timer had better have been programmed before this is first used!
+ */
+void
+DELAY(int n)
+{
+ int counter_limit, prev_tick, tick, ticks_left, sec, usec;
+
+#ifdef DELAYDEBUG
+ int getit_calls = 1;
+ int n1;
+ static int state = 0;
+
+ if (state == 0) {
+ state = 1;
+ for (n1 = 1; n1 <= 10000000; n1 *= 10)
+ DELAY(n1);
+ state = 2;
+ }
+ if (state == 1)
+ printf("DELAY(%d)...", n);
+#endif
+ /*
+ * Read the counter first, so that the rest of the setup overhead is
+ * counted. Guess the initial overhead is 20 usec (on most systems it
+ * takes about 1.5 usec for each of the i/o's in getit(). The loop
+ * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
+ * multiplications and divisions to scale the count take a while).
+ */
+ prev_tick = getit(0, 0);
+ n -= 20;
+ /*
+ * Calculate (n * (TIMER_FREQ / 1e6)) without using floating point
+ * and without any avoidable overflows.
+ */
+ sec = n / 1000000;
+ usec = n - sec * 1000000;
+ ticks_left = sec * TIMER_FREQ
+ + usec * (TIMER_FREQ / 1000000)
+ + usec * ((TIMER_FREQ % 1000000) / 1000) / 1000
+ + usec * (TIMER_FREQ % 1000) / 1000000;
+
+ while (ticks_left > 0) {
+ tick = getit(0, 0);
+#ifdef DELAYDEBUG
+ ++getit_calls;
+#endif
+ if (tick > prev_tick)
+ ticks_left -= prev_tick - (tick - timer0_divisor);
+ else
+ ticks_left -= prev_tick - tick;
+ prev_tick = tick;
+ }
+#ifdef DELAYDEBUG
+ if (state == 1)
+ printf(" %d calls to getit() at %d usec each\n",
+ getit_calls, (n + 5) / getit_calls);
+#endif
+}
+
+
+static void
+sysbeepstop()
+{
+ outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */
+ release_timer2();
+ beeping = 0;
+}
+
+
+int
+sysbeep(int pitch, int period)
+{
+
+ if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT))
+ return -1;
+ disable_intr();
+ outb(TIMER_CNTR2, pitch);
+ outb(TIMER_CNTR2, (pitch>>8));
+ enable_intr();
+ if (!beeping) {
+ outb(IO_PPI, inb(IO_PPI) | 3); /* enable counter2 output to speaker */
+ beeping = period;
+ timeout(sysbeepstop, 0, period);
+ }
+ return 0;
+}
+
+
+void
+startrtclock()
+{
+ int s;
+
+ /* initialize 8253 clock */
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+
+ /* Correct rounding will buy us a better precision in timekeeping */
+ outb (IO_TIMER1, TIMER_DIV(hz)%256);
+ outb (IO_TIMER1, TIMER_DIV(hz)/256);
+ timer0_divisor = hardclock_divisor = TIMER_DIV(hz);
+
+ /* initialize brain-dead battery powered clock */
+ outb (IO_RTC, RTC_STATUSA);
+ outb (IO_RTC+1, 0x26);
+ outb (IO_RTC, RTC_STATUSB);
+ outb (IO_RTC+1, 2);
+
+ outb (IO_RTC, RTC_DIAG);
+ if (s = inb (IO_RTC+1))
+ printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS);
+}
+
+
+/* convert 2 digit BCD number */
+int
+bcd(int i)
+{
+ return ((i/16)*10 + (i%16));
+}
+
+
+/* convert years to seconds (from 1970) */
+unsigned long
+ytos(int y)
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i = 1970; i < y; i++) {
+ if (i % 4) ret += 365*24*60*60;
+ else ret += 366*24*60*60;
+ }
+ return ret;
+}
+
+
+/* convert months to seconds */
+unsigned long
+mtos(int m, int leap)
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i=1; i<m; i++) {
+ switch(i){
+ case 1: case 3: case 5: case 7: case 8: case 10: case 12:
+ ret += 31*24*60*60; break;
+ case 4: case 6: case 9: case 11:
+ ret += 30*24*60*60; break;
+ case 2:
+ if (leap) ret += 29*24*60*60;
+ else ret += 28*24*60*60;
+ }
+ }
+ return ret;
+}
+
+
+/*
+ * Initialize the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+void
+inittodr(time_t base)
+{
+ unsigned long sec;
+ int leap, day_week, t, yd;
+ int sa,s;
+
+ /* do we have a realtime clock present? (otherwise we loop below) */
+ sa = rtcin(RTC_STATUSA);
+ if (sa == 0xff || sa == 0) return;
+
+ /* ready for a read? */
+ while ((sa&RTCSA_TUP) == RTCSA_TUP)
+ sa = rtcin(RTC_STATUSA);
+
+ sec = bcd(rtcin(RTC_YEAR)) + 1900;
+ if (sec < 1970)
+ sec += 100;
+
+ leap = !(sec % 4); sec = ytos(sec); /* year */
+ yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec+=yd; /* month */
+ t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec+=t; yd+=t; /* date */
+ day_week = rtcin(RTC_WDAY); /* day */
+ sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */
+ sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */
+ sec += bcd(rtcin(RTC_SEC)); /* seconds */
+ sec += tz.tz_minuteswest * 60;
+ time.tv_sec = sec;
+}
+
+
+#ifdef garbage
+/*
+ * Initialze the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+test_inittodr(time_t base)
+{
+
+ outb(IO_RTC,9); /* year */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,8); /* month */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,7); /* day */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,4); /* hour */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,2); /* minutes */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,0); /* seconds */
+ printf("%d\n",bcd(inb(IO_RTC+1)));
+
+ time.tv_sec = base;
+}
+#endif
+
+
+/*
+ * Restart the clock.
+ */
+void
+resettodr()
+{
+}
+
+
+/*
+ * Wire clock interrupt in.
+ */
+#define V(s) __CONCAT(V, s)
+extern void V(clk)();
+
+
+void
+enablertclock()
+{
+ setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL);
+ INTREN(IRQ0);
+}
+
+
+/*
+ * Delay for some number of milliseconds.
+ */
+void
+spinwait(int millisecs)
+{
+ DELAY(1000 * millisecs);
+}
diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c
new file mode 100644
index 0000000..a892c29
--- /dev/null
+++ b/sys/amd64/amd64/vm_machdep.c
@@ -0,0 +1,1151 @@
+/*-
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * Copyright (c) 1989, 1990 William Jolitz
+ * Copyright (c) 1994 John Dyson
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department, and William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91
+ * Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
+ * $Id: vm_machdep.c,v 1.20 1994/04/20 07:06:20 davidg Exp $
+ */
+
+#include "npx.h"
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "malloc.h"
+#include "buf.h"
+#include "user.h"
+
+#include "../include/cpu.h"
+
+#include "vm/vm.h"
+#include "vm/vm_kern.h"
+
+#define b_cylin b_resid
+
+#define MAXCLSTATS 256
+int clstats[MAXCLSTATS];
+int rqstats[MAXCLSTATS];
+
+
+#ifndef NOBOUNCE
+
+caddr_t bouncememory;
+vm_offset_t bouncepa, bouncepaend;
+int bouncepages, bpwait;
+vm_map_t io_map;
+int bmwait, bmfreeing;
+
+#define BITS_IN_UNSIGNED (8*sizeof(unsigned))
+int bounceallocarraysize;
+unsigned *bounceallocarray;
+int bouncefree;
+
+#define SIXTEENMEG (4096*4096)
+#define MAXBKVA 1024
+
+/* special list that can be used at interrupt time for eventual kva free */
+struct kvasfree {
+ vm_offset_t addr;
+ vm_offset_t size;
+} kvaf[MAXBKVA];
+
+int kvasfreecnt;
+
+vm_offset_t vm_bounce_kva();
+/*
+ * get bounce buffer pages (count physically contiguous)
+ * (only 1 inplemented now)
+ */
+vm_offset_t
+vm_bounce_page_find(count)
+ int count;
+{
+ int bit;
+ int s,i;
+
+ if (count != 1)
+ panic("vm_bounce_page_find -- no support for > 1 page yet!!!");
+
+ s = splbio();
+retry:
+ for (i = 0; i < bounceallocarraysize; i++) {
+ if (bounceallocarray[i] != 0xffffffff) {
+ if (bit = ffs(~bounceallocarray[i])) {
+ bounceallocarray[i] |= 1 << (bit - 1) ;
+ bouncefree -= count;
+ splx(s);
+ return bouncepa + (i * BITS_IN_UNSIGNED + (bit - 1)) * NBPG;
+ }
+ }
+ }
+ bpwait = 1;
+ tsleep((caddr_t) &bounceallocarray, PRIBIO, "bncwai", 0);
+ goto retry;
+}
+
+void
+vm_bounce_kva_free(addr, size, now)
+ vm_offset_t addr;
+ vm_offset_t size;
+ int now;
+{
+ int s = splbio();
+ kvaf[kvasfreecnt].addr = addr;
+ kvaf[kvasfreecnt++].size = size;
+ if( now) {
+ /*
+ * this will do wakeups
+ */
+ vm_bounce_kva(0,0);
+ } else {
+ if (bmwait) {
+ /*
+ * if anyone is waiting on the bounce-map, then wakeup
+ */
+ wakeup((caddr_t) io_map);
+ bmwait = 0;
+ }
+ }
+ splx(s);
+}
+
+/*
+ * free count bounce buffer pages
+ */
+void
+vm_bounce_page_free(pa, count)
+ vm_offset_t pa;
+ int count;
+{
+ int allocindex;
+ int index;
+ int bit;
+
+ if (count != 1)
+ panic("vm_bounce_page_free -- no support for > 1 page yet!!!\n");
+
+ index = (pa - bouncepa) / NBPG;
+
+ if ((index < 0) || (index >= bouncepages))
+ panic("vm_bounce_page_free -- bad index\n");
+
+ allocindex = index / BITS_IN_UNSIGNED;
+ bit = index % BITS_IN_UNSIGNED;
+
+ bounceallocarray[allocindex] &= ~(1 << bit);
+
+ bouncefree += count;
+ if (bpwait) {
+ bpwait = 0;
+ wakeup((caddr_t) &bounceallocarray);
+ }
+}
+
+/*
+ * allocate count bounce buffer kva pages
+ */
+vm_offset_t
+vm_bounce_kva(count, waitok)
+ int count;
+ int waitok;
+{
+ int tofree;
+ int i;
+ int startfree;
+ vm_offset_t kva = 0;
+ int s = splbio();
+ int size = count;
+ startfree = 0;
+more:
+ if (!bmfreeing && (tofree = kvasfreecnt)) {
+ bmfreeing = 1;
+ for (i = startfree; i < kvasfreecnt; i++) {
+ /*
+ * if we have a kva of the right size, no sense
+ * in freeing/reallocating...
+ * might affect fragmentation short term, but
+ * as long as the amount of io_map is
+ * significantly more than the maximum transfer
+ * size, I don't think that it is a problem.
+ */
+ pmap_remove(kernel_pmap,
+ kvaf[i].addr, kvaf[i].addr + kvaf[i].size);
+ if( size && !kva && kvaf[i].size == size) {
+ kva = kvaf[i].addr;
+ } else {
+ kmem_free_wakeup(io_map, kvaf[i].addr,
+ kvaf[i].size);
+ }
+ }
+ if (kvasfreecnt != tofree) {
+ startfree = i;
+ bmfreeing = 0;
+ goto more;
+ }
+ kvasfreecnt = 0;
+ bmfreeing = 0;
+ }
+
+ if( size == 0) {
+ splx(s);
+ return NULL;
+ }
+
+ if (!kva && !(kva = kmem_alloc_pageable(io_map, size))) {
+ if( !waitok) {
+ splx(s);
+ return NULL;
+ }
+ bmwait = 1;
+ tsleep((caddr_t) io_map, PRIBIO, "bmwait", 0);
+ goto more;
+ }
+ splx(s);
+
+ return kva;
+}
+
+/*
+ * same as vm_bounce_kva -- but really allocate
+ */
+vm_offset_t
+vm_bounce_kva_alloc(count)
+int count;
+{
+ int i;
+ vm_offset_t kva;
+ vm_offset_t pa;
+ if( bouncepages == 0) {
+ kva = (vm_offset_t) malloc(count*NBPG, M_TEMP, M_WAITOK);
+ return kva;
+ }
+ kva = vm_bounce_kva(count, 1);
+ for(i=0;i<count;i++) {
+ pa = vm_bounce_page_find(1);
+ pmap_kenter(kva + i * NBPG, pa);
+ }
+ return kva;
+}
+
+/*
+ * same as vm_bounce_kva_free -- but really free
+ */
+void
+vm_bounce_kva_alloc_free(kva, count)
+ vm_offset_t kva;
+ int count;
+{
+ int i;
+ vm_offset_t pa;
+ if( bouncepages == 0) {
+ free((caddr_t) kva, M_TEMP);
+ return;
+ }
+ for(i = 0; i < count; i++) {
+ pa = pmap_kextract(kva + i * NBPG);
+ vm_bounce_page_free(pa, 1);
+ }
+ vm_bounce_kva_free(kva, count);
+}
+
+/*
+ * do the things necessary to the struct buf to implement
+ * bounce buffers... inserted before the disk sort
+ */
+void
+vm_bounce_alloc(bp)
+ struct buf *bp;
+{
+ int countvmpg;
+ vm_offset_t vastart, vaend;
+ vm_offset_t vapstart, vapend;
+ vm_offset_t va, kva;
+ vm_offset_t pa;
+ int dobounceflag = 0;
+ int bounceindex;
+ int i;
+ int s;
+
+ if (bouncepages == 0)
+ return;
+
+ if (bp->b_bufsize < bp->b_bcount) {
+ printf("vm_bounce_alloc: b_bufsize(%d) < b_bcount(%d) !!!!\n",
+ bp->b_bufsize, bp->b_bcount);
+ bp->b_bufsize = bp->b_bcount;
+ }
+
+ vastart = (vm_offset_t) bp->b_un.b_addr;
+ vaend = (vm_offset_t) bp->b_un.b_addr + bp->b_bufsize;
+
+ vapstart = i386_trunc_page(vastart);
+ vapend = i386_round_page(vaend);
+ countvmpg = (vapend - vapstart) / NBPG;
+
+/*
+ * if any page is above 16MB, then go into bounce-buffer mode
+ */
+ va = vapstart;
+ for (i = 0; i < countvmpg; i++) {
+ pa = pmap_kextract(va);
+ if (pa >= SIXTEENMEG)
+ ++dobounceflag;
+ va += NBPG;
+ }
+ if (dobounceflag == 0)
+ return;
+
+ if (bouncepages < dobounceflag)
+ panic("Not enough bounce buffers!!!");
+
+/*
+ * allocate a replacement kva for b_addr
+ */
+ kva = vm_bounce_kva(countvmpg*NBPG, 1);
+ va = vapstart;
+ for (i = 0; i < countvmpg; i++) {
+ pa = pmap_kextract(va);
+ if (pa >= SIXTEENMEG) {
+ /*
+ * allocate a replacement page
+ */
+ vm_offset_t bpa = vm_bounce_page_find(1);
+ pmap_kenter(kva + (NBPG * i), bpa);
+ /*
+ * if we are writing, the copy the data into the page
+ */
+ if ((bp->b_flags & B_READ) == 0) {
+ pmap_update();
+ bcopy((caddr_t) va, (caddr_t) kva + (NBPG * i), NBPG);
+ }
+ } else {
+ /*
+ * use original page
+ */
+ pmap_kenter(kva + (NBPG * i), pa);
+ }
+ va += NBPG;
+ }
+ pmap_update();
+
+/*
+ * flag the buffer as being bounced
+ */
+ bp->b_flags |= B_BOUNCE;
+/*
+ * save the original buffer kva
+ */
+ bp->b_savekva = bp->b_un.b_addr;
+/*
+ * put our new kva into the buffer (offset by original offset)
+ */
+ bp->b_un.b_addr = (caddr_t) (((vm_offset_t) kva) |
+ ((vm_offset_t) bp->b_savekva & (NBPG - 1)));
+ return;
+}
+
+/*
+ * hook into biodone to free bounce buffer
+ */
+void
+vm_bounce_free(bp)
+ struct buf *bp;
+{
+ int i;
+ vm_offset_t origkva, bouncekva;
+ vm_offset_t vastart, vaend;
+ vm_offset_t vapstart, vapend;
+ int countbounce = 0;
+ vm_offset_t firstbouncepa = 0;
+ int firstbounceindex;
+ int countvmpg;
+ vm_offset_t bcount;
+ int s;
+
+/*
+ * if this isn't a bounced buffer, then just return
+ */
+ if ((bp->b_flags & B_BOUNCE) == 0)
+ return;
+
+ origkva = (vm_offset_t) bp->b_savekva;
+ bouncekva = (vm_offset_t) bp->b_un.b_addr;
+
+ vastart = bouncekva;
+ vaend = bouncekva + bp->b_bufsize;
+ bcount = bp->b_bufsize;
+
+ vapstart = i386_trunc_page(vastart);
+ vapend = i386_round_page(vaend);
+
+ countvmpg = (vapend - vapstart) / NBPG;
+
+/*
+ * check every page in the kva space for b_addr
+ */
+ for (i = 0; i < countvmpg; i++) {
+ vm_offset_t mybouncepa;
+ vm_offset_t copycount;
+
+ copycount = i386_round_page(bouncekva + 1) - bouncekva;
+ mybouncepa = pmap_kextract(i386_trunc_page(bouncekva));
+
+/*
+ * if this is a bounced pa, then process as one
+ */
+ if ((mybouncepa >= bouncepa) && (mybouncepa < bouncepaend)) {
+ if (copycount > bcount)
+ copycount = bcount;
+/*
+ * if this is a read, then copy from bounce buffer into original buffer
+ */
+ if (bp->b_flags & B_READ)
+ bcopy((caddr_t) bouncekva, (caddr_t) origkva, copycount);
+/*
+ * free the bounce allocation
+ */
+ vm_bounce_page_free(i386_trunc_page(mybouncepa), 1);
+ }
+
+ origkva += copycount;
+ bouncekva += copycount;
+ bcount -= copycount;
+ }
+
+/*
+ * add the old kva into the "to free" list
+ */
+ bouncekva = i386_trunc_page((vm_offset_t) bp->b_un.b_addr);
+ vm_bounce_kva_free( bouncekva, countvmpg*NBPG, 0);
+ bp->b_un.b_addr = bp->b_savekva;
+ bp->b_savekva = 0;
+ bp->b_flags &= ~B_BOUNCE;
+
+ return;
+}
+
+#endif /* NOBOUNCE */
+
+/*
+ * init the bounce buffer system
+ */
+void
+vm_bounce_init()
+{
+ vm_offset_t minaddr, maxaddr;
+
+ io_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, MAXBKVA * NBPG, FALSE);
+ kvasfreecnt = 0;
+
+#ifndef NOBOUNCE
+ if (bouncepages == 0)
+ return;
+
+ bounceallocarraysize = (bouncepages + BITS_IN_UNSIGNED - 1) / BITS_IN_UNSIGNED;
+ bounceallocarray = malloc(bounceallocarraysize * sizeof(unsigned), M_TEMP, M_NOWAIT);
+
+ if (!bounceallocarray)
+ panic("Cannot allocate bounce resource array\n");
+
+ bzero(bounceallocarray, bounceallocarraysize * sizeof(long));
+
+
+ bouncepa = pmap_kextract((vm_offset_t) bouncememory);
+ bouncepaend = bouncepa + bouncepages * NBPG;
+ bouncefree = bouncepages;
+#endif
+
+}
+
+
+static void
+cldiskvamerge( kvanew, orig1, orig1cnt, orig2, orig2cnt)
+ vm_offset_t kvanew;
+ vm_offset_t orig1, orig1cnt;
+ vm_offset_t orig2, orig2cnt;
+{
+ int i;
+ vm_offset_t pa;
+/*
+ * enter the transfer physical addresses into the new kva
+ */
+ for(i=0;i<orig1cnt;i++) {
+ vm_offset_t pa;
+ pa = pmap_kextract((caddr_t) orig1 + i * PAGE_SIZE);
+ pmap_kenter(kvanew + i * PAGE_SIZE, pa);
+ }
+
+ for(i=0;i<orig2cnt;i++) {
+ vm_offset_t pa;
+ pa = pmap_kextract((caddr_t) orig2 + i * PAGE_SIZE);
+ pmap_kenter(kvanew + (i + orig1cnt) * PAGE_SIZE, pa);
+ }
+ pmap_update();
+}
+
+void
+cldisksort(struct buf *dp, struct buf *bp, vm_offset_t maxio)
+{
+ register struct buf *ap, *newbp;
+ int i, trycount=0;
+ vm_offset_t orig1pages, orig2pages;
+ vm_offset_t orig1begin, orig2begin;
+ vm_offset_t kvanew, kvaorig;
+
+ if( bp->b_bcount < MAXCLSTATS*PAGE_SIZE)
+ ++rqstats[bp->b_bcount/PAGE_SIZE];
+ /*
+ * If nothing on the activity queue, then
+ * we become the only thing.
+ */
+ ap = dp->b_actf;
+ if(ap == NULL) {
+ dp->b_actf = bp;
+ dp->b_actl = bp;
+ bp->av_forw = NULL;
+ return;
+ }
+
+ /*
+ * If we lie after the first (currently active)
+ * request, then we must locate the second request list
+ * and add ourselves to it.
+ */
+
+ if (bp->b_pblkno < ap->b_pblkno) {
+ while (ap->av_forw) {
+ /*
+ * Check for an ``inversion'' in the
+ * normally ascending block numbers,
+ * indicating the start of the second request list.
+ */
+ if (ap->av_forw->b_pblkno < ap->b_pblkno) {
+ /*
+ * Search the second request list
+ * for the first request at a larger
+ * block number. We go before that;
+ * if there is no such request, we go at end.
+ */
+ do {
+ if (bp->b_pblkno < ap->av_forw->b_pblkno)
+ goto insert;
+ ap = ap->av_forw;
+ } while (ap->av_forw);
+ goto insert; /* after last */
+ }
+ ap = ap->av_forw;
+ }
+ /*
+ * No inversions... we will go after the last, and
+ * be the first request in the second request list.
+ */
+ goto insert;
+ }
+ /*
+ * Request is at/after the current request...
+ * sort in the first request list.
+ */
+ while (ap->av_forw) {
+ /*
+ * We want to go after the current request
+ * if there is an inversion after it (i.e. it is
+ * the end of the first request list), or if
+ * the next request is a larger block than our request.
+ */
+ if (ap->av_forw->b_pblkno < ap->b_pblkno ||
+ bp->b_pblkno < ap->av_forw->b_pblkno )
+ goto insert;
+ ap = ap->av_forw;
+ }
+
+insert:
+
+ /*
+ * read clustering with new read-ahead disk drives hurts mostly, so
+ * we don't bother...
+ */
+ if( bp->b_flags & B_READ)
+ goto nocluster;
+ /*
+ * we currently only cluster I/O transfers that are at page-aligned
+ * kvas and transfers that are multiples of page lengths.
+ */
+ if ((bp->b_flags & B_BAD) == 0 &&
+ ((bp->b_bcount & PAGE_MASK) == 0) &&
+ (((vm_offset_t) bp->b_un.b_addr & PAGE_MASK) == 0)) {
+ if( maxio > MAXCLSTATS*PAGE_SIZE)
+ maxio = MAXCLSTATS*PAGE_SIZE;
+ /*
+ * merge with previous?
+ * conditions:
+ * 1) We reside physically immediately after the previous block.
+ * 2) The previous block is not first on the device queue because
+ * such a block might be active.
+ * 3) The mode of the two I/Os is identical.
+ * 4) The previous kva is page aligned and the previous transfer
+ * is a multiple of a page in length.
+ * 5) And the total I/O size would be below the maximum.
+ */
+ if( (ap->b_pblkno + (ap->b_bcount / DEV_BSIZE) == bp->b_pblkno) &&
+ (dp->b_actf != ap) &&
+ ((ap->b_flags & ~B_CLUSTER) == bp->b_flags) &&
+ ((ap->b_flags & B_BAD) == 0) &&
+ ((ap->b_bcount & PAGE_MASK) == 0) &&
+ (((vm_offset_t) ap->b_un.b_addr & PAGE_MASK) == 0) &&
+ (ap->b_bcount + bp->b_bcount < maxio)) {
+
+ orig1begin = (vm_offset_t) ap->b_un.b_addr;
+ orig1pages = ap->b_bcount / PAGE_SIZE;
+
+ orig2begin = (vm_offset_t) bp->b_un.b_addr;
+ orig2pages = bp->b_bcount / PAGE_SIZE;
+ /*
+ * see if we can allocate a kva, if we cannot, the don't
+ * cluster.
+ */
+ kvanew = vm_bounce_kva( PAGE_SIZE * (orig1pages + orig2pages), 0);
+ if( !kvanew) {
+ goto nocluster;
+ }
+
+
+ if( (ap->b_flags & B_CLUSTER) == 0) {
+
+ /*
+ * get a physical buf pointer
+ */
+ newbp = (struct buf *)trypbuf();
+ if( !newbp) {
+ vm_bounce_kva_free( kvanew, PAGE_SIZE * (orig1pages + orig2pages), 1);
+ goto nocluster;
+ }
+
+ cldiskvamerge( kvanew, orig1begin, orig1pages, orig2begin, orig2pages);
+
+ /*
+ * build the new bp to be handed off to the device
+ */
+
+ --clstats[ap->b_bcount/PAGE_SIZE];
+ *newbp = *ap;
+ newbp->b_flags |= B_CLUSTER;
+ newbp->b_un.b_addr = (caddr_t) kvanew;
+ newbp->b_bcount += bp->b_bcount;
+ newbp->b_bufsize = newbp->b_bcount;
+ newbp->b_clusterf = ap;
+ newbp->b_clusterl = bp;
+ ++clstats[newbp->b_bcount/PAGE_SIZE];
+
+ /*
+ * enter the new bp onto the device queue
+ */
+ if( ap->av_forw)
+ ap->av_forw->av_back = newbp;
+ else
+ dp->b_actl = newbp;
+
+ if( dp->b_actf != ap )
+ ap->av_back->av_forw = newbp;
+ else
+ dp->b_actf = newbp;
+
+ /*
+ * enter the previous bps onto the cluster queue
+ */
+ ap->av_forw = bp;
+ bp->av_back = ap;
+
+ ap->av_back = NULL;
+ bp->av_forw = NULL;
+
+ } else {
+ vm_offset_t addr;
+
+ cldiskvamerge( kvanew, orig1begin, orig1pages, orig2begin, orig2pages);
+ /*
+ * free the old kva
+ */
+ vm_bounce_kva_free( orig1begin, ap->b_bufsize, 0);
+ --clstats[ap->b_bcount/PAGE_SIZE];
+
+ ap->b_un.b_addr = (caddr_t) kvanew;
+
+ ap->b_clusterl->av_forw = bp;
+ bp->av_forw = NULL;
+ bp->av_back = ap->b_clusterl;
+ ap->b_clusterl = bp;
+
+ ap->b_bcount += bp->b_bcount;
+ ap->b_bufsize = ap->b_bcount;
+ ++clstats[ap->b_bcount/PAGE_SIZE];
+ }
+ return;
+ /*
+ * merge with next?
+ * conditions:
+ * 1) We reside physically before the next block.
+ * 3) The mode of the two I/Os is identical.
+ * 4) The next kva is page aligned and the next transfer
+ * is a multiple of a page in length.
+ * 5) And the total I/O size would be below the maximum.
+ */
+ } else if( ap->av_forw &&
+ (bp->b_pblkno + (bp->b_bcount / DEV_BSIZE) == ap->av_forw->b_pblkno) &&
+ (bp->b_flags == (ap->av_forw->b_flags & ~B_CLUSTER)) &&
+ ((ap->av_forw->b_flags & B_BAD) == 0) &&
+ ((ap->av_forw->b_bcount & PAGE_MASK) == 0) &&
+ (((vm_offset_t) ap->av_forw->b_un.b_addr & PAGE_MASK) == 0) &&
+ (ap->av_forw->b_bcount + bp->b_bcount < maxio)) {
+
+ orig1begin = (vm_offset_t) bp->b_un.b_addr;
+ orig1pages = bp->b_bcount / PAGE_SIZE;
+
+ orig2begin = (vm_offset_t) ap->av_forw->b_un.b_addr;
+ orig2pages = ap->av_forw->b_bcount / PAGE_SIZE;
+
+ /*
+ * see if we can allocate a kva, if we cannot, the don't
+ * cluster.
+ */
+ kvanew = vm_bounce_kva( PAGE_SIZE * (orig1pages + orig2pages), 0);
+ if( !kvanew) {
+ goto nocluster;
+ }
+
+ /*
+ * if next isn't a cluster we need to create one
+ */
+ if( (ap->av_forw->b_flags & B_CLUSTER) == 0) {
+
+ /*
+ * get a physical buf pointer
+ */
+ newbp = (struct buf *)trypbuf();
+ if( !newbp) {
+ vm_bounce_kva_free( kvanew, PAGE_SIZE * (orig1pages + orig2pages), 1);
+ goto nocluster;
+ }
+
+ cldiskvamerge( kvanew, orig1begin, orig1pages, orig2begin, orig2pages);
+ ap = ap->av_forw;
+ --clstats[ap->b_bcount/PAGE_SIZE];
+ *newbp = *ap;
+ newbp->b_flags |= B_CLUSTER;
+ newbp->b_un.b_addr = (caddr_t) kvanew;
+ newbp->b_blkno = bp->b_blkno;
+ newbp->b_pblkno = bp->b_pblkno;
+ newbp->b_bcount += bp->b_bcount;
+ newbp->b_bufsize = newbp->b_bcount;
+ newbp->b_clusterf = bp;
+ newbp->b_clusterl = ap;
+ ++clstats[newbp->b_bcount/PAGE_SIZE];
+
+ if( ap->av_forw)
+ ap->av_forw->av_back = newbp;
+ else
+ dp->b_actl = newbp;
+
+ if( dp->b_actf != ap )
+ ap->av_back->av_forw = newbp;
+ else
+ dp->b_actf = newbp;
+
+ bp->av_forw = ap;
+ ap->av_back = bp;
+
+ bp->av_back = NULL;
+ ap->av_forw = NULL;
+ } else {
+ vm_offset_t addr;
+
+ cldiskvamerge( kvanew, orig1begin, orig1pages, orig2begin, orig2pages);
+ ap = ap->av_forw;
+ vm_bounce_kva_free( orig2begin, ap->b_bufsize, 0);
+
+ ap->b_un.b_addr = (caddr_t) kvanew;
+ bp->av_forw = ap->b_clusterf;
+ ap->b_clusterf->av_back = bp;
+ ap->b_clusterf = bp;
+ bp->av_back = NULL;
+ --clstats[ap->b_bcount/PAGE_SIZE];
+
+ ap->b_blkno = bp->b_blkno;
+ ap->b_pblkno = bp->b_pblkno;
+ ap->b_bcount += bp->b_bcount;
+ ap->b_bufsize = ap->b_bcount;
+ ++clstats[ap->b_bcount/PAGE_SIZE];
+
+ }
+ return;
+ }
+ }
+ /*
+ * don't merge
+ */
+nocluster:
+ ++clstats[bp->b_bcount/PAGE_SIZE];
+ bp->av_forw = ap->av_forw;
+ if( bp->av_forw)
+ bp->av_forw->av_back = bp;
+ else
+ dp->b_actl = bp;
+
+ ap->av_forw = bp;
+ bp->av_back = ap;
+}
+
+/*
+ * quick version of vm_fault
+ */
+
+void
+vm_fault_quick( v, prot)
+ vm_offset_t v;
+ int prot;
+{
+ if( (cpu_class == CPUCLASS_386) &&
+ (prot & VM_PROT_WRITE))
+ vm_fault(&curproc->p_vmspace->vm_map, v,
+ VM_PROT_READ|VM_PROT_WRITE, FALSE);
+ else if( prot & VM_PROT_WRITE)
+ *(volatile char *)v += 0;
+ else
+ *(volatile char *)v;
+}
+
+
+/*
+ * Finish a fork operation, with process p2 nearly set up.
+ * Copy and update the kernel stack and pcb, making the child
+ * ready to run, and marking it so that it can return differently
+ * than the parent. Returns 1 in the child process, 0 in the parent.
+ * We currently double-map the user area so that the stack is at the same
+ * address in each process; in the future we will probably relocate
+ * the frame pointers on the stack after copying.
+ */
+int
+cpu_fork(p1, p2)
+ register struct proc *p1, *p2;
+{
+ register struct user *up = p2->p_addr;
+ int foo, offset, addr, i;
+ extern char kstack[];
+ extern int mvesp();
+
+ /*
+ * Copy pcb and stack from proc p1 to p2.
+ * We do this as cheaply as possible, copying only the active
+ * part of the stack. The stack and pcb need to agree;
+ * this is tricky, as the final pcb is constructed by savectx,
+ * but its frame isn't yet on the stack when the stack is copied.
+ * swtch compensates for this when the child eventually runs.
+ * This should be done differently, with a single call
+ * that copies and updates the pcb+stack,
+ * replacing the bcopy and savectx.
+ */
+ p2->p_addr->u_pcb = p1->p_addr->u_pcb;
+ offset = mvesp() - (int)kstack;
+ bcopy((caddr_t)kstack + offset, (caddr_t)p2->p_addr + offset,
+ (unsigned) ctob(UPAGES) - offset);
+ p2->p_regs = p1->p_regs;
+
+ /*
+ * Wire top of address space of child to it's kstack.
+ * First, fault in a page of pte's to map it.
+ */
+#if 0
+ addr = trunc_page((u_int)vtopte(kstack));
+ vm_map_pageable(&p2->p_vmspace->vm_map, addr, addr+NBPG, FALSE);
+ for (i=0; i < UPAGES; i++)
+ pmap_enter(&p2->p_vmspace->vm_pmap, kstack+i*NBPG,
+ pmap_extract(kernel_pmap, ((int)p2->p_addr)+i*NBPG),
+ /*
+ * The user area has to be mapped writable because
+ * it contains the kernel stack (when CR0_WP is on
+ * on a 486 there is no user-read/kernel-write
+ * mode). It is protected from user mode access
+ * by the segment limits.
+ */
+ VM_PROT_READ|VM_PROT_WRITE, TRUE);
+#endif
+ pmap_activate(&p2->p_vmspace->vm_pmap, &up->u_pcb);
+
+ /*
+ *
+ * Arrange for a non-local goto when the new process
+ * is started, to resume here, returning nonzero from setjmp.
+ */
+ if (savectx(up, 1)) {
+ /*
+ * Return 1 in child.
+ */
+ return (1);
+ }
+ return (0);
+}
+
+#ifdef notyet
+/*
+ * cpu_exit is called as the last action during exit.
+ *
+ * We change to an inactive address space and a "safe" stack,
+ * passing thru an argument to the new stack. Now, safely isolated
+ * from the resources we're shedding, we release the address space
+ * and any remaining machine-dependent resources, including the
+ * memory for the user structure and kernel stack.
+ *
+ * Next, we assign a dummy context to be written over by swtch,
+ * calling it to send this process off to oblivion.
+ * [The nullpcb allows us to minimize cost in swtch() by not having
+ * a special case].
+ */
+struct proc *swtch_to_inactive();
+volatile void
+cpu_exit(p)
+ register struct proc *p;
+{
+ static struct pcb nullpcb; /* pcb to overwrite on last swtch */
+
+#if NNPX > 0
+ npxexit(p);
+#endif /* NNPX */
+
+ /* move to inactive space and stack, passing arg accross */
+ p = swtch_to_inactive(p);
+
+ /* drop per-process resources */
+ vmspace_free(p->p_vmspace);
+ kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES));
+
+ p->p_addr = (struct user *) &nullpcb;
+ splclock();
+ swtch();
+ /* NOTREACHED */
+}
+#else
+void
+cpu_exit(p)
+ register struct proc *p;
+{
+
+#if NNPX > 0
+ npxexit(p);
+#endif /* NNPX */
+ splclock();
+ curproc = 0;
+ swtch();
+ /*
+ * This is to shutup the compiler, and if swtch() failed I suppose
+ * this would be a good thing. This keeps gcc happy because panic
+ * is a volatile void function as well.
+ */
+ panic("cpu_exit");
+}
+
+void
+cpu_wait(p) struct proc *p; {
+/* extern vm_map_t upages_map; */
+ extern char kstack[];
+
+ /* drop per-process resources */
+ pmap_remove(vm_map_pmap(kernel_map), (vm_offset_t) p->p_addr,
+ ((vm_offset_t) p->p_addr) + ctob(UPAGES));
+ kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES));
+ vmspace_free(p->p_vmspace);
+}
+#endif
+
+/*
+ * Set a red zone in the kernel stack after the u. area.
+ */
+void
+setredzone(pte, vaddr)
+ u_short *pte;
+ caddr_t vaddr;
+{
+/* eventually do this by setting up an expand-down stack segment
+ for ss0: selector, allowing stack access down to top of u.
+ this means though that protection violations need to be handled
+ thru a double fault exception that must do an integral task
+ switch to a known good context, within which a dump can be
+ taken. a sensible scheme might be to save the initial context
+ used by sched (that has physical memory mapped 1:1 at bottom)
+ and take the dump while still in mapped mode */
+}
+
+/*
+ * Convert kernel VA to physical address
+ */
+u_long
+kvtop(void *addr)
+{
+ vm_offset_t va;
+
+ va = pmap_kextract((vm_offset_t)addr);
+ if (va == 0)
+ panic("kvtop: zero page frame");
+ return((int)va);
+}
+
+extern vm_map_t phys_map;
+
+/*
+ * Map an IO request into kernel virtual address space.
+ *
+ * All requests are (re)mapped into kernel VA space.
+ * Notice that we use b_bufsize for the size of the buffer
+ * to be mapped. b_bcount might be modified by the driver.
+ */
+void
+vmapbuf(bp)
+ register struct buf *bp;
+{
+ register int npf;
+ register caddr_t addr;
+ register long flags = bp->b_flags;
+ struct proc *p;
+ int off;
+ vm_offset_t kva;
+ register vm_offset_t pa;
+
+ if ((flags & B_PHYS) == 0)
+ panic("vmapbuf");
+ addr = bp->b_saveaddr = bp->b_un.b_addr;
+ off = (int)addr & PGOFSET;
+ p = bp->b_proc;
+ npf = btoc(round_page(bp->b_bufsize + off));
+ kva = kmem_alloc_wait(phys_map, ctob(npf));
+ bp->b_un.b_addr = (caddr_t) (kva + off);
+ while (npf--) {
+ pa = pmap_extract(&p->p_vmspace->vm_pmap, (vm_offset_t)addr);
+ if (pa == 0)
+ panic("vmapbuf: null page frame");
+ pmap_kenter(kva, trunc_page(pa));
+ addr += PAGE_SIZE;
+ kva += PAGE_SIZE;
+ }
+ pmap_update();
+}
+
+/*
+ * Free the io map PTEs associated with this IO operation.
+ * We also invalidate the TLB entries and restore the original b_addr.
+ */
+void
+vunmapbuf(bp)
+ register struct buf *bp;
+{
+ register int npf;
+ register caddr_t addr = bp->b_un.b_addr;
+ vm_offset_t kva;
+
+ if ((bp->b_flags & B_PHYS) == 0)
+ panic("vunmapbuf");
+ npf = btoc(round_page(bp->b_bufsize + ((int)addr & PGOFSET)));
+ kva = (vm_offset_t)((int)addr & ~PGOFSET);
+ kmem_free_wakeup(phys_map, kva, ctob(npf));
+ bp->b_un.b_addr = bp->b_saveaddr;
+ bp->b_saveaddr = NULL;
+}
+
+/*
+ * Force reset the processor by invalidating the entire address space!
+ */
+void
+cpu_reset() {
+
+ /* force a shutdown by unmapping entire address space ! */
+ bzero((caddr_t) PTD, NBPG);
+
+ /* "good night, sweet prince .... <THUNK!>" */
+ tlbflush();
+ /* NOTREACHED */
+ while(1);
+}
+
+/*
+ * Grow the user stack to allow for 'sp'. This version grows the stack in
+ * chunks of SGROWSIZ.
+ */
+int
+grow(p, sp)
+ struct proc *p;
+ int sp;
+{
+ unsigned int nss;
+ caddr_t v;
+ struct vmspace *vm = p->p_vmspace;
+
+ if ((caddr_t)sp <= vm->vm_maxsaddr || (unsigned)sp >= (unsigned)USRSTACK)
+ return (1);
+
+ nss = roundup(USRSTACK - (unsigned)sp, PAGE_SIZE);
+
+ if (nss > p->p_rlimit[RLIMIT_STACK].rlim_cur)
+ return (0);
+
+ if (vm->vm_ssize && roundup(vm->vm_ssize << PAGE_SHIFT,
+ SGROWSIZ) < nss) {
+ int grow_amount;
+ /*
+ * If necessary, grow the VM that the stack occupies
+ * to allow for the rlimit. This allows us to not have
+ * to allocate all of the VM up-front in execve (which
+ * is expensive).
+ * Grow the VM by the amount requested rounded up to
+ * the nearest SGROWSIZ to provide for some hysteresis.
+ */
+ grow_amount = roundup((nss - (vm->vm_ssize << PAGE_SHIFT)), SGROWSIZ);
+ v = (char *)USRSTACK - roundup(vm->vm_ssize << PAGE_SHIFT,
+ SGROWSIZ) - grow_amount;
+ /*
+ * If there isn't enough room to extend by SGROWSIZ, then
+ * just extend to the maximum size
+ */
+ if (v < vm->vm_maxsaddr) {
+ v = vm->vm_maxsaddr;
+ grow_amount = MAXSSIZ - (vm->vm_ssize << PAGE_SHIFT);
+ }
+ if (vm_allocate(&vm->vm_map, (vm_offset_t *)&v,
+ grow_amount, FALSE) != KERN_SUCCESS) {
+ return (0);
+ }
+ vm->vm_ssize += grow_amount >> PAGE_SHIFT;
+ }
+
+ return (1);
+}
diff --git a/sys/amd64/include/asmacros.h b/sys/amd64/include/asmacros.h
new file mode 100644
index 0000000..4af0b97
--- /dev/null
+++ b/sys/amd64/include/asmacros.h
@@ -0,0 +1,49 @@
+#define ALIGN_DATA .align 2 /* 4 byte alignment, zero filled */
+#define ALIGN_TEXT .align 2,0x90 /* 4-byte alignment, nop filled */
+#define SUPERALIGN_TEXT .align 4,0x90 /* 16-byte alignment (better for 486), nop filled */
+
+#define GEN_ENTRY(name) ALIGN_TEXT; .globl name; name:
+#define NON_GPROF_ENTRY(name) GEN_ENTRY(_/**/name)
+
+/* These three are place holders for future changes to the profiling code */
+#define MCOUNT_LABEL(name)
+#define MEXITCOUNT
+#define FAKE_MCOUNT(caller)
+
+#ifdef GPROF
+/*
+ * ALTENTRY() must be before a corresponding ENTRY() so that it can jump
+ * over the mcounting.
+ */
+#define ALTENTRY(name) GEN_ENTRY(_/**/name); MCOUNT; jmp 2f
+#define ENTRY(name) GEN_ENTRY(_/**/name); MCOUNT; 2:
+/*
+ * The call to mcount supports the usual (bad) conventions. We allocate
+ * some data and pass a pointer to it although the FreeBSD doesn't use
+ * the data. We set up a frame before calling mcount because that is
+ * the standard convention although it makes work for both mcount and
+ * callers.
+ */
+#define MCOUNT .data; ALIGN_DATA; 1:; .long 0; .text; \
+ pushl %ebp; movl %esp,%ebp; \
+ movl $1b,%eax; call mcount; popl %ebp
+#else
+/*
+ * ALTENTRY() has to align because it is before a corresponding ENTRY().
+ * ENTRY() has to align to because there may be no ALTENTRY() before it.
+ * If there is a previous ALTENTRY() then the alignment code is empty.
+ */
+#define ALTENTRY(name) GEN_ENTRY(_/**/name)
+#define ENTRY(name) GEN_ENTRY(_/**/name)
+#define MCOUNT
+
+#endif
+
+#ifdef DUMMY_NOPS /* this will break some older machines */
+#define FASTER_NOP
+#define NOP
+#else
+#define FASTER_NOP pushl %eax ; inb $0x84,%al ; popl %eax
+#define NOP pushl %eax ; inb $0x84,%al ; inb $0x84,%al ; popl %eax
+#endif
+
diff --git a/sys/amd64/include/cpu.h b/sys/amd64/include/cpu.h
new file mode 100644
index 0000000..a2df023
--- /dev/null
+++ b/sys/amd64/include/cpu.h
@@ -0,0 +1,110 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)cpu.h 5.4 (Berkeley) 5/9/91
+ * $Id: cpu.h,v 1.4 1993/11/07 17:42:46 wollman Exp $
+ */
+
+#ifndef _MACHINE_CPU_H_
+#define _MACHINE_CPU_H_ 1
+
+/*
+ * Definitions unique to i386 cpu support.
+ */
+#include "machine/frame.h"
+#include "machine/segments.h"
+
+/*
+ * definitions of cpu-dependent requirements
+ * referenced in generic code
+ */
+#undef COPY_SIGCODE /* don't copy sigcode above user stack in exec */
+
+#define cpu_exec(p) /* nothing */
+
+/*
+ * Arguments to hardclock, softclock and gatherstats
+ * encapsulate the previous machine state in an opaque
+ * clockframe; for now, use generic intrframe.
+ * XXX softclock() has been fixed. It never needed a
+ * whole frame, only a usermode flag, at least on this
+ * machine. Fix the rest.
+ */
+typedef struct intrframe clockframe;
+
+#define CLKF_USERMODE(framep) (ISPL((framep)->if_cs) == SEL_UPL)
+#define CLKF_BASEPRI(framep) (((framep)->if_ppl & ~SWI_AST_MASK) == 0)
+#define CLKF_PC(framep) ((framep)->if_eip)
+
+/*
+ * Preempt the current process if in interrupt from user mode,
+ * or after the current trap/syscall if in system mode.
+ */
+#define need_resched() { want_resched = 1; aston(); }
+
+/*
+ * Give a profiling tick to the current process from the softclock
+ * interrupt. On tahoe, request an ast to send us through trap(),
+ * marking the proc as needing a profiling tick.
+ */
+#define profile_tick(p, framep) { (p)->p_flag |= SOWEUPC; aston(); }
+
+/*
+ * Notify the current process (p) that it has a signal pending,
+ * process as soon as possible.
+ */
+#define signotify(p) aston()
+
+#define aston() setsoftast()
+#define astoff()
+
+/*
+ * pull in #defines for kinds of processors
+ */
+#include "machine/cputypes.h"
+
+struct cpu_nameclass {
+ char *cpu_name;
+ int cpu_class;
+};
+
+#ifdef KERNEL
+extern int want_resched; /* resched was called */
+
+extern int cpu;
+extern int cpu_class;
+extern struct cpu_nameclass i386_cpus[];
+#endif
+#endif /* _MACHINE_CPU_H_ */
diff --git a/sys/amd64/include/cpufunc.h b/sys/amd64/include/cpufunc.h
new file mode 100644
index 0000000..3c2dcc9
--- /dev/null
+++ b/sys/amd64/include/cpufunc.h
@@ -0,0 +1,240 @@
+/*
+ * Functions to provide access to special i386 instructions.
+ * XXX - bezillions more are defined in locore.s but are not declared anywhere.
+ *
+ * $Id: cpufunc.h,v 1.9 1994/01/31 23:48:23 davidg Exp $
+ */
+
+#ifndef _MACHINE_CPUFUNC_H_
+#define _MACHINE_CPUFUNC_H_ 1
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include "machine/spl.h"
+
+#ifdef __GNUC__
+
+static inline int bdb(void)
+{
+ extern int bdb_exists;
+
+ if (!bdb_exists)
+ return (0);
+ __asm("int $3");
+ return (1);
+}
+
+static inline void
+disable_intr(void)
+{
+ __asm __volatile("cli");
+}
+
+static inline void
+enable_intr(void)
+{
+ __asm __volatile("sti");
+}
+
+/*
+ * This roundabout method of returning a u_char helps stop gcc-1.40 from
+ * generating unnecessary movzbl's.
+ */
+#define inb(port) ((u_char) u_int_inb(port))
+
+static inline u_int
+u_int_inb(u_int port)
+{
+ u_char data;
+ /*
+ * We use %%dx and not %1 here because i/o is done at %dx and not at
+ * %edx, while gcc-2.2.2 generates inferior code (movw instead of movl)
+ * if we tell it to load (u_short) port.
+ */
+ __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
+ return data;
+}
+
+static inline void
+outb(u_int port, u_char data)
+{
+ register u_char al asm("ax");
+
+ al = data; /* help gcc-1.40's register allocator */
+ __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
+}
+
+static inline void
+tlbflush()
+{
+ __asm __volatile("movl %%cr3, %%eax; movl %%eax, %%cr3" : : : "ax");
+}
+
+static inline
+int
+imin(a, b)
+ int a, b;
+{
+
+ return (a < b ? a : b);
+}
+
+static inline
+int
+imax(a, b)
+ int a, b;
+{
+
+ return (a > b ? a : b);
+}
+
+static inline
+unsigned int
+min(a, b)
+ unsigned int a, b;
+{
+
+ return (a < b ? a : b);
+}
+
+static inline
+unsigned int
+max(a, b)
+ unsigned int a, b;
+{
+
+ return (a > b ? a : b);
+}
+
+static inline
+long
+lmin(a, b)
+ long a, b;
+{
+
+ return (a < b ? a : b);
+}
+
+static inline
+long
+lmax(a, b)
+ long a, b;
+{
+
+ return (a > b ? a : b);
+}
+
+static inline
+unsigned long
+ulmin(a, b)
+ unsigned long a, b;
+{
+
+ return (a < b ? a : b);
+}
+
+static inline
+unsigned long
+ulmax(a, b)
+ unsigned long a, b;
+{
+
+ return (a > b ? a : b);
+}
+
+static inline
+int
+ffs(mask)
+ register long mask;
+{
+ register int bit;
+
+ if (!mask)
+ return(0);
+ for (bit = 1;; ++bit) {
+ if (mask&0x01)
+ return(bit);
+ mask >>= 1;
+ }
+}
+
+static inline
+int
+bcmp(v1, v2, len)
+ void *v1, *v2;
+ register unsigned len;
+{
+ register u_char *s1 = v1, *s2 = v2;
+
+ while (len--)
+ if (*s1++ != *s2++)
+ return (1);
+ return (0);
+}
+
+static inline
+size_t
+strlen(s1)
+ register const char *s1;
+{
+ register size_t len;
+
+ for (len = 0; *s1++ != '\0'; len++)
+ ;
+ return (len);
+}
+
+struct quehead {
+ struct quehead *qh_link;
+ struct quehead *qh_rlink;
+};
+
+static inline void
+insque(void *a, void *b)
+{
+ register struct quehead *element = a, *head = b;
+ element->qh_link = head->qh_link;
+ head->qh_link = (struct quehead *)element;
+ element->qh_rlink = (struct quehead *)head;
+ ((struct quehead *)(element->qh_link))->qh_rlink
+ = (struct quehead *)element;
+}
+
+static inline void
+remque(void *a)
+{
+ register struct quehead *element = a;
+ ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink;
+ ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link;
+ element->qh_rlink = 0;
+}
+
+#else /* not __GNUC__ */
+extern void insque __P((void *, void *));
+extern void remque __P((void *));
+
+int bdb __P((void));
+void disable_intr __P((void));
+void enable_intr __P((void));
+u_char inb __P((u_int port));
+void outb __P((u_int port, u_int data)); /* XXX - incompat */
+
+#endif /* __GNUC__ */
+
+void load_cr0 __P((u_int cr0));
+u_int rcr0 __P((void));
+void load_cr3(u_long);
+u_long rcr3(void);
+u_long rcr2(void);
+
+void setidt __P((int, void (*)(), int, int));
+extern u_long kvtop(void *);
+extern void outw(int /*u_short*/, int /*u_short*/); /* XXX inline!*/
+extern void outsb(int /*u_short*/, void *, size_t);
+extern void outsw(int /*u_short*/, void *, size_t);
+extern void insw(int /*u_short*/, void *, size_t);
+extern void fillw(int /*u_short*/, void *, size_t);
+extern void filli(int, void *, size_t);
+
+#endif /* _MACHINE_CPUFUNC_H_ */
diff --git a/sys/amd64/include/cputypes.h b/sys/amd64/include/cputypes.h
new file mode 100644
index 0000000..c85fe19
--- /dev/null
+++ b/sys/amd64/include/cputypes.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1993 Christopher G. Demetriou
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: cputypes.h,v 1.1 1993/10/08 13:40:54 rgrimes Exp $
+ */
+
+#ifndef _MACHINE_CPUTYPES_H_
+#define _MACHINE_CPUTYPES_H_ 1
+
+/*
+ * Classes of Processor
+ */
+
+#define CPUCLASS_286 0
+#define CPUCLASS_386 1
+#define CPUCLASS_486 2
+#define CPUCLASS_586 3
+
+/*
+ * Kinds of Processor
+ */
+
+#define CPU_286 0 /* Intel 80286 */
+#define CPU_386SX 1 /* Intel 80386SX */
+#define CPU_386 2 /* Intel 80386DX */
+#define CPU_486SX 3 /* Intel 80486SX */
+#define CPU_486 4 /* Intel 80486DX */
+#define CPU_586 5 /* Intel P.....m (I hate lawyers; it's TM) */
+
+#endif /* _MACHINE_CPUTYPES_H_ */
diff --git a/sys/amd64/include/db_machdep.h b/sys/amd64/include/db_machdep.h
new file mode 100644
index 0000000..a3f4064
--- /dev/null
+++ b/sys/amd64/include/db_machdep.h
@@ -0,0 +1,120 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * $Id: db_machdep.h,v 1.2 1993/10/16 14:39:10 rgrimes Exp $
+ */
+
+#ifndef _I386_DB_MACHDEP_H_
+#define _I386_DB_MACHDEP_H_
+
+/*
+ * Machine-dependent defines for new kernel debugger.
+ */
+
+
+/* #include <mach/i386/vm_types.h> */
+/* #include <mach/i386/vm_param.h> */
+#include <vm/vm_prot.h>
+#include <vm/vm_param.h>
+#include <vm/vm_inherit.h>
+#include <vm/lock.h>
+/* #include <i386/thread.h> */ /* for thread_status */
+#include <machine/frame.h> /* for struct trapframe */
+/* #include <i386/eflags.h> */
+#include <machine/eflags.h> /* from Mach... */
+/* #include <i386/trap.h> */
+#include <machine/trap.h>
+
+#define i386_saved_state trapframe
+/* end of mangling */
+
+typedef vm_offset_t db_addr_t; /* address - unsigned */
+typedef int db_expr_t; /* expression - signed */
+
+typedef struct i386_saved_state db_regs_t;
+extern db_regs_t ddb_regs; /* register state */
+#define DDB_REGS (&ddb_regs)
+
+#define PC_REGS(regs) ((db_addr_t)(regs)->tf_eip)
+
+#define BKPT_INST 0xcc /* breakpoint instruction */
+#define BKPT_SIZE (1) /* size of breakpoint inst */
+#define BKPT_SET(inst) (BKPT_INST)
+
+#define FIXUP_PC_AFTER_BREAK ddb_regs.tf_eip -= 1;
+
+#define db_clear_single_step(regs) ((regs)->tf_eflags &= ~EFL_TF)
+#define db_set_single_step(regs) ((regs)->tf_eflags |= EFL_TF)
+
+/* #define IS_BREAKPOINT_TRAP(type, code) ((type) == T_INT3) */
+/* #define IS_WATCHPOINT_TRAP(type, code) ((type) == T_WATCHPOINT) */
+/* using the 386bsd values, rather than the Mach ones: */
+#define IS_BREAKPOINT_TRAP(type, code) ((type) == T_BPTFLT)
+#define IS_WATCHPOINT_TRAP(type, code) ((type) == T_KDBTRAP)
+
+#define I_CALL 0xe8
+#define I_CALLI 0xff
+#define I_RET 0xc3
+#define I_IRET 0xcf
+
+#define inst_trap_return(ins) (((ins)&0xff) == I_IRET)
+#define inst_return(ins) (((ins)&0xff) == I_RET)
+#define inst_call(ins) (((ins)&0xff) == I_CALL || \
+ (((ins)&0xff) == I_CALLI && \
+ ((ins)&0x3800) == 0x1000))
+#define inst_load(ins) 0
+#define inst_store(ins) 0
+
+/* access capability and access macros */
+
+#define DB_ACCESS_LEVEL 2 /* access any space */
+#define DB_CHECK_ACCESS(addr,size,task) \
+ db_check_access(addr,size,task)
+#define DB_PHYS_EQ(task1,addr1,task2,addr2) \
+ db_phys_eq(task1,addr1,task2,addr2)
+#define DB_VALID_KERN_ADDR(addr) \
+ ((addr) >= VM_MIN_KERNEL_ADDRESS && \
+ (addr) < VM_MAX_KERNEL_ADDRESS)
+#define DB_VALID_ADDRESS(addr,user) \
+ ((!(user) && DB_VALID_KERN_ADDR(addr)) || \
+ ((user) && (addr) < VM_MIN_KERNEL_ADDRESS))
+
+boolean_t db_check_access(/* vm_offset_t, int, task_t */);
+boolean_t db_phys_eq(/* task_t, vm_offset_t, task_t, vm_offset_t */);
+
+/* macros for printing OS server dependent task name */
+
+#define DB_TASK_NAME(task) db_task_name(task)
+#define DB_TASK_NAME_TITLE "COMMAND "
+#define DB_TASK_NAME_LEN 23
+#define DB_NULL_TASK_NAME "? "
+
+void db_task_name(/* task_t */);
+
+/* macro for checking if a thread has used floating-point */
+
+#define db_thread_fp_used(thread) ((thread)->pcb->ims.ifps != 0)
+
+#endif /* _I386_DB_MACHDEP_H_ */
diff --git a/sys/amd64/include/float.h b/sys/amd64/include/float.h
new file mode 100644
index 0000000..fb5967e
--- /dev/null
+++ b/sys/amd64/include/float.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)float.h 7.1 (Berkeley) 5/8/90
+ * $Id: float.h,v 1.4 1993/10/16 14:39:16 rgrimes Exp $
+ */
+
+#ifndef _MACHINE_FLOAT_H_
+#define _MACHINE_FLOAT_H_ 1
+
+#define FLT_RADIX 2 /* b */
+#define FLT_ROUNDS 1 /* FP addition rounds to nearest */
+
+#define FLT_MANT_DIG 24 /* p */
+#define FLT_EPSILON 1.19209290E-07F /* b**(1-p) */
+#define FLT_DIG 6 /* floor((p-1)*log10(b))+(b == 10) */
+#define FLT_MIN_EXP (-125) /* emin */
+#define FLT_MIN 1.17549435E-38F /* b**(emin-1) */
+#define FLT_MIN_10_EXP (-37) /* ceil(log10(b**(emin-1))) */
+#define FLT_MAX_EXP 128 /* emax */
+#define FLT_MAX 3.40282347E+38F /* (1-b**(-p))*b**emax */
+#define FLT_MAX_10_EXP 38 /* floor(log10((1-b**(-p))*b**emax)) */
+
+#define DBL_MANT_DIG 53
+#define DBL_EPSILON 2.2204460492503131E-16
+#define DBL_DIG 15
+#define DBL_MIN_EXP (-1021)
+#define DBL_MIN 2.2250738585072014E-308
+#define DBL_MIN_10_EXP (-307)
+#define DBL_MAX_EXP 1024
+#define DBL_MAX 1.7976931348623157E+308
+#define DBL_MAX_10_EXP 308
+
+#define LDBL_MANT_DIG DBL_MANT_DIG
+#define LDBL_EPSILON DBL_EPSILON
+#define LDBL_DIG DBL_DIG
+#define LDBL_MIN_EXP DBL_MIN_EXP
+#define LDBL_MIN DBL_MIN
+#define LDBL_MIN_10_EXP DBL_MIN_10_EXP
+#define LDBL_MAX_EXP DBL_MAX_EXP
+#define LDBL_MAX DBL_MAX
+#define LDBL_MAX_10_EXP DBL_MAX_10_EXP
+#endif /* _MACHINE_FLOAT_H_ */
diff --git a/sys/amd64/include/floatingpoint.h b/sys/amd64/include/floatingpoint.h
new file mode 100644
index 0000000..ed47cf6
--- /dev/null
+++ b/sys/amd64/include/floatingpoint.h
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1993 Andrew Moore, Talke Studio
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#) floatingpoint.h 1.0 (Berkeley) 9/23/93
+ * $Id: floatingpoint.h,v 1.3 1993/10/16 14:39:18 rgrimes Exp $
+ */
+
+/*
+ * IEEE floating point structure and function definitions
+ */
+
+#ifndef _FLOATINGPOINT_H_
+#define _FLOATINGPOINT_H_
+
+#include <sys/cdefs.h>
+#include <sys/ieeefp.h>
+
+#ifdef __GNUC__
+
+#ifdef __i386__
+
+#define fnstcw(addr) __asm("fnstcw %0" : "=m" (*addr) : "0" (*addr))
+#define fnstsw(addr) __asm("fnstsw %0" : "=m" (*addr) : "0" (*addr))
+#define fnstenv(addr) __asm("fnstenv %0" : "=m" (*addr) : "0" (*addr))
+#define fldenv(addr) __asm("fldenv %0" : : "m" (*addr))
+
+
+/*
+ * return the contents of a FP register
+ */
+static __inline__ int
+__fpgetreg(int _reg)
+{
+ unsigned short _mem;
+
+ switch(_reg) {
+ default:
+ fnstcw(&_mem);
+ break;
+ case FP_STKY_REG:
+ fnstsw(&_mem);
+ break;
+ }
+ return _mem;
+}
+
+/*
+ * set a FP mode; return previous mode
+ */
+static __inline__ int
+__fpsetreg(int _m, int _reg, int _fld, int _off)
+{
+ unsigned _env[7];
+ unsigned _p;
+
+ fnstenv(_env);
+ _p = (_env[_reg] & _fld) >> _off;
+ _env[_reg] = (_env[_reg] & ~_fld) | (_m << _off & _fld);
+ fldenv(_env);
+ return _p;
+}
+
+#endif /* __i386__ */
+
+#endif /* __GNUC__ */
+
+/*
+ * SysV/386 FP control interface
+ */
+#define fpgetround() ((__fpgetreg(FP_RND_REG) & FP_RND_FLD) >> FP_RND_OFF)
+#define fpsetround(m) __fpsetreg((m), FP_RND_REG, FP_RND_FLD, FP_RND_OFF)
+#define fpgetprec() ((__fpgetreg(FP_PRC_REG) & FP_PRC_FLD) >> FP_PRC_OFF)
+#define fpsetprec(m) __fpsetreg((m), FP_PRC_REG, FP_PRC_FLD, FP_PRC_OFF)
+#define fpgetmask() ((~__fpgetreg(FP_MSKS_REG) & FP_MSKS_FLD) >> FP_MSKS_OFF)
+#define fpsetmask(m) __fpsetreg(~(m), FP_MSKS_REG, FP_MSKS_FLD, FP_MSKS_OFF)
+#define fpgetsticky() ((__fpgetreg(FP_STKY_REG) & FP_STKY_FLD) >> FP_STKY_OFF)
+#define fpresetsticky(m) __fpsetreg(0, FP_STKY_REG, (m), FP_STKY_OFF)
+#define fpsetsticky(m) fpresetsticky(m)
+
+#endif /* !_FLOATINGPOINT_H_ */
diff --git a/sys/amd64/include/fpu.h b/sys/amd64/include/fpu.h
new file mode 100644
index 0000000..87cd6f9
--- /dev/null
+++ b/sys/amd64/include/fpu.h
@@ -0,0 +1,141 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)npx.h 5.3 (Berkeley) 1/18/91
+ * $Id: npx.h,v 1.2 1993/10/16 14:39:22 rgrimes Exp $
+ */
+
+/*
+ * 287/387 NPX Coprocessor Data Structures and Constants
+ * W. Jolitz 1/90
+ */
+
+#ifndef ___NPX87___
+#define ___NPX87___
+
+/* Environment information of floating point unit */
+struct env87 {
+ long en_cw; /* control word (16bits) */
+ long en_sw; /* status word (16bits) */
+ long en_tw; /* tag word (16bits) */
+ long en_fip; /* floating point instruction pointer */
+ u_short en_fcs; /* floating code segment selector */
+ u_short en_opcode; /* opcode last executed (11 bits ) */
+ long en_foo; /* floating operand offset */
+ long en_fos; /* floating operand segment selector */
+};
+
+/* Contents of each floating point accumulator */
+struct fpacc87 {
+#ifdef dontdef /* too unportable */
+ u_long fp_mantlo; /* mantissa low (31:0) */
+ u_long fp_manthi; /* mantissa high (63:32) */
+ int fp_exp:15; /* exponent */
+ int fp_sgn:1; /* mantissa sign */
+#else
+ u_char fp_bytes[10];
+#endif
+};
+
+/* Floating point context */
+struct save87 {
+ struct env87 sv_env; /* floating point control/status */
+ struct fpacc87 sv_ac[8]; /* accumulator contents, 0-7 */
+ u_long sv_ex_sw; /* status word for last exception (was pad) */
+ u_long sv_ex_tw; /* tag word for last exception (was pad) */
+#ifdef GPL_MATH_EMULATE
+ u_char sv_pad[60];
+#else
+ u_char sv_pad[8 * 2 - 2 * 4]; /* bogus historical padding */
+#endif /* GPL_MATH_EMULATE */
+};
+
+/* Cyrix EMC memory - mapped coprocessor context switch information */
+struct emcsts {
+ long em_msw; /* memory mapped status register when swtched */
+ long em_tar; /* memory mapped temp A register when swtched */
+ long em_dl; /* memory mapped D low register when swtched */
+};
+
+/* Intel prefers long real (53 bit) precision */
+#define __iBCS_NPXCW__ 0x262
+/* wfj prefers temporary real (64 bit) precision */
+#define __386BSD_NPXCW__ 0x362
+/*
+ * bde prefers 53 bit precision and all exceptions masked.
+ *
+ * The standard control word from finit is 0x37F, giving:
+ *
+ * round to nearest
+ * 64-bit precision
+ * all exceptions masked.
+ *
+ * Now I want:
+ *
+ * affine mode for 287's (if they work at all) (1 in bitfield 1<<12)
+ * 53-bit precision (2 in bitfield 3<<8)
+ * overflow exception unmasked (0 in bitfield 1<<3)
+ * zero divide exception unmasked (0 in bitfield 1<<2)
+ * invalid-operand exception unmasked (0 in bitfield 1<<0).
+ *
+ * 64-bit precision often gives bad results with high level languages
+ * because it makes the results of calculations depend on whether
+ * intermediate values are stored in memory or in FPU registers.
+ *
+ * The "Intel" and wfj control words have:
+ *
+ * underflow exception unmasked (0 in bitfield 1<<4)
+ *
+ * but that causes an unexpected exception in the test program 'paranoia'
+ * and makes denormals useless (DBL_MIN / 2 underflows). It doesn't make
+ * a lot of sense to trap underflow without trapping denormals.
+ *
+ * Later I will want the IEEE default of all exceptions masked. See the
+ * 0.0 math manpage for why this is better. The 0.1 math manpage is empty.
+ */
+#define __BDE_NPXCW__ 0x1272
+#define __BETTER_BDE_NPXCW__ 0x127f
+
+#ifdef __BROKEN_NPXCW__
+#ifdef __386BSD__
+#define __INITIAL_NPXCW__ __386BSD_NPXCW__
+#else
+#define __INITIAL_NPXCW__ __iBCS_NPXCW__
+#endif
+#else
+#define __INITIAL_NPXCW__ __BDE_NPXCW__
+#endif
+
+#endif ___NPX87___
diff --git a/sys/amd64/include/frame.h b/sys/amd64/include/frame.h
new file mode 100644
index 0000000..05bf265
--- /dev/null
+++ b/sys/amd64/include/frame.h
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)frame.h 5.2 (Berkeley) 1/18/91
+ * $Id: frame.h,v 1.7 1994/01/03 07:55:32 davidg Exp $
+ */
+
+#ifndef _MACHINE_FRAME_H_
+#define _MACHINE_FRAME_H_ 1
+
+#include <sys/signal.h>
+
+/*
+ * System stack frames.
+ */
+
+/*
+ * Exception/Trap Stack Frame
+ */
+
+struct trapframe {
+ int tf_es;
+ int tf_ds;
+ int tf_edi;
+ int tf_esi;
+ int tf_ebp;
+ int tf_isp;
+ int tf_ebx;
+ int tf_edx;
+ int tf_ecx;
+ int tf_eax;
+ int tf_trapno;
+ /* below portion defined in 386 hardware */
+ int tf_err;
+ int tf_eip;
+ int tf_cs;
+ int tf_eflags;
+ /* below only when transitting rings (e.g. user to kernel) */
+ int tf_esp;
+ int tf_ss;
+};
+
+extern int kdb_trap(int, int, struct trapframe *);
+
+/* Interrupt stack frame */
+
+struct intrframe {
+ int if_vec;
+ int if_ppl;
+ int if_es;
+ int if_ds;
+ int if_edi;
+ int if_esi;
+ int if_ebp;
+ int :32;
+ int if_ebx;
+ int if_edx;
+ int if_ecx;
+ int if_eax;
+ int :32; /* for compat with trap frame - trapno */
+ int :32; /* for compat with trap frame - err */
+ /* below portion defined in 386 hardware */
+ int if_eip;
+ int if_cs;
+ int if_eflags;
+ /* below only when transitting rings (e.g. user to kernel) */
+ int if_esp;
+ int if_ss;
+};
+
+/*
+ * Signal frame
+ */
+struct sigframe {
+ int sf_signum;
+ int sf_code;
+ struct sigcontext *sf_scp;
+ char *sf_addr;
+ sig_t sf_handler;
+ struct sigcontext sf_sc;
+};
+#endif /* _MACHINE_FRAME_H_ */
diff --git a/sys/amd64/include/npx.h b/sys/amd64/include/npx.h
new file mode 100644
index 0000000..87cd6f9
--- /dev/null
+++ b/sys/amd64/include/npx.h
@@ -0,0 +1,141 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)npx.h 5.3 (Berkeley) 1/18/91
+ * $Id: npx.h,v 1.2 1993/10/16 14:39:22 rgrimes Exp $
+ */
+
+/*
+ * 287/387 NPX Coprocessor Data Structures and Constants
+ * W. Jolitz 1/90
+ */
+
+#ifndef ___NPX87___
+#define ___NPX87___
+
+/* Environment information of floating point unit */
+struct env87 {
+ long en_cw; /* control word (16bits) */
+ long en_sw; /* status word (16bits) */
+ long en_tw; /* tag word (16bits) */
+ long en_fip; /* floating point instruction pointer */
+ u_short en_fcs; /* floating code segment selector */
+ u_short en_opcode; /* opcode last executed (11 bits ) */
+ long en_foo; /* floating operand offset */
+ long en_fos; /* floating operand segment selector */
+};
+
+/* Contents of each floating point accumulator */
+struct fpacc87 {
+#ifdef dontdef /* too unportable */
+ u_long fp_mantlo; /* mantissa low (31:0) */
+ u_long fp_manthi; /* mantissa high (63:32) */
+ int fp_exp:15; /* exponent */
+ int fp_sgn:1; /* mantissa sign */
+#else
+ u_char fp_bytes[10];
+#endif
+};
+
+/* Floating point context */
+struct save87 {
+ struct env87 sv_env; /* floating point control/status */
+ struct fpacc87 sv_ac[8]; /* accumulator contents, 0-7 */
+ u_long sv_ex_sw; /* status word for last exception (was pad) */
+ u_long sv_ex_tw; /* tag word for last exception (was pad) */
+#ifdef GPL_MATH_EMULATE
+ u_char sv_pad[60];
+#else
+ u_char sv_pad[8 * 2 - 2 * 4]; /* bogus historical padding */
+#endif /* GPL_MATH_EMULATE */
+};
+
+/* Cyrix EMC memory - mapped coprocessor context switch information */
+struct emcsts {
+ long em_msw; /* memory mapped status register when swtched */
+ long em_tar; /* memory mapped temp A register when swtched */
+ long em_dl; /* memory mapped D low register when swtched */
+};
+
+/* Intel prefers long real (53 bit) precision */
+#define __iBCS_NPXCW__ 0x262
+/* wfj prefers temporary real (64 bit) precision */
+#define __386BSD_NPXCW__ 0x362
+/*
+ * bde prefers 53 bit precision and all exceptions masked.
+ *
+ * The standard control word from finit is 0x37F, giving:
+ *
+ * round to nearest
+ * 64-bit precision
+ * all exceptions masked.
+ *
+ * Now I want:
+ *
+ * affine mode for 287's (if they work at all) (1 in bitfield 1<<12)
+ * 53-bit precision (2 in bitfield 3<<8)
+ * overflow exception unmasked (0 in bitfield 1<<3)
+ * zero divide exception unmasked (0 in bitfield 1<<2)
+ * invalid-operand exception unmasked (0 in bitfield 1<<0).
+ *
+ * 64-bit precision often gives bad results with high level languages
+ * because it makes the results of calculations depend on whether
+ * intermediate values are stored in memory or in FPU registers.
+ *
+ * The "Intel" and wfj control words have:
+ *
+ * underflow exception unmasked (0 in bitfield 1<<4)
+ *
+ * but that causes an unexpected exception in the test program 'paranoia'
+ * and makes denormals useless (DBL_MIN / 2 underflows). It doesn't make
+ * a lot of sense to trap underflow without trapping denormals.
+ *
+ * Later I will want the IEEE default of all exceptions masked. See the
+ * 0.0 math manpage for why this is better. The 0.1 math manpage is empty.
+ */
+#define __BDE_NPXCW__ 0x1272
+#define __BETTER_BDE_NPXCW__ 0x127f
+
+#ifdef __BROKEN_NPXCW__
+#ifdef __386BSD__
+#define __INITIAL_NPXCW__ __386BSD_NPXCW__
+#else
+#define __INITIAL_NPXCW__ __iBCS_NPXCW__
+#endif
+#else
+#define __INITIAL_NPXCW__ __BDE_NPXCW__
+#endif
+
+#endif ___NPX87___
diff --git a/sys/amd64/include/pc/display.h b/sys/amd64/include/pc/display.h
new file mode 100644
index 0000000..9e64a3f
--- /dev/null
+++ b/sys/amd64/include/pc/display.h
@@ -0,0 +1,45 @@
+/*
+ * IBM PC display definitions
+ *
+ * $Id$
+ */
+
+/* Color attributes for foreground text */
+
+#define FG_BLACK 0
+#define FG_BLUE 1
+#define FG_GREEN 2
+#define FG_CYAN 3
+#define FG_RED 4
+#define FG_MAGENTA 5
+#define FG_BROWN 6
+#define FG_LIGHTGREY 7
+#define FG_DARKGREY 8
+#define FG_LIGHTBLUE 9
+#define FG_LIGHTGREEN 10
+#define FG_LIGHTCYAN 11
+#define FG_LIGHTRED 12
+#define FG_LIGHTMAGENTA 13
+#define FG_YELLOW 14
+#define FG_WHITE 15
+#define FG_BLINK 0x80
+
+/* Color attributes for text background */
+
+#define BG_BLACK 0x00
+#define BG_BLUE 0x10
+#define BG_GREEN 0x20
+#define BG_CYAN 0x30
+#define BG_RED 0x40
+#define BG_MAGENTA 0x50
+#define BG_BROWN 0x60
+#define BG_LIGHTGREY 0x70
+
+/* Monochrome attributes for foreground text */
+
+#define FG_UNDERLINE 0x01
+#define FG_INTENSE 0x08
+
+/* Monochrome attributes for text background */
+
+#define BG_INTENSE 0x10
diff --git a/sys/amd64/include/pcb.h b/sys/amd64/include/pcb.h
new file mode 100644
index 0000000..a7a29df
--- /dev/null
+++ b/sys/amd64/include/pcb.h
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)pcb.h 5.10 (Berkeley) 5/12/91
+ * $Id: pcb.h,v 1.3 1993/11/07 17:42:59 wollman Exp $
+ */
+
+#ifndef _I386_PCB_H_
+#define _I386_PCB_H_
+
+/*
+ * Intel 386 process control block
+ */
+#include "machine/tss.h"
+#include "machine/npx.h"
+
+struct pcb {
+ struct i386tss pcb_tss;
+#define pcb_ksp pcb_tss.tss_esp0
+#define pcb_ptd pcb_tss.tss_cr3
+#define pcb_cr3 pcb_ptd
+#define pcb_pc pcb_tss.tss_eip
+#define pcb_psl pcb_tss.tss_eflags
+#define pcb_usp pcb_tss.tss_esp
+#define pcb_fp pcb_tss.tss_ebp
+#ifdef notyet
+ u_char pcb_iomap[NPORT/sizeof(u_char)]; /* i/o port bitmap */
+#endif
+ caddr_t pcb_ldt; /* per process (user) LDT */
+ int pcb_ldt_len; /* number of LDT entries */
+ struct save87 pcb_savefpu; /* floating point state for 287/387 */
+ struct emcsts pcb_saveemc; /* Cyrix EMC state */
+/*
+ * Software pcb (extension)
+ */
+ int pcb_flags;
+#ifdef notused
+#define FP_WASUSED 0x01 /* process has used fltng pnt hardware */
+#define FP_NEEDSSAVE 0x02 /* ... that needs save on next context switch */
+#define FP_NEEDSRESTORE 0x04 /* ... that needs restore on next DNA fault */
+#endif
+#define FP_USESEMC 0x08 /* process uses EMC memory-mapped mode */
+#define FP_SOFTFP 0x20 /* process using software fltng pnt emulator */
+ short pcb_iml; /* interrupt mask level */
+ caddr_t pcb_onfault; /* copyin/out fault recovery */
+ long pcb_sigc[8]; /* XXX signal code trampoline */
+ int pcb_cmap2; /* XXX temporary PTE - will prefault instead */
+};
+
+#ifdef KERNEL
+extern struct pcb *curpcb; /* our current running pcb */
+#endif
+
+#endif /* _I386_PCB_H_ */
diff --git a/sys/amd64/include/pmap.h b/sys/amd64/include/pmap.h
new file mode 100644
index 0000000..74f002d
--- /dev/null
+++ b/sys/amd64/include/pmap.h
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department and William Jolitz of UUNET Technologies Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Derived from hp300 version by Mike Hibler, this version by William
+ * Jolitz uses a recursive map [a pde points to the page directory] to
+ * map the page tables using the pagetables themselves. This is done to
+ * reduce the impact on kernel virtual memory for lots of sparse address
+ * space, and to reduce the cost of memory to each process.
+ *
+ * from: hp300: @(#)pmap.h 7.2 (Berkeley) 12/16/90
+ * from: @(#)pmap.h 7.4 (Berkeley) 5/12/91
+ * $Id: pmap.h,v 1.12 1994/03/24 23:12:48 davidg Exp $
+ */
+
+#ifndef _PMAP_MACHINE_
+#define _PMAP_MACHINE_ 1
+
+#include "vm/vm_prot.h"
+/*
+ * 386 page table entry and page table directory
+ * W.Jolitz, 8/89
+ */
+struct pde
+{
+unsigned int
+ pd_v:1, /* valid bit */
+ pd_prot:2, /* access control */
+ pd_mbz1:2, /* reserved, must be zero */
+ pd_u:1, /* hardware maintained 'used' bit */
+ :1, /* not used */
+ pd_mbz2:2, /* reserved, must be zero */
+ :3, /* reserved for software */
+ pd_pfnum:20; /* physical page frame number of pte's*/
+};
+
+#define PD_MASK 0xffc00000UL /* page directory address bits */
+#define PT_MASK 0x003ff000UL /* page table address bits */
+#define PD_SHIFT 22 /* page directory address shift */
+#define PG_SHIFT 12 /* page table address shift */
+
+struct pte
+{
+unsigned int
+ pg_v:1, /* valid bit */
+ pg_prot:2, /* access control */
+ pg_mbz1:2, /* reserved, must be zero */
+ pg_u:1, /* hardware maintained 'used' bit */
+ pg_m:1, /* hardware maintained modified bit */
+ pg_mbz2:2, /* reserved, must be zero */
+ pg_w:1, /* software, wired down page */
+ :1, /* software (unused) */
+ pg_nc:1, /* 'uncacheable page' bit */
+ pg_pfnum:20; /* physical page frame number */
+};
+
+#define PG_V 0x00000001
+#define PG_RO 0x00000000
+#define PG_RW 0x00000002
+#define PG_u 0x00000004
+#define PG_PROT 0x00000006 /* all protection bits . */
+#define PG_W 0x00000200
+#define PG_N 0x00000800 /* Non-cacheable */
+#define PG_M 0x00000040
+#define PG_U 0x00000020
+#define PG_FRAME 0xfffff000UL
+
+#define PG_NOACC 0
+#define PG_KR 0x00000000
+#define PG_KW 0x00000002
+#define PG_URKR 0x00000004
+#define PG_URKW 0x00000004
+#define PG_UW 0x00000006
+
+/* Garbage for current bastardized pager that assumes a hp300 */
+#define PG_NV 0
+#define PG_CI 0
+
+/*
+ * Page Protection Exception bits
+ */
+#define PGEX_P 0x01 /* Protection violation vs. not present */
+#define PGEX_W 0x02 /* during a Write cycle */
+#define PGEX_U 0x04 /* access from User mode (UPL) */
+
+/* typedef struct pde pd_entry_t; */ /* page directory entry */
+/* typedef struct pte pt_entry_t; */ /* Mach page table entry */
+typedef unsigned int *pd_entry_t;
+typedef unsigned int *pt_entry_t;
+
+/*
+ * NKPDE controls the virtual space of the kernel, what ever is left, minus
+ * the alternate page table area is given to the user (NUPDE)
+ */
+/*
+ * NKPDE controls the virtual space of the kernel, what ever is left is
+ * given to the user (NUPDE)
+ */
+#ifndef NKPT
+#define NKPT 15 /* actual number of kernel pte's */
+#endif
+#ifndef NKPDE
+#define NKPDE 63 /* addressable number of kpte's */
+#endif
+
+#define NUPDE (NPTEPG-NKPDE) /* number of user pde's */
+
+/*
+ * The *PTDI values control the layout of virtual memory
+ *
+ * XXX This works for now, but I am not real happy with it, I'll fix it
+ * right after I fix locore.s and the magic 28K hole
+ */
+#define APTDPTDI (NPTEPG-1) /* alt ptd entry that points to APTD */
+#define KPTDI (APTDPTDI-NKPDE)/* start of kernel virtual pde's */
+#define PTDPTDI (KPTDI-1) /* ptd entry that points to ptd! */
+#define KSTKPTDI (PTDPTDI-1) /* ptd entry for u./kernel&user stack */
+#define KSTKPTEOFF (NBPG/sizeof(pd_entry_t)-UPAGES) /* pte entry for kernel stack */
+
+#define PDESIZE sizeof(pd_entry_t) /* for assembly files */
+#define PTESIZE sizeof(pt_entry_t) /* for assembly files */
+
+/*
+ * Address of current and alternate address space page table maps
+ * and directories.
+ */
+#ifdef KERNEL
+extern pt_entry_t PTmap[], APTmap[], Upte;
+extern pd_entry_t PTD[], APTD[], PTDpde, APTDpde, Upde;
+extern pt_entry_t *Sysmap;
+
+extern int IdlePTD; /* physical address of "Idle" state directory */
+#endif
+
+/*
+ * virtual address to page table entry and
+ * to physical address. Likewise for alternate address space.
+ * Note: these work recursively, thus vtopte of a pte will give
+ * the corresponding pde that in turn maps it.
+ */
+#define vtopte(va) (PTmap + i386_btop(va))
+#define kvtopte(va) vtopte(va)
+#define ptetov(pt) (i386_ptob(pt - PTmap))
+#define vtophys(va) (((int) (*vtopte(va))&PG_FRAME) | ((int)(va) & PGOFSET))
+#define ispt(va) ((va) >= UPT_MIN_ADDRESS && (va) <= KPT_MAX_ADDRESS)
+
+#define avtopte(va) (APTmap + i386_btop(va))
+#define ptetoav(pt) (i386_ptob(pt - APTmap))
+#define avtophys(va) (((int) (*avtopte(va))&PG_FRAME) | ((int)(va) & PGOFSET))
+
+#ifdef KERNEL
+/*
+ * Routine: pmap_kextract
+ * Function:
+ * Extract the physical page address associated
+ * kernel virtual address.
+ */
+static inline vm_offset_t
+pmap_kextract(va)
+ vm_offset_t va;
+{
+ vm_offset_t pa = *(int *)vtopte(va);
+ pa = (pa & PG_FRAME) | (va & ~PG_FRAME);
+ return pa;
+}
+#endif
+
+/*
+ * macros to generate page directory/table indicies
+ */
+
+#define pdei(va) (((va)&PD_MASK)>>PD_SHIFT)
+#define ptei(va) (((va)&PT_MASK)>>PG_SHIFT)
+
+/*
+ * Pmap stuff
+ */
+
+struct pmap {
+ pd_entry_t *pm_pdir; /* KVA of page directory */
+ boolean_t pm_pdchanged; /* pdir changed */
+ short pm_dref; /* page directory ref count */
+ short pm_count; /* pmap reference count */
+ simple_lock_data_t pm_lock; /* lock on pmap */
+ struct pmap_statistics pm_stats; /* pmap statistics */
+ long pm_ptpages; /* more stats: PT pages */
+};
+
+typedef struct pmap *pmap_t;
+
+#ifdef KERNEL
+extern pmap_t kernel_pmap;
+#endif
+
+/*
+ * Macros for speed
+ */
+#define PMAP_ACTIVATE(pmapp, pcbp) \
+ if ((pmapp) != NULL /*&& (pmapp)->pm_pdchanged */) { \
+ (pcbp)->pcb_cr3 = \
+ pmap_extract(kernel_pmap, (vm_offset_t)(pmapp)->pm_pdir); \
+ if ((pmapp) == &curproc->p_vmspace->vm_pmap) \
+ load_cr3((pcbp)->pcb_cr3); \
+ (pmapp)->pm_pdchanged = FALSE; \
+ }
+
+#define PMAP_DEACTIVATE(pmapp, pcbp)
+
+/*
+ * For each vm_page_t, there is a list of all currently valid virtual
+ * mappings of that page. An entry is a pv_entry_t, the list is pv_table.
+ */
+typedef struct pv_entry {
+ struct pv_entry *pv_next; /* next pv_entry */
+ pmap_t pv_pmap; /* pmap where mapping lies */
+ vm_offset_t pv_va; /* virtual address for mapping */
+} *pv_entry_t;
+
+#define PV_ENTRY_NULL ((pv_entry_t) 0)
+
+#define PV_CI 0x01 /* all entries must be cache inhibited */
+#define PV_PTPAGE 0x02 /* entry maps a page table page */
+
+#ifdef KERNEL
+
+pv_entry_t pv_table; /* array of entries, one per page */
+
+#define pa_index(pa) atop(pa - vm_first_phys)
+#define pa_to_pvh(pa) (&pv_table[pa_index(pa)])
+
+#define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count)
+
+extern pmap_t pmap_create(vm_size_t);
+extern void pmap_pinit(struct pmap *);
+extern void pmap_destroy(pmap_t);
+extern void pmap_release(struct pmap *);
+extern void pmap_reference(pmap_t);
+extern void pmap_remove(struct pmap *, vm_offset_t, vm_offset_t);
+extern void pmap_protect(struct pmap *, vm_offset_t, vm_offset_t, vm_prot_t);
+extern void pmap_enter(pmap_t, vm_offset_t, vm_offset_t, vm_prot_t, boolean_t);
+extern void pmap_change_wiring(pmap_t, vm_offset_t, boolean_t);
+extern inline pt_entry_t *pmap_pte(pmap_t, vm_offset_t);
+extern vm_offset_t pmap_extract(pmap_t, vm_offset_t);
+extern void pmap_copy(pmap_t, pmap_t, vm_offset_t, vm_size_t, vm_offset_t);
+extern void pmap_collect(pmap_t);
+struct pcb; extern void pmap_activate(pmap_t, struct pcb *);
+extern pmap_t pmap_kernel(void);
+extern void pmap_pageable(pmap_t, vm_offset_t, vm_offset_t, boolean_t);
+
+
+#endif /* KERNEL */
+
+#endif /* _PMAP_MACHINE_ */
diff --git a/sys/amd64/include/proc.h b/sys/amd64/include/proc.h
new file mode 100644
index 0000000..1b9e4a2
--- /dev/null
+++ b/sys/amd64/include/proc.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)proc.h 7.1 (Berkeley) 5/15/91
+ * $Id: proc.h,v 1.2 1993/10/16 14:39:24 rgrimes Exp $
+ */
+
+#ifndef _MACHINE_PROC_H_
+#define _MACHINE_PROC_H_ 1
+
+/*
+ * Machine-dependent part of the proc structure for hp300.
+ */
+struct mdproc {
+ int md_flags; /* machine-dependent flags */
+#ifdef notyet
+ int *p_regs; /* registers on current frame */
+#endif
+};
+
+/* md_flags */
+#define MDP_AST 0x0001 /* async trap pending */
+#endif /* _MACHINE_PROC_H_ */
diff --git a/sys/amd64/include/psl.h b/sys/amd64/include/psl.h
new file mode 100644
index 0000000..997fb23
--- /dev/null
+++ b/sys/amd64/include/psl.h
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)psl.h 5.2 (Berkeley) 1/18/91
+ * $Id: psl.h,v 1.3 1993/11/07 17:43:04 wollman Exp $
+ */
+
+#ifndef _MACHINE_PSL_H_
+#define _MACHINE_PSL_H_ 1
+
+/*
+ * 386 processor status longword.
+ */
+#define PSL_C 0x00000001 /* carry bit */
+#define PSL_PF 0x00000004 /* parity bit */
+#define PSL_AF 0x00000010 /* bcd carry bit */
+#define PSL_Z 0x00000040 /* zero bit */
+#define PSL_N 0x00000080 /* negative bit */
+#define PSL_T 0x00000100 /* trace enable bit */
+#define PSL_I 0x00000200 /* interrupt enable bit */
+#define PSL_D 0x00000400 /* string instruction direction bit */
+#define PSL_V 0x00000800 /* overflow bit */
+#define PSL_IOPL 0x00003000 /* i/o priviledge level enable */
+#define PSL_NT 0x00004000 /* nested task bit */
+#define PSL_RF 0x00010000 /* restart flag bit */
+#define PSL_VM 0x00020000 /* virtual 8086 mode bit */
+
+#define PSL_MBZ 0xffc08028 /* must be zero bits */
+#define PSL_MBO 0x00000002 /* must be one bits */
+
+#define PSL_USERSET (PSL_MBO | PSL_I)
+#define PSL_USERCLR (PSL_MBZ | PSL_NT)
+#endif /* _MACHINE_PSL_H_ */
diff --git a/sys/amd64/include/reg.h b/sys/amd64/include/reg.h
new file mode 100644
index 0000000..d20f8d0
--- /dev/null
+++ b/sys/amd64/include/reg.h
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)reg.h 5.5 (Berkeley) 1/18/91
+ * $Id: reg.h,v 1.6 1994/01/03 07:55:34 davidg Exp $
+ */
+
+#ifndef _MACHINE_REG_H_
+#define _MACHINE_REG_H_ 1
+
+/*
+ * Location of the users' stored
+ * registers within appropriate frame of 'trap' and 'syscall', relative to
+ * base of stack frame.
+ * Normal usage is u.u_ar0[XX] in kernel.
+ */
+
+/* When referenced during a trap/exception, registers are at these offsets */
+
+#define tES (0)
+#define tDS (1)
+#define tEDI (2)
+#define tESI (3)
+#define tEBP (4)
+#define tISP (5)
+#define tEBX (6)
+#define tEDX (7)
+#define tECX (8)
+#define tEAX (9)
+
+#define tERR (11)
+
+#define tEIP (12)
+#define tCS (13)
+#define tEFLAGS (14)
+#define tESP (15)
+#define tSS (16)
+
+/*
+ * Registers accessible to ptrace(2) syscall for debugger
+ * The machine-dependent code for PT_{SET,GET}REGS needs to
+ * use whichver order, defined above, is correct, so that it
+ * is all invisible to the user.
+ */
+struct regs {
+ unsigned int r_es;
+ unsigned int r_ds;
+ unsigned int r_edi;
+ unsigned int r_esi;
+ unsigned int r_ebp;
+ unsigned int r_ebx;
+ unsigned int r_edx;
+ unsigned int r_ecx;
+ unsigned int r_eax;
+ unsigned int r_eip;
+ unsigned int r_cs;
+ unsigned int r_eflags;
+ unsigned int r_esp;
+ unsigned int r_ss;
+ unsigned int r_fs;
+ unsigned int r_gs;
+};
+
+#endif /* _MACHINE_REG_H_ */
diff --git a/sys/amd64/include/segments.h b/sys/amd64/include/segments.h
new file mode 100644
index 0000000..023a0cf
--- /dev/null
+++ b/sys/amd64/include/segments.h
@@ -0,0 +1,235 @@
+/*-
+ * Copyright (c) 1989, 1990 William F. Jolitz
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)segments.h 7.1 (Berkeley) 5/9/91
+ * $Id: segments.h,v 1.3 1993/11/07 17:43:08 wollman Exp $
+ */
+
+#ifndef _MACHINE_SEGMENTS_H_
+#define _MACHINE_SEGMENTS_H_ 1
+
+/*
+ * 386 Segmentation Data Structures and definitions
+ * William F. Jolitz (william@ernie.berkeley.edu) 6/20/1989
+ */
+
+/*
+ * Selectors
+ */
+
+#define ISPL(s) ((s)&3) /* what is the priority level of a selector */
+#define SEL_KPL 0 /* kernel priority level */
+#define SEL_UPL 3 /* user priority level */
+#define ISLDT(s) ((s)&SEL_LDT) /* is it local or global */
+#define SEL_LDT 4 /* local descriptor table */
+#define IDXSEL(s) (((s)>>3) & 0x1fff) /* index of selector */
+#define LSEL(s,r) (((s)<<3) | SEL_LDT | r) /* a local selector */
+#define GSEL(s,r) (((s)<<3) | r) /* a global selector */
+
+/*
+ * Memory and System segment descriptors
+ */
+struct segment_descriptor {
+ unsigned sd_lolimit:16 ; /* segment extent (lsb) */
+ unsigned sd_lobase:24 __attribute__ ((packed));
+ /* segment base address (lsb) */
+ unsigned sd_type:5 ; /* segment type */
+ unsigned sd_dpl:2 ; /* segment descriptor priority level */
+ unsigned sd_p:1 ; /* segment descriptor present */
+ unsigned sd_hilimit:4 ; /* segment extent (msb) */
+ unsigned sd_xx:2 ; /* unused */
+ unsigned sd_def32:1 ; /* default 32 vs 16 bit size */
+ unsigned sd_gran:1 ; /* limit granularity (byte/page units)*/
+ unsigned sd_hibase:8 ; /* segment base address (msb) */
+} ;
+
+/*
+ * Gate descriptors (e.g. indirect descriptors)
+ */
+struct gate_descriptor {
+ unsigned gd_looffset:16 ; /* gate offset (lsb) */
+ unsigned gd_selector:16 ; /* gate segment selector */
+ unsigned gd_stkcpy:5 ; /* number of stack wds to cpy */
+ unsigned gd_xx:3 ; /* unused */
+ unsigned gd_type:5 ; /* segment type */
+ unsigned gd_dpl:2 ; /* segment descriptor priority level */
+ unsigned gd_p:1 ; /* segment descriptor present */
+ unsigned gd_hioffset:16 ; /* gate offset (msb) */
+} ;
+
+/*
+ * Generic descriptor
+ */
+union descriptor {
+ struct segment_descriptor sd;
+ struct gate_descriptor gd;
+};
+
+ /* system segments and gate types */
+#define SDT_SYSNULL 0 /* system null */
+#define SDT_SYS286TSS 1 /* system 286 TSS available */
+#define SDT_SYSLDT 2 /* system local descriptor table */
+#define SDT_SYS286BSY 3 /* system 286 TSS busy */
+#define SDT_SYS286CGT 4 /* system 286 call gate */
+#define SDT_SYSTASKGT 5 /* system task gate */
+#define SDT_SYS286IGT 6 /* system 286 interrupt gate */
+#define SDT_SYS286TGT 7 /* system 286 trap gate */
+#define SDT_SYSNULL2 8 /* system null again */
+#define SDT_SYS386TSS 9 /* system 386 TSS available */
+#define SDT_SYSNULL3 10 /* system null again */
+#define SDT_SYS386BSY 11 /* system 386 TSS busy */
+#define SDT_SYS386CGT 12 /* system 386 call gate */
+#define SDT_SYSNULL4 13 /* system null again */
+#define SDT_SYS386IGT 14 /* system 386 interrupt gate */
+#define SDT_SYS386TGT 15 /* system 386 trap gate */
+
+ /* memory segment types */
+#define SDT_MEMRO 16 /* memory read only */
+#define SDT_MEMROA 17 /* memory read only accessed */
+#define SDT_MEMRW 18 /* memory read write */
+#define SDT_MEMRWA 19 /* memory read write accessed */
+#define SDT_MEMROD 20 /* memory read only expand dwn limit */
+#define SDT_MEMRODA 21 /* memory read only expand dwn limit accessed */
+#define SDT_MEMRWD 22 /* memory read write expand dwn limit */
+#define SDT_MEMRWDA 23 /* memory read write expand dwn limit acessed */
+#define SDT_MEME 24 /* memory execute only */
+#define SDT_MEMEA 25 /* memory execute only accessed */
+#define SDT_MEMER 26 /* memory execute read */
+#define SDT_MEMERA 27 /* memory execute read accessed */
+#define SDT_MEMEC 28 /* memory execute only conforming */
+#define SDT_MEMEAC 29 /* memory execute only accessed conforming */
+#define SDT_MEMERC 30 /* memory execute read conforming */
+#define SDT_MEMERAC 31 /* memory execute read accessed conforming */
+
+/* is memory segment descriptor pointer ? */
+#define ISMEMSDP(s) ((s->d_type) >= SDT_MEMRO && (s->d_type) <= SDT_MEMERAC)
+
+/* is 286 gate descriptor pointer ? */
+#define IS286GDP(s) (((s->d_type) >= SDT_SYS286CGT \
+ && (s->d_type) < SDT_SYS286TGT))
+
+/* is 386 gate descriptor pointer ? */
+#define IS386GDP(s) (((s->d_type) >= SDT_SYS386CGT \
+ && (s->d_type) < SDT_SYS386TGT))
+
+/* is gate descriptor pointer ? */
+#define ISGDP(s) (IS286GDP(s) || IS386GDP(s))
+
+/* is segment descriptor pointer ? */
+#define ISSDP(s) (ISMEMSDP(s) || !ISGDP(s))
+
+/* is system segment descriptor pointer ? */
+#define ISSYSSDP(s) (!ISMEMSDP(s) && !ISGDP(s))
+
+/*
+ * Software definitions are in this convenient format,
+ * which are translated into inconvenient segment descriptors
+ * when needed to be used by the 386 hardware
+ */
+
+struct soft_segment_descriptor {
+ unsigned ssd_base ; /* segment base address */
+ unsigned ssd_limit ; /* segment extent */
+ unsigned ssd_type:5 ; /* segment type */
+ unsigned ssd_dpl:2 ; /* segment descriptor priority level */
+ unsigned ssd_p:1 ; /* segment descriptor present */
+ unsigned ssd_xx:4 ; /* unused */
+ unsigned ssd_xx1:2 ; /* unused */
+ unsigned ssd_def32:1 ; /* default 32 vs 16 bit size */
+ unsigned ssd_gran:1 ; /* limit granularity (byte/page units)*/
+};
+
+extern ssdtosd() ; /* to decode a ssd */
+extern sdtossd() ; /* to encode a sd */
+
+/*
+ * region descriptors, used to load gdt/idt tables before segments yet exist.
+ */
+struct region_descriptor {
+ unsigned rd_limit:16; /* segment extent */
+ unsigned rd_base:32 __attribute__ ((packed)); /* base address */
+};
+
+/*
+ * Segment Protection Exception code bits
+ */
+
+#define SEGEX_EXT 0x01 /* recursive or externally induced */
+#define SEGEX_IDT 0x02 /* interrupt descriptor table */
+#define SEGEX_TI 0x04 /* local descriptor table */
+ /* other bits are affected descriptor index */
+#define SEGEX_IDX(s) ((s)>>3)&0x1fff)
+
+/*
+ * Size of IDT table
+ */
+
+#define NIDT 256
+#define NRSVIDT 32 /* reserved entries for cpu exceptions */
+
+/*
+ * Entries in the Global Descriptor Table (GDT)
+ */
+#define GNULL_SEL 0 /* Null Descriptor */
+#define GCODE_SEL 1 /* Kernel Code Descriptor */
+#define GDATA_SEL 2 /* Kernel Data Descriptor */
+#define GLDT_SEL 3 /* LDT - eventually one per process */
+#define GTGATE_SEL 4 /* Process task switch gate */
+#define GPANIC_SEL 5 /* Task state to consider panic from */
+#define GPROC0_SEL 6 /* Task state process slot zero and up */
+#define GUSERLDT_SEL 7 /* User LDT */
+#define NGDT GUSERLDT_SEL+1
+
+/*
+ * Entries in the Local Descriptor Table (LDT)
+ */
+#define LSYS5CALLS_SEL 0 /* forced by intel BCS */
+#define LSYS5SIGR_SEL 1
+#define L43BSDCALLS_SEL 2 /* notyet */
+#define LUCODE_SEL 3
+#define LUDATA_SEL 4
+/* seperate stack, es,fs,gs sels ? */
+/* #define LPOSIXCALLS_SEL 5*/ /* notyet */
+#define NLDT LUDATA_SEL+1
+
+#ifdef KERNEL
+extern int currentldt;
+extern union descriptor gdt[NGDT];
+extern union descriptor ldt[NLDT];
+extern struct soft_segment_descriptor gdt_segs[];
+#endif
+
+#endif /* _MACHINE_SEGMENTS_H_ */
diff --git a/sys/amd64/include/specialreg.h b/sys/amd64/include/specialreg.h
new file mode 100644
index 0000000..935b1ed
--- /dev/null
+++ b/sys/amd64/include/specialreg.h
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)specialreg.h 7.1 (Berkeley) 5/9/91
+ * $Id: specialreg.h,v 1.2 1993/10/16 14:39:32 rgrimes Exp $
+ */
+
+#ifndef _MACHINE_SPECIALREG_H_
+#define _MACHINE_SPECIALREG_H_ 1
+
+/*
+ * Bits in 386 special registers:
+ */
+
+#define CR0_PE 0x00000001 /* Protected mode Enable */
+#define CR0_MP 0x00000002 /* "Math" Present (NPX or NPX emulator) */
+#ifdef notused
+#define CR0_EM 0x00000004 /* EMulate non-NPX coproc. (trap ESC only) */
+#endif
+#define CR0_TS 0x00000008 /* Task Switched (if MP, trap ESC and WAIT) */
+#ifdef notused
+#define CR0_ET 0x00000010 /* Extension Type (387 (if set) vs 287) */
+#endif
+#define CR0_PG 0x80000000 /* PaGing enable */
+
+/*
+ * Bits in 486 special registers:
+ */
+
+#define CR0_NE 0x00000020 /* Numeric Error enable (EX16 vs IRQ13) */
+#define CR0_WP 0x00010000 /* Write Protect (honor ~PG_W in all modes) */
+#ifdef notyet
+#define CR0_AM 0x00040000 /* Alignment Mask (set to enable AC flag) */
+#endif
+#endif /* _MACHINE_SPECIALREG_H_ */
diff --git a/sys/amd64/include/sysarch.h b/sys/amd64/include/sysarch.h
new file mode 100644
index 0000000..2649ba5
--- /dev/null
+++ b/sys/amd64/include/sysarch.h
@@ -0,0 +1,24 @@
+/*
+ * Architecture specific syscalls (i386)
+ *
+ * $Id: sysarch.h,v 1.2 1993/10/16 14:39:35 rgrimes Exp $
+ */
+#ifndef _MACHINE_SYSARCH_H_
+#define _MACHINE_SYSARCH_H_ 1
+
+#include <sys/cdefs.h>
+
+#define I386_GET_LDT 0
+#define I386_SET_LDT 1
+
+#ifdef KERNEL
+/* nothing here yet... */
+#else /* not KERNEL */
+__BEGIN_DECLS
+
+int i386_get_ldt __P((int, union descriptor *, int));
+int i386_set_ldt __P((int, union descriptor *, int));
+
+__END_DECLS
+#endif /* not KERNEL */
+#endif /* _MACHINE_SYSARCH_H_ */
diff --git a/sys/amd64/include/trap.h b/sys/amd64/include/trap.h
new file mode 100644
index 0000000..aa832ff
--- /dev/null
+++ b/sys/amd64/include/trap.h
@@ -0,0 +1,101 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)trap.h 5.4 (Berkeley) 5/9/91
+ * $Id: trap.h,v 1.2 1993/10/16 14:39:37 rgrimes Exp $
+ */
+
+#ifndef _MACHINE_TRAP_H_
+#define _MACHINE_TRAP_H_ 1
+
+/*
+ * Trap type values
+ * also known in trap.c for name strings
+ */
+
+#define T_RESADFLT 0 /* reserved addressing */
+#define T_PRIVINFLT 1 /* privileged instruction */
+#define T_RESOPFLT 2 /* reserved operand */
+#define T_BPTFLT 3 /* breakpoint instruction */
+#define T_SYSCALL 5 /* system call (kcall) */
+#define T_ARITHTRAP 6 /* arithmetic trap */
+#define T_ASTFLT 7 /* system forced exception */
+#define T_SEGFLT 8 /* segmentation (limit) fault */
+#define T_PROTFLT 9 /* protection fault */
+#define T_TRCTRAP 10 /* trace trap */
+#define T_PAGEFLT 12 /* page fault */
+#define T_TABLEFLT 13 /* page table fault */
+#define T_ALIGNFLT 14 /* alignment fault */
+#define T_KSPNOTVAL 15 /* kernel stack pointer not valid */
+#define T_BUSERR 16 /* bus error */
+#define T_KDBTRAP 17 /* kernel debugger trap */
+
+#define T_DIVIDE 18 /* integer divide fault */
+#define T_NMI 19 /* non-maskable trap */
+#define T_OFLOW 20 /* overflow trap */
+#define T_BOUND 21 /* bound instruction fault */
+#define T_DNA 22 /* device not available fault */
+#define T_DOUBLEFLT 23 /* double fault */
+#define T_FPOPFLT 24 /* fp coprocessor operand fetch fault */
+#define T_TSSFLT 25 /* invalid tss fault */
+#define T_SEGNPFLT 26 /* segment not present fault */
+#define T_STKFLT 27 /* stack fault */
+#define T_RESERVED 28 /* reserved fault base */
+
+/* definitions for <sys/signal.h> */
+#define ILL_RESAD_FAULT T_RESADFLT
+#define ILL_PRIVIN_FAULT T_PRIVINFLT
+#define ILL_RESOP_FAULT T_RESOPFLT
+#define ILL_ALIGN_FAULT T_ALIGNFLT
+#define ILL_FPOP_FAULT T_FPOPFLT /* coprocessor operand fault */
+
+/* codes for SIGFPE/ARITHTRAP */
+#define FPE_INTOVF_TRAP 0x1 /* integer overflow */
+#define FPE_INTDIV_TRAP 0x2 /* integer divide by zero */
+#define FPE_FLTDIV_TRAP 0x3 /* floating/decimal divide by zero */
+#define FPE_FLTOVF_TRAP 0x4 /* floating overflow */
+#define FPE_FLTUND_TRAP 0x5 /* floating underflow */
+#define FPE_FPU_NP_TRAP 0x6 /* floating point unit not present */
+#define FPE_SUBRNG_TRAP 0x7 /* subrange out of bounds */
+
+/* codes for SIGBUS */
+#define BUS_PAGE_FAULT T_PAGEFLT /* page fault protection base */
+#define BUS_SEGNP_FAULT T_SEGNPFLT /* segment not present */
+#define BUS_STK_FAULT T_STKFLT /* stack segment */
+#define BUS_SEGM_FAULT T_RESERVED /* segment protection base */
+
+/* Trap's coming from user mode */
+#define T_USER 0x100
+#endif /* _MACHINE_TRAP_H_ */
diff --git a/sys/amd64/include/tss.h b/sys/amd64/include/tss.h
new file mode 100644
index 0000000..1fada6e
--- /dev/null
+++ b/sys/amd64/include/tss.h
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)tss.h 5.4 (Berkeley) 1/18/91
+ * $Id: tss.h,v 1.3 1993/11/07 17:43:16 wollman Exp $
+ */
+
+#ifndef _MACHINE_TSS_H_
+#define _MACHINE_TSS_H_ 1
+
+/*
+ * Intel 386 Context Data Type
+ */
+
+struct i386tss {
+ int tss_link; /* actually 16 bits: top 16 bits must be zero */
+ int tss_esp0; /* kernel stack pointer priviledge level 0 */
+#define tss_ksp tss_esp0
+ int tss_ss0; /* actually 16 bits: top 16 bits must be zero */
+ int tss_esp1; /* kernel stack pointer priviledge level 1 */
+ int tss_ss1; /* actually 16 bits: top 16 bits must be zero */
+ int tss_esp2; /* kernel stack pointer priviledge level 2 */
+ int tss_ss2; /* actually 16 bits: top 16 bits must be zero */
+ int tss_cr3; /* page table directory */
+#define tss_ptd tss_cr3
+ int tss_eip; /* program counter */
+#define tss_pc tss_eip
+ int tss_eflags; /* program status longword */
+#define tss_psl tss_eflags
+ int tss_eax;
+ int tss_ecx;
+ int tss_edx;
+ int tss_ebx;
+ int tss_esp; /* user stack pointer */
+#define tss_usp tss_esp
+ int tss_ebp; /* user frame pointer */
+#define tss_fp tss_ebp
+ int tss_esi;
+ int tss_edi;
+ int tss_es; /* actually 16 bits: top 16 bits must be zero */
+ int tss_cs; /* actually 16 bits: top 16 bits must be zero */
+ int tss_ss; /* actually 16 bits: top 16 bits must be zero */
+ int tss_ds; /* actually 16 bits: top 16 bits must be zero */
+ int tss_fs; /* actually 16 bits: top 16 bits must be zero */
+ int tss_gs; /* actually 16 bits: top 16 bits must be zero */
+ int tss_ldt; /* actually 16 bits: top 16 bits must be zero */
+ int tss_ioopt; /* options & io offset bitmap: currently zero */
+ /* XXX unimplemented .. i/o permission bitmap */
+};
+#endif /* _MACHINE_TSS_H_ */
diff --git a/sys/amd64/include/vmparam.h b/sys/amd64/include/vmparam.h
new file mode 100644
index 0000000..df90126
--- /dev/null
+++ b/sys/amd64/include/vmparam.h
@@ -0,0 +1,277 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ * Copyright (c) 1994 John S. Dyson
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)vmparam.h 5.9 (Berkeley) 5/12/91
+ * $Id: vmparam.h,v 1.11 1994/01/14 16:24:00 davidg Exp $
+ */
+
+
+#ifndef _MACHINE_VMPARAM_H_
+#define _MACHINE_VMPARAM_H_ 1
+
+/*
+ * Machine dependent constants for 386.
+ */
+
+/*
+ * Virtual address space arrangement. On 386, both user and kernel
+ * share the address space, not unlike the vax.
+ * USRTEXT is the start of the user text/data space, while USRSTACK
+ * is the top (end) of the user stack. Immediately above the user stack
+ * resides the user structure, which is UPAGES long and contains the
+ * kernel stack.
+ *
+ * Immediately after the user structure is the page table map, and then
+ * kernal address space.
+ */
+#define USRTEXT 0UL
+/* #define USRSTACK 0xFDBFE000UL */
+#define BTOPUSRSTACK (0xFDC00-(UPAGES)) /* btop(USRSTACK) */
+#define LOWPAGES 0UL
+#define HIGHPAGES UPAGES
+
+/*
+ * Virtual memory related constants, all in bytes
+ */
+#define MAXTSIZ (16UL*1024*1024) /* max text size */
+#ifndef DFLDSIZ
+#define DFLDSIZ (64UL*1024*1024) /* initial data size limit */
+#endif
+#ifndef MAXDSIZ
+#define MAXDSIZ (128UL*1024*1024) /* max data size */
+#endif
+#ifndef DFLSSIZ
+#define DFLSSIZ (8UL*1024*1024) /* initial stack size limit */
+#endif
+#ifndef MAXSSIZ
+#define MAXSSIZ (64UL*1024*1024) /* max stack size */
+#endif
+#ifndef SGROWSIZ
+#define SGROWSIZ (128UL*1024) /* amount to grow stack */
+#endif
+
+/*
+ * Default sizes of swap allocation chunks (see dmap.h).
+ * The actual values may be changed in vminit() based on MAXDSIZ.
+ * With MAXDSIZ of 16Mb and NDMAP of 38, dmmax will be 1024.
+ */
+#define DMMIN 32 /* smallest swap allocation */
+#define DMMAX 4096 /* largest potential swap allocation */
+#define DMTEXT 1024 /* swap allocation for text */
+
+/*
+ * Sizes of the system and user portions of the system page table.
+ */
+#define SYSPTSIZE (2*NPTEPG)
+#define USRPTSIZE (2*NPTEPG)
+
+/*
+ * Size of the Shared Memory Pages page table.
+ */
+#ifndef SHMMAXPGS
+#define SHMMAXPGS 512 /* XXX until we have more kmap space */
+#endif
+
+/*
+ * Size of User Raw I/O map
+ */
+#define USRIOSIZE 1024
+
+/*
+ * The size of the clock loop.
+ */
+#define LOOPPAGES (maxfree - firstfree)
+
+/*
+ * The time for a process to be blocked before being very swappable.
+ * This is a number of seconds which the system takes as being a non-trivial
+ * amount of real time. You probably shouldn't change this;
+ * it is used in subtle ways (fractions and multiples of it are, that is, like
+ * half of a ``long time'', almost a long time, etc.)
+ * It is related to human patience and other factors which don't really
+ * change over time.
+ */
+#define MAXSLP 20
+
+/*
+ * A swapped in process is given a small amount of core without being bothered
+ * by the page replacement algorithm. Basically this says that if you are
+ * swapped in you deserve some resources. We protect the last SAFERSS
+ * pages against paging and will just swap you out rather than paging you.
+ * Note that each process has at least UPAGES+CLSIZE pages which are not
+ * paged anyways (this is currently 8+2=10 pages or 5k bytes), so this
+ * number just means a swapped in process is given around 25k bytes.
+ * Just for fun: current memory prices are 4600$ a megabyte on VAX (4/22/81),
+ * so we loan each swapped in process memory worth 100$, or just admit
+ * that we don't consider it worthwhile and swap it out to disk which costs
+ * $30/mb or about $0.75.
+ * { wfj 6/16/89: Retail AT memory expansion $800/megabyte, loan of $17
+ * on disk costing $7/mb or $0.18 (in memory still 100:1 in cost!) }
+ */
+#define SAFERSS 8 /* nominal ``small'' resident set size
+ protected against replacement */
+
+/*
+ * DISKRPM is used to estimate the number of paging i/o operations
+ * which one can expect from a single disk controller.
+ */
+#define DISKRPM 60
+
+/*
+ * Klustering constants. Klustering is the gathering
+ * of pages together for pagein/pageout, while clustering
+ * is the treatment of hardware page size as though it were
+ * larger than it really is.
+ *
+ * KLMAX gives maximum cluster size in CLSIZE page (cluster-page)
+ * units. Note that KLMAX*CLSIZE must be <= DMMIN in dmap.h.
+ */
+
+#define KLMAX (4/CLSIZE)
+#define KLSEQL (2/CLSIZE) /* in klust if vadvise(VA_SEQL) */
+#define KLIN (4/CLSIZE) /* default data/stack in klust */
+#define KLTXT (4/CLSIZE) /* default text in klust */
+#define KLOUT (4/CLSIZE)
+
+/*
+ * KLSDIST is the advance or retard of the fifo reclaim for sequential
+ * processes data space.
+ */
+#define KLSDIST 3 /* klusters advance/retard for seq. fifo */
+
+/*
+ * Paging thresholds (see vm_sched.c).
+ * Strategy of 1/19/85:
+ * lotsfree is 512k bytes, but at most 1/4 of memory
+ * desfree is 200k bytes, but at most 1/8 of memory
+ * minfree is 64k bytes, but at most 1/2 of desfree
+ */
+#define LOTSFREE (512 * 1024)
+#define LOTSFREEFRACT 4
+#define DESFREE (200 * 1024)
+#define DESFREEFRACT 8
+#define MINFREE (64 * 1024)
+#define MINFREEFRACT 2
+
+/*
+ * There are two clock hands, initially separated by HANDSPREAD bytes
+ * (but at most all of user memory). The amount of time to reclaim
+ * a page once the pageout process examines it increases with this
+ * distance and decreases as the scan rate rises.
+ */
+#define HANDSPREAD (2 * 1024 * 1024)
+
+/*
+ * The number of times per second to recompute the desired paging rate
+ * and poke the pagedaemon.
+ */
+#define RATETOSCHEDPAGING 4
+
+/*
+ * Believed threshold (in megabytes) for which interleaved
+ * swapping area is desirable.
+ */
+#define LOTSOFMEM 2
+
+#define mapin(pte, v, pfnum, prot) \
+ {(*(int *)(pte) = ((pfnum)<<PGSHIFT) | (prot)) ; }
+
+/*
+ * Mach derived constants
+ */
+
+/* user/kernel map constants */
+#define KERNBASE (0-(NKPDE+1)*(NBPG*NPTEPG))
+#define KERNSIZE (NKPDE*NBPG*NPTEPG)
+
+#define VM_MIN_ADDRESS ((vm_offset_t)0)
+#define VM_MAXUSER_ADDRESS ((vm_offset_t)KERNBASE - (NBPG*(NPTEPG+UPAGES)))
+#define USRSTACK VM_MAXUSER_ADDRESS
+#define UPT_MIN_ADDRESS ((vm_offset_t)KERNBASE - (NBPG*NPTEPG))
+#define UPT_MAX_ADDRESS ((vm_offset_t)KERNBASE - (NBPG*(NKPDE+2)))
+#define VM_MAX_ADDRESS UPT_MAX_ADDRESS
+#define VM_MIN_KERNEL_ADDRESS ((vm_offset_t)KERNBASE - (NBPG*(NKPDE+2)))
+#define UPDT VM_MIN_KERNEL_ADDRESS
+#define KPT_MIN_ADDRESS ((vm_offset_t)(KERNBASE) - (NBPG*(NKPDE+1)))
+#define KPT_MAX_ADDRESS ((vm_offset_t)(KERNBASE) - NBPG)
+#define VM_MAX_KERNEL_ADDRESS ((vm_offset_t)ALT_MIN_ADDRESS - NBPG)
+#define ALT_MIN_ADDRESS ((vm_offset_t)((APTDPTDI) << 22))
+#define HIGHPAGES UPAGES
+
+
+/* virtual sizes (bytes) for various kernel submaps */
+#define VM_MBUF_SIZE (NMBCLUSTERS*MCLBYTES)
+#define VM_KMEM_SIZE (16 * 1024 * 1024)
+#define VM_PHYS_SIZE (USRIOSIZE*CLBYTES)
+
+/* pcb base */
+#define pcbb(p) ((u_int)(p)->p_addr)
+
+/*
+ * Flush MMU TLB
+ */
+
+#ifndef I386_CR3PAT
+#define I386_CR3PAT 0x0
+#endif
+
+#ifdef notyet
+#define _cr3() ({u_long rtn; \
+ asm (" movl %%cr3,%%eax; movl %%eax,%0 " \
+ : "=g" (rtn) \
+ : \
+ : "ax"); \
+ rtn; \
+})
+
+#define load_cr3(s) ({ u_long val; \
+ val = (s) | I386_CR3PAT; \
+ asm ("movl %0,%%eax; movl %%eax,%%cr3" \
+ : \
+ : "g" (val) \
+ : "ax"); \
+})
+
+#define tlbflush() ({ u_long val; \
+ val = u.u_pcb.pcb_ptd | I386_CR3PAT; \
+ asm ("movl %0,%%eax; movl %%eax,%%cr3" \
+ : \
+ : "g" (val) \
+ : "ax"); \
+})
+#endif
+#endif /* _MACHINE_VMPARAM_H_ */
diff --git a/sys/amd64/isa/clock.c b/sys/amd64/isa/clock.c
new file mode 100644
index 0000000..d338cd5
--- /dev/null
+++ b/sys/amd64/isa/clock.c
@@ -0,0 +1,430 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz and Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)clock.c 7.2 (Berkeley) 5/12/91
+ * $Id: clock.c,v 1.6 1994/02/06 22:48:13 davidg Exp $
+ */
+
+/*
+ * Primitive clock interrupt routines.
+ */
+#include "param.h"
+#include "systm.h"
+#include "time.h"
+#include "kernel.h"
+#include "machine/segments.h"
+#include "machine/frame.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/rtc.h"
+#include "i386/isa/timerreg.h"
+
+/* X-tals being what they are, it's nice to be able to fudge this one... */
+/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */
+#ifndef TIMER_FREQ
+#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
+#endif
+#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
+
+void hardclock();
+static int beeping;
+int timer0_divisor = TIMER_DIV(100); /* XXX should be hz */
+u_int timer0_prescale;
+static char timer0_state = 0, timer2_state = 0;
+static char timer0_reprogram = 0;
+static void (*timer_func)() = hardclock;
+static void (*new_function)();
+static u_int new_rate;
+static u_int hardclock_divisor;
+
+
+void
+timerintr(struct intrframe frame)
+{
+ timer_func(frame);
+ switch (timer0_state) {
+ case 0:
+ break;
+ case 1:
+ if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
+ hardclock(frame);
+ timer0_prescale = 0;
+ }
+ break;
+ case 2:
+ disable_intr();
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+ outb(TIMER_CNTR0, TIMER_DIV(new_rate)%256);
+ outb(TIMER_CNTR0, TIMER_DIV(new_rate)/256);
+ enable_intr();
+ timer0_divisor = TIMER_DIV(new_rate);
+ timer0_prescale = 0;
+ timer_func = new_function;
+ timer0_state = 1;
+ break;
+ case 3:
+ if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
+ hardclock(frame);
+ disable_intr();
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+ outb(TIMER_CNTR0, TIMER_DIV(hz)%256);
+ outb(TIMER_CNTR0, TIMER_DIV(hz)/256);
+ enable_intr();
+ timer0_divisor = TIMER_DIV(hz);
+ timer0_prescale = 0;
+ timer_func = hardclock;;
+ timer0_state = 0;
+ }
+ break;
+ }
+}
+
+
+int
+acquire_timer0(int rate, void (*function)() )
+{
+ if (timer0_state || !function)
+ return -1;
+
+ new_function = function;
+ new_rate = rate;
+ timer0_state = 2;
+ return 0;
+}
+
+
+int
+acquire_timer2(int mode)
+{
+ if (timer2_state)
+ return -1;
+ timer2_state = 1;
+ outb(TIMER_MODE, TIMER_SEL2 | (mode &0x3f));
+ return 0;
+}
+
+
+int
+release_timer0()
+{
+ if (!timer0_state)
+ return -1;
+ timer0_state = 3;
+ return 0;
+}
+
+
+int
+release_timer2()
+{
+ if (!timer2_state)
+ return -1;
+ timer2_state = 0;
+ outb(TIMER_MODE, TIMER_SEL2|TIMER_SQWAVE|TIMER_16BIT);
+ return 0;
+}
+
+
+static int
+getit()
+{
+ int high, low;
+
+ disable_intr();
+ /* select timer0 and latch counter value */
+ outb(TIMER_MODE, TIMER_SEL0);
+ low = inb(TIMER_CNTR0);
+ high = inb(TIMER_CNTR0);
+ enable_intr();
+ return ((high << 8) | low);
+}
+
+
+/*
+ * Wait "n" microseconds.
+ * Relies on timer 1 counting down from (TIMER_FREQ / hz)
+ * Note: timer had better have been programmed before this is first used!
+ */
+void
+DELAY(int n)
+{
+ int counter_limit, prev_tick, tick, ticks_left, sec, usec;
+
+#ifdef DELAYDEBUG
+ int getit_calls = 1;
+ int n1;
+ static int state = 0;
+
+ if (state == 0) {
+ state = 1;
+ for (n1 = 1; n1 <= 10000000; n1 *= 10)
+ DELAY(n1);
+ state = 2;
+ }
+ if (state == 1)
+ printf("DELAY(%d)...", n);
+#endif
+ /*
+ * Read the counter first, so that the rest of the setup overhead is
+ * counted. Guess the initial overhead is 20 usec (on most systems it
+ * takes about 1.5 usec for each of the i/o's in getit(). The loop
+ * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
+ * multiplications and divisions to scale the count take a while).
+ */
+ prev_tick = getit(0, 0);
+ n -= 20;
+ /*
+ * Calculate (n * (TIMER_FREQ / 1e6)) without using floating point
+ * and without any avoidable overflows.
+ */
+ sec = n / 1000000;
+ usec = n - sec * 1000000;
+ ticks_left = sec * TIMER_FREQ
+ + usec * (TIMER_FREQ / 1000000)
+ + usec * ((TIMER_FREQ % 1000000) / 1000) / 1000
+ + usec * (TIMER_FREQ % 1000) / 1000000;
+
+ while (ticks_left > 0) {
+ tick = getit(0, 0);
+#ifdef DELAYDEBUG
+ ++getit_calls;
+#endif
+ if (tick > prev_tick)
+ ticks_left -= prev_tick - (tick - timer0_divisor);
+ else
+ ticks_left -= prev_tick - tick;
+ prev_tick = tick;
+ }
+#ifdef DELAYDEBUG
+ if (state == 1)
+ printf(" %d calls to getit() at %d usec each\n",
+ getit_calls, (n + 5) / getit_calls);
+#endif
+}
+
+
+static void
+sysbeepstop()
+{
+ outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */
+ release_timer2();
+ beeping = 0;
+}
+
+
+int
+sysbeep(int pitch, int period)
+{
+
+ if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT))
+ return -1;
+ disable_intr();
+ outb(TIMER_CNTR2, pitch);
+ outb(TIMER_CNTR2, (pitch>>8));
+ enable_intr();
+ if (!beeping) {
+ outb(IO_PPI, inb(IO_PPI) | 3); /* enable counter2 output to speaker */
+ beeping = period;
+ timeout(sysbeepstop, 0, period);
+ }
+ return 0;
+}
+
+
+void
+startrtclock()
+{
+ int s;
+
+ /* initialize 8253 clock */
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+
+ /* Correct rounding will buy us a better precision in timekeeping */
+ outb (IO_TIMER1, TIMER_DIV(hz)%256);
+ outb (IO_TIMER1, TIMER_DIV(hz)/256);
+ timer0_divisor = hardclock_divisor = TIMER_DIV(hz);
+
+ /* initialize brain-dead battery powered clock */
+ outb (IO_RTC, RTC_STATUSA);
+ outb (IO_RTC+1, 0x26);
+ outb (IO_RTC, RTC_STATUSB);
+ outb (IO_RTC+1, 2);
+
+ outb (IO_RTC, RTC_DIAG);
+ if (s = inb (IO_RTC+1))
+ printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS);
+}
+
+
+/* convert 2 digit BCD number */
+int
+bcd(int i)
+{
+ return ((i/16)*10 + (i%16));
+}
+
+
+/* convert years to seconds (from 1970) */
+unsigned long
+ytos(int y)
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i = 1970; i < y; i++) {
+ if (i % 4) ret += 365*24*60*60;
+ else ret += 366*24*60*60;
+ }
+ return ret;
+}
+
+
+/* convert months to seconds */
+unsigned long
+mtos(int m, int leap)
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i=1; i<m; i++) {
+ switch(i){
+ case 1: case 3: case 5: case 7: case 8: case 10: case 12:
+ ret += 31*24*60*60; break;
+ case 4: case 6: case 9: case 11:
+ ret += 30*24*60*60; break;
+ case 2:
+ if (leap) ret += 29*24*60*60;
+ else ret += 28*24*60*60;
+ }
+ }
+ return ret;
+}
+
+
+/*
+ * Initialize the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+void
+inittodr(time_t base)
+{
+ unsigned long sec;
+ int leap, day_week, t, yd;
+ int sa,s;
+
+ /* do we have a realtime clock present? (otherwise we loop below) */
+ sa = rtcin(RTC_STATUSA);
+ if (sa == 0xff || sa == 0) return;
+
+ /* ready for a read? */
+ while ((sa&RTCSA_TUP) == RTCSA_TUP)
+ sa = rtcin(RTC_STATUSA);
+
+ sec = bcd(rtcin(RTC_YEAR)) + 1900;
+ if (sec < 1970)
+ sec += 100;
+
+ leap = !(sec % 4); sec = ytos(sec); /* year */
+ yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec+=yd; /* month */
+ t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec+=t; yd+=t; /* date */
+ day_week = rtcin(RTC_WDAY); /* day */
+ sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */
+ sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */
+ sec += bcd(rtcin(RTC_SEC)); /* seconds */
+ sec += tz.tz_minuteswest * 60;
+ time.tv_sec = sec;
+}
+
+
+#ifdef garbage
+/*
+ * Initialze the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+test_inittodr(time_t base)
+{
+
+ outb(IO_RTC,9); /* year */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,8); /* month */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,7); /* day */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,4); /* hour */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,2); /* minutes */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,0); /* seconds */
+ printf("%d\n",bcd(inb(IO_RTC+1)));
+
+ time.tv_sec = base;
+}
+#endif
+
+
+/*
+ * Restart the clock.
+ */
+void
+resettodr()
+{
+}
+
+
+/*
+ * Wire clock interrupt in.
+ */
+#define V(s) __CONCAT(V, s)
+extern void V(clk)();
+
+
+void
+enablertclock()
+{
+ setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL);
+ INTREN(IRQ0);
+}
+
+
+/*
+ * Delay for some number of milliseconds.
+ */
+void
+spinwait(int millisecs)
+{
+ DELAY(1000 * millisecs);
+}
diff --git a/sys/amd64/isa/icu.h b/sys/amd64/isa/icu.h
new file mode 100644
index 0000000..13216b0
--- /dev/null
+++ b/sys/amd64/isa/icu.h
@@ -0,0 +1,97 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)icu.h 5.6 (Berkeley) 5/9/91
+ * $Id: icu.h,v 1.2 1993/10/16 13:45:51 rgrimes Exp $
+ */
+
+/*
+ * AT/386 Interrupt Control constants
+ * W. Jolitz 8/89
+ */
+
+#ifndef __ICU__
+#define __ICU__
+
+#ifndef LOCORE
+
+/*
+ * Interrupt "level" mechanism variables, masks, and macros
+ */
+extern unsigned imen; /* interrupt mask enable */
+
+#define INTREN(s) (imen &= ~(s), SET_ICUS())
+#define INTRDIS(s) (imen |= (s), SET_ICUS())
+#define INTRMASK(msk,s) (msk |= (s))
+#if 0
+#define SET_ICUS() (outb(IO_ICU1 + 1, imen), outb(IU_ICU2 + 1, imen >> 8))
+#else
+/*
+ * XXX - IO_ICU* are defined in isa.h, not icu.h, and nothing much bothers to
+ * include isa.h, while too many things include icu.h.
+ */
+#define SET_ICUS() (outb(0x21, imen), outb(0xa1, imen >> 8))
+#endif
+
+#endif
+
+/*
+ * Interrupt enable bits - in normal order of priority (which we change)
+ */
+#define IRQ0 0x0001 /* highest priority - timer */
+#define IRQ1 0x0002
+#define IRQ_SLAVE 0x0004
+#define IRQ8 0x0100
+#define IRQ9 0x0200
+#define IRQ2 IRQ9
+#define IRQ10 0x0400
+#define IRQ11 0x0800
+#define IRQ12 0x1000
+#define IRQ13 0x2000
+#define IRQ14 0x4000
+#define IRQ15 0x8000
+#define IRQ3 0x0008 /* this is highest after rotation */
+#define IRQ4 0x0010
+#define IRQ5 0x0020
+#define IRQ6 0x0040
+#define IRQ7 0x0080 /* lowest - parallel printer */
+
+/*
+ * Interrupt Control offset into Interrupt descriptor table (IDT)
+ */
+#define ICU_OFFSET 32 /* 0-31 are processor exceptions */
+#define ICU_LEN 16 /* 32-47 are ISA interrupts */
+
+#endif __ICU__
diff --git a/sys/amd64/isa/isa.c b/sys/amd64/isa/isa.c
new file mode 100644
index 0000000..b0d84ef
--- /dev/null
+++ b/sys/amd64/isa/isa.c
@@ -0,0 +1,670 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)isa.c 7.2 (Berkeley) 5/13/91
+ * $Id: isa.c,v 1.16 1994/04/02 20:43:25 ache Exp $
+ */
+
+/*
+ * code to manage AT bus
+ *
+ * 92/08/18 Frank P. MacLachlan (fpm@crash.cts.com):
+ * Fixed uninitialized variable problem and added code to deal
+ * with DMA page boundaries in isa_dmarangecheck(). Fixed word
+ * mode DMA count compution and reorganized DMA setup code in
+ * isa_dmastart()
+ */
+
+#include "param.h"
+#include "systm.h" /* isn't it a joy */
+#include "kernel.h" /* to have three of these */
+#include "conf.h"
+#include "file.h"
+#include "buf.h"
+#include "uio.h"
+#include "syslog.h"
+#include "malloc.h"
+#include "rlist.h"
+#include "machine/segments.h"
+#include "vm/vm.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/ic/i8237.h"
+#include "i386/isa/ic/i8042.h"
+
+/*
+** Register definitions for DMA controller 1 (channels 0..3):
+*/
+#define DMA1_CHN(c) (IO_DMA1 + 1*(2*(c))) /* addr reg for channel c */
+#define DMA1_SMSK (IO_DMA1 + 1*10) /* single mask register */
+#define DMA1_MODE (IO_DMA1 + 1*11) /* mode register */
+#define DMA1_FFC (IO_DMA1 + 1*12) /* clear first/last FF */
+
+/*
+** Register definitions for DMA controller 2 (channels 4..7):
+*/
+#define DMA2_CHN(c) (IO_DMA2 + 2*(2*(c))) /* addr reg for channel c */
+#define DMA2_SMSK (IO_DMA2 + 2*10) /* single mask register */
+#define DMA2_MODE (IO_DMA2 + 2*11) /* mode register */
+#define DMA2_FFC (IO_DMA2 + 2*12) /* clear first/last FF */
+
+void config_isadev __P((struct isa_device *, u_int *));
+
+/*
+ * print a conflict message
+ */
+void
+conflict(dvp, tmpdvp, item, reason, format)
+ struct isa_device *dvp, *tmpdvp;
+ int item;
+ char *reason;
+ char *format;
+{
+ printf("%s%d not probed due to %s conflict with %s%d at ",
+ dvp->id_driver->name, dvp->id_unit, reason,
+ tmpdvp->id_driver->name, tmpdvp->id_unit);
+ printf(format, item);
+ printf("\n");
+}
+
+/*
+ * Check to see if things are alread in use, like IRQ's, I/O addresses
+ * and Memory addresses.
+ */
+int
+haveseen(dvp, tmpdvp)
+ struct isa_device *dvp, *tmpdvp;
+{
+ int status = 0;
+
+ /*
+ * Only check against devices that have already been found
+ */
+ if (tmpdvp->id_alive) {
+ /*
+ * Check for I/O address conflict. We can only check the
+ * starting address of the device against the range of the
+ * device that has already been probed since we do not
+ * know how many I/O addresses this device uses.
+ */
+ if (tmpdvp->id_alive != -1) {
+ if ((dvp->id_iobase >= tmpdvp->id_iobase) &&
+ (dvp->id_iobase <=
+ (tmpdvp->id_iobase + tmpdvp->id_alive - 1))) {
+ conflict(dvp, tmpdvp, dvp->id_iobase,
+ "I/O address", "0x%x");
+ status = 1;
+ }
+ }
+ /*
+ * Check for Memory address conflict. We can check for
+ * range overlap, but it will not catch all cases since the
+ * driver may adjust the msize paramater during probe, for
+ * now we just check that the starting address does not
+ * fall within any allocated region.
+ * XXX could add a second check after the probe for overlap,
+ * since at that time we would know the full range.
+ * XXX KERNBASE is a hack, we should have vaddr in the table!
+ */
+ if(tmpdvp->id_maddr) {
+ if((KERNBASE + dvp->id_maddr >= tmpdvp->id_maddr) &&
+ (KERNBASE + dvp->id_maddr <=
+ (tmpdvp->id_maddr + tmpdvp->id_msize - 1))) {
+ conflict(dvp, tmpdvp, dvp->id_maddr, "maddr",
+ "0x%x");
+ status = 1;
+ }
+ }
+#ifndef COM_MULTIPORT
+ /*
+ * Check for IRQ conflicts.
+ */
+ if(tmpdvp->id_irq) {
+ if (tmpdvp->id_irq == dvp->id_irq) {
+ conflict(dvp, tmpdvp, ffs(dvp->id_irq) - 1,
+ "irq", "%d");
+ status = 1;
+ }
+ }
+#endif
+ /*
+ * Check for DRQ conflicts.
+ */
+ if(tmpdvp->id_drq != -1) {
+ if (tmpdvp->id_drq == dvp->id_drq) {
+ conflict(dvp, tmpdvp, dvp->id_drq,
+ "drq", "%d");
+ status = 1;
+ }
+ }
+ }
+ return (status);
+}
+
+/*
+ * Search through all the isa_devtab_* tables looking for anything that
+ * conflicts with the current device.
+ */
+int
+haveseen_isadev(dvp)
+ struct isa_device *dvp;
+{
+ struct isa_device *tmpdvp;
+ int status = 0;
+
+ for (tmpdvp = isa_devtab_tty; tmpdvp->id_driver; tmpdvp++) {
+ status |= haveseen(dvp, tmpdvp);
+ }
+ for (tmpdvp = isa_devtab_bio; tmpdvp->id_driver; tmpdvp++) {
+ status |= haveseen(dvp, tmpdvp);
+ }
+ for (tmpdvp = isa_devtab_net; tmpdvp->id_driver; tmpdvp++) {
+ status |= haveseen(dvp, tmpdvp);
+ }
+ for (tmpdvp = isa_devtab_null; tmpdvp->id_driver; tmpdvp++) {
+ status |= haveseen(dvp, tmpdvp);
+ }
+ return(status);
+}
+
+/*
+ * Configure all ISA devices
+ */
+void
+isa_configure() {
+ struct isa_device *dvp;
+
+ enable_intr();
+ splhigh();
+ INTREN(IRQ_SLAVE);
+ printf("Probing for devices on the ISA bus:\n");
+ for (dvp = isa_devtab_tty; dvp->id_driver; dvp++) {
+ if (!haveseen_isadev(dvp))
+ config_isadev(dvp,&tty_imask);
+ }
+ for (dvp = isa_devtab_bio; dvp->id_driver; dvp++) {
+ if (!haveseen_isadev(dvp))
+ config_isadev(dvp,&bio_imask);
+ }
+ for (dvp = isa_devtab_net; dvp->id_driver; dvp++) {
+ if (!haveseen_isadev(dvp))
+ config_isadev(dvp,&net_imask);
+ }
+ for (dvp = isa_devtab_null; dvp->id_driver; dvp++) {
+ if (!haveseen_isadev(dvp))
+ config_isadev(dvp,(u_int *) NULL);
+ }
+ bio_imask |= SWI_CLOCK_MASK;
+ net_imask |= SWI_NET_MASK;
+ tty_imask |= SWI_TTY_MASK;
+
+/*
+ * XXX we should really add the tty device to net_imask when the line is
+ * switched to SLIPDISC, and then remove it when it is switched away from
+ * SLIPDISC. No need to block out ALL ttys during a splimp when only one
+ * of them is running slip.
+ *
+ * XXX actually, blocking all ttys during a splimp doesn't matter so much
+ * with sio because the serial interrupt layer doesn't use tty_imask. Only
+ * non-serial ttys suffer. It's more stupid that ALL 'net's are blocked
+ * during spltty.
+ */
+#include "sl.h"
+#if NSL > 0
+ net_imask |= tty_imask;
+ tty_imask = net_imask;
+#endif
+ /* bio_imask |= tty_imask ; can some tty devices use buffers? */
+#ifdef DIAGNOSTIC
+ printf("bio_imask %x tty_imask %x net_imask %x\n",
+ bio_imask, tty_imask, net_imask);
+#endif
+ splnone();
+}
+
+/*
+ * Configure an ISA device.
+ */
+void
+config_isadev(isdp, mp)
+ struct isa_device *isdp;
+ u_int *mp;
+{
+ struct isa_driver *dp = isdp->id_driver;
+
+ if (isdp->id_maddr) {
+ extern u_int atdevbase;
+
+ isdp->id_maddr -= 0xa0000; /* XXX should be a define */
+ isdp->id_maddr += atdevbase;
+ }
+ isdp->id_alive = (*dp->probe)(isdp);
+ if (isdp->id_alive) {
+ /*
+ * Only print the I/O address range if id_alive != -1
+ * Right now this is a temporary fix just for the new
+ * NPX code so that if it finds a 486 that can use trap
+ * 16 it will not report I/O addresses.
+ * Rod Grimes 04/26/94
+ */
+ printf("%s%d", dp->name, isdp->id_unit);
+ if (isdp->id_alive != -1) {
+ printf(" at 0x%x", isdp->id_iobase);
+ if ((isdp->id_iobase + isdp->id_alive - 1) !=
+ isdp->id_iobase) {
+ printf("-0x%x",
+ isdp->id_iobase +
+ isdp->id_alive - 1);
+ }
+ }
+ if(isdp->id_irq)
+ printf(" irq %d", ffs(isdp->id_irq) - 1);
+ if (isdp->id_drq != -1)
+ printf(" drq %d", isdp->id_drq);
+ if (isdp->id_maddr)
+ printf(" maddr 0x%x", kvtop(isdp->id_maddr));
+ if (isdp->id_msize)
+ printf(" msize %d", isdp->id_msize);
+ if (isdp->id_flags)
+ printf(" flags 0x%x", isdp->id_flags);
+ if (isdp->id_iobase) {
+ if (isdp->id_iobase < 0x100) {
+ printf(" on motherboard\n");
+ } else {
+ if (isdp->id_iobase >= 0x1000) {
+ printf (" on eisa\n");
+ } else {
+ printf (" on isa\n");
+ }
+ }
+ }
+
+ (*dp->attach)(isdp);
+
+ if(isdp->id_irq) {
+ int intrno;
+
+ intrno = ffs(isdp->id_irq)-1;
+ setidt(ICU_OFFSET+intrno, isdp->id_intr,
+ SDT_SYS386IGT, SEL_KPL);
+ if(mp) {
+ INTRMASK(*mp,isdp->id_irq);
+ }
+ INTREN(isdp->id_irq);
+ }
+ } else {
+ printf("%s%d not found", dp->name, isdp->id_unit);
+ if (isdp->id_iobase) {
+ printf(" at 0x%x", isdp->id_iobase);
+ }
+ printf("\n");
+ }
+}
+
+#define IDTVEC(name) __CONCAT(X,name)
+/* default interrupt vector table entries */
+typedef void inthand_t();
+typedef void (*inthand_func_t)();
+extern inthand_t
+ IDTVEC(intr0), IDTVEC(intr1), IDTVEC(intr2), IDTVEC(intr3),
+ IDTVEC(intr4), IDTVEC(intr5), IDTVEC(intr6), IDTVEC(intr7),
+ IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10), IDTVEC(intr11),
+ IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14), IDTVEC(intr15);
+
+static inthand_func_t defvec[ICU_LEN] = {
+ &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
+ &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
+ &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
+ &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15) };
+
+/*
+ * Fill in default interrupt table (in case of spuruious interrupt
+ * during configuration of kernel, setup interrupt control unit
+ */
+void
+isa_defaultirq()
+{
+ int i;
+
+ /* icu vectors */
+ for (i = 0; i < ICU_LEN; i++)
+ setidt(ICU_OFFSET + i, defvec[i], SDT_SYS386IGT, SEL_KPL);
+
+ /* initialize 8259's */
+ outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
+ outb(IO_ICU1+1, NRSVIDT); /* starting at this vector index */
+ outb(IO_ICU1+1, 1<<2); /* slave on line 2 */
+#ifdef AUTO_EOI_1
+ outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */
+#else
+ outb(IO_ICU1+1, 1); /* 8086 mode */
+#endif
+ outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
+ outb(IO_ICU1, 0x0a); /* default to IRR on read */
+ outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
+
+ outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
+ outb(IO_ICU2+1, NRSVIDT+8); /* staring at this vector index */
+ outb(IO_ICU2+1,2); /* my slave id is 2 */
+#ifdef AUTO_EOI_2
+ outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */
+#else
+ outb(IO_ICU2+1,1); /* 8086 mode */
+#endif
+ outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
+ outb(IO_ICU2, 0x0a); /* default to IRR on read */
+}
+
+/* region of physical memory known to be contiguous */
+vm_offset_t isaphysmem;
+static caddr_t dma_bounce[8]; /* XXX */
+static char bounced[8]; /* XXX */
+#define MAXDMASZ 512 /* XXX */
+
+/* high byte of address is stored in this port for i-th dma channel */
+static short dmapageport[8] =
+ { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
+
+/*
+ * isa_dmacascade(): program 8237 DMA controller channel to accept
+ * external dma control by a board.
+ */
+void isa_dmacascade(unsigned chan)
+{
+ if (chan > 7)
+ panic("isa_dmacascade: impossible request");
+
+ /* set dma channel mode, and set dma channel mode */
+ if ((chan & 4) == 0) {
+ outb(DMA1_MODE, DMA37MD_CASCADE | chan);
+ outb(DMA1_SMSK, chan);
+ } else {
+ outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3));
+ outb(DMA2_SMSK, chan & 3);
+ }
+}
+
+/*
+ * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment
+ * problems by using a bounce buffer.
+ */
+void isa_dmastart(int flags, caddr_t addr, unsigned nbytes, unsigned chan)
+{ vm_offset_t phys;
+ int waport;
+ caddr_t newaddr;
+
+ if ( chan > 7
+ || (chan < 4 && nbytes > (1<<16))
+ || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1)))
+ panic("isa_dmastart: impossible request");
+
+ if (isa_dmarangecheck(addr, nbytes, chan)) {
+ if (dma_bounce[chan] == 0)
+ dma_bounce[chan] =
+ /*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/
+ (caddr_t) isaphysmem + NBPG*chan;
+ bounced[chan] = 1;
+ newaddr = dma_bounce[chan];
+ *(int *) newaddr = 0; /* XXX */
+
+ /* copy bounce buffer on write */
+ if (!(flags & B_READ))
+ bcopy(addr, newaddr, nbytes);
+ addr = newaddr;
+ }
+
+ /* translate to physical */
+ phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
+
+ if ((chan & 4) == 0) {
+ /*
+ * Program one of DMA channels 0..3. These are
+ * byte mode channels.
+ */
+ /* set dma channel mode, and reset address ff */
+ if (flags & B_READ)
+ outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan);
+ else
+ outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan);
+ outb(DMA1_FFC, 0);
+
+ /* send start address */
+ waport = DMA1_CHN(chan);
+ outb(waport, phys);
+ outb(waport, phys>>8);
+ outb(dmapageport[chan], phys>>16);
+
+ /* send count */
+ outb(waport + 1, --nbytes);
+ outb(waport + 1, nbytes>>8);
+
+ /* unmask channel */
+ outb(DMA1_SMSK, chan);
+ } else {
+ /*
+ * Program one of DMA channels 4..7. These are
+ * word mode channels.
+ */
+ /* set dma channel mode, and reset address ff */
+ if (flags & B_READ)
+ outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3));
+ else
+ outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3));
+ outb(DMA2_FFC, 0);
+
+ /* send start address */
+ waport = DMA2_CHN(chan - 4);
+ outb(waport, phys>>1);
+ outb(waport, phys>>9);
+ outb(dmapageport[chan], phys>>16);
+
+ /* send count */
+ nbytes >>= 1;
+ outb(waport + 2, --nbytes);
+ outb(waport + 2, nbytes>>8);
+
+ /* unmask channel */
+ outb(DMA2_SMSK, chan & 3);
+ }
+}
+
+void isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
+{
+
+ /* copy bounce buffer on read */
+ /*if ((flags & (B_PHYS|B_READ)) == (B_PHYS|B_READ))*/
+ if (bounced[chan]) {
+ bcopy(dma_bounce[chan], addr, nbytes);
+ bounced[chan] = 0;
+ }
+}
+
+/*
+ * Check for problems with the address range of a DMA transfer
+ * (non-contiguous physical pages, outside of bus address space,
+ * crossing DMA page boundaries).
+ * Return true if special handling needed.
+ */
+
+int
+isa_dmarangecheck(caddr_t va, unsigned length, unsigned chan) {
+ vm_offset_t phys, priorpage = 0, endva;
+ u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1);
+
+ endva = (vm_offset_t)round_page(va + length);
+ for (; va < (caddr_t) endva ; va += NBPG) {
+ phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va));
+#define ISARAM_END RAM_END
+ if (phys == 0)
+ panic("isa_dmacheck: no physical page present");
+ if (phys >= ISARAM_END)
+ return (1);
+ if (priorpage) {
+ if (priorpage + NBPG != phys)
+ return (1);
+ /* check if crossing a DMA page boundary */
+ if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk)
+ return (1);
+ }
+ priorpage = phys;
+ }
+ return (0);
+}
+
+/* head of queue waiting for physmem to become available */
+struct buf isa_physmemq;
+
+/* blocked waiting for resource to become free for exclusive use */
+static isaphysmemflag;
+/* if waited for and call requested when free (B_CALL) */
+static void (*isaphysmemunblock)(); /* needs to be a list */
+
+/*
+ * Allocate contiguous physical memory for transfer, returning
+ * a *virtual* address to region. May block waiting for resource.
+ * (assumed to be called at splbio())
+ */
+caddr_t
+isa_allocphysmem(caddr_t va, unsigned length, void (*func)()) {
+
+ isaphysmemunblock = func;
+ while (isaphysmemflag & B_BUSY) {
+ isaphysmemflag |= B_WANTED;
+ tsleep((caddr_t)&isaphysmemflag, PRIBIO, "isaphys", 0);
+ }
+ isaphysmemflag |= B_BUSY;
+
+ return((caddr_t)isaphysmem);
+}
+
+/*
+ * Free contiguous physical memory used for transfer.
+ * (assumed to be called at splbio())
+ */
+void
+isa_freephysmem(caddr_t va, unsigned length) {
+
+ isaphysmemflag &= ~B_BUSY;
+ if (isaphysmemflag & B_WANTED) {
+ isaphysmemflag &= B_WANTED;
+ wakeup((caddr_t)&isaphysmemflag);
+ if (isaphysmemunblock)
+ (*isaphysmemunblock)();
+ }
+}
+
+/*
+ * Handle a NMI, possibly a machine check.
+ * return true to panic system, false to ignore.
+ */
+int
+isa_nmi(cd)
+ int cd;
+{
+
+ log(LOG_CRIT, "\nNMI port 61 %x, port 70 %x\n", inb(0x61), inb(0x70));
+ return(0);
+}
+
+/*
+ * Caught a stray interrupt, notify
+ */
+void
+isa_strayintr(d)
+ int d;
+{
+
+ /* DON'T BOTHER FOR NOW! */
+ /* for some reason, we get bursts of intr #7, even if not enabled! */
+ /*
+ * Well the reason you got bursts of intr #7 is because someone
+ * raised an interrupt line and dropped it before the 8259 could
+ * prioritize it. This is documented in the intel data book. This
+ * means you have BAD hardware! I have changed this so that only
+ * the first 5 get logged, then it quits logging them, and puts
+ * out a special message. rgrimes 3/25/1993
+ */
+ extern u_long intrcnt_stray;
+
+ intrcnt_stray++;
+ if (intrcnt_stray <= 5)
+ log(LOG_ERR,"ISA strayintr %x\n", d);
+ if (intrcnt_stray == 5)
+ log(LOG_CRIT,"Too many ISA strayintr not logging any more\n");
+}
+
+/*
+ * find an ISA device in a given isa_devtab_* table, given
+ * the table to search, the expected id_driver entry, and the unit number.
+ *
+ * this function is defined in isa_device.h, and this location is debatable;
+ * i put it there because it's useless w/o, and directly operates on
+ * the other stuff in that file.
+ *
+ */
+
+struct isa_device *find_isadev(table, driverp, unit)
+ struct isa_device *table;
+ struct isa_driver *driverp;
+ int unit;
+{
+ if (driverp == NULL) /* sanity check */
+ return NULL;
+
+ while ((table->id_driver != driverp) || (table->id_unit != unit)) {
+ if (table->id_driver == 0)
+ return NULL;
+
+ table++;
+ }
+
+ return table;
+}
+
+/*
+ * Return nonzero if a (masked) irq is pending for a given device.
+ */
+int
+isa_irq_pending(dvp)
+ struct isa_device *dvp;
+{
+ unsigned id_irq;
+
+ id_irq = (unsigned short) dvp->id_irq; /* XXX silly type in struct */
+ if (id_irq & 0xff)
+ return (inb(IO_ICU1) & id_irq);
+ return (inb(IO_ICU2) & (id_irq >> 8));
+}
diff --git a/sys/amd64/isa/isa.h b/sys/amd64/isa/isa.h
new file mode 100644
index 0000000..e2a26e7
--- /dev/null
+++ b/sys/amd64/isa/isa.h
@@ -0,0 +1,181 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)isa.h 5.7 (Berkeley) 5/9/91
+ * $Id: isa.h,v 1.4 1994/01/05 15:03:28 rgrimes Exp $
+ */
+
+#ifndef _I386_ISA_ISA_H_
+#define _I386_ISA_ISA_H_ 1
+
+/*
+ * ISA Bus conventions
+ */
+
+#ifndef LOCORE
+#include <sys/cdefs.h>
+
+extern unsigned int atdevbase; /* offset in virtual memory of ISA io mem */
+unsigned char rtcin __P((int));
+#endif
+
+
+/*
+ * Input / Output Port Assignments
+ */
+
+#ifndef IO_BEGIN
+#define IO_ISABEGIN 0x000 /* 0x000 - Beginning of I/O Registers */
+
+ /* CPU Board */
+#define IO_DMA1 0x000 /* 8237A DMA Controller #1 */
+#define IO_ICU1 0x020 /* 8259A Interrupt Controller #1 */
+#define IO_TIMER1 0x040 /* 8253 Timer #1 */
+#define IO_TIMER2 0x048 /* 8253 Timer #2 */
+#define IO_KBD 0x060 /* 8042 Keyboard */
+#define IO_PPI 0x061 /* Programmabel Peripheral Interface */
+#define IO_RTC 0x070 /* RTC */
+#define IO_NMI IO_RTC /* NMI Control */
+#define IO_DMAPG 0x080 /* DMA Page Registers */
+#define IO_ICU2 0x0A0 /* 8259A Interrupt Controller #2 */
+#define IO_DMA2 0x0C0 /* 8237A DMA Controller #2 */
+#define IO_NPX 0x0F0 /* Numeric Coprocessor */
+
+ /* Cards */
+ /* 0x100 - 0x16F Open */
+
+#define IO_WD2 0x170 /* Secondary Fixed Disk Controller */
+
+ /* 0x178 - 0x1EF Open */
+
+#define IO_WD1 0x1f0 /* Primary Fixed Disk Controller */
+#define IO_GAME 0x200 /* Game Controller */
+
+ /* 0x208 - 0x277 Open */
+
+#define IO_LPT2 0x278 /* Parallel Port #2 */
+
+ /* 0x280 - 0x2E7 Open */
+
+#define IO_COM4 0x2e8 /* COM4 i/o address */
+
+ /* 0x2F0 - 0x2F7 Open */
+
+#define IO_COM2 0x2f8 /* COM2 i/o address */
+ /* 0x300 - 0x32F Open */
+
+#define IO_BT0 0x330 /* bustek 742a default addr. */
+#define IO_AHA0 0x330 /* adaptec 1542 default addr. */
+#define IO_UHA0 0x330 /* ultrastore 14f default addr. */
+#define IO_BT1 0x334 /* bustek 742a default addr. */
+#define IO_AHA1 0x334 /* adaptec 1542 default addr. */
+ /* 0x338 - 0x36F Open */
+
+#define IO_FD2 0x370 /* secondary base i/o address */
+#define IO_LPT1 0x378 /* Parallel Port #1 */
+
+ /* 0x380 - 0x3AF Open */
+
+#define IO_MDA 0x3B0 /* Monochome Adapter */
+#define IO_LPT3 0x3BC /* Monochome Adapter Printer Port */
+#define IO_VGA 0x3C0 /* E/VGA Ports */
+#define IO_CGA 0x3D0 /* CGA Ports */
+
+ /* 0x3E0 - 0x3E7 Open */
+
+#define IO_COM3 0x3e8 /* COM3 i/o address */
+#define IO_FD1 0x3f0 /* primary base i/o address */
+#define IO_COM1 0x3f8 /* COM1 i/o address */
+
+#define IO_ISAEND 0x3FF /* - 0x3FF End of I/O Registers */
+#endif IO_ISABEGIN
+
+/*
+ * Input / Output Port Sizes - these are from several sources, and tend
+ * to be the larger of what was found, ie COM ports can be 4, but some
+ * boards do not fully decode the address, thus 8 ports are used.
+ */
+
+#ifndef IO_ISASIZES
+#define IO_ISASIZES
+
+#define IO_COMSIZE 8 /* 8250, 16X50 com controllers (4?) */
+#define IO_CGASIZE 16 /* CGA controllers */
+#define IO_DMASIZE 16 /* 8237 DMA controllers */
+#define IO_DPGSIZE 32 /* 74LS612 DMA page reisters */
+#define IO_FDCSIZE 8 /* Nec765 floppy controllers */
+#define IO_WDCSIZE 8 /* WD compatible disk controllers */
+#define IO_GAMSIZE 16 /* AT compatible game controllers */
+#define IO_ICUSIZE 16 /* 8259A interrupt controllers */
+#define IO_KBDSIZE 16 /* 8042 Keyboard controllers */
+#define IO_LPTSIZE 8 /* LPT controllers, some use only 4 */
+#define IO_MDASIZE 16 /* Monochrome display controllers */
+#define IO_RTCSIZE 16 /* CMOS real time clock, NMI control */
+#define IO_TMRSIZE 16 /* 8253 programmable timers */
+#define IO_NPXSIZE 16 /* 80387/80487 NPX registers */
+#define IO_VGASIZE 16 /* VGA controllers */
+
+#endif /* IO_ISASIZES */
+
+/*
+ * Input / Output Memory Physical Addresses
+ */
+
+#ifndef IOM_BEGIN
+#define IOM_BEGIN 0x0a0000 /* Start of I/O Memory "hole" */
+#define IOM_END 0x100000 /* End of I/O Memory "hole" */
+#define IOM_SIZE (IOM_END - IOM_BEGIN)
+#endif IOM_BEGIN
+
+/*
+ * RAM Physical Address Space (ignoring the above mentioned "hole")
+ */
+
+#ifndef RAM_BEGIN
+#define RAM_BEGIN 0x0000000 /* Start of RAM Memory */
+#define RAM_END 0x1000000 /* End of RAM Memory */
+#define RAM_SIZE (RAM_END - RAM_BEGIN)
+#endif RAM_BEGIN
+
+/*
+ * Oddball Physical Memory Addresses
+ */
+#ifndef COMPAQ_RAMRELOC
+#define COMPAQ_RAMRELOC 0x80c00000 /* Compaq RAM relocation/diag */
+#define COMPAQ_RAMSETUP 0x80c00002 /* Compaq RAM setup */
+#define WEITEK_FPU 0xC0000000 /* WTL 2167 */
+#define CYRIX_EMC 0xC0000000 /* Cyrix EMC */
+#endif COMPAQ_RAMRELOC
+#endif /* _I386_ISA_ISA_H_ */
diff --git a/sys/amd64/isa/npx.c b/sys/amd64/isa/npx.c
new file mode 100644
index 0000000..00424bf
--- /dev/null
+++ b/sys/amd64/isa/npx.c
@@ -0,0 +1,552 @@
+/*-
+ * Copyright (c) 1990 William Jolitz.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)npx.c 7.2 (Berkeley) 5/12/91
+ * $Id: npx.c,v 1.6 1994/01/03 07:55:43 davidg Exp $
+ */
+
+#include "npx.h"
+#if NNPX > 0
+
+#include "param.h"
+#include "systm.h"
+#include "conf.h"
+#include "file.h"
+#include "proc.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+#include "machine/trap.h"
+#include "ioctl.h"
+#include "machine/specialreg.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/isa.h"
+
+/*
+ * 387 and 287 Numeric Coprocessor Extension (NPX) Driver.
+ */
+
+#ifdef __GNUC__
+
+#define disable_intr() __asm("cli")
+#define enable_intr() __asm("sti")
+#define fldcw(addr) __asm("fldcw %0" : : "m" (*addr))
+#define fnclex() __asm("fnclex")
+#define fninit() __asm("fninit")
+#define fnsave(addr) __asm("fnsave %0" : "=m" (*addr) : "0" (*addr))
+#define fnstcw(addr) __asm("fnstcw %0" : "=m" (*addr) : "0" (*addr))
+#define fnstsw(addr) __asm("fnstsw %0" : "=m" (*addr) : "0" (*addr))
+#define fp_divide_by_0() __asm("fldz; fld1; fdiv %st,%st(1); fwait")
+#define frstor(addr) __asm("frstor %0" : : "m" (*addr))
+#define fwait() __asm("fwait")
+#define read_eflags() ({u_long ef; \
+ __asm("pushf; popl %0" : "=a" (ef)); \
+ ef; })
+#define start_emulating() __asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \
+ : : "n" (CR0_TS) : "ax")
+#define stop_emulating() __asm("clts")
+#define write_eflags(ef) __asm("pushl %0; popf" : : "a" ((u_long) ef))
+
+#else /* not __GNUC__ */
+
+void disable_intr __P((void));
+void enable_intr __P((void));
+void fldcw __P((caddr_t addr));
+void fnclex __P((void));
+void fninit __P((void));
+void fnsave __P((caddr_t addr));
+void fnstcw __P((caddr_t addr));
+void fnstsw __P((caddr_t addr));
+void fp_divide_by_0 __P((void));
+void frstor __P((caddr_t addr));
+void fwait __P((void));
+u_long read_eflags __P((void));
+void start_emulating __P((void));
+void stop_emulating __P((void));
+void write_eflags __P((u_long ef));
+
+#endif /* __GNUC__ */
+
+typedef u_char bool_t;
+
+extern struct gate_descriptor idt[];
+
+int npxdna __P((void));
+void npxexit __P((struct proc *p));
+void npxinit __P((u_int control));
+void npxintr __P((struct intrframe frame));
+void npxsave __P((struct save87 *addr));
+static int npxattach __P((struct isa_device *dvp));
+static int npxprobe __P((struct isa_device *dvp));
+static int npxprobe1 __P((struct isa_device *dvp));
+
+struct isa_driver npxdriver = {
+ npxprobe, npxattach, "npx",
+};
+
+u_int npx0_imask;
+struct proc *npxproc;
+
+static bool_t npx_ex16;
+static bool_t npx_exists;
+static struct gate_descriptor npx_idt_probeintr;
+static int npx_intrno;
+static volatile u_int npx_intrs_while_probing;
+static bool_t npx_irq13;
+static volatile u_int npx_traps_while_probing;
+
+/*
+ * Special interrupt handlers. Someday intr0-intr15 will be used to count
+ * interrupts. We'll still need a special exception 16 handler. The busy
+ * latch stuff in probintr() can be moved to npxprobe().
+ */
+void probeintr(void);
+asm
+("
+ .text
+_probeintr:
+ ss
+ incl _npx_intrs_while_probing
+ pushl %eax
+ movb $0x20,%al # EOI (asm in strings loses cpp features)
+ outb %al,$0xa0 # IO_ICU2
+ outb %al,$0x20 #IO_ICU1
+ movb $0,%al
+ outb %al,$0xf0 # clear BUSY# latch
+ popl %eax
+ iret
+");
+
+void probetrap(void);
+asm
+("
+ .text
+_probetrap:
+ ss
+ incl _npx_traps_while_probing
+ fnclex
+ iret
+");
+
+/*
+ * Probe routine. Initialize cr0 to give correct behaviour for [f]wait
+ * whether the device exists or not (XXX should be elsewhere). Set flags
+ * to tell npxattach() what to do. Modify device struct if npx doesn't
+ * need to use interrupts. Return 1 if device exists.
+ */
+static int
+npxprobe(dvp)
+ struct isa_device *dvp;
+{
+ int result;
+ u_long save_eflags;
+ u_char save_icu1_mask;
+ u_char save_icu2_mask;
+ struct gate_descriptor save_idt_npxintr;
+ struct gate_descriptor save_idt_npxtrap;
+ /*
+ * This routine is now just a wrapper for npxprobe1(), to install
+ * special npx interrupt and trap handlers, to enable npx interrupts
+ * and to disable other interrupts. Someday isa_configure() will
+ * install suitable handlers and run with interrupts enabled so we
+ * won't need to do so much here.
+ */
+ npx_intrno = NRSVIDT + ffs(dvp->id_irq) - 1;
+ save_eflags = read_eflags();
+ disable_intr();
+ save_icu1_mask = inb(IO_ICU1 + 1);
+ save_icu2_mask = inb(IO_ICU2 + 1);
+ save_idt_npxintr = idt[npx_intrno];
+ save_idt_npxtrap = idt[16];
+ outb(IO_ICU1 + 1, ~(IRQ_SLAVE | dvp->id_irq));
+ outb(IO_ICU2 + 1, ~(dvp->id_irq >> 8));
+ setidt(16, probetrap, SDT_SYS386TGT, SEL_KPL);
+ setidt(npx_intrno, probeintr, SDT_SYS386IGT, SEL_KPL);
+ npx_idt_probeintr = idt[npx_intrno];
+ enable_intr();
+ result = npxprobe1(dvp);
+ disable_intr();
+ outb(IO_ICU1 + 1, save_icu1_mask);
+ outb(IO_ICU2 + 1, save_icu2_mask);
+ idt[npx_intrno] = save_idt_npxintr;
+ idt[16] = save_idt_npxtrap;
+ write_eflags(save_eflags);
+ return (result);
+}
+
+static int
+npxprobe1(dvp)
+ struct isa_device *dvp;
+{
+ int control;
+ int status;
+#ifdef lint
+ npxintr();
+#endif
+ /*
+ * Partially reset the coprocessor, if any. Some BIOS's don't reset
+ * it after a warm boot.
+ */
+ outb(0xf1, 0); /* full reset on some systems, NOP on others */
+ outb(0xf0, 0); /* clear BUSY# latch */
+ /*
+ * Prepare to trap all ESC (i.e., NPX) instructions and all WAIT
+ * instructions. We must set the CR0_MP bit and use the CR0_TS
+ * bit to control the trap, because setting the CR0_EM bit does
+ * not cause WAIT instructions to trap. It's important to trap
+ * WAIT instructions - otherwise the "wait" variants of no-wait
+ * control instructions would degenerate to the "no-wait" variants
+ * after FP context switches but work correctly otherwise. It's
+ * particularly important to trap WAITs when there is no NPX -
+ * otherwise the "wait" variants would always degenerate.
+ *
+ * Try setting CR0_NE to get correct error reporting on 486DX's.
+ * Setting it should fail or do nothing on lesser processors.
+ */
+ load_cr0(rcr0() | CR0_MP | CR0_NE);
+ /*
+ * But don't trap while we're probing.
+ */
+ stop_emulating();
+ /*
+ * Finish resetting the coprocessor, if any. If there is an error
+ * pending, then we may get a bogus IRQ13, but probeintr() will handle
+ * it OK. Bogus halts have never been observed, but we enabled
+ * IRQ13 and cleared the BUSY# latch early to handle them anyway.
+ */
+ fninit();
+ DELAY(1000); /* wait for any IRQ13 (fwait might hang) */
+#ifdef DIAGNOSTIC
+ if (npx_intrs_while_probing != 0)
+ printf("fninit caused %u bogus npx interrupt(s)\n",
+ npx_intrs_while_probing);
+ if (npx_traps_while_probing != 0)
+ printf("fninit caused %u bogus npx trap(s)\n",
+ npx_traps_while_probing);
+#endif
+ /*
+ * Check for a status of mostly zero.
+ */
+ status = 0x5a5a;
+ fnstsw(&status);
+ if ((status & 0xb8ff) == 0) {
+ /*
+ * Good, now check for a proper control word.
+ */
+ control = 0x5a5a;
+ fnstcw(&control);
+ if ((control & 0x1f3f) == 0x033f) {
+ npx_exists = 1;
+ /*
+ * We have an npx, now divide by 0 to see if exception
+ * 16 works.
+ */
+ control &= ~(1 << 2); /* enable divide by 0 trap */
+ fldcw(&control);
+ npx_traps_while_probing = npx_intrs_while_probing = 0;
+ fp_divide_by_0();
+ if (npx_traps_while_probing != 0) {
+ /*
+ * Good, exception 16 works.
+ */
+ npx_ex16 = 1;
+ dvp->id_irq = 0; /* zap the interrupt */
+ /*
+ * special return value to flag that we do not
+ * actually use any I/O registers
+ */
+ return (-1);
+ }
+ if (npx_intrs_while_probing != 0) {
+ /*
+ * Bad, we are stuck with IRQ13.
+ */
+ npx_irq13 = 1;
+ npx0_imask = dvp->id_irq; /* npxattach too late */
+ return (IO_NPXSIZE);
+ }
+ /*
+ * Worse, even IRQ13 is broken. Use emulator.
+ */
+ }
+ }
+ /*
+ * Probe failed, but we want to get to npxattach to initialize the
+ * emulator and say that it has been installed. XXX handle devices
+ * that aren't really devices better.
+ */
+ dvp->id_irq = 0;
+ /*
+ * special return value to flag that we do not
+ * actually use any I/O registers
+ */
+ return (-1);
+}
+
+/*
+ * Attach routine - announce which it is, and wire into system
+ */
+int
+npxattach(dvp)
+ struct isa_device *dvp;
+{
+ if (!npx_ex16 && !npx_irq13) {
+ if (npx_exists)
+ printf("npx%d: Error reporting broken, using 387 emulator\n",dvp->id_unit);
+ else
+ printf("npx%d: 387 Emulator\n",dvp->id_unit);
+ }
+ npxinit(__INITIAL_NPXCW__);
+ return (1); /* XXX unused */
+}
+
+/*
+ * Initialize floating point unit.
+ */
+void
+npxinit(control)
+ u_int control;
+{
+ struct save87 dummy;
+
+ if (!npx_exists)
+ return;
+ /*
+ * fninit has the same h/w bugs as fnsave. Use the detoxified
+ * fnsave to throw away any junk in the fpu. fnsave initializes
+ * the fpu and sets npxproc = NULL as important side effects.
+ */
+ npxsave(&dummy);
+ stop_emulating();
+ fldcw(&control);
+ if (curpcb != NULL)
+ fnsave(&curpcb->pcb_savefpu);
+ start_emulating();
+}
+
+/*
+ * Free coprocessor (if we have it).
+ */
+void
+npxexit(p)
+ struct proc *p;
+{
+
+ if (p == npxproc) {
+ start_emulating();
+ npxproc = NULL;
+ }
+}
+
+/*
+ * Record the FPU state and reinitialize it all except for the control word.
+ * Then generate a SIGFPE.
+ *
+ * Reinitializing the state allows naive SIGFPE handlers to longjmp without
+ * doing any fixups.
+ *
+ * XXX there is currently no way to pass the full error state to signal
+ * handlers, and if this is a nested interrupt there is no way to pass even
+ * a status code! So there is no way to have a non-naive SIGFPE handler. At
+ * best a handler could do an fninit followed by an fldcw of a static value.
+ * fnclex would be of little use because it would leave junk on the FPU stack.
+ * Returning from the handler would be even less safe than usual because
+ * IRQ13 exception handling makes exceptions even less precise than usual.
+ */
+void
+npxintr(frame)
+ struct intrframe frame;
+{
+ int code;
+
+ if (npxproc == NULL || !npx_exists) {
+ /* XXX no %p in stand/printf.c. Cast to quiet gcc -Wall. */
+ printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n",
+ (u_long) npxproc, (u_long) curproc, npx_exists);
+ panic("npxintr from nowhere");
+ }
+ if (npxproc != curproc) {
+ printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n",
+ (u_long) npxproc, (u_long) curproc, npx_exists);
+ panic("npxintr from non-current process");
+ }
+ /*
+ * Save state. This does an implied fninit. It had better not halt
+ * the cpu or we'll hang.
+ */
+ outb(0xf0, 0);
+ fnsave(&curpcb->pcb_savefpu);
+ fwait();
+ /*
+ * Restore control word (was clobbered by fnsave).
+ */
+ fldcw(&curpcb->pcb_savefpu.sv_env.en_cw);
+ fwait();
+ /*
+ * Remember the exception status word and tag word. The current
+ * (almost fninit'ed) fpu state is in the fpu and the exception
+ * state just saved will soon be junk. However, the implied fninit
+ * doesn't change the error pointers or register contents, and we
+ * preserved the control word and will copy the status and tag
+ * words, so the complete exception state can be recovered.
+ */
+ curpcb->pcb_savefpu.sv_ex_sw = curpcb->pcb_savefpu.sv_env.en_sw;
+ curpcb->pcb_savefpu.sv_ex_tw = curpcb->pcb_savefpu.sv_env.en_tw;
+
+ /*
+ * Pass exception to process.
+ */
+ if (ISPL(frame.if_cs) == SEL_UPL) {
+ /*
+ * Interrupt is essentially a trap, so we can afford to call
+ * the SIGFPE handler (if any) as soon as the interrupt
+ * returns.
+ *
+ * XXX little or nothing is gained from this, and plenty is
+ * lost - the interrupt frame has to contain the trap frame
+ * (this is otherwise only necessary for the rescheduling trap
+ * in doreti, and the frame for that could easily be set up
+ * just before it is used).
+ */
+ curproc->p_regs = (int *)&frame.if_es;
+#ifdef notyet
+ /*
+ * Encode the appropriate code for detailed information on
+ * this exception.
+ */
+ code = XXX_ENCODE(curpcb->pcb_savefpu.sv_ex_sw);
+#else
+ code = 0; /* XXX */
+#endif
+ trapsignal(curproc, SIGFPE, code);
+ } else {
+ /*
+ * Nested interrupt. These losers occur when:
+ * o an IRQ13 is bogusly generated at a bogus time, e.g.:
+ * o immediately after an fnsave or frstor of an
+ * error state.
+ * o a couple of 386 instructions after
+ * "fstpl _memvar" causes a stack overflow.
+ * These are especially nasty when combined with a
+ * trace trap.
+ * o an IRQ13 occurs at the same time as another higher-
+ * priority interrupt.
+ *
+ * Treat them like a true async interrupt.
+ */
+ psignal(npxproc, SIGFPE);
+ }
+}
+
+/*
+ * Implement device not available (DNA) exception
+ *
+ * It would be better to switch FP context here (only). This would require
+ * saving the state in the proc table instead of in the pcb.
+ */
+int
+npxdna()
+{
+ if (!npx_exists)
+ return (0);
+ if (npxproc != NULL) {
+ printf("npxdna: npxproc = %lx, curproc = %lx\n",
+ (u_long) npxproc, (u_long) curproc);
+ panic("npxdna");
+ }
+ stop_emulating();
+ /*
+ * Record new context early in case frstor causes an IRQ13.
+ */
+ npxproc = curproc;
+ /*
+ * The following frstor may cause an IRQ13 when the state being
+ * restored has a pending error. The error will appear to have been
+ * triggered by the current (npx) user instruction even when that
+ * instruction is a no-wait instruction that should not trigger an
+ * error (e.g., fnclex). On at least one 486 system all of the
+ * no-wait instructions are broken the same as frstor, so our
+ * treatment does not amplify the breakage. On at least one
+ * 386/Cyrix 387 system, fnclex works correctly while frstor and
+ * fnsave are broken, so our treatment breaks fnclex if it is the
+ * first FPU instruction after a context switch.
+ */
+ frstor(&curpcb->pcb_savefpu);
+
+ return (1);
+}
+
+/*
+ * Wrapper for fnsave instruction to handle h/w bugs. If there is an error
+ * pending, then fnsave generates a bogus IRQ13 on some systems. Force
+ * any IRQ13 to be handled immediately, and then ignore it. This routine is
+ * often called at splhigh so it must not use many system services. In
+ * particular, it's much easier to install a special handler than to
+ * guarantee that it's safe to use npxintr() and its supporting code.
+ */
+void
+npxsave(addr)
+ struct save87 *addr;
+{
+ u_char icu1_mask;
+ u_char icu2_mask;
+ u_char old_icu1_mask;
+ u_char old_icu2_mask;
+ struct gate_descriptor save_idt_npxintr;
+
+ disable_intr();
+ old_icu1_mask = inb(IO_ICU1 + 1);
+ old_icu2_mask = inb(IO_ICU2 + 1);
+ save_idt_npxintr = idt[npx_intrno];
+ outb(IO_ICU1 + 1, old_icu1_mask & ~(IRQ_SLAVE | npx0_imask));
+ outb(IO_ICU2 + 1, old_icu2_mask & ~(npx0_imask >> 8));
+ idt[npx_intrno] = npx_idt_probeintr;
+ enable_intr();
+ stop_emulating();
+ fnsave(addr);
+ fwait();
+ start_emulating();
+ npxproc = NULL;
+ disable_intr();
+ icu1_mask = inb(IO_ICU1 + 1); /* masks may have changed */
+ icu2_mask = inb(IO_ICU2 + 1);
+ outb(IO_ICU1 + 1,
+ (icu1_mask & ~npx0_imask) | (old_icu1_mask & npx0_imask));
+ outb(IO_ICU2 + 1,
+ (icu2_mask & ~(npx0_imask >> 8))
+ | (old_icu2_mask & (npx0_imask >> 8)));
+ idt[npx_intrno] = save_idt_npxintr;
+ enable_intr(); /* back to usual state */
+}
+
+#endif /* NNPX > 0 */
diff --git a/sys/amd64/isa/timerreg.h b/sys/amd64/isa/timerreg.h
new file mode 100644
index 0000000..5742f66
--- /dev/null
+++ b/sys/amd64/isa/timerreg.h
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Header: timerreg.h,v 1.2 93/02/28 15:08:58 mccanne Exp
+ * $Id$
+ */
+
+/*
+ *
+ * Register definitions for the Intel 8253 Programmable Interval Timer.
+ *
+ * This chip has three independent 16-bit down counters that can be
+ * read on the fly. There are three mode registers and three countdown
+ * registers. The countdown registers are addressed directly, via the
+ * first three I/O ports. The three mode registers are accessed via
+ * the fourth I/O port, with two bits in the mode byte indicating the
+ * register. (Why are hardware interfaces always so braindead?).
+ *
+ * To write a value into the countdown register, the mode register
+ * is first programmed with a command indicating the which byte of
+ * the two byte register is to be modified. The three possibilities
+ * are load msb (TMR_MR_MSB), load lsb (TMR_MR_LSB), or load lsb then
+ * msb (TMR_MR_BOTH).
+ *
+ * To read the current value ("on the fly") from the countdown register,
+ * you write a "latch" command into the mode register, then read the stable
+ * value from the corresponding I/O port. For example, you write
+ * TMR_MR_LATCH into the corresponding mode register. Presumably,
+ * after doing this, a write operation to the I/O port would result
+ * in undefined behavior (but hopefully not fry the chip).
+ * Reading in this manner has no side effects.
+ *
+ * The outputs of the three timers are connected as follows:
+ *
+ * timer 0 -> irq 0
+ * timer 1 -> dma chan 0 (for dram refresh)
+ * timer 2 -> speaker (via keyboard controller)
+ *
+ * Timer 0 is used to call hardclock.
+ * Timer 2 is used to generate console beeps.
+ */
+
+/*
+ * Macros for specifying values to be written into a mode register.
+ */
+#define TIMER_CNTR0 (IO_TIMER1 + 0) /* timer 0 counter port */
+#define TIMER_CNTR1 (IO_TIMER1 + 1) /* timer 1 counter port */
+#define TIMER_CNTR2 (IO_TIMER1 + 2) /* timer 2 counter port */
+#define TIMER_MODE (IO_TIMER1 + 3) /* timer mode port */
+#define TIMER_SEL0 0x00 /* select counter 0 */
+#define TIMER_SEL1 0x40 /* select counter 1 */
+#define TIMER_SEL2 0x80 /* select counter 2 */
+#define TIMER_INTTC 0x00 /* mode 0, intr on terminal cnt */
+#define TIMER_ONESHOT 0x02 /* mode 1, one shot */
+#define TIMER_RATEGEN 0x04 /* mode 2, rate generator */
+#define TIMER_SQWAVE 0x06 /* mode 3, square wave */
+#define TIMER_SWSTROBE 0x08 /* mode 4, s/w triggered strobe */
+#define TIMER_HWSTROBE 0x0a /* mode 5, h/w triggered strobe */
+#define TIMER_LATCH 0x00 /* latch counter for reading */
+#define TIMER_LSB 0x10 /* r/w counter LSB */
+#define TIMER_MSB 0x20 /* r/w counter MSB */
+#define TIMER_16BIT 0x30 /* r/w counter 16 bits, LSB first */
+#define TIMER_BCD 0x01 /* count in BCD */
+
diff --git a/sys/amd64/isa/vector.S b/sys/amd64/isa/vector.S
new file mode 100644
index 0000000..7135ae7
--- /dev/null
+++ b/sys/amd64/isa/vector.S
@@ -0,0 +1,360 @@
+/*
+ * from: vector.s, 386BSD 0.1 unknown origin
+ * $Id: vector.s,v 1.6 1994/01/10 23:15:09 ache Exp $
+ */
+
+#include "i386/isa/icu.h"
+#include "i386/isa/isa.h"
+#include "vector.h"
+
+#define ICU_EOI 0x20 /* XXX - define elsewhere */
+
+#define IRQ_BIT(irq_num) (1 << ((irq_num) % 8))
+#define IRQ_BYTE(irq_num) ((irq_num) / 8)
+
+#ifdef AUTO_EOI_1
+#define ENABLE_ICU1 /* use auto-EOI to reduce i/o */
+#else
+#define ENABLE_ICU1 \
+ movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \
+ FASTER_NOP ; /* ... ASAP ... */ \
+ outb %al,$IO_ICU1 /* ... to clear in service bit */
+#endif
+
+#ifdef AUTO_EOI_2
+/*
+ * The data sheet says no auto-EOI on slave, but it sometimes works.
+ */
+#define ENABLE_ICU1_AND_2 ENABLE_ICU1
+#else
+#define ENABLE_ICU1_AND_2 \
+ movb $ICU_EOI,%al ; /* as above */ \
+ FASTER_NOP ; \
+ outb %al,$IO_ICU2 ; /* but do second icu first */ \
+ FASTER_NOP ; \
+ outb %al,$IO_ICU1 /* then first icu */
+#endif
+
+#ifdef FAST_INTR_HANDLER_USES_ES
+#define ACTUALLY_PUSHED 1
+#define MAYBE_MOVW_AX_ES movl %ax,%es
+#define MAYBE_POPL_ES popl %es
+#define MAYBE_PUSHL_ES pushl %es
+#else
+/*
+ * We can usually skip loading %es for fastintr handlers. %es should
+ * only be used for string instructions, and fastintr handlers shouldn't
+ * do anything slow enough to justify using a string instruction.
+ */
+#define ACTUALLY_PUSHED 0
+#define MAYBE_MOVW_AX_ES
+#define MAYBE_POPL_ES
+#define MAYBE_PUSHL_ES
+#endif
+
+/*
+ * Macros for interrupt interrupt entry, call to handler, and exit.
+ *
+ * XXX - the interrupt frame is set up to look like a trap frame. This is
+ * usually a waste of time. The only interrupt handlers that want a frame
+ * are the clock handler (it wants a clock frame), the npx handler (it's
+ * easier to do right all in assembler). The interrupt return routine
+ * needs a trap frame for rare AST's (it could easily convert the frame).
+ * The direct costs of setting up a trap frame are two pushl's (error
+ * code and trap number), an addl to get rid of these, and pushing and
+ * popping the call-saved regs %esi, %edi and %ebp twice, The indirect
+ * costs are making the driver interface nonuniform so unpending of
+ * interrupts is more complicated and slower (call_driver(unit) would
+ * be easier than ensuring an interrupt frame for all handlers. Finally,
+ * there are some struct copies in the npx handler and maybe in the clock
+ * handler that could be avoided by working more with pointers to frames
+ * instead of frames.
+ *
+ * XXX - should we do a cld on every system entry to avoid the requirement
+ * for scattered cld's?
+ *
+ * Coding notes for *.s:
+ *
+ * If possible, avoid operations that involve an operand size override.
+ * Word-sized operations might be smaller, but the operand size override
+ * makes them slower on on 486's and no faster on 386's unless perhaps
+ * the instruction pipeline is depleted. E.g.,
+ *
+ * Use movl to seg regs instead of the equivalent but more descriptive
+ * movw - gas generates an irelevant (slower) operand size override.
+ *
+ * Use movl to ordinary regs in preference to movw and especially
+ * in preference to movz[bw]l. Use unsigned (long) variables with the
+ * top bits clear instead of unsigned short variables to provide more
+ * opportunities for movl.
+ *
+ * If possible, use byte-sized operations. They are smaller and no slower.
+ *
+ * Use (%reg) instead of 0(%reg) - gas generates larger code for the latter.
+ *
+ * If the interrupt frame is made more flexible, INTR can push %eax first
+ * and decide the ipending case with less overhead, e.g., by avoiding
+ * loading segregs.
+ */
+
+#define FAST_INTR(unit, irq_num, id_num, handler, enable_icus) \
+ pushl %eax ; /* save only call-used registers */ \
+ pushl %ecx ; \
+ pushl %edx ; \
+ pushl %ds ; \
+ MAYBE_PUSHL_ES ; \
+ movl $KDSEL,%eax ; \
+ movl %ax,%ds ; \
+ MAYBE_MOVW_AX_ES ; \
+ FAKE_MCOUNT((4+ACTUALLY_PUSHED)*4(%esp)) ; \
+ pushl $unit ; \
+ call handler ; /* do the work ASAP */ \
+ enable_icus ; /* (re)enable ASAP (helps edge trigger?) */ \
+ addl $4,%esp ; \
+ incl _cnt+V_INTR ; /* book-keeping can wait */ \
+ incl _intrcnt_actv + (id_num) * 4 ; \
+ movl _cpl,%eax ; /* are we unmasking pending HWIs or SWIs? */ \
+ notl %eax ; \
+ andl _ipending,%eax ; \
+ jne 1f ; /* yes, handle them */ \
+ MEXITCOUNT ; \
+ MAYBE_POPL_ES ; \
+ popl %ds ; \
+ popl %edx ; \
+ popl %ecx ; \
+ popl %eax ; \
+ iret ; \
+; \
+ ALIGN_TEXT ; \
+1: ; \
+ movl _cpl,%eax ; \
+ movl $HWI_MASK|SWI_MASK,_cpl ; /* limit nesting ... */ \
+ sti ; /* ... to do this as early as possible */ \
+ MAYBE_POPL_ES ; /* discard most of thin frame ... */ \
+ popl %ecx ; /* ... original %ds ... */ \
+ popl %edx ; \
+ xchgl %eax,(1+ACTUALLY_PUSHED)*4(%esp) ; /* orig %eax; save cpl */ \
+ pushal ; /* build fat frame (grrr) ... */ \
+ pushl %ecx ; /* ... actually %ds ... */ \
+ pushl %es ; \
+ movl $KDSEL,%eax ; \
+ movl %ax,%es ; \
+ movl (2+8+0)*4(%esp),%ecx ; /* ... %ecx from thin frame ... */ \
+ movl %ecx,(2+6)*4(%esp) ; /* ... to fat frame ... */ \
+ movl (2+8+1)*4(%esp),%eax ; /* ... cpl from thin frame */ \
+ pushl %eax ; \
+ subl $4,%esp ; /* junk for unit number */ \
+ MEXITCOUNT ; \
+ jmp _doreti
+
+#define INTR(unit, irq_num, id_num, mask, handler, icu, enable_icus, reg, stray) \
+ pushl $0 ; /* dumby error code */ \
+ pushl $0 ; /* dumby trap type */ \
+ pushal ; \
+ pushl %ds ; /* save our data and extra segments ... */ \
+ pushl %es ; \
+ movl $KDSEL,%eax ; /* ... and reload with kernel's own ... */ \
+ movl %ax,%ds ; /* ... early for obsolete reasons */ \
+ movl %ax,%es ; \
+ movb _imen + IRQ_BYTE(irq_num),%al ; \
+ orb $IRQ_BIT(irq_num),%al ; \
+ movb %al,_imen + IRQ_BYTE(irq_num) ; \
+ FASTER_NOP ; \
+ outb %al,$icu+1 ; \
+ enable_icus ; \
+ incl _cnt+V_INTR ; /* tally interrupts */ \
+ movl _cpl,%eax ; \
+ testb $IRQ_BIT(irq_num),%reg ; \
+ jne 2f ; \
+1: ; \
+ FAKE_MCOUNT(12*4(%esp)) ; /* XXX late to avoid double count */ \
+ incl _intrcnt_actv + (id_num) * 4 ; \
+ movl _cpl,%eax ; \
+ pushl %eax ; \
+ pushl $unit ; \
+ orl mask,%eax ; \
+ movl %eax,_cpl ; \
+ sti ; \
+ call handler ; \
+ movb _imen + IRQ_BYTE(irq_num),%al ; \
+ andb $~IRQ_BIT(irq_num),%al ; \
+ movb %al,_imen + IRQ_BYTE(irq_num) ; \
+ FASTER_NOP ; \
+ outb %al,$icu+1 ; \
+ MEXITCOUNT ; \
+ /* We could usually avoid the following jmp by inlining some of */ \
+ /* _doreti, but it's probably better to use less cache. */ \
+ jmp _doreti ; \
+; \
+ ALIGN_TEXT ; \
+2: ; \
+ /* XXX skip mcounting here to avoid double count */ \
+ movl $1b,%eax ; /* register resume address */ \
+ /* XXX - someday do it at attach time */ \
+ movl %eax,ihandlers + (irq_num) * 4 ; \
+ orb $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) ; \
+ popl %es ; \
+ popl %ds ; \
+ popal ; \
+ addl $4+4,%esp ; \
+ iret
+
+/*
+ * vector.h has defined a macro 'BUILD_VECTORS' containing a big list of info
+ * about vectors, including a submacro 'BUILD_VECTOR' that operates on the
+ * info about each vector. We redefine 'BUILD_VECTOR' to expand the info
+ * in different ways. Here we expand it to a list of interrupt handlers.
+ * This order is of course unimportant. Elsewhere we expand it to inline
+ * linear search code for which the order is a little more important and
+ * concatenating the code with no holes is very important.
+ *
+ * XXX - now there is BUILD_FAST_VECTOR as well as BUILD_VECTOR.
+ *
+ * The info consists of the following items for each vector:
+ *
+ * name (identifier): name of the vector; used to build labels
+ * unit (expression): unit number to call the device driver with
+ * irq_num (number): number of the IRQ to handled (0-15)
+ * id_num (number): uniq numeric id for handler (assigned by config)
+ * mask (blank-ident): priority mask used
+ * handler (blank-ident): interrupt handler to call
+ * icu_num (number): (1 + irq_num / 8) converted for label building
+ * icu_enables (number): 1 for icu_num == 1, 1_AND_2 for icu_num == 2
+ * reg (blank-ident): al for icu_num == 1, ah for icu_num == 2
+ *
+ * 'irq_num' is converted in several ways at config time to get around
+ * limitations in cpp. The macros have blanks after commas iff they would
+ * not mess up identifiers and numbers.
+ */
+
+#undef BUILD_FAST_VECTOR
+#define BUILD_FAST_VECTOR(name, unit, irq_num, id_num, mask, handler, \
+ icu_num, icu_enables, reg) \
+ .globl handler ; \
+ .text ; \
+ .globl _V/**/name ; \
+ SUPERALIGN_TEXT ; \
+_V/**/name: ; \
+ FAST_INTR(unit, irq_num,id_num, handler, ENABLE_ICU/**/icu_enables)
+
+#undef BUILD_VECTOR
+#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \
+ icu_num, icu_enables, reg) \
+ .globl handler ; \
+ .text ; \
+ .globl _V/**/name ; \
+ SUPERALIGN_TEXT ; \
+_V/**/name: ; \
+ INTR(unit,irq_num, id_num, mask, handler, IO_ICU/**/icu_num, \
+ ENABLE_ICU/**/icu_enables, reg,)
+
+MCOUNT_LABEL(bintr)
+ BUILD_VECTORS
+
+ /* hardware interrupt catcher (IDT 32 - 47) */
+ .globl _isa_strayintr
+
+#define STRAYINTR(irq_num, icu_num, icu_enables, reg) \
+IDTVEC(intr/**/irq_num) ; \
+ INTR(irq_num,irq_num,irq_num, _high_imask, _isa_strayintr, \
+ IO_ICU/**/icu_num, ENABLE_ICU/**/icu_enables, reg,stray)
+
+/*
+ * XXX - the mask (1 << 2) == IRQ_SLAVE will be generated for IRQ 2, instead
+ * of the mask IRQ2 (defined as IRQ9 == (1 << 9)). But IRQ 2 "can't happen".
+ * In fact, all stray interrupts "can't happen" except for bugs. The
+ * "stray" IRQ 7 is documented behaviour of the 8259. It happens when there
+ * is a glitch on any of its interrupt inputs. Does it really interrupt when
+ * IRQ 7 is masked?
+ *
+ * XXX - unpend doesn't work for these, it sends them to the real handler.
+ *
+ * XXX - the race bug during initialization may be because I changed the
+ * order of switching from the stray to the real interrupt handler to before
+ * enabling interrupts. The old order looked unsafe but maybe it is OK with
+ * the stray interrupt handler installed. But these handlers only reduce
+ * the window of vulnerability - it is still open at the end of
+ * isa_configure().
+ *
+ * XXX - many comments are stale.
+ */
+
+ STRAYINTR(0,1,1, al)
+ STRAYINTR(1,1,1, al)
+ STRAYINTR(2,1,1, al)
+ STRAYINTR(3,1,1, al)
+ STRAYINTR(4,1,1, al)
+ STRAYINTR(5,1,1, al)
+ STRAYINTR(6,1,1, al)
+ STRAYINTR(7,1,1, al)
+ STRAYINTR(8,2,1_AND_2, ah)
+ STRAYINTR(9,2,1_AND_2, ah)
+ STRAYINTR(10,2,1_AND_2, ah)
+ STRAYINTR(11,2,1_AND_2, ah)
+ STRAYINTR(12,2,1_AND_2, ah)
+ STRAYINTR(13,2,1_AND_2, ah)
+ STRAYINTR(14,2,1_AND_2, ah)
+ STRAYINTR(15,2,1_AND_2, ah)
+#if 0
+ INTRSTRAY(255, _highmask, 255) ; call _isa_strayintr ; INTREXIT2
+#endif
+MCOUNT_LABEL(eintr)
+
+/*
+ * These are the interrupt counters, I moved them here from icu.s so that
+ * they are with the name table. rgrimes
+ *
+ * There are now lots of counters, this has been redone to work with
+ * Bruce Evans intr-0.1 code, which I modified some more to make it all
+ * work with vmstat.
+ */
+ .data
+ihandlers: /* addresses of interrupt handlers */
+ .space NHWI*4 /* actually resumption addresses for HWI's */
+ .long swi_tty, swi_net, 0, 0, 0, 0, 0, 0
+ .long 0, 0, 0, 0, 0, 0, swi_clock, swi_ast
+imasks: /* masks for interrupt handlers */
+ .space NHWI*4 /* padding; HWI masks are elsewhere */
+ .long SWI_TTY_MASK, SWI_NET_MASK, 0, 0, 0, 0, 0, 0
+ .long 0, 0, 0, 0, 0, 0, SWI_CLOCK_MASK, SWI_AST_MASK
+
+ .globl _intrcnt
+_intrcnt: /* used by vmstat to calc size of table */
+ .globl _intrcnt_bad7
+_intrcnt_bad7: .space 4 /* glitches on irq 7 */
+ .globl _intrcnt_bad15
+_intrcnt_bad15: .space 4 /* glitches on irq 15 */
+ .globl _intrcnt_stray
+_intrcnt_stray: .space 4 /* total count of stray interrupts */
+ .globl _intrcnt_actv
+_intrcnt_actv: .space NR_REAL_INT_HANDLERS * 4 /* active interrupts */
+ .globl _eintrcnt
+_eintrcnt: /* used by vmstat to calc size of table */
+
+/*
+ * Build the interrupt name table for vmstat
+ */
+
+#undef BUILD_FAST_VECTOR
+#define BUILD_FAST_VECTOR BUILD_VECTOR
+
+#undef BUILD_VECTOR
+#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \
+ icu_num, icu_enables, reg) \
+ .ascii "name irq" ; \
+ .asciz "irq_num"
+/*
+ * XXX - use the __STRING and __CONCAT macros from <sys/cdefs.h> to stringize
+ * and concatenate names above and elsewhere. Note that __CONCAT doesn't
+ * work when nested.
+ */
+
+ .text
+ .globl _intrnames, _eintrnames
+_intrnames:
+ BUILD_VECTOR(bad,,7,,,,,,)
+ BUILD_VECTOR(bad,,15,,,,,,)
+ BUILD_VECTOR(stray,,,,,,,,)
+ BUILD_VECTORS
+
+_eintrnames:
diff --git a/sys/amd64/isa/vector.s b/sys/amd64/isa/vector.s
new file mode 100644
index 0000000..7135ae7
--- /dev/null
+++ b/sys/amd64/isa/vector.s
@@ -0,0 +1,360 @@
+/*
+ * from: vector.s, 386BSD 0.1 unknown origin
+ * $Id: vector.s,v 1.6 1994/01/10 23:15:09 ache Exp $
+ */
+
+#include "i386/isa/icu.h"
+#include "i386/isa/isa.h"
+#include "vector.h"
+
+#define ICU_EOI 0x20 /* XXX - define elsewhere */
+
+#define IRQ_BIT(irq_num) (1 << ((irq_num) % 8))
+#define IRQ_BYTE(irq_num) ((irq_num) / 8)
+
+#ifdef AUTO_EOI_1
+#define ENABLE_ICU1 /* use auto-EOI to reduce i/o */
+#else
+#define ENABLE_ICU1 \
+ movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \
+ FASTER_NOP ; /* ... ASAP ... */ \
+ outb %al,$IO_ICU1 /* ... to clear in service bit */
+#endif
+
+#ifdef AUTO_EOI_2
+/*
+ * The data sheet says no auto-EOI on slave, but it sometimes works.
+ */
+#define ENABLE_ICU1_AND_2 ENABLE_ICU1
+#else
+#define ENABLE_ICU1_AND_2 \
+ movb $ICU_EOI,%al ; /* as above */ \
+ FASTER_NOP ; \
+ outb %al,$IO_ICU2 ; /* but do second icu first */ \
+ FASTER_NOP ; \
+ outb %al,$IO_ICU1 /* then first icu */
+#endif
+
+#ifdef FAST_INTR_HANDLER_USES_ES
+#define ACTUALLY_PUSHED 1
+#define MAYBE_MOVW_AX_ES movl %ax,%es
+#define MAYBE_POPL_ES popl %es
+#define MAYBE_PUSHL_ES pushl %es
+#else
+/*
+ * We can usually skip loading %es for fastintr handlers. %es should
+ * only be used for string instructions, and fastintr handlers shouldn't
+ * do anything slow enough to justify using a string instruction.
+ */
+#define ACTUALLY_PUSHED 0
+#define MAYBE_MOVW_AX_ES
+#define MAYBE_POPL_ES
+#define MAYBE_PUSHL_ES
+#endif
+
+/*
+ * Macros for interrupt interrupt entry, call to handler, and exit.
+ *
+ * XXX - the interrupt frame is set up to look like a trap frame. This is
+ * usually a waste of time. The only interrupt handlers that want a frame
+ * are the clock handler (it wants a clock frame), the npx handler (it's
+ * easier to do right all in assembler). The interrupt return routine
+ * needs a trap frame for rare AST's (it could easily convert the frame).
+ * The direct costs of setting up a trap frame are two pushl's (error
+ * code and trap number), an addl to get rid of these, and pushing and
+ * popping the call-saved regs %esi, %edi and %ebp twice, The indirect
+ * costs are making the driver interface nonuniform so unpending of
+ * interrupts is more complicated and slower (call_driver(unit) would
+ * be easier than ensuring an interrupt frame for all handlers. Finally,
+ * there are some struct copies in the npx handler and maybe in the clock
+ * handler that could be avoided by working more with pointers to frames
+ * instead of frames.
+ *
+ * XXX - should we do a cld on every system entry to avoid the requirement
+ * for scattered cld's?
+ *
+ * Coding notes for *.s:
+ *
+ * If possible, avoid operations that involve an operand size override.
+ * Word-sized operations might be smaller, but the operand size override
+ * makes them slower on on 486's and no faster on 386's unless perhaps
+ * the instruction pipeline is depleted. E.g.,
+ *
+ * Use movl to seg regs instead of the equivalent but more descriptive
+ * movw - gas generates an irelevant (slower) operand size override.
+ *
+ * Use movl to ordinary regs in preference to movw and especially
+ * in preference to movz[bw]l. Use unsigned (long) variables with the
+ * top bits clear instead of unsigned short variables to provide more
+ * opportunities for movl.
+ *
+ * If possible, use byte-sized operations. They are smaller and no slower.
+ *
+ * Use (%reg) instead of 0(%reg) - gas generates larger code for the latter.
+ *
+ * If the interrupt frame is made more flexible, INTR can push %eax first
+ * and decide the ipending case with less overhead, e.g., by avoiding
+ * loading segregs.
+ */
+
+#define FAST_INTR(unit, irq_num, id_num, handler, enable_icus) \
+ pushl %eax ; /* save only call-used registers */ \
+ pushl %ecx ; \
+ pushl %edx ; \
+ pushl %ds ; \
+ MAYBE_PUSHL_ES ; \
+ movl $KDSEL,%eax ; \
+ movl %ax,%ds ; \
+ MAYBE_MOVW_AX_ES ; \
+ FAKE_MCOUNT((4+ACTUALLY_PUSHED)*4(%esp)) ; \
+ pushl $unit ; \
+ call handler ; /* do the work ASAP */ \
+ enable_icus ; /* (re)enable ASAP (helps edge trigger?) */ \
+ addl $4,%esp ; \
+ incl _cnt+V_INTR ; /* book-keeping can wait */ \
+ incl _intrcnt_actv + (id_num) * 4 ; \
+ movl _cpl,%eax ; /* are we unmasking pending HWIs or SWIs? */ \
+ notl %eax ; \
+ andl _ipending,%eax ; \
+ jne 1f ; /* yes, handle them */ \
+ MEXITCOUNT ; \
+ MAYBE_POPL_ES ; \
+ popl %ds ; \
+ popl %edx ; \
+ popl %ecx ; \
+ popl %eax ; \
+ iret ; \
+; \
+ ALIGN_TEXT ; \
+1: ; \
+ movl _cpl,%eax ; \
+ movl $HWI_MASK|SWI_MASK,_cpl ; /* limit nesting ... */ \
+ sti ; /* ... to do this as early as possible */ \
+ MAYBE_POPL_ES ; /* discard most of thin frame ... */ \
+ popl %ecx ; /* ... original %ds ... */ \
+ popl %edx ; \
+ xchgl %eax,(1+ACTUALLY_PUSHED)*4(%esp) ; /* orig %eax; save cpl */ \
+ pushal ; /* build fat frame (grrr) ... */ \
+ pushl %ecx ; /* ... actually %ds ... */ \
+ pushl %es ; \
+ movl $KDSEL,%eax ; \
+ movl %ax,%es ; \
+ movl (2+8+0)*4(%esp),%ecx ; /* ... %ecx from thin frame ... */ \
+ movl %ecx,(2+6)*4(%esp) ; /* ... to fat frame ... */ \
+ movl (2+8+1)*4(%esp),%eax ; /* ... cpl from thin frame */ \
+ pushl %eax ; \
+ subl $4,%esp ; /* junk for unit number */ \
+ MEXITCOUNT ; \
+ jmp _doreti
+
+#define INTR(unit, irq_num, id_num, mask, handler, icu, enable_icus, reg, stray) \
+ pushl $0 ; /* dumby error code */ \
+ pushl $0 ; /* dumby trap type */ \
+ pushal ; \
+ pushl %ds ; /* save our data and extra segments ... */ \
+ pushl %es ; \
+ movl $KDSEL,%eax ; /* ... and reload with kernel's own ... */ \
+ movl %ax,%ds ; /* ... early for obsolete reasons */ \
+ movl %ax,%es ; \
+ movb _imen + IRQ_BYTE(irq_num),%al ; \
+ orb $IRQ_BIT(irq_num),%al ; \
+ movb %al,_imen + IRQ_BYTE(irq_num) ; \
+ FASTER_NOP ; \
+ outb %al,$icu+1 ; \
+ enable_icus ; \
+ incl _cnt+V_INTR ; /* tally interrupts */ \
+ movl _cpl,%eax ; \
+ testb $IRQ_BIT(irq_num),%reg ; \
+ jne 2f ; \
+1: ; \
+ FAKE_MCOUNT(12*4(%esp)) ; /* XXX late to avoid double count */ \
+ incl _intrcnt_actv + (id_num) * 4 ; \
+ movl _cpl,%eax ; \
+ pushl %eax ; \
+ pushl $unit ; \
+ orl mask,%eax ; \
+ movl %eax,_cpl ; \
+ sti ; \
+ call handler ; \
+ movb _imen + IRQ_BYTE(irq_num),%al ; \
+ andb $~IRQ_BIT(irq_num),%al ; \
+ movb %al,_imen + IRQ_BYTE(irq_num) ; \
+ FASTER_NOP ; \
+ outb %al,$icu+1 ; \
+ MEXITCOUNT ; \
+ /* We could usually avoid the following jmp by inlining some of */ \
+ /* _doreti, but it's probably better to use less cache. */ \
+ jmp _doreti ; \
+; \
+ ALIGN_TEXT ; \
+2: ; \
+ /* XXX skip mcounting here to avoid double count */ \
+ movl $1b,%eax ; /* register resume address */ \
+ /* XXX - someday do it at attach time */ \
+ movl %eax,ihandlers + (irq_num) * 4 ; \
+ orb $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) ; \
+ popl %es ; \
+ popl %ds ; \
+ popal ; \
+ addl $4+4,%esp ; \
+ iret
+
+/*
+ * vector.h has defined a macro 'BUILD_VECTORS' containing a big list of info
+ * about vectors, including a submacro 'BUILD_VECTOR' that operates on the
+ * info about each vector. We redefine 'BUILD_VECTOR' to expand the info
+ * in different ways. Here we expand it to a list of interrupt handlers.
+ * This order is of course unimportant. Elsewhere we expand it to inline
+ * linear search code for which the order is a little more important and
+ * concatenating the code with no holes is very important.
+ *
+ * XXX - now there is BUILD_FAST_VECTOR as well as BUILD_VECTOR.
+ *
+ * The info consists of the following items for each vector:
+ *
+ * name (identifier): name of the vector; used to build labels
+ * unit (expression): unit number to call the device driver with
+ * irq_num (number): number of the IRQ to handled (0-15)
+ * id_num (number): uniq numeric id for handler (assigned by config)
+ * mask (blank-ident): priority mask used
+ * handler (blank-ident): interrupt handler to call
+ * icu_num (number): (1 + irq_num / 8) converted for label building
+ * icu_enables (number): 1 for icu_num == 1, 1_AND_2 for icu_num == 2
+ * reg (blank-ident): al for icu_num == 1, ah for icu_num == 2
+ *
+ * 'irq_num' is converted in several ways at config time to get around
+ * limitations in cpp. The macros have blanks after commas iff they would
+ * not mess up identifiers and numbers.
+ */
+
+#undef BUILD_FAST_VECTOR
+#define BUILD_FAST_VECTOR(name, unit, irq_num, id_num, mask, handler, \
+ icu_num, icu_enables, reg) \
+ .globl handler ; \
+ .text ; \
+ .globl _V/**/name ; \
+ SUPERALIGN_TEXT ; \
+_V/**/name: ; \
+ FAST_INTR(unit, irq_num,id_num, handler, ENABLE_ICU/**/icu_enables)
+
+#undef BUILD_VECTOR
+#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \
+ icu_num, icu_enables, reg) \
+ .globl handler ; \
+ .text ; \
+ .globl _V/**/name ; \
+ SUPERALIGN_TEXT ; \
+_V/**/name: ; \
+ INTR(unit,irq_num, id_num, mask, handler, IO_ICU/**/icu_num, \
+ ENABLE_ICU/**/icu_enables, reg,)
+
+MCOUNT_LABEL(bintr)
+ BUILD_VECTORS
+
+ /* hardware interrupt catcher (IDT 32 - 47) */
+ .globl _isa_strayintr
+
+#define STRAYINTR(irq_num, icu_num, icu_enables, reg) \
+IDTVEC(intr/**/irq_num) ; \
+ INTR(irq_num,irq_num,irq_num, _high_imask, _isa_strayintr, \
+ IO_ICU/**/icu_num, ENABLE_ICU/**/icu_enables, reg,stray)
+
+/*
+ * XXX - the mask (1 << 2) == IRQ_SLAVE will be generated for IRQ 2, instead
+ * of the mask IRQ2 (defined as IRQ9 == (1 << 9)). But IRQ 2 "can't happen".
+ * In fact, all stray interrupts "can't happen" except for bugs. The
+ * "stray" IRQ 7 is documented behaviour of the 8259. It happens when there
+ * is a glitch on any of its interrupt inputs. Does it really interrupt when
+ * IRQ 7 is masked?
+ *
+ * XXX - unpend doesn't work for these, it sends them to the real handler.
+ *
+ * XXX - the race bug during initialization may be because I changed the
+ * order of switching from the stray to the real interrupt handler to before
+ * enabling interrupts. The old order looked unsafe but maybe it is OK with
+ * the stray interrupt handler installed. But these handlers only reduce
+ * the window of vulnerability - it is still open at the end of
+ * isa_configure().
+ *
+ * XXX - many comments are stale.
+ */
+
+ STRAYINTR(0,1,1, al)
+ STRAYINTR(1,1,1, al)
+ STRAYINTR(2,1,1, al)
+ STRAYINTR(3,1,1, al)
+ STRAYINTR(4,1,1, al)
+ STRAYINTR(5,1,1, al)
+ STRAYINTR(6,1,1, al)
+ STRAYINTR(7,1,1, al)
+ STRAYINTR(8,2,1_AND_2, ah)
+ STRAYINTR(9,2,1_AND_2, ah)
+ STRAYINTR(10,2,1_AND_2, ah)
+ STRAYINTR(11,2,1_AND_2, ah)
+ STRAYINTR(12,2,1_AND_2, ah)
+ STRAYINTR(13,2,1_AND_2, ah)
+ STRAYINTR(14,2,1_AND_2, ah)
+ STRAYINTR(15,2,1_AND_2, ah)
+#if 0
+ INTRSTRAY(255, _highmask, 255) ; call _isa_strayintr ; INTREXIT2
+#endif
+MCOUNT_LABEL(eintr)
+
+/*
+ * These are the interrupt counters, I moved them here from icu.s so that
+ * they are with the name table. rgrimes
+ *
+ * There are now lots of counters, this has been redone to work with
+ * Bruce Evans intr-0.1 code, which I modified some more to make it all
+ * work with vmstat.
+ */
+ .data
+ihandlers: /* addresses of interrupt handlers */
+ .space NHWI*4 /* actually resumption addresses for HWI's */
+ .long swi_tty, swi_net, 0, 0, 0, 0, 0, 0
+ .long 0, 0, 0, 0, 0, 0, swi_clock, swi_ast
+imasks: /* masks for interrupt handlers */
+ .space NHWI*4 /* padding; HWI masks are elsewhere */
+ .long SWI_TTY_MASK, SWI_NET_MASK, 0, 0, 0, 0, 0, 0
+ .long 0, 0, 0, 0, 0, 0, SWI_CLOCK_MASK, SWI_AST_MASK
+
+ .globl _intrcnt
+_intrcnt: /* used by vmstat to calc size of table */
+ .globl _intrcnt_bad7
+_intrcnt_bad7: .space 4 /* glitches on irq 7 */
+ .globl _intrcnt_bad15
+_intrcnt_bad15: .space 4 /* glitches on irq 15 */
+ .globl _intrcnt_stray
+_intrcnt_stray: .space 4 /* total count of stray interrupts */
+ .globl _intrcnt_actv
+_intrcnt_actv: .space NR_REAL_INT_HANDLERS * 4 /* active interrupts */
+ .globl _eintrcnt
+_eintrcnt: /* used by vmstat to calc size of table */
+
+/*
+ * Build the interrupt name table for vmstat
+ */
+
+#undef BUILD_FAST_VECTOR
+#define BUILD_FAST_VECTOR BUILD_VECTOR
+
+#undef BUILD_VECTOR
+#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \
+ icu_num, icu_enables, reg) \
+ .ascii "name irq" ; \
+ .asciz "irq_num"
+/*
+ * XXX - use the __STRING and __CONCAT macros from <sys/cdefs.h> to stringize
+ * and concatenate names above and elsewhere. Note that __CONCAT doesn't
+ * work when nested.
+ */
+
+ .text
+ .globl _intrnames, _eintrnames
+_intrnames:
+ BUILD_VECTOR(bad,,7,,,,,,)
+ BUILD_VECTOR(bad,,15,,,,,,)
+ BUILD_VECTOR(stray,,,,,,,,)
+ BUILD_VECTORS
+
+_eintrnames:
diff --git a/sys/conf/Makefile.i386 b/sys/conf/Makefile.i386
new file mode 100644
index 0000000..db28a34
--- /dev/null
+++ b/sys/conf/Makefile.i386
@@ -0,0 +1,179 @@
+# Copyright 1990 W. Jolitz
+# from: @(#)Makefile.i386 7.1 5/10/91
+# $Id: Makefile.i386,v 1.23 1994/03/21 20:48:47 ats Exp $
+#
+# Makefile for FreeBSD
+#
+# This makefile is constructed from a machine description:
+# config machineid
+# Most changes should be made in the machine description
+# /sys/i386/conf/``machineid''
+# after which you should do
+# config machineid
+# Generic makefile changes should be made in
+# /sys/i386/conf/Makefile.i386
+# after which config should be rerun for all machines.
+#
+# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE INVISIBLE TO MAKEFILE
+# IF YOU CHANGE THE DEFINITION OF ANY OF THESE RECOMPILE EVERYTHING
+#
+# -DTRACE compile in kernel tracing hooks
+# -DQUOTA compile in file system quotas
+#
+TOUCH= touch -f -c
+LD= /usr/bin/ld
+CC= cc
+CPP= cpp
+STRIP= strip
+DBSYM= /usr/sbin/dbsym
+
+S= ../..
+I386= ../../i386
+
+CWARNFLAGS=-W -Wreturn-type -Wcomment
+#
+# The following flags are next up for working on:
+# -Wredundant-decls -Wnested-externs
+#
+# When working on removing warnings from code, the `-Werror' flag should be
+# of material assistance.
+#
+COPTFLAGS=-O
+COPTFLAGS+=-D__FreeBSD__
+INCLUDES= -I. -I$S -I$S/sys
+COPTS= ${INCLUDES} ${IDENT} -DKERNEL -Di386 -DNPX
+ASFLAGS=
+CFLAGS= ${COPTFLAGS} ${CWARNFLAGS} ${DEBUG} ${COPTS}
+LOAD_ADDRESS?= F0100000
+
+NORMAL_C= ${CC} -c ${CFLAGS} ${PROF} $<
+NORMAL_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $<
+NORMAL_S= ${CPP} -I. -DLOCORE ${COPTS} $< | ${AS} ${ASFLAGS} -o $*.o
+DRIVER_C= ${CC} -c ${CFLAGS} ${PROF} $<
+DRIVER_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $<
+SYSTEM_OBJS=locore.o exception.o swtch.o support.o ${OBJS} param.o \
+ ioconf.o conf.o machdep.o
+SYSTEM_DEP=Makefile symbols.sort ${SYSTEM_OBJS}
+SYSTEM_LD_HEAD= @echo loading $@; rm -f $@
+SYSTEM_LD= @${LD} -Bstatic -Z -T ${LOAD_ADDRESS} -o $@ -X ${SYSTEM_OBJS} vers.o
+SYSTEM_LD_TAIL= @echo rearranging symbols; symorder symbols.sort $@; \
+ ${DBSYM} -fT ${LOAD_ADDRESS} $@; ${STRIP} -x $@; size $@; chmod 755 $@
+
+# (XXX) ok, this is weird. but we've got a working ed, and a broken ex, and
+# the script is identical for either... -- cgd
+#
+GPROF.EX= /usr/src/lib/csu.i386/gprof.ex
+PROFILE_C= ${CC} -S -c ${CFLAGS} $< ; \
+ ed - $*.s < ${GPROF.EX} ; \
+ ${AS} -o $@ $*.s ; \
+ rm -f $*.s
+
+%OBJS
+
+%CFILES
+
+%LOAD
+
+clean:
+ rm -f eddep *386bsd tags *.o locore.i [a-uw-z]*.s \
+ errs linterrs makelinks genassym ,assym.s stamp-assym
+
+#lint: /tmp param.c
+# @lint -hbxn -I. -DGENERIC -Dvolatile= ${COPTS} ${PARAM} \
+# ${I386}/i386/Locore.c ${CFILES} ioconf.c param.c | \
+# grep -v 'struct/union .* never defined' | \
+# grep -v 'possible pointer alignment problem'
+
+symbols.sort: ${I386}/i386/symbols.raw
+ grep -v '^#' ${I386}/i386/symbols.raw \
+ | sed 's/^ //' | sort -u > symbols.sort
+
+locore.o: assym.s ${I386}/i386/locore.s machine/trap.h machine/psl.h \
+ machine/pte.h ${I386}/isa/vector.s ${I386}/isa/icu.s \
+ $S/sys/errno.h machine/specialreg.h \
+ ${I386}/isa/icu.h ${I386}/isa/isa.h vector.h $S/net/netisr.h \
+ machine/asmacros.h
+ ${CPP} -I. -DLOCORE ${COPTS} ${I386}/i386/locore.s | \
+ ${AS} ${ASFLAGS} -o locore.o
+
+exception.o: assym.s ${I386}/i386/exception.s machine/trap.h \
+ ${I386}/isa/vector.s ${I386}/isa/icu.s \
+ $S/sys/errno.h ${I386}/isa/icu.h ${I386}/isa/isa.h vector.h \
+ $S/net/netisr.h machine/asmacros.h
+ ${CPP} -I. -DLOCORE ${COPTS} ${I386}/i386/exception.s | \
+ ${AS} ${ASFLAGS} -o exception.o
+
+swtch.o: assym.s ${I386}/i386/swtch.s \
+ $S/sys/errno.h machine/asmacros.h
+ ${CPP} -I. ${COPTS} ${I386}/i386/swtch.s | \
+ ${AS} ${ASFLAGS} -o swtch.o
+
+support.o: assym.s ${I386}/i386/support.s \
+ $S/sys/errno.h machine/asmacros.h
+ ${CPP} -I. ${COPTS} ${I386}/i386/support.s | \
+ ${AS} ${ASFLAGS} -o support.o
+
+machdep.o: ${I386}/i386/machdep.c Makefile
+ ${CC} -c ${CFLAGS} -DLOAD_ADDRESS=0x${LOAD_ADDRESS} ${PROF} $<
+
+# the following is necessary because autoconf.o depends on #if GENERIC
+autoconf.o: Makefile
+
+# depend on network configuration
+af.o uipc_proto.o locore.o: Makefile
+
+# depends on KDB (cons.o also depends on GENERIC)
+trap.o cons.o: Makefile
+
+assym.s: genassym
+ ./genassym >,assym.s
+ if cmp -s assym.s ,assym.s; then \
+ rm -f ,assym.s; \
+ else \
+ rm -f assym.s; \
+ mv ,assym.s assym.s; \
+ fi
+
+# Some of the defines that genassym outputs may well depend on the
+# value of kernel options.
+genassym: Makefile
+ ${CC} ${INCLUDES} -DKERNEL ${IDENT} ${PARAM} \
+ ${I386}/i386/genassym.c -static -o genassym
+
+depend: assym.s param.c
+ sh /usr/bin/mkdep -DLOAD_ADDRESS=0x${LOAD_ADDRESS} ${COPTS} ${CFILES} ioconf.c param.c ${I386}/i386/conf.c
+ sh /usr/bin/mkdep -a -p ${INCLUDES} ${IDENT} ${PARAM} ${I386}/i386/genassym.c
+
+links:
+ egrep '#if' ${CFILES} | sed -f $S/conf/defines | \
+ sed -e 's/:.*//' -e 's/\.c/.o/' | sort -u > dontlink
+ echo ${CFILES} | tr -s ' ' '\12' | sed 's/\.c/.o/' | \
+ sort -u | comm -23 - dontlink | \
+ sed 's,../.*/\(.*.o\),rm -f \1;ln -s ../GENERIC/\1 \1,' > makelinks
+ sh makelinks && rm -f dontlink
+
+tags:
+ @echo "see $S/kern/Makefile for tags"
+
+ioconf.o: ioconf.c $S/sys/param.h machine/pte.h $S/sys/buf.h \
+ ${I386}/isa/isa_device.h ${I386}/isa/isa.h ${I386}/isa/icu.h
+ ${CC} -c ${CFLAGS} ioconf.c
+
+conf.o: ${I386}/i386/conf.c $S/sys/conf.h
+ ${CC} -c ${CFLAGS} ${I386}/i386/conf.c
+
+param.c: $S/conf/param.c
+ -rm -f param.c
+ cp $S/conf/param.c .
+
+param.o: param.c Makefile
+ ${CC} -c ${CFLAGS} ${PARAM} param.c
+
+vers.o: ${SYSTEM_DEP} ${SYSTEM_SWAP_DEP}
+ sh $S/conf/newvers.sh ${KERN_IDENT} ${IDENT}
+ ${CC} ${CFLAGS} -c vers.c
+
+%RULES
+
+# DO NOT DELETE THIS LINE -- make depend uses it
+
diff --git a/sys/conf/Makefile.powerpc b/sys/conf/Makefile.powerpc
new file mode 100644
index 0000000..db28a34
--- /dev/null
+++ b/sys/conf/Makefile.powerpc
@@ -0,0 +1,179 @@
+# Copyright 1990 W. Jolitz
+# from: @(#)Makefile.i386 7.1 5/10/91
+# $Id: Makefile.i386,v 1.23 1994/03/21 20:48:47 ats Exp $
+#
+# Makefile for FreeBSD
+#
+# This makefile is constructed from a machine description:
+# config machineid
+# Most changes should be made in the machine description
+# /sys/i386/conf/``machineid''
+# after which you should do
+# config machineid
+# Generic makefile changes should be made in
+# /sys/i386/conf/Makefile.i386
+# after which config should be rerun for all machines.
+#
+# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE INVISIBLE TO MAKEFILE
+# IF YOU CHANGE THE DEFINITION OF ANY OF THESE RECOMPILE EVERYTHING
+#
+# -DTRACE compile in kernel tracing hooks
+# -DQUOTA compile in file system quotas
+#
+TOUCH= touch -f -c
+LD= /usr/bin/ld
+CC= cc
+CPP= cpp
+STRIP= strip
+DBSYM= /usr/sbin/dbsym
+
+S= ../..
+I386= ../../i386
+
+CWARNFLAGS=-W -Wreturn-type -Wcomment
+#
+# The following flags are next up for working on:
+# -Wredundant-decls -Wnested-externs
+#
+# When working on removing warnings from code, the `-Werror' flag should be
+# of material assistance.
+#
+COPTFLAGS=-O
+COPTFLAGS+=-D__FreeBSD__
+INCLUDES= -I. -I$S -I$S/sys
+COPTS= ${INCLUDES} ${IDENT} -DKERNEL -Di386 -DNPX
+ASFLAGS=
+CFLAGS= ${COPTFLAGS} ${CWARNFLAGS} ${DEBUG} ${COPTS}
+LOAD_ADDRESS?= F0100000
+
+NORMAL_C= ${CC} -c ${CFLAGS} ${PROF} $<
+NORMAL_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $<
+NORMAL_S= ${CPP} -I. -DLOCORE ${COPTS} $< | ${AS} ${ASFLAGS} -o $*.o
+DRIVER_C= ${CC} -c ${CFLAGS} ${PROF} $<
+DRIVER_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $<
+SYSTEM_OBJS=locore.o exception.o swtch.o support.o ${OBJS} param.o \
+ ioconf.o conf.o machdep.o
+SYSTEM_DEP=Makefile symbols.sort ${SYSTEM_OBJS}
+SYSTEM_LD_HEAD= @echo loading $@; rm -f $@
+SYSTEM_LD= @${LD} -Bstatic -Z -T ${LOAD_ADDRESS} -o $@ -X ${SYSTEM_OBJS} vers.o
+SYSTEM_LD_TAIL= @echo rearranging symbols; symorder symbols.sort $@; \
+ ${DBSYM} -fT ${LOAD_ADDRESS} $@; ${STRIP} -x $@; size $@; chmod 755 $@
+
+# (XXX) ok, this is weird. but we've got a working ed, and a broken ex, and
+# the script is identical for either... -- cgd
+#
+GPROF.EX= /usr/src/lib/csu.i386/gprof.ex
+PROFILE_C= ${CC} -S -c ${CFLAGS} $< ; \
+ ed - $*.s < ${GPROF.EX} ; \
+ ${AS} -o $@ $*.s ; \
+ rm -f $*.s
+
+%OBJS
+
+%CFILES
+
+%LOAD
+
+clean:
+ rm -f eddep *386bsd tags *.o locore.i [a-uw-z]*.s \
+ errs linterrs makelinks genassym ,assym.s stamp-assym
+
+#lint: /tmp param.c
+# @lint -hbxn -I. -DGENERIC -Dvolatile= ${COPTS} ${PARAM} \
+# ${I386}/i386/Locore.c ${CFILES} ioconf.c param.c | \
+# grep -v 'struct/union .* never defined' | \
+# grep -v 'possible pointer alignment problem'
+
+symbols.sort: ${I386}/i386/symbols.raw
+ grep -v '^#' ${I386}/i386/symbols.raw \
+ | sed 's/^ //' | sort -u > symbols.sort
+
+locore.o: assym.s ${I386}/i386/locore.s machine/trap.h machine/psl.h \
+ machine/pte.h ${I386}/isa/vector.s ${I386}/isa/icu.s \
+ $S/sys/errno.h machine/specialreg.h \
+ ${I386}/isa/icu.h ${I386}/isa/isa.h vector.h $S/net/netisr.h \
+ machine/asmacros.h
+ ${CPP} -I. -DLOCORE ${COPTS} ${I386}/i386/locore.s | \
+ ${AS} ${ASFLAGS} -o locore.o
+
+exception.o: assym.s ${I386}/i386/exception.s machine/trap.h \
+ ${I386}/isa/vector.s ${I386}/isa/icu.s \
+ $S/sys/errno.h ${I386}/isa/icu.h ${I386}/isa/isa.h vector.h \
+ $S/net/netisr.h machine/asmacros.h
+ ${CPP} -I. -DLOCORE ${COPTS} ${I386}/i386/exception.s | \
+ ${AS} ${ASFLAGS} -o exception.o
+
+swtch.o: assym.s ${I386}/i386/swtch.s \
+ $S/sys/errno.h machine/asmacros.h
+ ${CPP} -I. ${COPTS} ${I386}/i386/swtch.s | \
+ ${AS} ${ASFLAGS} -o swtch.o
+
+support.o: assym.s ${I386}/i386/support.s \
+ $S/sys/errno.h machine/asmacros.h
+ ${CPP} -I. ${COPTS} ${I386}/i386/support.s | \
+ ${AS} ${ASFLAGS} -o support.o
+
+machdep.o: ${I386}/i386/machdep.c Makefile
+ ${CC} -c ${CFLAGS} -DLOAD_ADDRESS=0x${LOAD_ADDRESS} ${PROF} $<
+
+# the following is necessary because autoconf.o depends on #if GENERIC
+autoconf.o: Makefile
+
+# depend on network configuration
+af.o uipc_proto.o locore.o: Makefile
+
+# depends on KDB (cons.o also depends on GENERIC)
+trap.o cons.o: Makefile
+
+assym.s: genassym
+ ./genassym >,assym.s
+ if cmp -s assym.s ,assym.s; then \
+ rm -f ,assym.s; \
+ else \
+ rm -f assym.s; \
+ mv ,assym.s assym.s; \
+ fi
+
+# Some of the defines that genassym outputs may well depend on the
+# value of kernel options.
+genassym: Makefile
+ ${CC} ${INCLUDES} -DKERNEL ${IDENT} ${PARAM} \
+ ${I386}/i386/genassym.c -static -o genassym
+
+depend: assym.s param.c
+ sh /usr/bin/mkdep -DLOAD_ADDRESS=0x${LOAD_ADDRESS} ${COPTS} ${CFILES} ioconf.c param.c ${I386}/i386/conf.c
+ sh /usr/bin/mkdep -a -p ${INCLUDES} ${IDENT} ${PARAM} ${I386}/i386/genassym.c
+
+links:
+ egrep '#if' ${CFILES} | sed -f $S/conf/defines | \
+ sed -e 's/:.*//' -e 's/\.c/.o/' | sort -u > dontlink
+ echo ${CFILES} | tr -s ' ' '\12' | sed 's/\.c/.o/' | \
+ sort -u | comm -23 - dontlink | \
+ sed 's,../.*/\(.*.o\),rm -f \1;ln -s ../GENERIC/\1 \1,' > makelinks
+ sh makelinks && rm -f dontlink
+
+tags:
+ @echo "see $S/kern/Makefile for tags"
+
+ioconf.o: ioconf.c $S/sys/param.h machine/pte.h $S/sys/buf.h \
+ ${I386}/isa/isa_device.h ${I386}/isa/isa.h ${I386}/isa/icu.h
+ ${CC} -c ${CFLAGS} ioconf.c
+
+conf.o: ${I386}/i386/conf.c $S/sys/conf.h
+ ${CC} -c ${CFLAGS} ${I386}/i386/conf.c
+
+param.c: $S/conf/param.c
+ -rm -f param.c
+ cp $S/conf/param.c .
+
+param.o: param.c Makefile
+ ${CC} -c ${CFLAGS} ${PARAM} param.c
+
+vers.o: ${SYSTEM_DEP} ${SYSTEM_SWAP_DEP}
+ sh $S/conf/newvers.sh ${KERN_IDENT} ${IDENT}
+ ${CC} ${CFLAGS} -c vers.c
+
+%RULES
+
+# DO NOT DELETE THIS LINE -- make depend uses it
+
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
new file mode 100644
index 0000000..90c79b8
--- /dev/null
+++ b/sys/conf/NOTES
@@ -0,0 +1,197 @@
+#
+# LINT -- config file for checking all the sources, tries to pull in
+# as much of the source tree as it can.
+#
+# This kernel is NOT MEANT to be runnable!
+#
+# $Id: LINT,v 1.70 1994/05/17 23:20:32 jkh Exp $
+#
+
+machine "i386"
+cpu "I386_CPU"
+cpu "I486_CPU"
+ident LINT
+timezone 8 dst
+maxusers 10
+maxfdescs 2048 #Max file descriptors per process
+options MATH_EMULATE #Support for x87 emulation
+
+# Do not use in binary distributions
+#options GPL_MATH_EMULATE #Support for x87 emualtion via
+ #new math emulator
+
+config "386bsd" root on wd0 swap on wd0 and sd0 dumps on wd0
+
+#
+# options that appear as inline #ifdef's
+#
+options "COM_BIDIR" #Bidirectional support in sys/isa/sio.c
+options "COM_MULTIPORT" #Multiport support in sys/isa/sio.c
+options "FIFO_TRIGGER=FIFO_TRIGGER_1" #Use this fifo value in sio.c
+
+options "COMPAT_43" #compatible with BSD 4.3
+options "SYMTAB_SPACE=113498" #This kernel needs LOTS of symtable
+options GATEWAY #internetwork gateway
+options KTRACE #kernel tracing
+
+options "NCONS=8" #number of syscons virtual consoles
+options "FAT_CURSOR" #block cursor in syscons or pccons
+options "STAR_SAVER" #syscons "stars" screen saver
+options "FADE_SAVER" #syscons "fade" screen saver
+options "SNAKE_SAVER" #syscons "snake" screen saver
+options "BLANK_SAVER" #syscons "blank" screen saver
+
+#options ALLOW_CONFLICT_IOADDR #no IO addr conflict checks (PS/2 mice)
+#options ALLOW_CONFLICT_IRQ #no IRQ conflict checks (mport serial)
+
+options "TCP_COMPAT_42" #tcp/ip compatible with 4.2
+ # ^^^ NOT RECOMMENDED FOR NORMAL USE
+options UCONSOLE #x console support
+options XSERVER #xserver
+options DECBIT #here because clnp.h wanted it here
+ #support for CLNP ``congestion
+ #experienced'' bit in ISO-TP
+options TROLL #CLNP network error simulator
+options ICMPPRINTFS #ICMP packet dump by printf()
+options NSERRPRINTFS #ditto for XNS Error protocol
+ #^^above three NOT RECOMMENTED
+options FASTLINKS #support for fast symbolic links
+options MACHVMCOMPAT #support for Mach-style vm calls
+options IPBROADCASTECHO=1 #send reply to broadcast pings
+options IPMASKAGENT=1 #send reply to icmp mask requests
+options TPCONS #support X.25 network-layer service
+options USER_LDT #allow user-level control of i386 ldt
+
+# See /sys/i386/doc/sound.doc for information about EXCLUDE options for
+# the sound drivers.
+
+# Multicast support.
+options MULTICAST # Multicast code
+options MROUTING # Multicast routing
+
+#
+# options that are in sys/conf/files
+#
+pseudo-device bpfilter 4 #berkeley packet filter
+options CCITT
+device cd0 #Only need one of these, the code dynamically grows
+device ch0
+pseudo-device ddb
+pseudo-device devpager
+options EON
+pseudo-device ether
+options FIFO
+#pseudo-device imp
+options INET #Internet communications protocols
+options ISO
+options ISOFS #ISO 9660 File System
+pseudo-device loop
+options MFS #Memory File System
+options NFS #Network File System
+options NS #Xerox NS communications protocols
+options NSIP #XNS over IP
+options PCFS #PC (MSDOS) File System
+pseudo-device ppp 2
+pseudo-device pty 4
+options QUOTA #enable disk quotas
+options RMP #HP remote maint protocol
+controller scbus0
+device sd0
+device sd1
+device sd2
+device sd3
+pseudo-device sl 2
+device st0
+device st1
+pseudo-device swappager
+options SYSVSHM
+options "SHMMAXPGS=64" # 256Kb of sharable memory
+options SYSVSEM
+options SYSVMSG
+#pseudo-device tb #tablet line discipline.
+options TPIP # ISO TP class 4 over IP
+#pseudo-device tun
+device uk0 #unknown scsi devices
+pseudo-device vnodepager
+
+#
+# options that are in sys/i386/conf/files.i386
+#
+#This is needed here so the isa? below will work
+controller isa0
+
+# driver for the Adaptec 154x SCSI cards.
+controller aha0 at isa? port "IO_AHA0" bio irq 11 drq 5 vector ahaintr
+# driver for the Adaptec 174x SCSI cards.
+controller ahb0 at isa? bio irq 11 vector ahbintr
+# driver for the Bustek 742.
+controller bt0 at isa? port "IO_BT0" bio irq 12 vector btintr
+# driver for the Seagate ST01/ST02 card, not yet finished.
+#controller sg0 at isa? bio irq 5 iomem 0xc8000 iosiz 0x2000 vector sgintr
+controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
+disk fd0 at fdc0 drive 0
+disk fd1 at fdc0 drive 1
+tape ft0 at fdc0 drive 2
+
+# driver for the Western Digital and SMCC WD80xx cards, for the Novell
+# NE1000/2000 card and the 3COM 3C503 card.
+device ed0 at isa? port 0x280 net irq 5 iomem 0xd8000 vector edintr
+# driver for the AT&T Starlan card.
+device ie0 at isa? port 0x360 net irq 7 iomem 0xd0000 vector ieintr
+#driver for the Isolan AT 4114-0 and the Isolink 4110 ethernet card.
+device is0 at isa? port 0x280 net irq 10 drq 7 vector isintr
+#device ix0 at isa? port 0x320 net irq 10 iomem 0xd0000 iosiz 32768 vector ixintr
+# driver for the Etherlink III ( 3C509 ) card, beta version.
+device ep0 at isa? port 0x300 net irq 10 vector epintr
+#driver for the 3c501
+device el0 at isa? port 0x300 net irq 9 vector elintr
+
+#special cased above:
+#controller isa0
+# interruptless parallel printer port driver
+device lpa0 at isa? port "IO_LPT1" tty
+device lpa1 at isa? port "IO_LPT2" tty
+# interrupt driven parallel printer port driver
+device lpt0 at isa? port "IO_LPT3" tty irq 7 vector lptintr
+# Driver for Mitsumi CD-ROM players
+device mcd0 at isa? port 0x300 bio irq 10 vector mcdintr
+# Driver for Logitech and ATI inport bus mice
+device mse0 at isa? port 0x23c tty irq 5 vector mseintr
+device npx0 at isa? port "IO_NPX" irq 13 vector npxintr
+device pc0 at isa? port "IO_KBD" tty irq 1 vector pcrint
+#only one of pc0 or sc0 allowed
+#device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr
+device sio0 at isa? port "IO_COM1" tty irq 4 vector siointr
+device sio1 at isa? port "IO_COM2" tty irq 3 vector siointr
+device sio2 at isa? port "IO_COM3" tty irq 5 vector siointr
+device sio3 at isa? port "IO_COM4" tty irq 9 vector siointr
+#PS/2 mouse driver (must follow pc0 or sc0 if enabled). Also enable
+#ALLOW_CONFLICT_IOADDR option (see above) if you want to use this.
+#device psm0 at isa? port "IO_KBD" tty irq 12 vector psmintr
+
+pseudo-device speaker
+#tw device-driver
+controller uha0 at isa? port "IO_UHA0" bio irq 14 drq 5 vector uhaintr
+controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr
+disk wd0 at wdc0 drive 0
+disk wd1 at wdc0 drive 1
+controller wdc1 at isa? port "IO_WD2" bio irq 15 vector wdintr
+disk wd2 at wdc1 drive 0
+disk wd3 at wdc1 drive 1
+device wt0 at isa? port 0x300 bio irq 5 drq 1 vector wtintr
+
+# Various sound card drivers.
+# See /sys/doc/sound.doc for more information.
+device snd5 at isa? port 0x330 irq 6 vector mpuintr
+device snd4 at isa? port 0x220 irq 15 drq 6 vector gusintr
+device snd3 at isa? port 0x388 irq 10 drq 6 vector pasintr
+device snd2 at isa? port 0x220 irq 7 drq 1 vector sbintr
+device snd6 at isa? port 0x220 irq 7 drq 5 vector sbintr
+device snd7 at isa? port 0x300
+device snd1 at isa? port 0x388
+
+# The digital speaker driver (/dev/pcaudio).
+device pca0 at isa? tty
+
+# options that have not been resolved yet
+pseudo-device log
diff --git a/sys/conf/files.i386 b/sys/conf/files.i386
new file mode 100644
index 0000000..7aec440
--- /dev/null
+++ b/sys/conf/files.i386
@@ -0,0 +1,116 @@
+# This file tells config what files go into building a kernel,
+# files marked standard are always included.
+#
+# $Id: files.i386,v 1.32 1994/04/29 21:49:02 gclarkii Exp $
+#
+i386/i386/autoconf.c standard device-driver
+i386/i386/cons.c standard
+i386/i386/db_disasm.c optional ddb
+i386/i386/db_interface.c optional ddb
+i386/i386/db_trace.c optional ddb
+i386/i386/in_cksum.c optional inet
+i386/i386/math_emulate.c optional math_emulate
+i386/i386/mem.c standard
+i386/i386/microtime.s standard
+i386/i386/ns_cksum.c optional ns
+i386/i386/pmap.c standard
+i386/i386/sys_machdep.c standard
+i386/i386/trap.c standard
+i386/i386/vm_machdep.c standard
+i386/isa/aha1542.c optional aha device-driver
+i386/isa/aha1742.c optional ahb device-driver
+i386/isa/bt742a.c optional bt device-driver
+i386/isa/clock.c standard
+i386/isa/com.c optional com device-driver
+i386/isa/fd.c optional fd device-driver
+i386/isa/ft.c optional ft device-driver
+i386/isa/if_ed.c optional ed device-driver
+i386/isa/if_el.c optional el device-driver
+i386/isa/if_ep.c optional ep device-driver
+i386/isa/if_ie.c optional ie device-driver
+i386/isa/if_is.c optional is device-driver
+i386/isa/if_ix.c optional ix device-driver
+i386/isa/isa.c optional isa device-driver
+i386/isa/lpa.c optional lpa device-driver
+i386/isa/lpt.c optional lpt device-driver
+i386/isa/mcd.c optional mcd device-driver
+i386/isa/mse.c optional mse device-driver
+i386/isa/npx.c optional npx device-driver
+i386/isa/syscons.c optional sc device-driver
+i386/isa/pccons.c optional pc device-driver
+i386/isa/pcaudio.c optional pca device-driver
+i386/isa/psm.c optional psm device-driver
+i386/isa/sb.c optional sb device-driver
+i386/isa/scd.c optional scd device-driver
+i386/isa/sg.c optional sg device-driver
+i386/isa/sio.c optional sio device-driver
+i386/isa/sound/adlib_card.c optional snd device-driver
+i386/isa/sound/audio.c optional snd device-driver
+i386/isa/sound/dev_table.c optional snd device-driver
+i386/isa/sound/dmabuf.c optional snd device-driver
+i386/isa/sound/gus_card.c optional snd device-driver
+i386/isa/sound/gus_midi.c optional snd device-driver
+i386/isa/sound/gus_vol.c optional snd device-driver
+i386/isa/sound/gus_wave.c optional snd device-driver
+i386/isa/sound/ics2101.c optional snd device-driver
+i386/isa/sound/midi.c optional snd device-driver
+i386/isa/sound/midibuf.c optional snd device-driver
+i386/isa/sound/mpu401.c optional snd device-driver
+i386/isa/sound/opl3.c optional snd device-driver
+i386/isa/sound/pas2_card.c optional snd device-driver
+i386/isa/sound/pas2_midi.c optional snd device-driver
+i386/isa/sound/pas2_mixer.c optional snd device-driver
+i386/isa/sound/pas2_pcm.c optional snd device-driver
+i386/isa/sound/patmgr.c optional snd device-driver
+i386/isa/sound/pro_midi.c optional snd device-driver
+i386/isa/sound/sb16_dsp.c optional snd device-driver
+i386/isa/sound/sb16_midi.c optional snd device-driver
+i386/isa/sound/sb_card.c optional snd device-driver
+i386/isa/sound/sb_dsp.c optional snd device-driver
+i386/isa/sound/sb_midi.c optional snd device-driver
+i386/isa/sound/sb_mixer.c optional snd device-driver
+i386/isa/sound/sequencer.c optional snd device-driver
+i386/isa/sound/sound_switch.c optional snd device-driver
+i386/isa/sound/soundcard.c optional snd device-driver
+i386/isa/spkr.c optional speaker
+i386/isa/tw.c optional tw device-driver
+i386/isa/ultra14f.c optional uha device-driver
+i386/isa/wd.c optional wd device-driver
+i386/isa/wt.c optional wt device-driver
+i386/isa/pcvt/pcvt_drv.c optional vt device-driver
+i386/isa/pcvt/pcvt_sup.c optional vt device-driver
+i386/isa/pcvt/pcvt_out.c optional vt device-driver
+i386/isa/pcvt/pcvt_kbd.c optional vt device-driver
+i386/isa/pcvt/pcvt_vtf.c optional vt device-driver
+i386/isa/pcvt/pcvt_ext.c optional vt device-driver
+gnu/fpemul/div_small.s optional gpl_math_emulate
+gnu/fpemul/errors.c optional gpl_math_emulate
+gnu/fpemul/fpu_arith.c optional gpl_math_emulate
+gnu/fpemul/fpu_aux.c optional gpl_math_emulate
+gnu/fpemul/fpu_entry.c optional gpl_math_emulate
+gnu/fpemul/fpu_etc.c optional gpl_math_emulate
+gnu/fpemul/fpu_trig.c optional gpl_math_emulate
+gnu/fpemul/get_address.c optional gpl_math_emulate
+gnu/fpemul/load_store.c optional gpl_math_emulate
+gnu/fpemul/poly_2xm1.c optional gpl_math_emulate
+gnu/fpemul/poly_atan.c optional gpl_math_emulate
+gnu/fpemul/poly_div.s optional gpl_math_emulate
+gnu/fpemul/poly_l2.c optional gpl_math_emulate
+gnu/fpemul/poly_mul64.s optional gpl_math_emulate
+gnu/fpemul/poly_sin.c optional gpl_math_emulate
+gnu/fpemul/poly_tan.c optional gpl_math_emulate
+gnu/fpemul/polynomial.s optional gpl_math_emulate
+gnu/fpemul/reg_add_sub.c optional gpl_math_emulate
+gnu/fpemul/reg_compare.c optional gpl_math_emulate
+gnu/fpemul/reg_constant.c optional gpl_math_emulate
+gnu/fpemul/reg_div.s optional gpl_math_emulate
+gnu/fpemul/reg_ld_str.c optional gpl_math_emulate
+gnu/fpemul/reg_mul.c optional gpl_math_emulate
+gnu/fpemul/reg_norm.s optional gpl_math_emulate
+gnu/fpemul/reg_round.s optional gpl_math_emulate
+gnu/fpemul/reg_u_add.s optional gpl_math_emulate
+gnu/fpemul/reg_u_div.s optional gpl_math_emulate
+gnu/fpemul/reg_u_mul.s optional gpl_math_emulate
+gnu/fpemul/reg_u_sub.s optional gpl_math_emulate
+gnu/fpemul/wm_shrx.s optional gpl_math_emulate
+gnu/fpemul/wm_sqrt.s optional gpl_math_emulate
diff --git a/sys/ddb/db_access.c b/sys/ddb/db_access.c
new file mode 100644
index 0000000..9c8a00b
--- /dev/null
+++ b/sys/ddb/db_access.c
@@ -0,0 +1,103 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_access.c,v 1.3 1993/11/25 01:30:01 wollman Exp $
+ */
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "ddb/ddb.h"
+
+/*
+ * Access unaligned data items on aligned (longword)
+ * boundaries.
+ */
+
+extern void db_read_bytes(); /* machine-dependent */
+extern void db_write_bytes(); /* machine-dependent */
+
+unsigned db_extend[] = { /* table for sign-extending */
+ 0,
+ 0xFFFFFF80U,
+ 0xFFFF8000U,
+ 0xFF800000U
+};
+
+db_expr_t
+db_get_value(addr, size, is_signed)
+ db_addr_t addr;
+ register int size;
+ boolean_t is_signed;
+{
+ char data[sizeof(int)];
+ register db_expr_t value;
+ register int i;
+
+ db_read_bytes(addr, size, data);
+
+ value = 0;
+#if BYTE_MSF
+ for (i = 0; i < size; i++)
+#else /* BYTE_LSF */
+ for (i = size - 1; i >= 0; i--)
+#endif
+ {
+ value = (value << 8) + (data[i] & 0xFF);
+ }
+
+ if (size < 4) {
+ if (is_signed && (value & db_extend[size]) != 0)
+ value |= db_extend[size];
+ }
+ return (value);
+}
+
+void
+db_put_value(addr, size, value)
+ db_addr_t addr;
+ register int size;
+ register db_expr_t value;
+{
+ char data[sizeof(int)];
+ register int i;
+
+#if BYTE_MSF
+ for (i = size - 1; i >= 0; i--)
+#else /* BYTE_LSF */
+ for (i = 0; i < size; i++)
+#endif
+ {
+ data[i] = value & 0xFF;
+ value >>= 8;
+ }
+
+ db_write_bytes(addr, size, data);
+}
+
diff --git a/sys/ddb/db_access.h b/sys/ddb/db_access.h
new file mode 100644
index 0000000..a62edba
--- /dev/null
+++ b/sys/ddb/db_access.h
@@ -0,0 +1,47 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_access.h,v 1.2 1993/10/16 16:47:05 rgrimes Exp $
+ */
+
+#ifndef _DDB_DB_ACCESS_H_
+#define _DDB_DB_ACCESS_H_ 1
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+/*
+ * Data access functions for debugger.
+ */
+#include <machine/db_machdep.h> /* expression types */
+
+extern db_expr_t db_get_value(/* db_addr_t addr,
+ int size,
+ boolean_t is_signed */);
+extern void db_put_value(/* db_addr_t addr,
+ int size,
+ db_expr_t value */);
+#endif /* _DDB_DB_ACCESS_H_ */
diff --git a/sys/ddb/db_aout.c b/sys/ddb/db_aout.c
new file mode 100644
index 0000000..e256f21
--- /dev/null
+++ b/sys/ddb/db_aout.c
@@ -0,0 +1,407 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_aout.c,v 1.5 1994/01/03 07:54:08 davidg Exp $
+ */
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+/*
+ * Symbol table routines for a.out format files.
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "ddb/ddb.h"
+#include <ddb/db_sym.h>
+
+#ifndef DB_NO_AOUT
+
+#define _AOUT_INCLUDE_
+#include "nlist.h"
+#include "stab.h"
+
+/*
+ * An a.out symbol table as loaded into the kernel debugger:
+ *
+ * symtab -> size of symbol entries, in bytes
+ * sp -> first symbol entry
+ * ...
+ * ep -> last symbol entry + 1
+ * strtab == start of string table
+ * size of string table in bytes,
+ * including this word
+ * -> strings
+ */
+
+/*
+ * Find pointers to the start and end of the symbol entries,
+ * given a pointer to the start of the symbol table.
+ */
+#define db_get_aout_symtab(symtab, sp, ep) \
+ (sp = (struct nlist *)((symtab) + 1), \
+ ep = (struct nlist *)((char *)sp + *(symtab)))
+
+#ifndef SYMTAB_SPACE
+#define SYMTAB_SPACE 73000
+#endif /*SYMTAB_SPACE*/
+
+int db_symtabsize = SYMTAB_SPACE;
+char db_symtab[SYMTAB_SPACE] = { 1 };
+
+void
+X_db_sym_init(symtab, esymtab, name)
+ int * symtab; /* pointer to start of symbol table */
+ char * esymtab; /* pointer to end of string table,
+ for checking - rounded up to integer
+ boundary */
+ char * name;
+{
+ register struct nlist *sym_start, *sym_end;
+ register struct nlist *sp;
+ register char * strtab;
+ register int strlen;
+
+ if (*symtab < 4) {
+ printf ("DDB: no symbols\n");
+ return;
+ }
+
+ db_get_aout_symtab(symtab, sym_start, sym_end);
+
+ strtab = (char *)sym_end;
+ strlen = *(int *)strtab;
+
+#if 0
+ if (strtab + ((strlen + sizeof(int) - 1) & ~(sizeof(int)-1))
+ != esymtab)
+ {
+ db_printf("[ %s symbol table not valid ]\n", name);
+ return;
+ }
+
+ db_printf("[ preserving %#x bytes of %s symbol table ]\n",
+ esymtab - (char *)symtab, name);
+#endif
+
+ for (sp = sym_start; sp < sym_end; sp++) {
+ register int strx;
+ strx = sp->n_un.n_strx;
+ if (strx != 0) {
+ if (strx > strlen) {
+ db_printf("Bad string table index (%#x)\n", strx);
+ sp->n_un.n_name = 0;
+ continue;
+ }
+ sp->n_un.n_name = strtab + strx;
+ }
+ }
+
+ db_add_symbol_table(sym_start, sym_end, name, (char *)symtab);
+}
+
+db_sym_t
+X_db_lookup(stab, symstr)
+ db_symtab_t *stab;
+ char * symstr;
+{
+ register struct nlist *sp, *ep;
+
+ sp = (struct nlist *)stab->start;
+ ep = (struct nlist *)stab->end;
+
+ for (; sp < ep; sp++) {
+ if (sp->n_un.n_name == 0)
+ continue;
+ if ((sp->n_type & N_STAB) == 0 &&
+ sp->n_un.n_name != 0 &&
+ db_eqname(sp->n_un.n_name, symstr, '_'))
+ {
+ return ((db_sym_t)sp);
+ }
+ }
+ return ((db_sym_t)0);
+}
+
+db_sym_t
+X_db_search_symbol(symtab, off, strategy, diffp)
+ db_symtab_t * symtab;
+ register
+ db_addr_t off;
+ db_strategy_t strategy;
+ db_expr_t *diffp; /* in/out */
+{
+ register unsigned int diff = *diffp;
+ register struct nlist *symp = 0;
+ register struct nlist *sp, *ep;
+
+ sp = (struct nlist *)symtab->start;
+ ep = (struct nlist *)symtab->end;
+
+ for (; sp < ep; sp++) {
+ if (sp->n_un.n_name == 0)
+ continue;
+ if ((sp->n_type & N_STAB) != 0 || (sp->n_type & N_TYPE) == N_FN)
+ continue;
+ if (off >= sp->n_value) {
+ if (off - sp->n_value < diff) {
+ diff = off - sp->n_value;
+ symp = sp;
+ if (diff == 0 &&
+ (strategy == DB_STGY_PROC &&
+ sp->n_type == (N_TEXT|N_EXT) ||
+ strategy == DB_STGY_ANY &&
+ (sp->n_type & N_EXT)))
+ break;
+ }
+ else if (off - sp->n_value == diff) {
+ if (symp == 0)
+ symp = sp;
+ else if ((symp->n_type & N_EXT) == 0 &&
+ (sp->n_type & N_EXT) != 0)
+ symp = sp; /* pick the external symbol */
+ }
+ }
+ }
+ if (symp == 0) {
+ *diffp = off;
+ }
+ else {
+ *diffp = diff;
+ }
+ return ((db_sym_t)symp);
+}
+
+/*
+ * Return the name and value for a symbol.
+ */
+void
+X_db_symbol_values(sym, namep, valuep)
+ db_sym_t sym;
+ char **namep;
+ db_expr_t *valuep;
+{
+ register struct nlist *sp;
+
+ sp = (struct nlist *)sym;
+ if (namep)
+ *namep = sp->n_un.n_name;
+ if (valuep)
+ *valuep = sp->n_value;
+}
+
+
+boolean_t
+X_db_line_at_pc(symtab, cursym, filename, linenum, off)
+ db_symtab_t * symtab;
+ db_sym_t cursym;
+ char **filename;
+ int *linenum;
+ db_expr_t off;
+{
+ register struct nlist *sp, *ep;
+ register struct nlist *sym = (struct nlist *)cursym;
+ unsigned long sodiff = -1UL, lndiff = -1UL, ln = 0;
+ char *fname = NULL;
+
+ sp = (struct nlist *)symtab->start;
+ ep = (struct nlist *)symtab->end;
+
+/* XXX - gcc specific */
+#define NEWSRC(str) ((str) != NULL && \
+ (str)[0] == 'g' && strcmp((str), "gcc_compiled.") == 0)
+
+ for (; sp < ep; sp++) {
+
+ /*
+ * Prevent bogus linenumbers in case module not compiled
+ * with debugging options
+ */
+#if 0
+ if (sp->n_value <= off && (off - sp->n_value) <= sodiff &&
+ NEWSRC(sp->n_un.n_name)) {
+#endif
+ if ((sp->n_type & N_TYPE) == N_FN || NEWSRC(sp->n_un.n_name)) {
+ sodiff = lndiff = -1UL;
+ ln = 0;
+ fname = NULL;
+ }
+
+ if (sp->n_type == N_SO) {
+ if (sp->n_value <= off && (off - sp->n_value) < sodiff) {
+ sodiff = off - sp->n_value;
+ fname = sp->n_un.n_name;
+ }
+ continue;
+ }
+
+ if (sp->n_type != N_SLINE)
+ continue;
+
+ if (sp->n_value > off)
+ break;
+
+ if (off - sp->n_value < lndiff) {
+ lndiff = off - sp->n_value;
+ ln = sp->n_desc;
+ }
+ }
+
+ if (fname != NULL && ln != 0) {
+ *filename = fname;
+ *linenum = ln;
+ return TRUE;
+ }
+
+ return (FALSE);
+}
+
+boolean_t
+X_db_sym_numargs(symtab, cursym, nargp, argnamep)
+ db_symtab_t * symtab;
+ db_sym_t cursym;
+ int *nargp;
+ char **argnamep;
+{
+ register struct nlist *sp, *ep;
+ u_long addr;
+ int maxnarg = *nargp, nargs = 0;
+
+ if (cursym == NULL)
+ return FALSE;
+
+ addr = ((struct nlist *)cursym)->n_value;
+ sp = (struct nlist *)symtab->start;
+ ep = (struct nlist *)symtab->end;
+
+ for (; sp < ep; sp++) {
+ if (sp->n_type == N_FUN && sp->n_value == addr) {
+ while (++sp < ep && sp->n_type == N_PSYM) {
+ if (nargs >= maxnarg)
+ break;
+ nargs++;
+ *argnamep++ = sp->n_un.n_name?sp->n_un.n_name:"???";
+ {
+ /* XXX - remove trailers */
+ char *cp = *(argnamep-1);
+ while (*cp != '\0' && *cp != ':') cp++;
+ if (*cp == ':') *cp = '\0';
+ }
+ }
+ *nargp = nargs;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Initialization routine for a.out files.
+ */
+void
+kdb_init(void)
+{
+#if 0
+ extern char *esym;
+ extern int end;
+
+ if (esym > (char *)&end) {
+ X_db_sym_init((int *)&end, esym, "386bsd");
+ }
+#endif
+
+ X_db_sym_init (db_symtab, 0, "386bsd");
+}
+
+#if 0
+/*
+ * Read symbol table from file.
+ * (should be somewhere else)
+ */
+#include <boot_ufs/file_io.h>
+#include <vm/vm_kern.h>
+
+read_symtab_from_file(fp, symtab_name)
+ struct file *fp;
+ char * symtab_name;
+{
+ vm_size_t resid;
+ kern_return_t result;
+ vm_offset_t symoff;
+ vm_size_t symsize;
+ vm_offset_t stroff;
+ vm_size_t strsize;
+ vm_size_t table_size;
+ vm_offset_t symtab;
+
+ if (!get_symtab(fp, &symoff, &symsize)) {
+ boot_printf("[ error %d reading %s file header ]\n",
+ result, symtab_name);
+ return;
+ }
+
+ stroff = symoff + symsize;
+ result = read_file(fp, (vm_offset_t)stroff,
+ (vm_offset_t)&strsize, sizeof(strsize), &resid);
+ if (result || resid) {
+ boot_printf("[ no valid symbol table present for %s ]\n",
+ symtab_name);
+ return;
+ }
+
+ table_size = sizeof(int) + symsize + strsize;
+ table_size = (table_size + sizeof(int)-1) & ~(sizeof(int)-1);
+
+ symtab = kmem_alloc_wired(kernel_map, table_size);
+
+ *(int *)symtab = symsize;
+
+ result = read_file(fp, symoff,
+ symtab + sizeof(int), symsize, &resid);
+ if (result || resid) {
+ boot_printf("[ error %d reading %s symbol table ]\n",
+ result, symtab_name);
+ return;
+ }
+
+ result = read_file(fp, stroff,
+ symtab + sizeof(int) + symsize, strsize, &resid);
+ if (result || resid) {
+ boot_printf("[ error %d reading %s string table ]\n",
+ result, symtab_name);
+ return;
+ }
+
+ X_db_sym_init((int *)symtab,
+ (char *)(symtab + table_size),
+ symtab_name);
+
+}
+#endif
+
+#endif /* DB_NO_AOUT */
diff --git a/sys/ddb/db_break.c b/sys/ddb/db_break.c
new file mode 100644
index 0000000..41761e8
--- /dev/null
+++ b/sys/ddb/db_break.c
@@ -0,0 +1,353 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_break.c,v 1.2 1993/10/16 16:47:07 rgrimes Exp $
+ */
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+/*
+ * Breakpoints.
+ */
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "ddb/ddb.h"
+
+#include <ddb/db_lex.h>
+#include <ddb/db_break.h>
+#include <ddb/db_access.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_break.h>
+
+extern boolean_t db_map_equal();
+extern boolean_t db_map_current();
+extern vm_map_t db_map_addr();
+
+#define NBREAKPOINTS 100
+struct db_breakpoint db_break_table[NBREAKPOINTS];
+db_breakpoint_t db_next_free_breakpoint = &db_break_table[0];
+db_breakpoint_t db_free_breakpoints = 0;
+db_breakpoint_t db_breakpoint_list = 0;
+
+db_breakpoint_t
+db_breakpoint_alloc()
+{
+ register db_breakpoint_t bkpt;
+
+ if ((bkpt = db_free_breakpoints) != 0) {
+ db_free_breakpoints = bkpt->link;
+ return (bkpt);
+ }
+ if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) {
+ db_printf("All breakpoints used.\n");
+ return (0);
+ }
+ bkpt = db_next_free_breakpoint;
+ db_next_free_breakpoint++;
+
+ return (bkpt);
+}
+
+void
+db_breakpoint_free(bkpt)
+ register db_breakpoint_t bkpt;
+{
+ bkpt->link = db_free_breakpoints;
+ db_free_breakpoints = bkpt;
+}
+
+void
+db_set_breakpoint(map, addr, count)
+ vm_map_t map;
+ db_addr_t addr;
+ int count;
+{
+ register db_breakpoint_t bkpt;
+
+ if (db_find_breakpoint(map, addr)) {
+ db_printf("Already set.\n");
+ return;
+ }
+
+ bkpt = db_breakpoint_alloc();
+ if (bkpt == 0) {
+ db_printf("Too many breakpoints.\n");
+ return;
+ }
+
+ bkpt->map = map;
+ bkpt->address = addr;
+ bkpt->flags = 0;
+ bkpt->init_count = count;
+ bkpt->count = count;
+
+ bkpt->link = db_breakpoint_list;
+ db_breakpoint_list = bkpt;
+}
+
+void
+db_delete_breakpoint(map, addr)
+ vm_map_t map;
+ db_addr_t addr;
+{
+ register db_breakpoint_t bkpt;
+ register db_breakpoint_t *prev;
+
+ for (prev = &db_breakpoint_list;
+ (bkpt = *prev) != 0;
+ prev = &bkpt->link) {
+ if (db_map_equal(bkpt->map, map) &&
+ (bkpt->address == addr)) {
+ *prev = bkpt->link;
+ break;
+ }
+ }
+ if (bkpt == 0) {
+ db_printf("Not set.\n");
+ return;
+ }
+
+ db_breakpoint_free(bkpt);
+}
+
+db_breakpoint_t
+db_find_breakpoint(map, addr)
+ vm_map_t map;
+ db_addr_t addr;
+{
+ register db_breakpoint_t bkpt;
+
+ for (bkpt = db_breakpoint_list;
+ bkpt != 0;
+ bkpt = bkpt->link)
+ {
+ if (db_map_equal(bkpt->map, map) &&
+ (bkpt->address == addr))
+ return (bkpt);
+ }
+ return (0);
+}
+
+db_breakpoint_t
+db_find_breakpoint_here(addr)
+ db_addr_t addr;
+{
+ return db_find_breakpoint(db_map_addr(addr), addr);
+}
+
+boolean_t db_breakpoints_inserted = TRUE;
+
+void
+db_set_breakpoints()
+{
+ register db_breakpoint_t bkpt;
+
+ if (!db_breakpoints_inserted) {
+
+ for (bkpt = db_breakpoint_list;
+ bkpt != 0;
+ bkpt = bkpt->link)
+ if (db_map_current(bkpt->map)) {
+ bkpt->bkpt_inst = db_get_value(bkpt->address,
+ BKPT_SIZE,
+ FALSE);
+ db_put_value(bkpt->address,
+ BKPT_SIZE,
+ BKPT_SET(bkpt->bkpt_inst));
+ }
+ db_breakpoints_inserted = TRUE;
+ }
+}
+
+void
+db_clear_breakpoints()
+{
+ register db_breakpoint_t bkpt;
+
+ if (db_breakpoints_inserted) {
+
+ for (bkpt = db_breakpoint_list;
+ bkpt != 0;
+ bkpt = bkpt->link)
+ if (db_map_current(bkpt->map)) {
+ db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
+ }
+ db_breakpoints_inserted = FALSE;
+ }
+}
+
+/*
+ * Set a temporary breakpoint.
+ * The instruction is changed immediately,
+ * so the breakpoint does not have to be on the breakpoint list.
+ */
+db_breakpoint_t
+db_set_temp_breakpoint(addr)
+ db_addr_t addr;
+{
+ register db_breakpoint_t bkpt;
+
+ bkpt = db_breakpoint_alloc();
+ if (bkpt == 0) {
+ db_printf("Too many breakpoints.\n");
+ return 0;
+ }
+
+ bkpt->map = NULL;
+ bkpt->address = addr;
+ bkpt->flags = BKPT_TEMP;
+ bkpt->init_count = 1;
+ bkpt->count = 1;
+
+ bkpt->bkpt_inst = db_get_value(bkpt->address, BKPT_SIZE, FALSE);
+ db_put_value(bkpt->address, BKPT_SIZE, BKPT_SET(bkpt->bkpt_inst));
+ return bkpt;
+}
+
+void
+db_delete_temp_breakpoint(bkpt)
+ db_breakpoint_t bkpt;
+{
+ db_put_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst);
+ db_breakpoint_free(bkpt);
+}
+
+/*
+ * List breakpoints.
+ */
+void
+db_list_breakpoints()
+{
+ register db_breakpoint_t bkpt;
+
+ if (db_breakpoint_list == 0) {
+ db_printf("No breakpoints set\n");
+ return;
+ }
+
+ db_printf(" Map Count Address\n");
+ for (bkpt = db_breakpoint_list;
+ bkpt != 0;
+ bkpt = bkpt->link)
+ {
+ db_printf("%s%8x %5d ",
+ db_map_current(bkpt->map) ? "*" : " ",
+ bkpt->map, bkpt->init_count);
+ db_printsym(bkpt->address, DB_STGY_PROC);
+ db_printf("\n");
+ }
+}
+
+/* Delete breakpoint */
+/*ARGSUSED*/
+void
+db_delete_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ db_delete_breakpoint(db_map_addr(addr), (db_addr_t)addr);
+}
+
+/* Set breakpoint with skip count */
+/*ARGSUSED*/
+void
+db_breakpoint_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ if (count == -1)
+ count = 1;
+
+ db_set_breakpoint(db_map_addr(addr), (db_addr_t)addr, count);
+}
+
+/* list breakpoints */
+void
+db_listbreak_cmd(db_expr_t dummy1, int dummy2, db_expr_t dummy3, char *dummy4)
+{
+ db_list_breakpoints();
+}
+
+#include <vm/vm_kern.h>
+
+/*
+ * We want ddb to be usable before most of the kernel has been
+ * initialized. In particular, current_thread() or kernel_map
+ * (or both) may be null.
+ */
+
+boolean_t
+db_map_equal(map1, map2)
+ vm_map_t map1, map2;
+{
+ return ((map1 == map2) ||
+ ((map1 == NULL) && (map2 == kernel_map)) ||
+ ((map1 == kernel_map) && (map2 == NULL)));
+}
+
+boolean_t
+db_map_current(map)
+ vm_map_t map;
+{
+#if 0
+ thread_t thread;
+
+ return ((map == NULL) ||
+ (map == kernel_map) ||
+ (((thread = current_thread()) != NULL) &&
+ (map == thread->task->map)));
+#else
+ return (1);
+#endif
+}
+
+vm_map_t
+db_map_addr(addr)
+ vm_offset_t addr;
+{
+#if 0
+ thread_t thread;
+
+ /*
+ * We want to return kernel_map for all
+ * non-user addresses, even when debugging
+ * kernel tasks with their own maps.
+ */
+
+ if ((VM_MIN_ADDRESS <= addr) &&
+ (addr < VM_MAX_ADDRESS) &&
+ ((thread = current_thread()) != NULL))
+ return thread->task->map;
+ else
+#endif
+ return kernel_map;
+}
diff --git a/sys/ddb/db_break.h b/sys/ddb/db_break.h
new file mode 100644
index 0000000..dc66dca
--- /dev/null
+++ b/sys/ddb/db_break.h
@@ -0,0 +1,64 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id$
+ */
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+#ifndef _DDB_DB_BREAK_H_
+#define _DDB_DB_BREAK_H_
+
+#include <vm/vm_map.h>
+#include <machine/db_machdep.h>
+
+/*
+ * Breakpoint.
+ */
+
+struct db_breakpoint {
+ vm_map_t map; /* in this map */
+ db_addr_t address; /* set here */
+ int init_count; /* number of times to skip bkpt */
+ int count; /* current count */
+ int flags; /* flags: */
+#define BKPT_SINGLE_STEP 0x2 /* to simulate single step */
+#define BKPT_TEMP 0x4 /* temporary */
+ int bkpt_inst; /* saved instruction at bkpt */
+ struct db_breakpoint *link; /* link in in-use or free chain */
+};
+typedef struct db_breakpoint *db_breakpoint_t;
+
+extern db_breakpoint_t db_find_breakpoint();
+extern db_breakpoint_t db_find_breakpoint_here();
+extern void db_set_breakpoints();
+extern void db_clear_breakpoints();
+
+extern db_breakpoint_t db_set_temp_breakpoint(/* db_addr_t addr */);
+extern void db_delete_temp_breakpoint(/* db_breakpoint_t bkpt */);
+
+#endif _DDB_DB_BREAK_H_
diff --git a/sys/ddb/db_command.c b/sys/ddb/db_command.c
new file mode 100644
index 0000000..735b3c0
--- /dev/null
+++ b/sys/ddb/db_command.c
@@ -0,0 +1,483 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_command.c,v 1.3 1993/11/25 01:30:04 wollman Exp $
+ */
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+/*
+ * Command dispatcher.
+ */
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "ddb/ddb.h"
+
+#include <ddb/db_lex.h>
+#include <ddb/db_output.h>
+
+#include <setjmp.h>
+
+/*
+ * Exported global variables
+ */
+boolean_t db_cmd_loop_done;
+jmp_buf db_jmpbuf;
+db_addr_t db_dot;
+db_addr_t db_last_addr;
+db_addr_t db_prev;
+db_addr_t db_next;
+
+/*
+ * if 'ed' style: 'dot' is set at start of last item printed,
+ * and '+' points to next line.
+ * Otherwise: 'dot' points to next item, '..' points to last.
+ */
+boolean_t db_ed_style = TRUE;
+
+
+/*
+ * Utility routine - discard tokens through end-of-line.
+ */
+void
+db_skip_to_eol()
+{
+ int t;
+ do {
+ t = db_read_token();
+ } while (t != tEOL);
+}
+
+/*
+ * Command table
+ */
+struct command {
+ char * name; /* command name */
+ void (*fcn)(); /* function to call */
+ int flag; /* extra info: */
+#define CS_OWN 0x1 /* non-standard syntax */
+#define CS_MORE 0x2 /* standard syntax, but may have other
+ words at end */
+#define CS_SET_DOT 0x100 /* set dot after command */
+ struct command *more; /* another level of command */
+};
+
+/*
+ * Results of command search.
+ */
+#define CMD_UNIQUE 0
+#define CMD_FOUND 1
+#define CMD_NONE 2
+#define CMD_AMBIGUOUS 3
+#define CMD_HELP 4
+
+/*
+ * Search for command prefix.
+ */
+int
+db_cmd_search(name, table, cmdp)
+ char * name;
+ struct command *table;
+ struct command **cmdp; /* out */
+{
+ struct command *cmd;
+ int result = CMD_NONE;
+
+ for (cmd = table; cmd->name != 0; cmd++) {
+ register char *lp;
+ register char *rp;
+ register int c;
+
+ lp = name;
+ rp = cmd->name;
+ while ((c = *lp) == *rp) {
+ if (c == 0) {
+ /* complete match */
+ *cmdp = cmd;
+ return (CMD_UNIQUE);
+ }
+ lp++;
+ rp++;
+ }
+ if (c == 0) {
+ /* end of name, not end of command -
+ partial match */
+ if (result == CMD_FOUND) {
+ result = CMD_AMBIGUOUS;
+ /* but keep looking for a full match -
+ this lets us match single letters */
+ }
+ else {
+ *cmdp = cmd;
+ result = CMD_FOUND;
+ }
+ }
+ }
+ if (result == CMD_NONE) {
+ /* check for 'help' */
+ if (name[0] == 'h' && name[1] == 'e'
+ && name[2] == 'l' && name[3] == 'p')
+ result = CMD_HELP;
+ }
+ return (result);
+}
+
+void
+db_cmd_list(table)
+ struct command *table;
+{
+ register struct command *cmd;
+
+ for (cmd = table; cmd->name != 0; cmd++) {
+ db_printf("%-12s", cmd->name);
+ db_end_line();
+ }
+}
+
+void
+db_command(last_cmdp, cmd_table)
+ struct command **last_cmdp; /* IN_OUT */
+ struct command *cmd_table;
+{
+ struct command *cmd;
+ int t;
+ char modif[TOK_STRING_SIZE];
+ db_expr_t addr, count;
+ boolean_t have_addr = FALSE;
+ int result;
+
+ t = db_read_token();
+ if (t == tEOL) {
+ /* empty line repeats last command, at 'next' */
+ cmd = *last_cmdp;
+ addr = (db_expr_t)db_next;
+ have_addr = FALSE;
+ count = 1;
+ modif[0] = '\0';
+ }
+ else if (t == tEXCL) {
+ void db_fncall();
+ db_fncall();
+ return;
+ }
+ else if (t != tIDENT) {
+ db_printf("?\n");
+ db_flush_lex();
+ return;
+ }
+ else {
+ /*
+ * Search for command
+ */
+ while (cmd_table) {
+ result = db_cmd_search(db_tok_string,
+ cmd_table,
+ &cmd);
+ switch (result) {
+ case CMD_NONE:
+ db_printf("No such command\n");
+ db_flush_lex();
+ return;
+ case CMD_AMBIGUOUS:
+ db_printf("Ambiguous\n");
+ db_flush_lex();
+ return;
+ case CMD_HELP:
+ db_cmd_list(cmd_table);
+ db_flush_lex();
+ return;
+ default:
+ break;
+ }
+ if ((cmd_table = cmd->more) != 0) {
+ t = db_read_token();
+ if (t != tIDENT) {
+ db_cmd_list(cmd_table);
+ db_flush_lex();
+ return;
+ }
+ }
+ }
+
+ if ((cmd->flag & CS_OWN) == 0) {
+ /*
+ * Standard syntax:
+ * command [/modifier] [addr] [,count]
+ */
+ t = db_read_token();
+ if (t == tSLASH) {
+ t = db_read_token();
+ if (t != tIDENT) {
+ db_printf("Bad modifier\n");
+ db_flush_lex();
+ return;
+ }
+ db_strcpy(modif, db_tok_string);
+ }
+ else {
+ db_unread_token(t);
+ modif[0] = '\0';
+ }
+
+ if (db_expression(&addr)) {
+ db_dot = (db_addr_t) addr;
+ db_last_addr = db_dot;
+ have_addr = TRUE;
+ }
+ else {
+ addr = (db_expr_t) db_dot;
+ have_addr = FALSE;
+ }
+ t = db_read_token();
+ if (t == tCOMMA) {
+ if (!db_expression(&count)) {
+ db_printf("Count missing\n");
+ db_flush_lex();
+ return;
+ }
+ }
+ else {
+ db_unread_token(t);
+ count = -1;
+ }
+ if ((cmd->flag & CS_MORE) == 0) {
+ db_skip_to_eol();
+ }
+ }
+ }
+ *last_cmdp = cmd;
+ if (cmd != 0) {
+ /*
+ * Execute the command.
+ */
+ (*cmd->fcn)(addr, have_addr, count, modif);
+
+ if (cmd->flag & CS_SET_DOT) {
+ /*
+ * If command changes dot, set dot to
+ * previous address displayed (if 'ed' style).
+ */
+ if (db_ed_style) {
+ db_dot = db_prev;
+ }
+ else {
+ db_dot = db_next;
+ }
+ }
+ else {
+ /*
+ * If command does not change dot,
+ * set 'next' location to be the same.
+ */
+ db_next = db_dot;
+ }
+ }
+}
+
+/*
+ * 'show' commands
+ */
+extern void db_listbreak_cmd();
+extern void db_listwatch_cmd();
+extern void db_show_regs(), db_show_one_thread(), db_show_all_threads();
+extern void vm_map_print(), vm_object_print(), vm_page_print();
+extern void db_ps();
+extern void ipc_port_print();
+void db_show_help();
+
+struct command db_show_all_cmds[] = {
+#if 0
+ { "threads", db_show_all_threads, 0, 0 },
+#endif
+ { "procs", db_ps, 0, 0 },
+ { (char *)0 }
+};
+
+struct command db_show_cmds[] = {
+ { "all", 0, 0, db_show_all_cmds },
+ { "registers", db_show_regs, 0, 0 },
+ { "breaks", db_listbreak_cmd, 0, 0 },
+ { "watches", db_listwatch_cmd, 0, 0 },
+#if 0
+ { "thread", db_show_one_thread, 0, 0 },
+#endif
+ { "map", vm_map_print, 0, 0 },
+ { "object", vm_object_print, 0, 0 },
+#if 0
+ { "page", vm_page_print, 0, 0 },
+#endif
+#if 0
+ { "port", ipc_port_print, 0, 0 },
+#endif
+ { (char *)0, }
+};
+
+extern void db_print_cmd(), db_examine_cmd(), db_set_cmd();
+extern void db_search_cmd();
+extern void db_write_cmd();
+extern void db_delete_cmd(), db_breakpoint_cmd();
+extern void db_deletewatch_cmd(), db_watchpoint_cmd();
+extern void db_single_step_cmd(), db_trace_until_call_cmd(),
+ db_trace_until_matching_cmd(), db_continue_cmd();
+extern void db_stack_trace_cmd();
+void db_help_cmd();
+void db_fncall();
+
+struct command db_command_table[] = {
+ { "print", db_print_cmd, 0, 0 },
+ { "examine", db_examine_cmd, CS_SET_DOT, 0 },
+ { "x", db_examine_cmd, CS_SET_DOT, 0 },
+ { "search", db_search_cmd, CS_OWN|CS_SET_DOT, 0 },
+ { "set", db_set_cmd, CS_OWN, 0 },
+ { "write", db_write_cmd, CS_MORE|CS_SET_DOT, 0 },
+ { "w", db_write_cmd, CS_MORE|CS_SET_DOT, 0 },
+ { "delete", db_delete_cmd, 0, 0 },
+ { "d", db_delete_cmd, 0, 0 },
+ { "break", db_breakpoint_cmd, 0, 0 },
+ { "dwatch", db_deletewatch_cmd, 0, 0 },
+ { "watch", db_watchpoint_cmd, CS_MORE,0 },
+ { "step", db_single_step_cmd, 0, 0 },
+ { "s", db_single_step_cmd, 0, 0 },
+ { "continue", db_continue_cmd, 0, 0 },
+ { "c", db_continue_cmd, 0, 0 },
+ { "until", db_trace_until_call_cmd,0, 0 },
+ { "next", db_trace_until_matching_cmd,0, 0 },
+ { "match", db_trace_until_matching_cmd,0, 0 },
+ { "trace", db_stack_trace_cmd, 0, 0 },
+ { "call", db_fncall, CS_OWN, 0 },
+ { "show", 0, 0, db_show_cmds },
+ { "ps", db_ps, 0, 0 },
+ { (char *)0, }
+};
+
+struct command *db_last_command = 0;
+
+void
+db_help_cmd()
+{
+ struct command *cmd = db_command_table;
+
+ while (cmd->name != 0) {
+ db_printf("%-12s", cmd->name);
+ db_end_line();
+ cmd++;
+ }
+}
+
+void
+db_command_loop()
+{
+ /*
+ * Initialize 'prev' and 'next' to dot.
+ */
+ db_prev = db_dot;
+ db_next = db_dot;
+
+ db_cmd_loop_done = 0;
+ while (!db_cmd_loop_done) {
+
+ (void) setjmp(db_jmpbuf);
+ if (db_print_position() != 0)
+ db_printf("\n");
+
+ db_printf("db> ");
+ (void) db_read_line();
+
+ db_command(&db_last_command, db_command_table);
+ }
+}
+
+void
+db_error(s)
+ char *s;
+{
+ if (s)
+ db_printf(s);
+ db_flush_lex();
+ longjmp(db_jmpbuf, 1);
+}
+
+
+/*
+ * Call random function:
+ * !expr(arg,arg,arg)
+ */
+void
+db_fncall()
+{
+ db_expr_t fn_addr;
+#define MAXARGS 11
+ db_expr_t args[MAXARGS];
+ int nargs = 0;
+ db_expr_t retval;
+ db_expr_t (*func)();
+ int t;
+
+ if (!db_expression(&fn_addr)) {
+ db_printf("Bad function\n");
+ db_flush_lex();
+ return;
+ }
+ func = (db_expr_t (*) ()) fn_addr;
+
+ t = db_read_token();
+ if (t == tLPAREN) {
+ if (db_expression(&args[0])) {
+ nargs++;
+ while ((t = db_read_token()) == tCOMMA) {
+ if (nargs == MAXARGS) {
+ db_printf("Too many arguments\n");
+ db_flush_lex();
+ return;
+ }
+ if (!db_expression(&args[nargs])) {
+ db_printf("Argument missing\n");
+ db_flush_lex();
+ return;
+ }
+ nargs++;
+ }
+ db_unread_token(t);
+ }
+ if (db_read_token() != tRPAREN) {
+ db_printf("?\n");
+ db_flush_lex();
+ return;
+ }
+ }
+ db_skip_to_eol();
+
+ while (nargs < MAXARGS) {
+ args[nargs++] = 0;
+ }
+
+ retval = (*func)(args[0], args[1], args[2], args[3], args[4],
+ args[5], args[6], args[7], args[8], args[9] );
+ db_printf("%#n\n", retval);
+}
diff --git a/sys/ddb/db_command.h b/sys/ddb/db_command.h
new file mode 100644
index 0000000..a883e63
--- /dev/null
+++ b/sys/ddb/db_command.h
@@ -0,0 +1,57 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_command.h,v 1.2 1993/10/16 16:47:12 rgrimes Exp $
+ */
+
+#ifndef _DDB_DB_COMMAND_H_
+#define _DDB_DB_COMMAND_H_ 1
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+/*
+ * Command loop declarations.
+ */
+
+#include "param.h"
+#include "proc.h"
+#include <machine/db_machdep.h>
+
+extern void db_command_loop();
+extern void db_skip_to_eol();
+
+extern void db_error(/* char * */); /* report error */
+
+extern db_addr_t db_dot; /* current location */
+extern db_addr_t db_last_addr; /* last explicit address typed */
+extern db_addr_t db_prev; /* last address examined
+ or written */
+extern db_addr_t db_next; /* next address to be examined
+ or written */
+
+
+#endif /* _DDB_DB_COMMAND_H_ */
diff --git a/sys/ddb/db_examine.c b/sys/ddb/db_examine.c
new file mode 100644
index 0000000..f4f7ba1
--- /dev/null
+++ b/sys/ddb/db_examine.c
@@ -0,0 +1,340 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_examine.c,v 1.3 1993/11/25 01:30:05 wollman Exp $
+ */
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+
+#include "ddb/ddb.h"
+
+#include "ddb/db_lex.h"
+#include "ddb/db_output.h"
+#include "ddb/db_command.h"
+#include "ddb/db_sym.h"
+#include "ddb/db_access.h"
+
+char db_examine_format[TOK_STRING_SIZE] = "x";
+
+extern db_addr_t db_disasm(/* db_addr_t, boolean_t */);
+ /* instruction disassembler */
+
+static void db_examine(db_addr_t, char *, int);
+static void db_search(db_addr_t, int, db_expr_t, db_expr_t, u_int);
+
+/*
+ * Examine (print) data.
+ */
+/*ARGSUSED*/
+void
+db_examine_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ if (modif[0] != '\0')
+ db_strcpy(db_examine_format, modif);
+
+ if (count == -1)
+ count = 1;
+
+ db_examine((db_addr_t) addr, db_examine_format, count);
+}
+
+static void
+db_examine(addr, fmt, count)
+ register
+ db_addr_t addr;
+ char * fmt; /* format string */
+ int count; /* repeat count */
+{
+ int c;
+ db_expr_t value;
+ int size;
+ int width;
+ char * fp;
+
+ while (--count >= 0) {
+ fp = fmt;
+ size = 4;
+ width = 16;
+ while ((c = *fp++) != 0) {
+ switch (c) {
+ case 'b':
+ size = 1;
+ width = 4;
+ break;
+ case 'h':
+ size = 2;
+ width = 8;
+ break;
+ case 'l':
+ size = 4;
+ width = 16;
+ break;
+ case 'a': /* address */
+ /* always forces a new line */
+ if (db_print_position() != 0)
+ db_printf("\n");
+ db_prev = addr;
+ db_printsym(addr, DB_STGY_ANY);
+ db_printf(":\t");
+ break;
+ default:
+ if (db_print_position() == 0) {
+ /* If we hit a new symbol, print it */
+ char * name;
+ db_expr_t off;
+
+ db_find_sym_and_offset(addr, &name, &off);
+ if (off == 0)
+ db_printf("%s:\t", name);
+ else
+ db_printf("\t\t");
+
+ db_prev = addr;
+ }
+
+ switch (c) {
+ case 'r': /* signed, current radix */
+ value = db_get_value(addr, size, TRUE);
+ addr += size;
+ db_printf("%-*r", width, value);
+ break;
+ case 'x': /* unsigned hex */
+ value = db_get_value(addr, size, FALSE);
+ addr += size;
+ db_printf("%-*x", width, value);
+ break;
+ case 'z': /* signed hex */
+ value = db_get_value(addr, size, TRUE);
+ addr += size;
+ db_printf("%-*z", width, value);
+ break;
+ case 'd': /* signed decimal */
+ value = db_get_value(addr, size, TRUE);
+ addr += size;
+ db_printf("%-*d", width, value);
+ break;
+ case 'u': /* unsigned decimal */
+ value = db_get_value(addr, size, FALSE);
+ addr += size;
+ db_printf("%-*u", width, value);
+ break;
+ case 'o': /* unsigned octal */
+ value = db_get_value(addr, size, FALSE);
+ addr += size;
+ db_printf("%-*o", width, value);
+ break;
+ case 'c': /* character */
+ value = db_get_value(addr, 1, FALSE);
+ addr += 1;
+ if (value >= ' ' && value <= '~')
+ db_printf("%c", value);
+ else
+ db_printf("\\%03o", value);
+ break;
+ case 's': /* null-terminated string */
+ for (;;) {
+ value = db_get_value(addr, 1, FALSE);
+ addr += 1;
+ if (value == 0)
+ break;
+ if (value >= ' ' && value <= '~')
+ db_printf("%c", value);
+ else
+ db_printf("\\%03o", value);
+ }
+ break;
+ case 'i': /* instruction */
+ addr = db_disasm(addr, FALSE);
+ break;
+ case 'I': /* instruction, alternate form */
+ addr = db_disasm(addr, TRUE);
+ break;
+ default:
+ break;
+ }
+ if (db_print_position() != 0)
+ db_end_line();
+ break;
+ }
+ }
+ }
+ db_next = addr;
+}
+
+/*
+ * Print value.
+ */
+char db_print_format = 'x';
+
+/*ARGSUSED*/
+void
+db_print_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ db_expr_t value;
+
+ if (modif[0] != '\0')
+ db_print_format = modif[0];
+
+ switch (db_print_format) {
+ case 'a':
+ db_printsym((db_addr_t)addr, DB_STGY_ANY);
+ break;
+ case 'r':
+ db_printf("%11r", addr);
+ break;
+ case 'x':
+ db_printf("%8x", addr);
+ break;
+ case 'z':
+ db_printf("%8z", addr);
+ break;
+ case 'd':
+ db_printf("%11d", addr);
+ break;
+ case 'u':
+ db_printf("%11u", addr);
+ break;
+ case 'o':
+ db_printf("%16o", addr);
+ break;
+ case 'c':
+ value = addr & 0xFF;
+ if (value >= ' ' && value <= '~')
+ db_printf("%c", value);
+ else
+ db_printf("\\%03o", value);
+ break;
+ }
+ db_printf("\n");
+}
+
+void
+db_print_loc_and_inst(loc)
+ db_addr_t loc;
+{
+ db_printsym(loc, DB_STGY_PROC);
+ db_printf(":\t");
+ (void) db_disasm(loc, TRUE);
+}
+
+/*
+ * Search for a value in memory.
+ * Syntax: search [/bhl] addr value [mask] [,count]
+ */
+void
+db_search_cmd(db_expr_t dummy1, int dummy2, db_expr_t dummy3, char *dummy4)
+{
+ int t;
+ db_addr_t addr;
+ int size;
+ db_expr_t value;
+ db_expr_t mask;
+ unsigned int count;
+
+ t = db_read_token();
+ if (t == tSLASH) {
+ t = db_read_token();
+ if (t != tIDENT) {
+ bad_modifier:
+ db_printf("Bad modifier\n");
+ db_flush_lex();
+ return;
+ }
+
+ if (!strcmp(db_tok_string, "b"))
+ size = 1;
+ else if (!strcmp(db_tok_string, "h"))
+ size = 2;
+ else if (!strcmp(db_tok_string, "l"))
+ size = 4;
+ else
+ goto bad_modifier;
+ } else {
+ db_unread_token(t);
+ size = 4;
+ }
+
+ if (!db_expression((db_expr_t *)&addr)) {
+ db_printf("Address missing\n");
+ db_flush_lex();
+ return;
+ }
+
+ if (!db_expression(&value)) {
+ db_printf("Value missing\n");
+ db_flush_lex();
+ return;
+ }
+
+ if (!db_expression(&mask))
+ mask = 0xffffffffUL;
+
+ t = db_read_token();
+ if (t == tCOMMA) {
+ if (!db_expression(&count)) {
+ db_printf("Count missing\n");
+ db_flush_lex();
+ return;
+ }
+ } else {
+ db_unread_token(t);
+ count = -1; /* effectively forever */
+ }
+ db_skip_to_eol();
+
+ db_search(addr, size, value, mask, count);
+}
+
+static void
+db_search(addr, size, value, mask, count)
+ register
+ db_addr_t addr;
+ int size;
+ db_expr_t value;
+ db_expr_t mask;
+ unsigned int count;
+{
+ while (count-- != 0) {
+ db_prev = addr;
+ if ((db_get_value(addr, size, FALSE) & mask) == value)
+ break;
+ addr += size;
+ }
+ db_next = addr;
+}
diff --git a/sys/ddb/db_expr.c b/sys/ddb/db_expr.c
new file mode 100644
index 0000000..3d23949
--- /dev/null
+++ b/sys/ddb/db_expr.c
@@ -0,0 +1,226 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_expr.c,v 1.2 1993/10/16 16:47:14 rgrimes Exp $
+ */
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "ddb/ddb.h"
+#include <ddb/db_lex.h>
+#include <ddb/db_access.h>
+#include <ddb/db_command.h>
+
+boolean_t
+db_term(valuep)
+ db_expr_t *valuep;
+{
+ int t;
+
+ t = db_read_token();
+ if (t == tIDENT) {
+ if (!db_value_of_name(db_tok_string, valuep)) {
+ db_error("Symbol not found\n");
+ /*NOTREACHED*/
+ }
+ return (TRUE);
+ }
+ if (t == tNUMBER) {
+ *valuep = (db_expr_t)db_tok_number;
+ return (TRUE);
+ }
+ if (t == tDOT) {
+ *valuep = (db_expr_t)db_dot;
+ return (TRUE);
+ }
+ if (t == tDOTDOT) {
+ *valuep = (db_expr_t)db_prev;
+ return (TRUE);
+ }
+ if (t == tPLUS) {
+ *valuep = (db_expr_t) db_next;
+ return (TRUE);
+ }
+ if (t == tDITTO) {
+ *valuep = (db_expr_t)db_last_addr;
+ return (TRUE);
+ }
+ if (t == tDOLLAR) {
+ if (!db_get_variable(valuep))
+ return (FALSE);
+ return (TRUE);
+ }
+ if (t == tLPAREN) {
+ if (!db_expression(valuep)) {
+ db_error("Syntax error\n");
+ /*NOTREACHED*/
+ }
+ t = db_read_token();
+ if (t != tRPAREN) {
+ db_error("Syntax error\n");
+ /*NOTREACHED*/
+ }
+ return (TRUE);
+ }
+ db_unread_token(t);
+ return (FALSE);
+}
+
+boolean_t
+db_unary(valuep)
+ db_expr_t *valuep;
+{
+ int t;
+
+ t = db_read_token();
+ if (t == tMINUS) {
+ if (!db_unary(valuep)) {
+ db_error("Syntax error\n");
+ /*NOTREACHED*/
+ }
+ *valuep = -*valuep;
+ return (TRUE);
+ }
+ if (t == tSTAR) {
+ /* indirection */
+ if (!db_unary(valuep)) {
+ db_error("Syntax error\n");
+ /*NOTREACHED*/
+ }
+ *valuep = db_get_value((db_addr_t)*valuep, sizeof(int), FALSE);
+ return (TRUE);
+ }
+ db_unread_token(t);
+ return (db_term(valuep));
+}
+
+boolean_t
+db_mult_expr(valuep)
+ db_expr_t *valuep;
+{
+ db_expr_t lhs, rhs;
+ int t;
+
+ if (!db_unary(&lhs))
+ return (FALSE);
+
+ t = db_read_token();
+ while (t == tSTAR || t == tSLASH || t == tPCT || t == tHASH) {
+ if (!db_term(&rhs)) {
+ db_error("Syntax error\n");
+ /*NOTREACHED*/
+ }
+ if (t == tSTAR)
+ lhs *= rhs;
+ else {
+ if (rhs == 0) {
+ db_error("Divide by 0\n");
+ /*NOTREACHED*/
+ }
+ if (t == tSLASH)
+ lhs /= rhs;
+ else if (t == tPCT)
+ lhs %= rhs;
+ else
+ lhs = ((lhs+rhs-1)/rhs)*rhs;
+ }
+ t = db_read_token();
+ }
+ db_unread_token(t);
+ *valuep = lhs;
+ return (TRUE);
+}
+
+boolean_t
+db_add_expr(valuep)
+ db_expr_t *valuep;
+{
+ db_expr_t lhs, rhs;
+ int t;
+
+ if (!db_mult_expr(&lhs))
+ return (FALSE);
+
+ t = db_read_token();
+ while (t == tPLUS || t == tMINUS) {
+ if (!db_mult_expr(&rhs)) {
+ db_error("Syntax error\n");
+ /*NOTREACHED*/
+ }
+ if (t == tPLUS)
+ lhs += rhs;
+ else
+ lhs -= rhs;
+ t = db_read_token();
+ }
+ db_unread_token(t);
+ *valuep = lhs;
+ return (TRUE);
+}
+
+boolean_t
+db_shift_expr(valuep)
+ db_expr_t *valuep;
+{
+ db_expr_t lhs, rhs;
+ int t;
+
+ if (!db_add_expr(&lhs))
+ return (FALSE);
+
+ t = db_read_token();
+ while (t == tSHIFT_L || t == tSHIFT_R) {
+ if (!db_add_expr(&rhs)) {
+ db_error("Syntax error\n");
+ /*NOTREACHED*/
+ }
+ if (rhs < 0) {
+ db_error("Negative shift amount\n");
+ /*NOTREACHED*/
+ }
+ if (t == tSHIFT_L)
+ lhs <<= rhs;
+ else {
+ /* Shift right is unsigned */
+ lhs = (unsigned) lhs >> rhs;
+ }
+ t = db_read_token();
+ }
+ db_unread_token(t);
+ *valuep = lhs;
+ return (TRUE);
+}
+
+int
+db_expression(valuep)
+ db_expr_t *valuep;
+{
+ return (db_shift_expr(valuep));
+}
diff --git a/sys/ddb/db_input.c b/sys/ddb/db_input.c
new file mode 100644
index 0000000..94bab94
--- /dev/null
+++ b/sys/ddb/db_input.c
@@ -0,0 +1,256 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_input.c,v 1.3 1993/11/25 01:30:06 wollman Exp $
+ */
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "ddb/ddb.h"
+#include "ddb/db_output.h"
+#include "machine/cons.h"
+
+/*
+ * Character input and editing.
+ */
+
+/*
+ * We don't track output position while editing input,
+ * since input always ends with a new-line. We just
+ * reset the line position at the end.
+ */
+char * db_lbuf_start; /* start of input line buffer */
+char * db_lbuf_end; /* end of input line buffer */
+char * db_lc; /* current character */
+char * db_le; /* one past last character */
+
+#define CTRL(c) ((c) & 0x1f)
+#define isspace(c) ((c) == ' ' || (c) == '\t')
+#define BLANK ' '
+#define BACKUP '\b'
+
+void
+db_putstring(s, count)
+ char *s;
+ int count;
+{
+ while (--count >= 0)
+ cnputc(*s++);
+}
+
+void
+db_putnchars(c, count)
+ int c;
+ int count;
+{
+ while (--count >= 0)
+ cnputc(c);
+}
+
+/*
+ * Delete N characters, forward or backward
+ */
+#define DEL_FWD 0
+#define DEL_BWD 1
+void
+db_delete(n, bwd)
+ int n;
+ int bwd;
+{
+ register char *p;
+
+ if (bwd) {
+ db_lc -= n;
+ db_putnchars(BACKUP, n);
+ }
+ for (p = db_lc; p < db_le-n; p++) {
+ *p = *(p+n);
+ cnputc(*p);
+ }
+ db_putnchars(BLANK, n);
+ db_putnchars(BACKUP, db_le - db_lc);
+ db_le -= n;
+}
+
+/* returns TRUE at end-of-line */
+int
+db_inputchar(c)
+ int c;
+{
+ switch (c) {
+ case CTRL('b'):
+ /* back up one character */
+ if (db_lc > db_lbuf_start) {
+ cnputc(BACKUP);
+ db_lc--;
+ }
+ break;
+ case CTRL('f'):
+ /* forward one character */
+ if (db_lc < db_le) {
+ cnputc(*db_lc);
+ db_lc++;
+ }
+ break;
+ case CTRL('a'):
+ /* beginning of line */
+ while (db_lc > db_lbuf_start) {
+ cnputc(BACKUP);
+ db_lc--;
+ }
+ break;
+ case CTRL('e'):
+ /* end of line */
+ while (db_lc < db_le) {
+ cnputc(*db_lc);
+ db_lc++;
+ }
+ break;
+ case CTRL('h'):
+ case 0177:
+ /* erase previous character */
+ if (db_lc > db_lbuf_start)
+ db_delete(1, DEL_BWD);
+ break;
+ case CTRL('d'):
+ /* erase next character */
+ if (db_lc < db_le)
+ db_delete(1, DEL_FWD);
+ break;
+ case CTRL('k'):
+ /* delete to end of line */
+ if (db_lc < db_le)
+ db_delete(db_le - db_lc, DEL_FWD);
+ break;
+ case CTRL('t'):
+ /* twiddle last 2 characters */
+ if (db_lc >= db_lbuf_start + 2) {
+ c = db_lc[-2];
+ db_lc[-2] = db_lc[-1];
+ db_lc[-1] = c;
+ cnputc(BACKUP);
+ cnputc(BACKUP);
+ cnputc(db_lc[-2]);
+ cnputc(db_lc[-1]);
+ }
+ break;
+ case CTRL('r'):
+ db_putstring("^R\n", 3);
+ if (db_le > db_lbuf_start) {
+ db_putstring(db_lbuf_start, db_le - db_lbuf_start);
+ db_putnchars(BACKUP, db_le - db_lc);
+ }
+ break;
+ case '\n':
+ case '\r':
+ *db_le++ = c;
+ return (1);
+ default:
+ if (db_le == db_lbuf_end) {
+ cnputc('\007');
+ }
+ else if (c >= ' ' && c <= '~') {
+ register char *p;
+
+ for (p = db_le; p > db_lc; p--)
+ *p = *(p-1);
+ *db_lc++ = c;
+ db_le++;
+ cnputc(c);
+ db_putstring(db_lc, db_le - db_lc);
+ db_putnchars(BACKUP, db_le - db_lc);
+ }
+ break;
+ }
+ return (0);
+}
+
+int
+db_readline(lstart, lsize)
+ char * lstart;
+ int lsize;
+{
+ db_force_whitespace(); /* synch output position */
+
+ db_lbuf_start = lstart;
+ db_lbuf_end = lstart + lsize;
+ db_lc = lstart;
+ db_le = lstart;
+
+ while (!db_inputchar(cngetc()))
+ continue;
+
+ db_putchar('\n'); /* synch output position */
+
+ *db_le = 0;
+ return (db_le - db_lbuf_start);
+}
+
+void
+db_check_interrupt()
+{
+ register int c;
+
+ c = cnmaygetc();
+ switch (c) {
+ case -1: /* no character */
+ return;
+
+ case CTRL('c'):
+ db_error((char *)0);
+ /*NOTREACHED*/
+
+ case CTRL('s'):
+ do {
+ c = cnmaygetc();
+ if (c == CTRL('c'))
+ db_error((char *)0);
+ } while (c != CTRL('q'));
+ break;
+
+ default:
+ /* drop on floor */
+ break;
+ }
+}
+
+int
+cnmaygetc (void)
+{
+ return (-1);
+}
+
+/* called from kdb_trap in db_interface.c */
+void
+cnpollc (flag)
+ int flag;
+{
+}
diff --git a/sys/ddb/db_lex.c b/sys/ddb/db_lex.c
new file mode 100644
index 0000000..655a1b5
--- /dev/null
+++ b/sys/ddb/db_lex.c
@@ -0,0 +1,279 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_lex.c,v 1.2 1993/10/16 16:47:17 rgrimes Exp $
+ */
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+/*
+ * Lexical analyzer.
+ */
+#include "param.h"
+#include "systm.h"
+#include "ddb/ddb.h"
+#include <ddb/db_lex.h>
+
+char db_line[120];
+char * db_lp, *db_endlp;
+
+int
+db_read_line()
+{
+ int i;
+
+ i = db_readline(db_line, sizeof(db_line));
+ if (i == 0)
+ return (0); /* EOI */
+ db_lp = db_line;
+ db_endlp = db_lp + i;
+ return (i);
+}
+
+void
+db_flush_line()
+{
+ db_lp = db_line;
+ db_endlp = db_line;
+}
+
+int db_look_char = 0;
+
+int
+db_read_char()
+{
+ int c;
+
+ if (db_look_char != 0) {
+ c = db_look_char;
+ db_look_char = 0;
+ }
+ else if (db_lp >= db_endlp)
+ c = -1;
+ else
+ c = *db_lp++;
+ return (c);
+}
+
+void
+db_unread_char(c)
+ int c;
+{
+ db_look_char = c;
+}
+
+int db_look_token = 0;
+
+void
+db_unread_token(t)
+ int t;
+{
+ db_look_token = t;
+}
+
+int
+db_read_token()
+{
+ int t;
+
+ if (db_look_token) {
+ t = db_look_token;
+ db_look_token = 0;
+ }
+ else
+ t = db_lex();
+ return (t);
+}
+
+int db_tok_number;
+char db_tok_string[TOK_STRING_SIZE];
+
+int db_radix = 16;
+
+void
+db_flush_lex()
+{
+ db_flush_line();
+ db_look_char = 0;
+ db_look_token = 0;
+}
+
+int
+db_lex()
+{
+ int c;
+
+ c = db_read_char();
+ while (c <= ' ' || c > '~') {
+ if (c == '\n' || c == -1)
+ return (tEOL);
+ c = db_read_char();
+ }
+
+ if (c >= '0' && c <= '9') {
+ /* number */
+ int r, digit = 0;
+
+ if (c > '0')
+ r = db_radix;
+ else {
+ c = db_read_char();
+ if (c == 'O' || c == 'o')
+ r = 8;
+ else if (c == 'T' || c == 't')
+ r = 10;
+ else if (c == 'X' || c == 'x')
+ r = 16;
+ else {
+ r = db_radix;
+ db_unread_char(c);
+ }
+ c = db_read_char();
+ }
+ db_tok_number = 0;
+ for (;;) {
+ if (c >= '0' && c <= ((r == 8) ? '7' : '9'))
+ digit = c - '0';
+ else if (r == 16 && ((c >= 'A' && c <= 'F') ||
+ (c >= 'a' && c <= 'f'))) {
+ if (c >= 'a')
+ digit = c - 'a' + 10;
+ else if (c >= 'A')
+ digit = c - 'A' + 10;
+ }
+ else
+ break;
+ db_tok_number = db_tok_number * r + digit;
+ c = db_read_char();
+ }
+ if ((c >= '0' && c <= '9') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z') ||
+ (c == '_'))
+ {
+ db_error("Bad character in number\n");
+ db_flush_lex();
+ return (tEOF);
+ }
+ db_unread_char(c);
+ return (tNUMBER);
+ }
+ if ((c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z') ||
+ c == '_' || c == '\\')
+ {
+ /* string */
+ char *cp;
+
+ cp = db_tok_string;
+ if (c == '\\') {
+ c = db_read_char();
+ if (c == '\n' || c == -1)
+ db_error("Bad escape\n");
+ }
+ *cp++ = c;
+ while (1) {
+ c = db_read_char();
+ if ((c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') ||
+ c == '_' || c == '\\' || c == ':')
+ {
+ if (c == '\\') {
+ c = db_read_char();
+ if (c == '\n' || c == -1)
+ db_error("Bad escape\n");
+ }
+ *cp++ = c;
+ if (cp == db_tok_string+sizeof(db_tok_string)) {
+ db_error("String too long\n");
+ db_flush_lex();
+ return (tEOF);
+ }
+ continue;
+ }
+ else {
+ *cp = '\0';
+ break;
+ }
+ }
+ db_unread_char(c);
+ return (tIDENT);
+ }
+
+ switch (c) {
+ case '+':
+ return (tPLUS);
+ case '-':
+ return (tMINUS);
+ case '.':
+ c = db_read_char();
+ if (c == '.')
+ return (tDOTDOT);
+ db_unread_char(c);
+ return (tDOT);
+ case '*':
+ return (tSTAR);
+ case '/':
+ return (tSLASH);
+ case '=':
+ return (tEQ);
+ case '%':
+ return (tPCT);
+ case '#':
+ return (tHASH);
+ case '(':
+ return (tLPAREN);
+ case ')':
+ return (tRPAREN);
+ case ',':
+ return (tCOMMA);
+ case '"':
+ return (tDITTO);
+ case '$':
+ return (tDOLLAR);
+ case '!':
+ return (tEXCL);
+ case '<':
+ c = db_read_char();
+ if (c == '<')
+ return (tSHIFT_L);
+ db_unread_char(c);
+ break;
+ case '>':
+ c = db_read_char();
+ if (c == '>')
+ return (tSHIFT_R);
+ db_unread_char(c);
+ break;
+ case -1:
+ return (tEOF);
+ }
+ db_printf("Bad character\n");
+ db_flush_lex();
+ return (tEOF);
+}
diff --git a/sys/ddb/db_lex.h b/sys/ddb/db_lex.h
new file mode 100644
index 0000000..e2f224e
--- /dev/null
+++ b/sys/ddb/db_lex.h
@@ -0,0 +1,77 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_lex.h,v 1.2 1993/10/16 16:47:19 rgrimes Exp $
+ */
+
+#ifndef _DDB_DB_LEX_H_
+#define _DDB_DB_LEX_H_ 1
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+/*
+ * Lexical analyzer.
+ */
+extern int db_read_line();
+extern void db_flush_line();
+extern int db_read_char();
+extern void db_unread_char(/* char c */);
+extern int db_read_token();
+extern void db_unread_token(/* int t */);
+extern void db_flush_lex();
+
+extern int db_tok_number;
+#define TOK_STRING_SIZE 120
+extern char db_tok_string[TOK_STRING_SIZE];
+extern int db_radix;
+
+#define tEOF (-1)
+#define tEOL 1
+#define tNUMBER 2
+#define tIDENT 3
+#define tPLUS 4
+#define tMINUS 5
+#define tDOT 6
+#define tSTAR 7
+#define tSLASH 8
+#define tEQ 9
+#define tLPAREN 10
+#define tRPAREN 11
+#define tPCT 12
+#define tHASH 13
+#define tCOMMA 14
+#define tDITTO 15
+#define tDOLLAR 16
+#define tEXCL 17
+#define tSHIFT_L 18
+#define tSHIFT_R 19
+#define tDOTDOT 20
+
+
+
+
+#endif /* _DDB_DB_LEX_H_ */
diff --git a/sys/ddb/db_output.c b/sys/ddb/db_output.c
new file mode 100644
index 0000000..fc1bb14
--- /dev/null
+++ b/sys/ddb/db_output.c
@@ -0,0 +1,370 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_output.c,v 1.5 1993/11/25 01:30:08 wollman Exp $
+ */
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+/*
+ * Printf and character output for debugger.
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "machine/stdarg.h"
+#include "ddb/ddb.h"
+#include "machine/cons.h"
+
+/*
+ * Character output - tracks position in line.
+ * To do this correctly, we should know how wide
+ * the output device is - then we could zero
+ * the line position when the output device wraps
+ * around to the start of the next line.
+ *
+ * Instead, we count the number of spaces printed
+ * since the last printing character so that we
+ * don't print trailing spaces. This avoids most
+ * of the wraparounds.
+ */
+int db_output_position = 0; /* output column */
+int db_last_non_space = 0; /* last non-space character */
+int db_tab_stop_width = 8; /* how wide are tab stops? */
+#define NEXT_TAB(i) \
+ ((((i) + db_tab_stop_width) / db_tab_stop_width) * db_tab_stop_width)
+int db_max_width = 80; /* output line width */
+
+
+static void db_printf_guts(const char *, va_list);
+
+/*
+ * Force pending whitespace.
+ */
+void
+db_force_whitespace()
+{
+ register int last_print, next_tab;
+
+ last_print = db_last_non_space;
+ while (last_print < db_output_position) {
+ next_tab = NEXT_TAB(last_print);
+ if (next_tab <= db_output_position) {
+ while (last_print < next_tab) { /* DON'T send a tab!!! */
+ cnputc(' ');
+ last_print++;
+ }
+ }
+ else {
+ cnputc(' ');
+ last_print++;
+ }
+ }
+ db_last_non_space = db_output_position;
+}
+
+/*
+ * Output character. Buffer whitespace.
+ */
+void
+db_putchar(c)
+ int c; /* character to output */
+{
+ if (c > ' ' && c <= '~') {
+ /*
+ * Printing character.
+ * If we have spaces to print, print them first.
+ * Use tabs if possible.
+ */
+ db_force_whitespace();
+ cnputc(c);
+ db_output_position++;
+ db_last_non_space = db_output_position;
+ }
+ else if (c == '\n') {
+ /* Return */
+ cnputc(c);
+ db_output_position = 0;
+ db_last_non_space = 0;
+ db_check_interrupt();
+ }
+ else if (c == '\t') {
+ /* assume tabs every 8 positions */
+ db_output_position = NEXT_TAB(db_output_position);
+ }
+ else if (c == ' ') {
+ /* space */
+ db_output_position++;
+ }
+ else if (c == '\007') {
+ /* bell */
+ cnputc(c);
+ }
+ /* other characters are assumed non-printing */
+}
+
+/*
+ * Return output position
+ */
+int
+db_print_position()
+{
+ return (db_output_position);
+}
+
+/*
+ * Printing
+ */
+void
+db_printf(const char *fmt, ...)
+{
+ va_list listp;
+ va_start(listp, fmt);
+ db_printf_guts (fmt, listp);
+ va_end(listp);
+}
+
+/* alternate name */
+
+/*VARARGS1*/
+void
+kdbprintf(char *fmt, ...)
+{
+ va_list listp;
+ va_start(listp, fmt);
+ db_printf_guts (fmt, listp);
+ va_end(listp);
+}
+
+/*
+ * End line if too long.
+ */
+void
+db_end_line()
+{
+ if (db_output_position >= db_max_width)
+ db_printf("\n");
+}
+
+/*
+ * Put a number (base <= 16) in a buffer in reverse order; return an
+ * optional length and a pointer to the NULL terminated (preceded?)
+ * buffer.
+ */
+static char *
+db_ksprintn(ul, base, lenp)
+ register u_long ul;
+ register int base, *lenp;
+{ /* A long in base 8, plus NULL. */
+ static char buf[sizeof(long) * NBBY / 3 + 2];
+ register char *p;
+
+ p = buf;
+ do {
+ *++p = "0123456789abcdef"[ul % base];
+ } while (ul /= base);
+ if (lenp)
+ *lenp = p - buf;
+ return (p);
+}
+
+static void
+db_printf_guts(fmt, ap)
+ register const char *fmt;
+ va_list ap;
+{
+ register char *p;
+ register int ch, n;
+ u_long ul;
+ int base, lflag, tmp, width;
+ char padc;
+ int ladjust;
+ int sharpflag;
+ int neg;
+
+ for (;;) {
+ padc = ' ';
+ width = 0;
+ while ((ch = *(u_char *)fmt++) != '%') {
+ if (ch == '\0')
+ return;
+ db_putchar(ch);
+ }
+ lflag = 0;
+ ladjust = 0;
+ sharpflag = 0;
+ neg = 0;
+reswitch: switch (ch = *(u_char *)fmt++) {
+ case '0':
+ padc = '0';
+ goto reswitch;
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ for (width = 0;; ++fmt) {
+ width = width * 10 + ch - '0';
+ ch = *fmt;
+ if (ch < '0' || ch > '9')
+ break;
+ }
+ goto reswitch;
+ case 'l':
+ lflag = 1;
+ goto reswitch;
+ case '-':
+ ladjust = 1;
+ goto reswitch;
+ case '#':
+ sharpflag = 1;
+ goto reswitch;
+ case 'b':
+ ul = va_arg(ap, int);
+ p = va_arg(ap, char *);
+ for (p = db_ksprintn(ul, *p++, NULL); ch = *p--;)
+ db_putchar(ch);
+
+ if (!ul)
+ break;
+
+ for (tmp = 0; n = *p++;) {
+ if (ul & (1 << (n - 1))) {
+ db_putchar(tmp ? ',' : '<');
+ for (; (n = *p) > ' '; ++p)
+ db_putchar(n);
+ tmp = 1;
+ } else
+ for (; *p > ' '; ++p);
+ }
+ if (tmp)
+ db_putchar('>');
+ break;
+ case '*':
+ width = va_arg (ap, int);
+ if (width < 0) {
+ ladjust = !ladjust;
+ width = -width;
+ }
+ goto reswitch;
+ case 'c':
+ db_putchar(va_arg(ap, int));
+ break;
+ case 's':
+ p = va_arg(ap, char *);
+ width -= strlen (p);
+ if (!ladjust && width > 0)
+ while (width--)
+ db_putchar (padc);
+ while (ch = *p++)
+ db_putchar(ch);
+ if (ladjust && width > 0)
+ while (width--)
+ db_putchar (padc);
+ break;
+ case 'r':
+ ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
+ if ((long)ul < 0) {
+ neg = 1;
+ ul = -(long)ul;
+ }
+ base = db_radix;
+ if (base < 8 || base > 16)
+ base = 10;
+ goto number;
+ case 'n':
+ ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
+ base = db_radix;
+ if (base < 8 || base > 16)
+ base = 10;
+ goto number;
+ case 'd':
+ ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
+ if ((long)ul < 0) {
+ neg = 1;
+ ul = -(long)ul;
+ }
+ base = 10;
+ goto number;
+ case 'o':
+ ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
+ base = 8;
+ goto number;
+ case 'u':
+ ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
+ base = 10;
+ goto number;
+ case 'z':
+ ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
+ if ((long)ul < 0) {
+ neg = 1;
+ ul = -(long)ul;
+ }
+ base = 16;
+ goto number;
+ case 'x':
+ ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
+ base = 16;
+number: p = (char *)db_ksprintn(ul, base, &tmp);
+ if (sharpflag && ul != 0) {
+ if (base == 8)
+ tmp++;
+ else if (base == 16)
+ tmp += 2;
+ }
+ if (neg)
+ tmp++;
+
+ if (!ladjust && width && (width -= tmp) > 0)
+ while (width--)
+ db_putchar(padc);
+ if (neg)
+ db_putchar ('-');
+ if (sharpflag && ul != 0) {
+ if (base == 8) {
+ db_putchar ('0');
+ } else if (base == 16) {
+ db_putchar ('0');
+ db_putchar ('x');
+ }
+ }
+ if (ladjust && width && (width -= tmp) > 0)
+ while (width--)
+ db_putchar(padc);
+
+ while (ch = *p--)
+ db_putchar(ch);
+ break;
+ default:
+ db_putchar('%');
+ if (lflag)
+ db_putchar('l');
+ /* FALLTHROUGH */
+ case '%':
+ db_putchar(ch);
+ }
+ }
+}
+
diff --git a/sys/ddb/db_output.h b/sys/ddb/db_output.h
new file mode 100644
index 0000000..3969a34
--- /dev/null
+++ b/sys/ddb/db_output.h
@@ -0,0 +1,44 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_output.h,v 1.3 1993/11/07 17:39:24 wollman Exp $
+ */
+
+#ifndef _DDB_DB_OUTPUT_H_
+#define _DDB_DB_OUTPUT_H_ 1
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 8/90
+ */
+
+/*
+ * Printing routines for kernel debugger.
+ */
+
+extern void db_force_whitespace();
+extern int db_print_position();
+extern void db_end_line();
+#endif /* _DDB_DB_OUTPUT_H_ */
diff --git a/sys/ddb/db_print.c b/sys/ddb/db_print.c
new file mode 100644
index 0000000..7ab2099
--- /dev/null
+++ b/sys/ddb/db_print.c
@@ -0,0 +1,70 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_print.c,v 1.2 1993/10/16 16:47:22 rgrimes Exp $
+ */
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+/*
+ * Miscellaneous printing.
+ */
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+
+#include "ddb/ddb.h"
+
+#include <ddb/db_lex.h>
+#include <ddb/db_variables.h>
+#include <ddb/db_sym.h>
+
+extern unsigned int db_maxoff;
+
+void
+db_show_regs(db_expr_t dummy1, int dummy2, db_expr_t dummy3, char *dummy4)
+{
+ int (*func)();
+ register struct db_variable *regp;
+ db_expr_t value, offset;
+ char * name;
+
+ for (regp = db_regs; regp < db_eregs; regp++) {
+ db_read_variable(regp, &value);
+ db_printf("%-12s%#10n", regp->name, value);
+ db_find_xtrn_sym_and_offset((db_addr_t)value, &name, &offset);
+ if (name != 0 && offset <= db_maxoff && offset != value) {
+ db_printf("\t%s", name);
+ if (offset != 0)
+ db_printf("+%#r", offset);
+ }
+ db_printf("\n");
+ }
+ db_print_loc_and_inst(PC_REGS(DDB_REGS));
+}
+
diff --git a/sys/ddb/db_run.c b/sys/ddb/db_run.c
new file mode 100644
index 0000000..1ba43c1
--- /dev/null
+++ b/sys/ddb/db_run.c
@@ -0,0 +1,391 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_run.c,v 1.2 1993/10/16 16:47:24 rgrimes Exp $
+ */
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+/*
+ * Commands to run process.
+ */
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "ddb/ddb.h"
+
+#include <ddb/db_lex.h>
+#include <ddb/db_break.h>
+#include <ddb/db_access.h>
+
+int db_run_mode;
+#define STEP_NONE 0
+#define STEP_ONCE 1
+#define STEP_RETURN 2
+#define STEP_CALLT 3
+#define STEP_CONTINUE 4
+#define STEP_INVISIBLE 5
+#define STEP_COUNT 6
+
+boolean_t db_sstep_print;
+int db_loop_count;
+int db_call_depth;
+
+int db_inst_count;
+int db_load_count;
+int db_store_count;
+
+#ifndef db_set_single_step
+void db_set_single_step(/* db_regs_t *regs */); /* forward */
+#endif
+#ifndef db_clear_single_step
+void db_clear_single_step(/* db_regs_t *regs */);
+#endif
+
+boolean_t
+db_stop_at_pc(is_breakpoint)
+ boolean_t *is_breakpoint;
+{
+ register db_addr_t pc;
+ register db_breakpoint_t bkpt;
+
+ db_clear_single_step(DDB_REGS);
+ db_clear_breakpoints();
+ db_clear_watchpoints();
+ pc = PC_REGS(DDB_REGS);
+
+#ifdef FIXUP_PC_AFTER_BREAK
+ if (*is_breakpoint) {
+ /*
+ * Breakpoint trap. Fix up the PC if the
+ * machine requires it.
+ */
+ FIXUP_PC_AFTER_BREAK
+ pc = PC_REGS(DDB_REGS);
+ }
+#endif
+
+ /*
+ * Now check for a breakpoint at this address.
+ */
+ bkpt = db_find_breakpoint_here(pc);
+ if (bkpt) {
+ if (--bkpt->count == 0) {
+ bkpt->count = bkpt->init_count;
+ *is_breakpoint = TRUE;
+ return (TRUE); /* stop here */
+ }
+ } else if (*is_breakpoint) {
+ ddb_regs.tf_eip += 1;
+ }
+
+ *is_breakpoint = FALSE;
+
+ if (db_run_mode == STEP_INVISIBLE) {
+ db_run_mode = STEP_CONTINUE;
+ return (FALSE); /* continue */
+ }
+ if (db_run_mode == STEP_COUNT) {
+ return (FALSE); /* continue */
+ }
+ if (db_run_mode == STEP_ONCE) {
+ if (--db_loop_count > 0) {
+ if (db_sstep_print) {
+ db_printf("\t\t");
+ db_print_loc_and_inst(pc);
+ db_printf("\n");
+ }
+ return (FALSE); /* continue */
+ }
+ }
+ if (db_run_mode == STEP_RETURN) {
+ db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
+
+ /* continue until matching return */
+
+ if (!inst_trap_return(ins) &&
+ (!inst_return(ins) || --db_call_depth != 0)) {
+ if (db_sstep_print) {
+ if (inst_call(ins) || inst_return(ins)) {
+ register int i;
+
+ db_printf("[after %6d] ", db_inst_count);
+ for (i = db_call_depth; --i > 0; )
+ db_printf(" ");
+ db_print_loc_and_inst(pc);
+ db_printf("\n");
+ }
+ }
+ if (inst_call(ins))
+ db_call_depth++;
+ return (FALSE); /* continue */
+ }
+ }
+ if (db_run_mode == STEP_CALLT) {
+ db_expr_t ins = db_get_value(pc, sizeof(int), FALSE);
+
+ /* continue until call or return */
+
+ if (!inst_call(ins) &&
+ !inst_return(ins) &&
+ !inst_trap_return(ins)) {
+ return (FALSE); /* continue */
+ }
+ }
+ db_run_mode = STEP_NONE;
+ return (TRUE);
+}
+
+void
+db_restart_at_pc(watchpt)
+ boolean_t watchpt;
+{
+ register db_addr_t pc = PC_REGS(DDB_REGS);
+
+ if ((db_run_mode == STEP_COUNT) ||
+ (db_run_mode == STEP_RETURN) ||
+ (db_run_mode == STEP_CALLT)) {
+ db_expr_t ins;
+
+ /*
+ * We are about to execute this instruction,
+ * so count it now.
+ */
+
+ ins = db_get_value(pc, sizeof(int), FALSE);
+ db_inst_count++;
+ db_load_count += inst_load(ins);
+ db_store_count += inst_store(ins);
+#ifdef SOFTWARE_SSTEP
+ /* XXX works on mips, but... */
+ if (inst_branch(ins) || inst_call(ins)) {
+ ins = db_get_value(next_instr_address(pc,1),
+ sizeof(int), FALSE);
+ db_inst_count++;
+ db_load_count += inst_load(ins);
+ db_store_count += inst_store(ins);
+ }
+#endif SOFTWARE_SSTEP
+ }
+
+ if (db_run_mode == STEP_CONTINUE) {
+ if (watchpt || db_find_breakpoint_here(pc)) {
+ /*
+ * Step over breakpoint/watchpoint.
+ */
+ db_run_mode = STEP_INVISIBLE;
+ db_set_single_step(DDB_REGS);
+ } else {
+ db_set_breakpoints();
+ db_set_watchpoints();
+ }
+ } else {
+ db_set_single_step(DDB_REGS);
+ }
+}
+
+void
+db_single_step(regs)
+ db_regs_t *regs;
+{
+ if (db_run_mode == STEP_CONTINUE) {
+ db_run_mode = STEP_INVISIBLE;
+ db_set_single_step(regs);
+ }
+}
+
+#ifdef SOFTWARE_SSTEP
+/*
+ * Software implementation of single-stepping.
+ * If your machine does not have a trace mode
+ * similar to the vax or sun ones you can use
+ * this implementation, done for the mips.
+ * Just define the above conditional and provide
+ * the functions/macros defined below.
+ *
+ * extern boolean_t
+ * inst_branch(), returns true if the instruction might branch
+ * extern unsigned
+ * branch_taken(), return the address the instruction might
+ * branch to
+ * db_getreg_val(); return the value of a user register,
+ * as indicated in the hardware instruction
+ * encoding, e.g. 8 for r8
+ *
+ * next_instr_address(pc,bd) returns the address of the first
+ * instruction following the one at "pc",
+ * which is either in the taken path of
+ * the branch (bd==1) or not. This is
+ * for machines (mips) with branch delays.
+ *
+ * A single-step may involve at most 2 breakpoints -
+ * one for branch-not-taken and one for branch taken.
+ * If one of these addresses does not already have a breakpoint,
+ * we allocate a breakpoint and save it here.
+ * These breakpoints are deleted on return.
+ */
+db_breakpoint_t db_not_taken_bkpt = 0;
+db_breakpoint_t db_taken_bkpt = 0;
+
+void
+db_set_single_step(regs)
+ register db_regs_t *regs;
+{
+ db_addr_t pc = PC_REGS(regs);
+ register unsigned inst, brpc;
+
+ /*
+ * User was stopped at pc, e.g. the instruction
+ * at pc was not executed.
+ */
+ inst = db_get_value(pc, sizeof(int), FALSE);
+ if (inst_branch(inst) || inst_call(inst)) {
+ extern unsigned getreg_val();
+
+ brpc = branch_taken(inst, pc, getreg_val, regs);
+ if (brpc != pc) { /* self-branches are hopeless */
+ db_taken_bkpt = db_set_temp_breakpoint(brpc);
+ }
+ pc = next_instr_address(pc,1);
+ }
+ pc = next_instr_address(pc,0);
+ db_not_taken_bkpt = db_set_temp_breakpoint(pc);
+}
+
+void
+db_clear_single_step(regs)
+ db_regs_t *regs;
+{
+ register db_breakpoint_t bkpt;
+
+ if (db_taken_bkpt != 0) {
+ db_delete_temp_breakpoint(db_taken_bkpt);
+ db_taken_bkpt = 0;
+ }
+ if (db_not_taken_bkpt != 0) {
+ db_delete_temp_breakpoint(db_not_taken_bkpt);
+ db_not_taken_bkpt = 0;
+ }
+}
+
+#endif SOFTWARE_SSTEP
+
+extern int db_cmd_loop_done;
+
+/* single-step */
+/*ARGSUSED*/
+void
+db_single_step_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ boolean_t print = FALSE;
+
+ if (count == -1)
+ count = 1;
+
+ if (modif[0] == 'p')
+ print = TRUE;
+
+ db_run_mode = STEP_ONCE;
+ db_loop_count = count;
+ db_sstep_print = print;
+ db_inst_count = 0;
+ db_load_count = 0;
+ db_store_count = 0;
+
+ db_cmd_loop_done = 1;
+}
+
+/* trace and print until call/return */
+/*ARGSUSED*/
+void
+db_trace_until_call_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ boolean_t print = FALSE;
+
+ if (modif[0] == 'p')
+ print = TRUE;
+
+ db_run_mode = STEP_CALLT;
+ db_sstep_print = print;
+ db_inst_count = 0;
+ db_load_count = 0;
+ db_store_count = 0;
+
+ db_cmd_loop_done = 1;
+}
+
+/*ARGSUSED*/
+void
+db_trace_until_matching_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ boolean_t print = FALSE;
+
+ if (modif[0] == 'p')
+ print = TRUE;
+
+ db_run_mode = STEP_RETURN;
+ db_call_depth = 1;
+ db_sstep_print = print;
+ db_inst_count = 0;
+ db_load_count = 0;
+ db_store_count = 0;
+
+ db_cmd_loop_done = 1;
+}
+
+/* continue */
+/*ARGSUSED*/
+void
+db_continue_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ if (modif[0] == 'c')
+ db_run_mode = STEP_COUNT;
+ else
+ db_run_mode = STEP_CONTINUE;
+ db_inst_count = 0;
+ db_load_count = 0;
+ db_store_count = 0;
+
+ db_cmd_loop_done = 1;
+}
diff --git a/sys/ddb/db_sym.c b/sys/ddb/db_sym.c
new file mode 100644
index 0000000..af22a97
--- /dev/null
+++ b/sys/ddb/db_sym.c
@@ -0,0 +1,333 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_sym.c,v 1.3 1993/11/25 01:30:12 wollman Exp $
+ */
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "ddb/ddb.h"
+#include <ddb/db_sym.h>
+
+/*
+ * We import from the symbol-table dependent routines:
+ */
+extern db_sym_t X_db_lookup();
+extern db_sym_t X_db_search_symbol();
+extern boolean_t X_db_line_at_pc();
+extern void X_db_symbol_values();
+
+/*
+ * Multiple symbol tables
+ */
+#ifndef MAXNOSYMTABS
+#define MAXNOSYMTABS 3 /* mach, ux, emulator */
+#endif
+
+db_symtab_t db_symtabs[MAXNOSYMTABS] = {{0,},};
+int db_nsymtab = 0;
+
+db_symtab_t *db_last_symtab;
+
+db_sym_t db_lookup(); /* forward */
+
+/*
+ * Add symbol table, with given name, to list of symbol tables.
+ */
+void
+db_add_symbol_table(start, end, name, ref)
+ char *start;
+ char *end;
+ char *name;
+ char *ref;
+{
+ if (db_nsymtab >= MAXNOSYMTABS) {
+ printf ("No slots left for %s symbol table", name);
+ panic ("db_sym.c: db_add_symbol_table");
+ }
+
+ db_symtabs[db_nsymtab].start = start;
+ db_symtabs[db_nsymtab].end = end;
+ db_symtabs[db_nsymtab].name = name;
+ db_symtabs[db_nsymtab].private = ref;
+ db_nsymtab++;
+}
+
+/*
+ * db_qualify("vm_map", "ux") returns "unix:vm_map".
+ *
+ * Note: return value points to static data whose content is
+ * overwritten by each call... but in practice this seems okay.
+ */
+static char *
+db_qualify(sym, symtabname)
+ db_sym_t sym;
+ register char *symtabname;
+{
+ char *symname;
+ static char tmp[256];
+ register char *s;
+
+ db_symbol_values(sym, &symname, 0);
+ s = tmp;
+ while (*s++ = *symtabname++) {
+ }
+ s[-1] = ':';
+ while (*s++ = *symname++) {
+ }
+ return tmp;
+}
+
+
+boolean_t
+db_eqname(src, dst, c)
+ char *src;
+ char *dst;
+ char c;
+{
+ if (!strcmp(src, dst))
+ return (TRUE);
+ if (src[0] == c)
+ return (!strcmp(src+1,dst));
+ return (FALSE);
+}
+
+boolean_t
+db_value_of_name(name, valuep)
+ char *name;
+ db_expr_t *valuep;
+{
+ db_sym_t sym;
+
+ sym = db_lookup(name);
+ if (sym == DB_SYM_NULL)
+ return (FALSE);
+ db_symbol_values(sym, &name, valuep);
+ return (TRUE);
+}
+
+
+/*
+ * Lookup a symbol.
+ * If the symbol has a qualifier (e.g., ux:vm_map),
+ * then only the specified symbol table will be searched;
+ * otherwise, all symbol tables will be searched.
+ */
+db_sym_t
+db_lookup(symstr)
+ char *symstr;
+{
+ db_sym_t sp;
+ register int i;
+ int symtab_start = 0;
+ int symtab_end = db_nsymtab;
+ register char *cp;
+
+ /*
+ * Look for, remove, and remember any symbol table specifier.
+ */
+ for (cp = symstr; *cp; cp++) {
+ if (*cp == ':') {
+ *cp = '\0';
+ for (i = 0; i < db_nsymtab; i++) {
+ if (! strcmp(symstr, db_symtabs[i].name)) {
+ symtab_start = i;
+ symtab_end = i + 1;
+ break;
+ }
+ }
+ *cp = ':';
+ if (i == db_nsymtab) {
+ db_error("invalid symbol table name");
+ }
+ symstr = cp+1;
+ }
+ }
+
+ /*
+ * Look in the specified set of symbol tables.
+ * Return on first match.
+ */
+ for (i = symtab_start; i < symtab_end; i++) {
+ if (sp = X_db_lookup(&db_symtabs[i], symstr)) {
+ db_last_symtab = &db_symtabs[i];
+ return sp;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Does this symbol name appear in more than one symbol table?
+ * Used by db_symbol_values to decide whether to qualify a symbol.
+ */
+boolean_t db_qualify_ambiguous_names = FALSE;
+
+boolean_t
+db_symbol_is_ambiguous(sym)
+ db_sym_t sym;
+{
+ char *sym_name;
+ register int i;
+ register
+ boolean_t found_once = FALSE;
+
+ if (!db_qualify_ambiguous_names)
+ return FALSE;
+
+ db_symbol_values(sym, &sym_name, 0);
+ for (i = 0; i < db_nsymtab; i++) {
+ if (X_db_lookup(&db_symtabs[i], sym_name)) {
+ if (found_once)
+ return TRUE;
+ found_once = TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Find the closest symbol to val, and return its name
+ * and the difference between val and the symbol found.
+ */
+db_sym_t
+db_search_symbol( val, strategy, offp)
+ register db_addr_t val;
+ db_strategy_t strategy;
+ db_expr_t *offp;
+{
+ register
+ unsigned int diff;
+ unsigned int newdiff;
+ register int i;
+ db_sym_t ret = DB_SYM_NULL, sym;
+
+ newdiff = diff = ~0;
+ db_last_symtab = 0;
+ for (i = 0; i < db_nsymtab; i++) {
+ sym = X_db_search_symbol(&db_symtabs[i], val, strategy, &newdiff);
+ if (newdiff < diff) {
+ db_last_symtab = &db_symtabs[i];
+ diff = newdiff;
+ ret = sym;
+ }
+ }
+ *offp = diff;
+ return ret;
+}
+
+/*
+ * Return name and value of a symbol
+ */
+void
+db_symbol_values(sym, namep, valuep)
+ db_sym_t sym;
+ char **namep;
+ db_expr_t *valuep;
+{
+ db_expr_t value;
+
+ if (sym == DB_SYM_NULL) {
+ *namep = 0;
+ return;
+ }
+
+ X_db_symbol_values(sym, namep, &value);
+
+ if (db_symbol_is_ambiguous(sym))
+ *namep = db_qualify(sym, db_last_symtab->name);
+ if (valuep)
+ *valuep = value;
+}
+
+
+/*
+ * Print a the closest symbol to value
+ *
+ * After matching the symbol according to the given strategy
+ * we print it in the name+offset format, provided the symbol's
+ * value is close enough (eg smaller than db_maxoff).
+ * We also attempt to print [filename:linenum] when applicable
+ * (eg for procedure names).
+ *
+ * If we could not find a reasonable name+offset representation,
+ * then we just print the value in hex. Small values might get
+ * bogus symbol associations, e.g. 3 might get some absolute
+ * value like _INCLUDE_VERSION or something, therefore we do
+ * not accept symbols whose value is zero (and use plain hex).
+ */
+
+unsigned int db_maxoff = 0x10000000;
+
+void
+db_printsym(off, strategy)
+ db_expr_t off;
+ db_strategy_t strategy;
+{
+ db_expr_t d;
+ char *filename;
+ char *name;
+ db_expr_t value;
+ int linenum;
+ db_sym_t cursym;
+
+ cursym = db_search_symbol(off, strategy, &d);
+ db_symbol_values(cursym, &name, &value);
+ if (name == 0 || d >= db_maxoff || value == 0) {
+ db_printf("%#n", off);
+ return;
+ }
+ db_printf("%s", name);
+ if (d)
+ db_printf("+%#r", d);
+ if (strategy == DB_STGY_PROC) {
+ if (db_line_at_pc(cursym, &filename, &linenum, off))
+ db_printf(" [%s:%d]", filename, linenum);
+ }
+}
+
+boolean_t
+db_line_at_pc( sym, filename, linenum, pc)
+ int sym;
+ int filename;
+ int linenum;
+ int pc;
+{
+ return X_db_line_at_pc( db_last_symtab, sym, filename, linenum, pc);
+}
+
+int
+db_sym_numargs(sym, nargp, argnames)
+ db_sym_t sym;
+ int *nargp;
+ char **argnames;
+{
+ return X_db_sym_numargs(db_last_symtab, sym, nargp, argnames);
+}
diff --git a/sys/ddb/db_sym.h b/sys/ddb/db_sym.h
new file mode 100644
index 0000000..a256b79
--- /dev/null
+++ b/sys/ddb/db_sym.h
@@ -0,0 +1,102 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_sym.h,v 1.2 1993/10/16 16:47:27 rgrimes Exp $
+ */
+
+#ifndef _DDB_DB_SYM_H_
+#define _DDB_DB_SYM_H_ 1
+
+/*
+ * Author: Alessandro Forin, Carnegie Mellon University
+ * Date: 8/90
+ */
+
+/*
+ * This module can handle multiple symbol tables
+ */
+typedef struct {
+ char *name; /* symtab name */
+ char *start; /* symtab location */
+ char *end;
+ char *private; /* optional machdep pointer */
+} db_symtab_t;
+
+extern db_symtab_t *db_last_symtab; /* where last symbol was found */
+
+/*
+ * Symbol representation is specific to the symtab style:
+ * BSD compilers use dbx' nlist, other compilers might use
+ * a different one
+ */
+typedef char * db_sym_t; /* opaque handle on symbols */
+#define DB_SYM_NULL ((db_sym_t)0)
+
+/*
+ * Non-stripped symbol tables will have duplicates, for instance
+ * the same string could match a parameter name, a local var, a
+ * global var, etc.
+ * We are most concern with the following matches.
+ */
+typedef int db_strategy_t; /* search strategy */
+
+#define DB_STGY_ANY 0 /* anything goes */
+#define DB_STGY_XTRN 1 /* only external symbols */
+#define DB_STGY_PROC 2 /* only procedures */
+
+extern boolean_t db_qualify_ambiguous_names;
+ /* if TRUE, check across symbol tables
+ * for multiple occurrences of a name.
+ * Might slow down quite a bit */
+
+/*
+ * Functions exported by the symtable module
+ */
+extern void db_add_symbol_table();
+ /* extend the list of symbol tables */
+
+extern int db_value_of_name(/* char*, db_expr_t* */);
+ /* find symbol value given name */
+
+extern db_sym_t db_search_symbol(/* db_expr_t, db_strategy_t, int* */);
+ /* find symbol given value */
+
+extern void db_symbol_values(/* db_sym_t, char**, db_expr_t* */);
+ /* return name and value of symbol */
+
+#define db_find_sym_and_offset(val,namep,offp) \
+ db_symbol_values(db_search_symbol(val,DB_STGY_ANY,offp),namep,0)
+ /* find name&value given approx val */
+
+#define db_find_xtrn_sym_and_offset(val,namep,offp) \
+ db_symbol_values(db_search_symbol(val,DB_STGY_XTRN,offp),namep,0)
+ /* ditto, but no locals */
+
+extern int db_eqname(/* char*, char*, char */);
+ /* strcmp, modulo leading char */
+
+extern void db_printsym(/* db_expr_t, db_strategy_t */);
+ /* print closest symbol to a value */
+#endif /* _DDB_DB_SYM_H_ */
diff --git a/sys/ddb/db_trap.c b/sys/ddb/db_trap.c
new file mode 100644
index 0000000..abfa770
--- /dev/null
+++ b/sys/ddb/db_trap.c
@@ -0,0 +1,79 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_trap.c,v 1.2 1993/10/16 16:47:28 rgrimes Exp $
+ */
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+/*
+ * Trap entry point to kernel debugger.
+ */
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "ddb/ddb.h"
+#include <ddb/db_command.h>
+#include <ddb/db_break.h>
+
+extern void db_restart_at_pc();
+extern boolean_t db_stop_at_pc();
+
+extern int db_inst_count;
+extern int db_load_count;
+extern int db_store_count;
+
+void
+db_trap(type, code)
+ int type, code;
+{
+ boolean_t bkpt;
+ boolean_t watchpt;
+
+ bkpt = IS_BREAKPOINT_TRAP(type, code);
+ watchpt = IS_WATCHPOINT_TRAP(type, code);
+
+ if (db_stop_at_pc(&bkpt)) {
+ if (db_inst_count) {
+ db_printf("After %d instructions (%d loads, %d stores),\n",
+ db_inst_count, db_load_count, db_store_count);
+ }
+ if (bkpt)
+ db_printf("Breakpoint at\t");
+ else if (watchpt)
+ db_printf("Watchpoint at\t");
+ else
+ db_printf("Stopped at\t");
+ db_dot = PC_REGS(DDB_REGS);
+ db_print_loc_and_inst(db_dot);
+
+ db_command_loop();
+ }
+
+ db_restart_at_pc(watchpt);
+}
diff --git a/sys/ddb/db_variables.c b/sys/ddb/db_variables.c
new file mode 100644
index 0000000..96ef620
--- /dev/null
+++ b/sys/ddb/db_variables.c
@@ -0,0 +1,165 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_variables.c,v 1.2 1993/10/16 16:47:29 rgrimes Exp $
+ */
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "ddb/ddb.h"
+
+#include <ddb/db_lex.h>
+#include <ddb/db_variables.h>
+
+void db_read_variable(struct db_variable *, db_expr_t *);
+static void db_write_variable(struct db_variable *, db_expr_t *);
+
+struct db_variable db_vars[] = {
+ { "radix", &db_radix, FCN_NULL },
+ { "maxoff", (int *)&db_maxoff, FCN_NULL },
+ { "maxwidth", &db_max_width, FCN_NULL },
+ { "tabstops", &db_tab_stop_width, FCN_NULL },
+};
+struct db_variable *db_evars = db_vars + sizeof(db_vars)/sizeof(db_vars[0]);
+
+int
+db_find_variable(varp)
+ struct db_variable **varp;
+{
+ int t;
+ struct db_variable *vp;
+
+ t = db_read_token();
+ if (t == tIDENT) {
+ for (vp = db_vars; vp < db_evars; vp++) {
+ if (!strcmp(db_tok_string, vp->name)) {
+ *varp = vp;
+ return (1);
+ }
+ }
+ for (vp = db_regs; vp < db_eregs; vp++) {
+ if (!strcmp(db_tok_string, vp->name)) {
+ *varp = vp;
+ return (1);
+ }
+ }
+ }
+ db_error("Unknown variable\n");
+ return (0);
+}
+
+int
+db_get_variable(valuep)
+ db_expr_t *valuep;
+{
+ struct db_variable *vp;
+
+ if (!db_find_variable(&vp))
+ return (0);
+
+ db_read_variable(vp, valuep);
+
+ return (1);
+}
+
+int
+db_set_variable(value)
+ db_expr_t value;
+{
+ struct db_variable *vp;
+
+ if (!db_find_variable(&vp))
+ return (0);
+
+ db_write_variable(vp, &value);
+
+ return (1);
+}
+
+
+void
+db_read_variable(vp, valuep)
+ struct db_variable *vp;
+ db_expr_t *valuep;
+{
+ int (*func)() = vp->fcn;
+
+ if (func == FCN_NULL)
+ *valuep = *(vp->valuep);
+ else
+ (*func)(vp, valuep, DB_VAR_GET);
+}
+
+static void
+db_write_variable(vp, valuep)
+ struct db_variable *vp;
+ db_expr_t *valuep;
+{
+ int (*func)() = vp->fcn;
+
+ if (func == FCN_NULL)
+ *(vp->valuep) = *valuep;
+ else
+ (*func)(vp, valuep, DB_VAR_SET);
+}
+
+void
+db_set_cmd(db_expr_t dummy1, int dummy2, db_expr_t dummy3, char *dummy4)
+{
+ db_expr_t value;
+ int (*func)();
+ struct db_variable *vp;
+ int t;
+
+ t = db_read_token();
+ if (t != tDOLLAR) {
+ db_error("Unknown variable\n");
+ return;
+ }
+ if (!db_find_variable(&vp)) {
+ db_error("Unknown variable\n");
+ return;
+ }
+
+ t = db_read_token();
+ if (t != tEQ)
+ db_unread_token(t);
+
+ if (!db_expression(&value)) {
+ db_error("No value\n");
+ return;
+ }
+ if (db_read_token() != tEOL) {
+ db_error("?\n");
+ }
+
+ db_write_variable(vp, &value);
+}
diff --git a/sys/ddb/db_variables.h b/sys/ddb/db_variables.h
new file mode 100644
index 0000000..35e5a00
--- /dev/null
+++ b/sys/ddb/db_variables.h
@@ -0,0 +1,57 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_variables.h,v 1.2 1993/10/16 16:47:31 rgrimes Exp $
+ */
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#ifndef _DB_VARIABLES_H_
+#define _DB_VARIABLES_H_
+
+/*
+ * Debugger variables.
+ */
+struct db_variable {
+ char *name; /* Name of variable */
+ int *valuep; /* value of variable */
+ /* function to call when reading/writing */
+ int (*fcn)(/* db_variable *vp, db_expr_t *valuep, int op */);
+#define DB_VAR_GET 0
+#define DB_VAR_SET 1
+};
+#define FCN_NULL ((int (*)())0)
+
+extern struct db_variable db_vars[]; /* debugger variables */
+extern struct db_variable *db_evars;
+extern struct db_variable db_regs[]; /* machine registers */
+extern struct db_variable *db_eregs;
+
+extern void db_read_variable(struct db_variable *, db_expr_t *);
+
+#endif /* _DB_VARIABLES_H_ */
diff --git a/sys/ddb/db_watch.c b/sys/ddb/db_watch.c
new file mode 100644
index 0000000..0322a18
--- /dev/null
+++ b/sys/ddb/db_watch.c
@@ -0,0 +1,270 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_watch.c,v 1.2 1993/10/16 16:47:32 rgrimes Exp $
+ */
+
+/*
+ * Author: Richard P. Draves, Carnegie Mellon University
+ * Date: 10/90
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "ddb/ddb.h"
+
+#include <vm/vm_map.h>
+#include <ddb/db_lex.h>
+#include <ddb/db_watch.h>
+#include <ddb/db_access.h>
+#include <ddb/db_sym.h>
+
+/*
+ * Watchpoints.
+ */
+
+extern boolean_t db_map_equal();
+extern boolean_t db_map_current();
+extern vm_map_t db_map_addr();
+
+boolean_t db_watchpoints_inserted = TRUE;
+
+#define NWATCHPOINTS 100
+struct db_watchpoint db_watch_table[NWATCHPOINTS];
+db_watchpoint_t db_next_free_watchpoint = &db_watch_table[0];
+db_watchpoint_t db_free_watchpoints = 0;
+db_watchpoint_t db_watchpoint_list = 0;
+
+db_watchpoint_t
+db_watchpoint_alloc()
+{
+ register db_watchpoint_t watch;
+
+ if ((watch = db_free_watchpoints) != 0) {
+ db_free_watchpoints = watch->link;
+ return (watch);
+ }
+ if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) {
+ db_printf("All watchpoints used.\n");
+ return (0);
+ }
+ watch = db_next_free_watchpoint;
+ db_next_free_watchpoint++;
+
+ return (watch);
+}
+
+void
+db_watchpoint_free(watch)
+ register db_watchpoint_t watch;
+{
+ watch->link = db_free_watchpoints;
+ db_free_watchpoints = watch;
+}
+
+void
+db_set_watchpoint(map, addr, size)
+ vm_map_t map;
+ db_addr_t addr;
+ vm_size_t size;
+{
+ register db_watchpoint_t watch;
+
+ if (map == NULL) {
+ db_printf("No map.\n");
+ return;
+ }
+
+ /*
+ * Should we do anything fancy with overlapping regions?
+ */
+
+ for (watch = db_watchpoint_list;
+ watch != 0;
+ watch = watch->link)
+ if (db_map_equal(watch->map, map) &&
+ (watch->loaddr == addr) &&
+ (watch->hiaddr == addr+size)) {
+ db_printf("Already set.\n");
+ return;
+ }
+
+ watch = db_watchpoint_alloc();
+ if (watch == 0) {
+ db_printf("Too many watchpoints.\n");
+ return;
+ }
+
+ watch->map = map;
+ watch->loaddr = addr;
+ watch->hiaddr = addr+size;
+
+ watch->link = db_watchpoint_list;
+ db_watchpoint_list = watch;
+
+ db_watchpoints_inserted = FALSE;
+}
+
+void
+db_delete_watchpoint(map, addr)
+ vm_map_t map;
+ db_addr_t addr;
+{
+ register db_watchpoint_t watch;
+ register db_watchpoint_t *prev;
+
+ for (prev = &db_watchpoint_list;
+ (watch = *prev) != 0;
+ prev = &watch->link)
+ if (db_map_equal(watch->map, map) &&
+ (watch->loaddr <= addr) &&
+ (addr < watch->hiaddr)) {
+ *prev = watch->link;
+ db_watchpoint_free(watch);
+ return;
+ }
+
+ db_printf("Not set.\n");
+}
+
+void
+db_list_watchpoints()
+{
+ register db_watchpoint_t watch;
+
+ if (db_watchpoint_list == 0) {
+ db_printf("No watchpoints set\n");
+ return;
+ }
+
+ db_printf(" Map Address Size\n");
+ for (watch = db_watchpoint_list;
+ watch != 0;
+ watch = watch->link)
+ db_printf("%s%8x %8x %x\n",
+ db_map_current(watch->map) ? "*" : " ",
+ watch->map, watch->loaddr,
+ watch->hiaddr - watch->loaddr);
+}
+
+/* Delete watchpoint */
+/*ARGSUSED*/
+void
+db_deletewatch_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ db_delete_watchpoint(db_map_addr(addr), addr);
+}
+
+/* Set watchpoint */
+/*ARGSUSED*/
+void
+db_watchpoint_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ vm_size_t size;
+ db_expr_t value;
+
+ if (db_expression(&value))
+ size = (vm_size_t) value;
+ else
+ size = 4;
+ db_skip_to_eol();
+
+ db_set_watchpoint(db_map_addr(addr), addr, size);
+}
+
+/* list watchpoints */
+void
+db_listwatch_cmd(db_expr_t dummy1, int dummy2, db_expr_t dummy3, char *dummmy4)
+{
+ db_list_watchpoints();
+}
+
+void
+db_set_watchpoints()
+{
+ register db_watchpoint_t watch;
+
+ if (!db_watchpoints_inserted) {
+ for (watch = db_watchpoint_list;
+ watch != 0;
+ watch = watch->link)
+ pmap_protect(watch->map->pmap,
+ trunc_page(watch->loaddr),
+ round_page(watch->hiaddr),
+ VM_PROT_READ);
+
+ db_watchpoints_inserted = TRUE;
+ }
+}
+
+void
+db_clear_watchpoints()
+{
+ db_watchpoints_inserted = FALSE;
+}
+
+boolean_t
+db_find_watchpoint(map, addr, regs)
+ vm_map_t map;
+ db_addr_t addr;
+ db_regs_t *regs;
+{
+ register db_watchpoint_t watch;
+ db_watchpoint_t found = 0;
+
+ for (watch = db_watchpoint_list;
+ watch != 0;
+ watch = watch->link)
+ if (db_map_equal(watch->map, map)) {
+ if ((watch->loaddr <= addr) &&
+ (addr < watch->hiaddr))
+ return (TRUE);
+ else if ((trunc_page(watch->loaddr) <= addr) &&
+ (addr < round_page(watch->hiaddr)))
+ found = watch;
+ }
+
+ /*
+ * We didn't hit exactly on a watchpoint, but we are
+ * in a protected region. We want to single-step
+ * and then re-protect.
+ */
+
+ if (found) {
+ db_watchpoints_inserted = FALSE;
+ db_single_step(regs);
+ }
+
+ return (FALSE);
+}
diff --git a/sys/ddb/db_watch.h b/sys/ddb/db_watch.h
new file mode 100644
index 0000000..f8932de
--- /dev/null
+++ b/sys/ddb/db_watch.h
@@ -0,0 +1,60 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id$
+ */
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 10/90
+ */
+
+#ifndef _DDB_DB_WATCH_
+#define _DDB_DB_WATCH_
+
+#include <vm/vm_map.h>
+#include <machine/db_machdep.h>
+
+/*
+ * Watchpoint.
+ */
+
+typedef struct db_watchpoint {
+ vm_map_t map; /* in this map */
+ db_addr_t loaddr; /* from this address */
+ db_addr_t hiaddr; /* to this address */
+ struct db_watchpoint *link; /* link in in-use or free chain */
+} *db_watchpoint_t;
+
+extern boolean_t db_find_watchpoint(/* vm_map_t map, db_addr_t addr,
+ db_regs_t *regs */);
+extern void db_set_watchpoints();
+extern void db_clear_watchpoints();
+
+extern void db_set_watchpoint(/* vm_map_t map, db_addr_t addr, vm_size_t size */);
+extern void db_delete_watchpoint(/* vm_map_t map, db_addr_t addr */);
+extern void db_list_watchpoints();
+
+#endif _DDB_DB_WATCH_
diff --git a/sys/ddb/db_write_cmd.c b/sys/ddb/db_write_cmd.c
new file mode 100644
index 0000000..6de58a6
--- /dev/null
+++ b/sys/ddb/db_write_cmd.c
@@ -0,0 +1,99 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_write_cmd.c,v 1.2 1993/10/16 16:47:35 rgrimes Exp $
+ */
+
+/*
+ * Author: David B. Golub, Carnegie Mellon University
+ * Date: 7/90
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "ddb/ddb.h"
+
+#include <ddb/db_lex.h>
+#include <ddb/db_access.h>
+#include <ddb/db_command.h>
+#include <ddb/db_sym.h>
+
+/*
+ * Write to file.
+ */
+/*ARGSUSED*/
+void
+db_write_cmd(address, have_addr, count, modif)
+ db_expr_t address;
+ boolean_t have_addr;
+ db_expr_t count;
+ char * modif;
+{
+ register
+ db_addr_t addr;
+ register
+ db_expr_t old_value;
+ db_expr_t new_value;
+ register int size;
+ boolean_t wrote_one = FALSE;
+
+ addr = (db_addr_t) address;
+
+ switch (modif[0]) {
+ case 'b':
+ size = 1;
+ break;
+ case 'h':
+ size = 2;
+ break;
+ case 'l':
+ case '\0':
+ size = 4;
+ break;
+ default:
+ db_error("Unknown size\n");
+ return;
+ }
+
+ while (db_expression(&new_value)) {
+ old_value = db_get_value(addr, size, FALSE);
+ db_printsym(addr, DB_STGY_ANY);
+ db_printf("\t\t%#8n\t=\t%#8n\n", old_value, new_value);
+ db_put_value(addr, size, new_value);
+ addr += size;
+
+ wrote_one = TRUE;
+ }
+
+ if (!wrote_one)
+ db_error("Nothing written.\n");
+
+ db_next = addr;
+ db_prev = addr - size;
+
+ db_skip_to_eol();
+}
+
diff --git a/sys/ddb/ddb.h b/sys/ddb/ddb.h
new file mode 100644
index 0000000..4d7b206
--- /dev/null
+++ b/sys/ddb/ddb.h
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1993, Garrett A. Wollman.
+ * Copyright (c) 1993, University of Vermont and State Agricultural College.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+/*
+ * Necessary declarations for the `ddb' kernel debugger.
+ */
+
+#ifndef __h_ddb_ddb
+#define __h_ddb_ddb 1
+
+#include "machine/db_machdep.h" /* type definitions */
+
+/*
+ * Global variables...
+ */
+extern char *esym;
+extern unsigned int db_maxoff;
+extern int db_inst_count;
+extern int db_load_count;
+extern int db_store_count;
+extern int db_radix;
+extern int db_max_width;
+extern int db_tab_stop_width;
+
+/*
+ * Functions...
+ */
+extern void
+db_read_bytes(vm_offset_t addr, register int size, register char *data);
+ /* machine-dependent */
+
+extern void
+db_write_bytes(vm_offset_t addr, register int size, register char *data);
+ /* machine-dependent */
+
+struct vm_map; /* forward declaration */
+
+extern boolean_t db_map_equal(struct vm_map *, struct vm_map *);
+extern boolean_t db_map_current(struct vm_map *);
+extern struct vm_map *db_map_addr(vm_offset_t);
+
+#define db_strcpy strcpy
+extern int db_expression (db_expr_t *valuep);
+
+typedef void db_cmd_fcn(db_expr_t, int, db_expr_t, char *);
+
+extern db_cmd_fcn db_listbreak_cmd, db_listwatch_cmd, db_show_regs;
+extern db_cmd_fcn db_print_cmd, db_examine_cmd, db_set_cmd, db_search_cmd;
+extern db_cmd_fcn db_write_cmd, db_delete_cmd, db_breakpoint_cmd;
+extern db_cmd_fcn db_deletewatch_cmd, db_watchpoint_cmd;
+extern db_cmd_fcn db_single_step_cmd, db_trace_until_call_cmd;
+extern db_cmd_fcn db_trace_until_matching_cmd, db_continue_cmd;
+extern db_cmd_fcn db_stack_trace_cmd;
+
+extern db_addr_t db_disasm(db_addr_t loc, boolean_t altfmt);
+ /* instruction disassembler */
+
+extern int db_value_of_name (char *name, db_expr_t *valuep);
+extern int db_get_variable (db_expr_t *valuep);
+extern void db_putchar (int c);
+extern void db_error (char *s);
+extern int db_readline (char *lstart, int lsize);
+extern void db_printf (const char *fmt, ...);
+extern void db_check_interrupt(void);
+extern void db_print_loc_and_inst (db_addr_t loc);
+
+extern void db_clear_watchpoints (void);
+extern void db_set_watchpoints (void);
+
+extern void db_restart_at_pc(boolean_t watchpt);
+extern boolean_t db_stop_at_pc(boolean_t *is_breakpoint);
+
+extern void db_skip_to_eol (void);
+extern void db_single_step (db_regs_t *regs);
+
+extern void db_trap (int type, int code);
+
+extern void kdbprinttrap(int, int);
+
+#endif /* __h_ddb_ddb */
diff --git a/sys/dev/ed/if_ed.c b/sys/dev/ed/if_ed.c
new file mode 100644
index 0000000..84047e2
--- /dev/null
+++ b/sys/dev/ed/if_ed.c
@@ -0,0 +1,2488 @@
+/*
+ * Device driver for National Semiconductor DS8390/WD83C690 based ethernet
+ * adapters. By David Greenman, 29-April-1993
+ *
+ * Copyright (C) 1993, David Greenman. This software may be used, modified,
+ * copied, distributed, and sold, in both source and binary form provided
+ * that the above copyright and these terms are retained. Under no
+ * circumstances is the author responsible for the proper functioning
+ * of this software, nor does the author assume any responsibility
+ * for damages incurred with its use.
+ *
+ * Currently supports the Western Digital/SMC 8003 and 8013 series,
+ * the SMC Elite Ultra (8216), the 3Com 3c503, the NE1000 and NE2000,
+ * and a variety of similar clones.
+ *
+ */
+
+/*
+ * $Id: if_ed.c,v 1.36 1994/04/10 20:06:26 davidg Exp $
+ */
+
+#include "ed.h"
+#if NED > 0
+/* bpfilter included here in case it is needed in future net includes */
+#include "bpfilter.h"
+
+#include "param.h"
+#include "systm.h"
+#include "errno.h"
+#include "ioctl.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "syslog.h"
+
+#include "net/if.h"
+#include "net/if_dl.h"
+#include "net/if_types.h"
+
+#ifdef INET
+#include "netinet/in.h"
+#include "netinet/in_systm.h"
+#include "netinet/in_var.h"
+#include "netinet/ip.h"
+#include "netinet/if_ether.h"
+#endif
+
+#ifdef NS
+#include "netns/ns.h"
+#include "netns/ns_if.h"
+#endif
+
+#if NBPFILTER > 0
+#include "net/bpf.h"
+#include "net/bpfdesc.h"
+#endif
+
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/if_edreg.h"
+
+#include "i386/include/pio.h"
+
+/* For backwards compatibility */
+#ifndef IFF_ALTPHYS
+#define IFF_ALTPHYS IFF_LLC0
+#endif
+
+/*
+ * ed_softc: per line info and status
+ */
+struct ed_softc {
+ struct arpcom arpcom; /* ethernet common */
+
+ char *type_str; /* pointer to type string */
+ u_char vendor; /* interface vendor */
+ u_char type; /* interface type code */
+
+ u_short asic_addr; /* ASIC I/O bus address */
+ u_short nic_addr; /* NIC (DS8390) I/O bus address */
+
+/*
+ * The following 'proto' variable is part of a work-around for 8013EBT asics
+ * being write-only. It's sort of a prototype/shadow of the real thing.
+ */
+ u_char wd_laar_proto;
+ u_char isa16bit; /* width of access to card 0=8 or 1=16 */
+ int is790; /* set by the probe code if the card is 790 based */
+
+ caddr_t bpf; /* BPF "magic cookie" */
+ caddr_t mem_start; /* NIC memory start address */
+ caddr_t mem_end; /* NIC memory end address */
+ u_long mem_size; /* total NIC memory size */
+ caddr_t mem_ring; /* start of RX ring-buffer (in NIC mem) */
+
+ u_char mem_shared; /* NIC memory is shared with host */
+ u_char xmit_busy; /* transmitter is busy */
+ u_char txb_cnt; /* number of transmit buffers */
+ u_char txb_inuse; /* number of TX buffers currently in-use*/
+
+ u_char txb_new; /* pointer to where new buffer will be added */
+ u_char txb_next_tx; /* pointer to next buffer ready to xmit */
+ u_short txb_len[8]; /* buffered xmit buffer lengths */
+ u_char tx_page_start; /* first page of TX buffer area */
+ u_char rec_page_start; /* first page of RX ring-buffer */
+ u_char rec_page_stop; /* last page of RX ring-buffer */
+ u_char next_packet; /* pointer to next unread RX packet */
+} ed_softc[NED];
+
+int ed_attach(struct isa_device *);
+void ed_init(int);
+void edintr(int);
+int ed_ioctl(struct ifnet *, int, caddr_t);
+int ed_probe(struct isa_device *);
+void ed_start(struct ifnet *);
+void ed_reset(int, int);
+void ed_watchdog(int);
+
+static void ed_get_packet(struct ed_softc *, char *, int /*u_short*/);
+static void ed_stop(int);
+
+static inline void ed_rint();
+static inline void ed_xmit();
+static inline char *ed_ring_copy();
+
+void ed_pio_readmem(), ed_pio_writemem();
+u_short ed_pio_write_mbufs();
+
+extern int ether_output();
+
+struct trailer_header {
+ u_short ether_type;
+ u_short ether_residual;
+};
+
+struct isa_driver eddriver = {
+ ed_probe,
+ ed_attach,
+ "ed"
+};
+/*
+ * Interrupt conversion table for WD/SMC ASIC
+ * (IRQ* are defined in icu.h)
+ */
+static unsigned short ed_intr_mask[] = {
+ IRQ9,
+ IRQ3,
+ IRQ5,
+ IRQ7,
+ IRQ10,
+ IRQ11,
+ IRQ15,
+ IRQ4
+};
+
+/*
+ * Interrupt conversion table for 585/790 Combo
+ */
+static unsigned short ed_790_intr_mask[] = {
+ 0,
+ IRQ9,
+ IRQ3,
+ IRQ5,
+ IRQ7,
+ IRQ10,
+ IRQ11,
+ IRQ15
+};
+#define ETHER_MIN_LEN 64
+#define ETHER_MAX_LEN 1518
+#define ETHER_ADDR_LEN 6
+#define ETHER_HDR_SIZE 14
+
+/*
+ * Determine if the device is present
+ *
+ * on entry:
+ * a pointer to an isa_device struct
+ * on exit:
+ * NULL if device not found
+ * or # of i/o addresses used (if found)
+ */
+int
+ed_probe(isa_dev)
+ struct isa_device *isa_dev;
+{
+ struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
+ int nports;
+
+ if (nports = ed_probe_WD80x3(isa_dev))
+ return (nports);
+
+ if (nports = ed_probe_3Com(isa_dev))
+ return (nports);
+
+ if (nports = ed_probe_Novell(isa_dev))
+ return (nports);
+
+ return(0);
+}
+
+/*
+ * Generic probe routine for testing for the existance of a DS8390.
+ * Must be called after the NIC has just been reset. This routine
+ * works by looking at certain register values that are gauranteed
+ * to be initialized a certain way after power-up or reset. Seems
+ * not to currently work on the 83C690.
+ *
+ * Specifically:
+ *
+ * Register reset bits set bits
+ * Command Register (CR) TXP, STA RD2, STP
+ * Interrupt Status (ISR) RST
+ * Interrupt Mask (IMR) All bits
+ * Data Control (DCR) LAS
+ * Transmit Config. (TCR) LB1, LB0
+ *
+ * We only look at the CR and ISR registers, however, because looking at
+ * the others would require changing register pages (which would be
+ * intrusive if this isn't an 8390).
+ *
+ * Return 1 if 8390 was found, 0 if not.
+ */
+
+int
+ed_probe_generic8390(sc)
+ struct ed_softc *sc;
+{
+ if ((inb(sc->nic_addr + ED_P0_CR) &
+ (ED_CR_RD2|ED_CR_TXP|ED_CR_STA|ED_CR_STP)) !=
+ (ED_CR_RD2|ED_CR_STP))
+ return (0);
+ if ((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RST) != ED_ISR_RST)
+ return (0);
+
+ return(1);
+}
+
+/*
+ * Probe and vendor-specific initialization routine for SMC/WD80x3 boards
+ */
+int
+ed_probe_WD80x3(isa_dev)
+ struct isa_device *isa_dev;
+{
+ struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
+ int i;
+ u_int memsize;
+ u_char iptr, isa16bit, sum;
+
+ sc->asic_addr = isa_dev->id_iobase;
+ sc->nic_addr = sc->asic_addr + ED_WD_NIC_OFFSET;
+ sc->is790 = 0;
+
+#ifdef TOSH_ETHER
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_POW);
+ DELAY(10000);
+#endif
+ /*
+ * Attempt to do a checksum over the station address PROM.
+ * If it fails, it's probably not a SMC/WD board. There
+ * is a problem with this, though: some clone WD boards
+ * don't pass the checksum test. Danpex boards for one.
+ */
+ for (sum = 0, i = 0; i < 8; ++i)
+ sum += inb(sc->asic_addr + ED_WD_PROM + i);
+
+ if (sum != ED_WD_ROM_CHECKSUM_TOTAL) {
+ /*
+ * Checksum is invalid. This often happens with cheap
+ * WD8003E clones. In this case, the checksum byte
+ * (the eighth byte) seems to always be zero.
+ */
+ if (inb(sc->asic_addr + ED_WD_CARD_ID) != ED_TYPE_WD8003E ||
+ inb(sc->asic_addr + ED_WD_PROM + 7) != 0)
+ return(0);
+ }
+
+ /* reset card to force it into a known state. */
+#ifdef TOSH_ETHER
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_RST | ED_WD_MSR_POW);
+#else
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_RST);
+#endif
+ DELAY(100);
+ outb(sc->asic_addr + ED_WD_MSR, inb(sc->asic_addr + ED_WD_MSR) & ~ED_WD_MSR_RST);
+ /* wait in the case this card is reading it's EEROM */
+ DELAY(5000);
+
+ sc->vendor = ED_VENDOR_WD_SMC;
+ sc->type = inb(sc->asic_addr + ED_WD_CARD_ID);
+
+ /*
+ * Set initial values for width/size.
+ */
+ memsize = 8192;
+ isa16bit = 0;
+ switch (sc->type) {
+ case ED_TYPE_WD8003S:
+ sc->type_str = "WD8003S";
+ break;
+ case ED_TYPE_WD8003E:
+ sc->type_str = "WD8003E";
+ break;
+ case ED_TYPE_WD8003EB:
+ sc->type_str = "WD8003EB";
+ break;
+ case ED_TYPE_WD8003W:
+ sc->type_str = "WD8003W";
+ break;
+ case ED_TYPE_WD8013EBT:
+ sc->type_str = "WD8013EBT";
+ memsize = 16384;
+ isa16bit = 1;
+ break;
+ case ED_TYPE_WD8013W:
+ sc->type_str = "WD8013W";
+ memsize = 16384;
+ isa16bit = 1;
+ break;
+ case ED_TYPE_WD8013EP: /* also WD8003EP */
+ if (inb(sc->asic_addr + ED_WD_ICR)
+ & ED_WD_ICR_16BIT) {
+ isa16bit = 1;
+ memsize = 16384;
+ sc->type_str = "WD8013EP";
+ } else {
+ sc->type_str = "WD8003EP";
+ }
+ break;
+ case ED_TYPE_WD8013WC:
+ sc->type_str = "WD8013WC";
+ memsize = 16384;
+ isa16bit = 1;
+ break;
+ case ED_TYPE_WD8013EBP:
+ sc->type_str = "WD8013EBP";
+ memsize = 16384;
+ isa16bit = 1;
+ break;
+ case ED_TYPE_WD8013EPC:
+ sc->type_str = "WD8013EPC";
+ memsize = 16384;
+ isa16bit = 1;
+ break;
+ case ED_TYPE_SMC8216C:
+ sc->type_str = "SMC8216/SMC8216C";
+ memsize = 16384;
+ isa16bit = 1;
+ sc->is790 = 1;
+ break;
+ case ED_TYPE_SMC8216T:
+ sc->type_str = "SMC8216T";
+ memsize = 16384;
+ isa16bit = 1;
+ sc->is790 = 1;
+ break;
+#ifdef TOSH_ETHER
+ case ED_TYPE_TOSHIBA1:
+ sc->type_str = "Toshiba1";
+ memsize = 32768;
+ isa16bit = 1;
+ break;
+ case ED_TYPE_TOSHIBA4:
+ sc->type_str = "Toshiba4";
+ memsize = 32768;
+ isa16bit = 1;
+ break;
+#endif
+ default:
+ sc->type_str = "";
+ break;
+ }
+ /*
+ * Make some adjustments to initial values depending on what is
+ * found in the ICR.
+ */
+ if (isa16bit && (sc->type != ED_TYPE_WD8013EBT)
+#ifdef TOSH_ETHER
+ && (sc->type != ED_TYPE_TOSHIBA1) && (sc->type != ED_TYPE_TOSHIBA4)
+#endif
+ && ((inb(sc->asic_addr + ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) {
+ isa16bit = 0;
+ memsize = 8192;
+ }
+
+#if ED_DEBUG
+ printf("type = %x type_str=%s isa16bit=%d memsize=%d id_msize=%d\n",
+ sc->type,sc->type_str,isa16bit,memsize,isa_dev->id_msize);
+ for (i=0; i<8; i++)
+ printf("%x -> %x\n", i, inb(sc->asic_addr + i));
+#endif
+ /*
+ * Allow the user to override the autoconfiguration
+ */
+ if (isa_dev->id_msize)
+ memsize = isa_dev->id_msize;
+ /*
+ * (note that if the user specifies both of the following flags
+ * that '8bit' mode intentionally has precedence)
+ */
+ if (isa_dev->id_flags & ED_FLAGS_FORCE_16BIT_MODE)
+ isa16bit = 1;
+ if (isa_dev->id_flags & ED_FLAGS_FORCE_8BIT_MODE)
+ isa16bit = 0;
+
+ /*
+ * Check 83C584 interrupt configuration register if this board has one
+ * XXX - we could also check the IO address register. But why
+ * bother...if we get past this, it *has* to be correct.
+ */
+ if ((sc->type & ED_WD_SOFTCONFIG) && (!sc->is790)) {
+ /*
+ * Assemble together the encoded interrupt number.
+ */
+ iptr = (inb(isa_dev->id_iobase + ED_WD_ICR) & ED_WD_ICR_IR2) |
+ ((inb(isa_dev->id_iobase + ED_WD_IRR) &
+ (ED_WD_IRR_IR0 | ED_WD_IRR_IR1)) >> 5);
+ /*
+ * Translate it using translation table, and check for correctness.
+ */
+ if (ed_intr_mask[iptr] != isa_dev->id_irq) {
+ printf("ed%d: kernel configured irq %d doesn't match board configured irq %d\n",
+ isa_dev->id_unit, ffs(isa_dev->id_irq) - 1,
+ ffs(ed_intr_mask[iptr]) - 1);
+ return(0);
+ }
+ /*
+ * Enable the interrupt.
+ */
+ outb(isa_dev->id_iobase + ED_WD_IRR,
+ inb(isa_dev->id_iobase + ED_WD_IRR) | ED_WD_IRR_IEN);
+ }
+ if (sc->is790) {
+ outb(isa_dev->id_iobase + ED_WD790_HWR,
+ inb(isa_dev->id_iobase + ED_WD790_HWR) | ED_WD790_HWR_SWH);
+ iptr = (((inb(isa_dev->id_iobase + ED_WD790_GCR) & ED_WD790_GCR_IR2) >> 4) |
+ (inb(isa_dev->id_iobase + ED_WD790_GCR) &
+ (ED_WD790_GCR_IR1|ED_WD790_GCR_IR0)) >> 2);
+ outb(isa_dev->id_iobase + ED_WD790_HWR,
+ inb(isa_dev->id_iobase + ED_WD790_HWR) & ~ED_WD790_HWR_SWH);
+
+ if (ed_790_intr_mask[iptr] != isa_dev->id_irq) {
+ printf("ed%d: kernel configured irq %d doesn't match board configured irq %d %d\n",
+ isa_dev->id_unit, ffs(isa_dev->id_irq) - 1,
+ ffs(ed_790_intr_mask[iptr]) - 1, iptr);
+ return 0;
+ }
+ /*
+ * Enable interrupts.
+ */
+ outb(isa_dev->id_iobase + ED_WD790_ICR,
+ inb(isa_dev->id_iobase + ED_WD790_ICR) | ED_WD790_ICR_EIL);
+ }
+
+ sc->isa16bit = isa16bit;
+
+#ifdef notyet /* XXX - I'm not sure if PIO mode is even possible on WD/SMC boards */
+ /*
+ * The following allows the WD/SMC boards to be used in Programmed I/O
+ * mode - without mapping the NIC memory shared. ...Not the prefered
+ * way, but it might be the only way.
+ */
+ if (isa_dev->id_flags & ED_FLAGS_FORCE_PIO) {
+ sc->mem_shared = 0;
+ isa_dev->id_maddr = 0;
+ } else {
+ sc->mem_shared = 1;
+ }
+#else
+ sc->mem_shared = 1;
+#endif
+ isa_dev->id_msize = memsize;
+
+ sc->mem_start = (caddr_t)isa_dev->id_maddr;
+
+ /*
+ * allocate one xmit buffer if < 16k, two buffers otherwise
+ */
+ if ((memsize < 16384) || (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING)) {
+ sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE);
+ sc->txb_cnt = 1;
+ sc->rec_page_start = ED_TXBUF_SIZE;
+ } else {
+ sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE * 2);
+ sc->txb_cnt = 2;
+ sc->rec_page_start = ED_TXBUF_SIZE * 2;
+ }
+ sc->mem_size = memsize;
+ sc->mem_end = sc->mem_start + memsize;
+ sc->rec_page_stop = memsize / ED_PAGE_SIZE;
+ sc->tx_page_start = ED_WD_PAGE_OFFSET;
+
+ /*
+ * Get station address from on-board ROM
+ */
+ for (i = 0; i < ETHER_ADDR_LEN; ++i)
+ sc->arpcom.ac_enaddr[i] = inb(sc->asic_addr + ED_WD_PROM + i);
+
+ if (sc->mem_shared) {
+ /*
+ * Set address and enable interface shared memory.
+ */
+ if(!sc->is790) {
+#ifdef TOSH_ETHER
+ outb(sc->asic_addr + ED_WD_MSR + 1, ((kvtop(sc->mem_start) >> 8) & 0xe0) | 4);
+ outb(sc->asic_addr + ED_WD_MSR + 2, ((kvtop(sc->mem_start) >> 16) & 0x0f));
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB | ED_WD_MSR_POW);
+
+#else
+ outb(sc->asic_addr + ED_WD_MSR, ((kvtop(sc->mem_start) >> 13) &
+ ED_WD_MSR_ADDR) | ED_WD_MSR_MENB);
+#endif
+ } else {
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB);
+ outb(sc->asic_addr + 0x04, (inb(sc->asic_addr + 0x04) | 0x80));
+ outb(sc->asic_addr + 0x0b, ((kvtop(sc->mem_start) >> 13) & 0x0f) |
+ ((kvtop(sc->mem_start) >> 11) & 0x40) |
+ (inb(sc->asic_addr + 0x0b) & 0xb0));
+ outb(sc->asic_addr + 0x04, (inb(sc->asic_addr + 0x04) & ~0x80));
+ }
+
+ /*
+ * Set upper address bits and 8/16 bit access to shared memory
+ */
+ if (isa16bit) {
+ if (sc->is790) {
+ sc->wd_laar_proto = inb(sc->asic_addr + ED_WD_LAAR);
+ outb(sc->asic_addr + ED_WD_LAAR, ED_WD_LAAR_M16EN);
+ (void) inb(0x84);
+ } else {
+ outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto =
+ ED_WD_LAAR_L16EN | ED_WD_LAAR_M16EN |
+ ((kvtop(sc->mem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
+ }
+ } else {
+ if ((sc->type & ED_WD_SOFTCONFIG) ||
+#ifdef TOSH_ETHER
+ (sc->type == ED_TYPE_TOSHIBA1) || (sc->type == ED_TYPE_TOSHIBA4) ||
+#endif
+ (sc->type == ED_TYPE_WD8013EBT) && (!sc->is790)) {
+ outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto =
+ ((kvtop(sc->mem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
+ }
+ }
+
+ /*
+ * Now zero memory and verify that it is clear
+ */
+ bzero(sc->mem_start, memsize);
+
+ for (i = 0; i < memsize; ++i)
+ if (sc->mem_start[i]) {
+ printf("ed%d: failed to clear shared memory at %x - check configuration\n",
+ isa_dev->id_unit, kvtop(sc->mem_start + i));
+
+ /*
+ * Disable 16 bit access to shared memory
+ */
+ if (isa16bit) {
+ outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto &=
+ ~ED_WD_LAAR_M16EN));
+ (void) inb(0x84);
+ }
+
+ return(0);
+ }
+
+ /*
+ * Disable 16bit access to shared memory - we leave it disabled so
+ * that 1) machines reboot properly when the board is set
+ * 16 bit mode and there are conflicting 8bit devices/ROMS
+ * in the same 128k address space as this boards shared
+ * memory. and 2) so that other 8 bit devices with shared
+ * memory can be used in this 128k region, too.
+ */
+ if (isa16bit) {
+ outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto &=
+ ~ED_WD_LAAR_M16EN));
+ (void) inb(0x84);
+ }
+ }
+
+ return (ED_WD_IO_PORTS);
+}
+
+/*
+ * Probe and vendor-specific initialization routine for 3Com 3c503 boards
+ */
+int
+ed_probe_3Com(isa_dev)
+ struct isa_device *isa_dev;
+{
+ struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
+ int i;
+ u_int memsize;
+ u_char isa16bit, sum;
+
+ sc->asic_addr = isa_dev->id_iobase + ED_3COM_ASIC_OFFSET;
+ sc->nic_addr = isa_dev->id_iobase + ED_3COM_NIC_OFFSET;
+
+ /*
+ * Verify that the kernel configured I/O address matches the board
+ * configured address
+ */
+ switch (inb(sc->asic_addr + ED_3COM_BCFR)) {
+ case ED_3COM_BCFR_300:
+ if (isa_dev->id_iobase != 0x300)
+ return(0);
+ break;
+ case ED_3COM_BCFR_310:
+ if (isa_dev->id_iobase != 0x310)
+ return(0);
+ break;
+ case ED_3COM_BCFR_330:
+ if (isa_dev->id_iobase != 0x330)
+ return(0);
+ break;
+ case ED_3COM_BCFR_350:
+ if (isa_dev->id_iobase != 0x350)
+ return(0);
+ break;
+ case ED_3COM_BCFR_250:
+ if (isa_dev->id_iobase != 0x250)
+ return(0);
+ break;
+ case ED_3COM_BCFR_280:
+ if (isa_dev->id_iobase != 0x280)
+ return(0);
+ break;
+ case ED_3COM_BCFR_2A0:
+ if (isa_dev->id_iobase != 0x2a0)
+ return(0);
+ break;
+ case ED_3COM_BCFR_2E0:
+ if (isa_dev->id_iobase != 0x2e0)
+ return(0);
+ break;
+ default:
+ return(0);
+ }
+
+ /*
+ * Verify that the kernel shared memory address matches the
+ * board configured address.
+ */
+ switch (inb(sc->asic_addr + ED_3COM_PCFR)) {
+ case ED_3COM_PCFR_DC000:
+ if (kvtop(isa_dev->id_maddr) != 0xdc000)
+ return(0);
+ break;
+ case ED_3COM_PCFR_D8000:
+ if (kvtop(isa_dev->id_maddr) != 0xd8000)
+ return(0);
+ break;
+ case ED_3COM_PCFR_CC000:
+ if (kvtop(isa_dev->id_maddr) != 0xcc000)
+ return(0);
+ break;
+ case ED_3COM_PCFR_C8000:
+ if (kvtop(isa_dev->id_maddr) != 0xc8000)
+ return(0);
+ break;
+ default:
+ return(0);
+ }
+
+
+ /*
+ * Reset NIC and ASIC. Enable on-board transceiver throughout reset
+ * sequence because it'll lock up if the cable isn't connected
+ * if we don't.
+ */
+ outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_RST | ED_3COM_CR_XSEL);
+
+ /*
+ * Wait for a while, then un-reset it
+ */
+ DELAY(50);
+ /*
+ * The 3Com ASIC defaults to rather strange settings for the CR after
+ * a reset - it's important to set it again after the following
+ * outb (this is done when we map the PROM below).
+ */
+ outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
+
+ /*
+ * Wait a bit for the NIC to recover from the reset
+ */
+ DELAY(5000);
+
+ sc->vendor = ED_VENDOR_3COM;
+ sc->type_str = "3c503";
+
+ sc->mem_shared = 1;
+
+ /*
+ * Hmmm...a 16bit 3Com board has 16k of memory, but only an 8k
+ * window to it.
+ */
+ memsize = 8192;
+
+ /*
+ * Get station address from on-board ROM
+ */
+ /*
+ * First, map ethernet address PROM over the top of where the NIC
+ * registers normally appear.
+ */
+ outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_EALO | ED_3COM_CR_XSEL);
+
+ for (i = 0; i < ETHER_ADDR_LEN; ++i)
+ sc->arpcom.ac_enaddr[i] = inb(sc->nic_addr + i);
+
+ /*
+ * Unmap PROM - select NIC registers. The proper setting of the
+ * tranceiver is set in ed_init so that the attach code
+ * is given a chance to set the default based on a compile-time
+ * config option
+ */
+ outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
+
+ /*
+ * Determine if this is an 8bit or 16bit board
+ */
+
+ /*
+ * select page 0 registers
+ */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
+
+ /*
+ * Attempt to clear WTS bit. If it doesn't clear, then this is a
+ * 16bit board.
+ */
+ outb(sc->nic_addr + ED_P0_DCR, 0);
+
+ /*
+ * select page 2 registers
+ */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_2|ED_CR_RD2|ED_CR_STP);
+
+ /*
+ * The 3c503 forces the WTS bit to a one if this is a 16bit board
+ */
+ if (inb(sc->nic_addr + ED_P2_DCR) & ED_DCR_WTS)
+ isa16bit = 1;
+ else
+ isa16bit = 0;
+
+ /*
+ * select page 0 registers
+ */
+ outb(sc->nic_addr + ED_P2_CR, ED_CR_RD2|ED_CR_STP);
+
+ sc->mem_start = (caddr_t)isa_dev->id_maddr;
+ sc->mem_size = memsize;
+ sc->mem_end = sc->mem_start + memsize;
+
+ /*
+ * We have an entire 8k window to put the transmit buffers on the
+ * 16bit boards. But since the 16bit 3c503's shared memory
+ * is only fast enough to overlap the loading of one full-size
+ * packet, trying to load more than 2 buffers can actually
+ * leave the transmitter idle during the load. So 2 seems
+ * the best value. (Although a mix of variable-sized packets
+ * might change this assumption. Nonetheless, we optimize for
+ * linear transfers of same-size packets.)
+ */
+ if (isa16bit) {
+ if (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING)
+ sc->txb_cnt = 1;
+ else
+ sc->txb_cnt = 2;
+
+ sc->tx_page_start = ED_3COM_TX_PAGE_OFFSET_16BIT;
+ sc->rec_page_start = ED_3COM_RX_PAGE_OFFSET_16BIT;
+ sc->rec_page_stop = memsize / ED_PAGE_SIZE +
+ ED_3COM_RX_PAGE_OFFSET_16BIT;
+ sc->mem_ring = sc->mem_start;
+ } else {
+ sc->txb_cnt = 1;
+ sc->tx_page_start = ED_3COM_TX_PAGE_OFFSET_8BIT;
+ sc->rec_page_start = ED_TXBUF_SIZE + ED_3COM_TX_PAGE_OFFSET_8BIT;
+ sc->rec_page_stop = memsize / ED_PAGE_SIZE +
+ ED_3COM_TX_PAGE_OFFSET_8BIT;
+ sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE);
+ }
+
+ sc->isa16bit = isa16bit;
+
+ /*
+ * Initialize GA page start/stop registers. Probably only needed
+ * if doing DMA, but what the hell.
+ */
+ outb(sc->asic_addr + ED_3COM_PSTR, sc->rec_page_start);
+ outb(sc->asic_addr + ED_3COM_PSPR, sc->rec_page_stop);
+
+ /*
+ * Set IRQ. 3c503 only allows a choice of irq 2-5.
+ */
+ switch (isa_dev->id_irq) {
+ case IRQ2:
+ outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ2);
+ break;
+ case IRQ3:
+ outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ3);
+ break;
+ case IRQ4:
+ outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ4);
+ break;
+ case IRQ5:
+ outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ5);
+ break;
+ default:
+ printf("ed%d: Invalid irq configuration (%d) must be 2-5 for 3c503\n",
+ isa_dev->id_unit, ffs(isa_dev->id_irq) - 1);
+ return(0);
+ }
+
+ /*
+ * Initialize GA configuration register. Set bank and enable shared mem.
+ */
+ outb(sc->asic_addr + ED_3COM_GACFR, ED_3COM_GACFR_RSEL |
+ ED_3COM_GACFR_MBS0);
+
+ /*
+ * Initialize "Vector Pointer" registers. These gawd-awful things
+ * are compared to 20 bits of the address on ISA, and if they
+ * match, the shared memory is disabled. We set them to
+ * 0xffff0...allegedly the reset vector.
+ */
+ outb(sc->asic_addr + ED_3COM_VPTR2, 0xff);
+ outb(sc->asic_addr + ED_3COM_VPTR1, 0xff);
+ outb(sc->asic_addr + ED_3COM_VPTR0, 0x00);
+
+ /*
+ * Zero memory and verify that it is clear
+ */
+ bzero(sc->mem_start, memsize);
+
+ for (i = 0; i < memsize; ++i)
+ if (sc->mem_start[i]) {
+ printf("ed%d: failed to clear shared memory at %x - check configuration\n",
+ isa_dev->id_unit, kvtop(sc->mem_start + i));
+ return(0);
+ }
+
+ isa_dev->id_msize = memsize;
+ return(ED_3COM_IO_PORTS);
+}
+
+/*
+ * Probe and vendor-specific initialization routine for NE1000/2000 boards
+ */
+int
+ed_probe_Novell(isa_dev)
+ struct isa_device *isa_dev;
+{
+ struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
+ u_int memsize, n;
+ u_char romdata[16], isa16bit = 0, tmp;
+ static char test_pattern[32] = "THIS is A memory TEST pattern";
+ char test_buffer[32];
+
+ sc->asic_addr = isa_dev->id_iobase + ED_NOVELL_ASIC_OFFSET;
+ sc->nic_addr = isa_dev->id_iobase + ED_NOVELL_NIC_OFFSET;
+
+ /* XXX - do Novell-specific probe here */
+
+ /* Reset the board */
+ tmp = inb(sc->asic_addr + ED_NOVELL_RESET);
+
+ /*
+ * I don't know if this is necessary; probably cruft leftover from
+ * Clarkson packet driver code. Doesn't do a thing on the boards
+ * I've tested. -DG [note that a outb(0x84, 0) seems to work
+ * here, and is non-invasive...but some boards don't seem to reset
+ * and I don't have complete documentation on what the 'right'
+ * thing to do is...so we do the invasive thing for now. Yuck.]
+ */
+ outb(sc->asic_addr + ED_NOVELL_RESET, tmp);
+ DELAY(5000);
+
+ /*
+ * This is needed because some NE clones apparently don't reset the
+ * NIC properly (or the NIC chip doesn't reset fully on power-up)
+ * XXX - this makes the probe invasive! ...Done against my better
+ * judgement. -DLG
+ */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
+
+ DELAY(5000);
+
+ /* Make sure that we really have an 8390 based board */
+ if (!ed_probe_generic8390(sc))
+ return(0);
+
+ sc->vendor = ED_VENDOR_NOVELL;
+ sc->mem_shared = 0;
+ isa_dev->id_maddr = 0;
+
+ /*
+ * Test the ability to read and write to the NIC memory. This has
+ * the side affect of determining if this is an NE1000 or an NE2000.
+ */
+
+ /*
+ * This prevents packets from being stored in the NIC memory when
+ * the readmem routine turns on the start bit in the CR.
+ */
+ outb(sc->nic_addr + ED_P0_RCR, ED_RCR_MON);
+
+ /* Temporarily initialize DCR for byte operations */
+ outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1|ED_DCR_LS);
+
+ outb(sc->nic_addr + ED_P0_PSTART, 8192 / ED_PAGE_SIZE);
+ outb(sc->nic_addr + ED_P0_PSTOP, 16384 / ED_PAGE_SIZE);
+
+ sc->isa16bit = 0;
+
+ /*
+ * Write a test pattern in byte mode. If this fails, then there
+ * probably isn't any memory at 8k - which likely means
+ * that the board is an NE2000.
+ */
+ ed_pio_writemem(sc, test_pattern, 8192, sizeof(test_pattern));
+ ed_pio_readmem(sc, 8192, test_buffer, sizeof(test_pattern));
+
+ if (bcmp(test_pattern, test_buffer, sizeof(test_pattern))) {
+ /* not an NE1000 - try NE2000 */
+
+ outb(sc->nic_addr + ED_P0_DCR, ED_DCR_WTS|ED_DCR_FT1|ED_DCR_LS);
+ outb(sc->nic_addr + ED_P0_PSTART, 16384 / ED_PAGE_SIZE);
+ outb(sc->nic_addr + ED_P0_PSTOP, 32768 / ED_PAGE_SIZE);
+
+ sc->isa16bit = 1;
+ /*
+ * Write a test pattern in word mode. If this also fails, then
+ * we don't know what this board is.
+ */
+ ed_pio_writemem(sc, test_pattern, 16384, sizeof(test_pattern));
+ ed_pio_readmem(sc, 16384, test_buffer, sizeof(test_pattern));
+
+ if (bcmp(test_pattern, test_buffer, sizeof(test_pattern)))
+ return(0); /* not an NE2000 either */
+
+ sc->type = ED_TYPE_NE2000;
+ sc->type_str = "NE2000";
+ } else {
+ sc->type = ED_TYPE_NE1000;
+ sc->type_str = "NE1000";
+ }
+
+ /* 8k of memory plus an additional 8k if 16bit */
+ memsize = 8192 + sc->isa16bit * 8192;
+
+#if 0 /* probably not useful - NE boards only come two ways */
+ /* allow kernel config file overrides */
+ if (isa_dev->id_msize)
+ memsize = isa_dev->id_msize;
+#endif
+
+ sc->mem_size = memsize;
+
+ /* NIC memory doesn't start at zero on an NE board */
+ /* The start address is tied to the bus width */
+ sc->mem_start = (char *) 8192 + sc->isa16bit * 8192;
+ sc->mem_end = sc->mem_start + memsize;
+ sc->tx_page_start = memsize / ED_PAGE_SIZE;
+
+ /*
+ * Use one xmit buffer if < 16k, two buffers otherwise (if not told
+ * otherwise).
+ */
+ if ((memsize < 16384) || (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING))
+ sc->txb_cnt = 1;
+ else
+ sc->txb_cnt = 2;
+
+ sc->rec_page_start = sc->tx_page_start + sc->txb_cnt * ED_TXBUF_SIZE;
+ sc->rec_page_stop = sc->tx_page_start + memsize / ED_PAGE_SIZE;
+
+ sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE;
+
+ ed_pio_readmem(sc, 0, romdata, 16);
+ for (n = 0; n < ETHER_ADDR_LEN; n++)
+ sc->arpcom.ac_enaddr[n] = romdata[n*(sc->isa16bit+1)];
+
+ /* clear any pending interrupts that might have occurred above */
+ outb(sc->nic_addr + ED_P0_ISR, 0xff);
+
+ return(ED_NOVELL_IO_PORTS);
+}
+
+/*
+ * Install interface into kernel networking data structures
+ */
+int
+ed_attach(isa_dev)
+ struct isa_device *isa_dev;
+{
+ struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct ifaddr *ifa;
+ struct sockaddr_dl *sdl;
+
+ /*
+ * Set interface to stopped condition (reset)
+ */
+ ed_stop(isa_dev->id_unit);
+
+ /*
+ * Initialize ifnet structure
+ */
+ ifp->if_unit = isa_dev->id_unit;
+ ifp->if_name = "ed" ;
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_init = ed_init;
+ ifp->if_output = ether_output;
+ ifp->if_start = ed_start;
+ ifp->if_ioctl = ed_ioctl;
+ ifp->if_reset = ed_reset;
+ ifp->if_watchdog = ed_watchdog;
+
+ /*
+ * Set default state for ALTPHYS flag (used to disable the tranceiver
+ * for AUI operation), based on compile-time config option.
+ */
+ if (isa_dev->id_flags & ED_FLAGS_DISABLE_TRANCEIVER)
+ ifp->if_flags =
+ (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_ALTPHYS);
+ else
+ ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS);
+
+ /*
+ * Attach the interface
+ */
+ if_attach(ifp);
+
+ /*
+ * Search down the ifa address list looking for the AF_LINK type entry
+ */
+ ifa = ifp->if_addrlist;
+ while ((ifa != 0) && (ifa->ifa_addr != 0) &&
+ (ifa->ifa_addr->sa_family != AF_LINK))
+ ifa = ifa->ifa_next;
+ /*
+ * If we find an AF_LINK type entry we fill in the hardware address.
+ * This is useful for netstat(1) to keep track of which interface
+ * is which.
+ */
+ if ((ifa != 0) && (ifa->ifa_addr != 0)) {
+ /*
+ * Fill in the link-level address for this interface
+ */
+ sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ sdl->sdl_type = IFT_ETHER;
+ sdl->sdl_alen = ETHER_ADDR_LEN;
+ sdl->sdl_slen = 0;
+ bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN);
+ }
+
+ /*
+ * Print additional info when attached
+ */
+ printf("ed%d: address %s, ", isa_dev->id_unit,
+ ether_sprintf(sc->arpcom.ac_enaddr));
+
+ if (sc->type_str && (*sc->type_str != 0))
+ printf("type %s ", sc->type_str);
+ else
+ printf("type unknown (0x%x) ", sc->type);
+
+ printf("%s ",sc->isa16bit ? "(16 bit)" : "(8 bit)");
+
+ printf("%s\n", ((sc->vendor == ED_VENDOR_3COM) &&
+ (ifp->if_flags & IFF_ALTPHYS)) ? " tranceiver disabled" : "");
+
+ /*
+ * If BPF is in the kernel, call the attach for it
+ */
+#if NBPFILTER > 0
+ bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+ return 1;
+}
+
+/*
+ * Reset interface.
+ */
+void
+ed_reset(unit, uban)
+ int unit;
+ int uban; /* XXX */
+{
+ int s;
+
+ s = splimp();
+
+ /*
+ * Stop interface and re-initialize.
+ */
+ ed_stop(unit);
+ ed_init(unit);
+
+ (void) splx(s);
+}
+
+/*
+ * Take interface offline.
+ */
+void
+ed_stop(unit)
+ int unit;
+{
+ struct ed_softc *sc = &ed_softc[unit];
+ int n = 5000;
+
+ /*
+ * Stop everything on the interface, and select page 0 registers.
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_STP);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
+ }
+ /*
+ * Wait for interface to enter stopped state, but limit # of checks
+ * to 'n' (about 5ms). It shouldn't even take 5us on modern
+ * DS8390's, but just in case it's an old one.
+ */
+ while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RST) == 0) && --n);
+
+}
+
+/*
+ * Device timeout/watchdog routine. Entered if the device neglects to
+ * generate an interrupt after a transmit has been started on it.
+ */
+void
+ed_watchdog(unit)
+ int unit;
+{
+ struct ed_softc *sc = &ed_softc[unit];
+
+ log(LOG_ERR, "ed%d: device timeout\n", unit);
+ ++sc->arpcom.ac_if.if_oerrors;
+
+ ed_reset(unit, 0);
+}
+
+/*
+ * Initialize device.
+ */
+void
+ed_init(unit)
+ int unit;
+{
+ struct ed_softc *sc = &ed_softc[unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ int i, s;
+ u_char command;
+
+
+ /* address not known */
+ if (ifp->if_addrlist == (struct ifaddr *)0) return;
+
+ /*
+ * Initialize the NIC in the exact order outlined in the NS manual.
+ * This init procedure is "mandatory"...don't change what or when
+ * things happen.
+ */
+ s = splimp();
+
+ /* reset transmitter flags */
+ sc->xmit_busy = 0;
+ sc->arpcom.ac_if.if_timer = 0;
+
+ sc->txb_inuse = 0;
+ sc->txb_new = 0;
+ sc->txb_next_tx = 0;
+
+ /* This variable is used below - don't move this assignment */
+ sc->next_packet = sc->rec_page_start + 1;
+
+ /*
+ * Set interface for page 0, Remote DMA complete, Stopped
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_STP);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
+ }
+ if (sc->isa16bit) {
+ /*
+ * Set FIFO threshold to 8, No auto-init Remote DMA,
+ * byte order=80x86, word-wide DMA xfers,
+ */
+ outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1|ED_DCR_WTS|ED_DCR_LS);
+ } else {
+ /*
+ * Same as above, but byte-wide DMA xfers
+ */
+ outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1|ED_DCR_LS);
+ }
+
+ /*
+ * Clear Remote Byte Count Registers
+ */
+ outb(sc->nic_addr + ED_P0_RBCR0, 0);
+ outb(sc->nic_addr + ED_P0_RBCR1, 0);
+
+ /*
+ * Enable reception of broadcast packets
+ */
+ outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB);
+
+ /*
+ * Place NIC in internal loopback mode
+ */
+ outb(sc->nic_addr + ED_P0_TCR, ED_TCR_LB0);
+
+ /*
+ * Initialize transmit/receive (ring-buffer) Page Start
+ */
+ outb(sc->nic_addr + ED_P0_TPSR, sc->tx_page_start);
+ outb(sc->nic_addr + ED_P0_PSTART, sc->rec_page_start);
+ /* Set lower bits of byte addressable framing to 0 */
+ if (sc->is790)
+ outb(sc->nic_addr + 0x09, 0);
+
+ /*
+ * Initialize Receiver (ring-buffer) Page Stop and Boundry
+ */
+ outb(sc->nic_addr + ED_P0_PSTOP, sc->rec_page_stop);
+ outb(sc->nic_addr + ED_P0_BNRY, sc->rec_page_start);
+
+ /*
+ * Clear all interrupts. A '1' in each bit position clears the
+ * corresponding flag.
+ */
+ outb(sc->nic_addr + ED_P0_ISR, 0xff);
+
+ /*
+ * Enable the following interrupts: receive/transmit complete,
+ * receive/transmit error, and Receiver OverWrite.
+ *
+ * Counter overflow and Remote DMA complete are *not* enabled.
+ */
+ outb(sc->nic_addr + ED_P0_IMR,
+ ED_IMR_PRXE|ED_IMR_PTXE|ED_IMR_RXEE|ED_IMR_TXEE|ED_IMR_OVWE);
+
+ /*
+ * Program Command Register for page 1
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_STP);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STP);
+ }
+ /*
+ * Copy out our station address
+ */
+ for (i = 0; i < ETHER_ADDR_LEN; ++i)
+ outb(sc->nic_addr + ED_P1_PAR0 + i, sc->arpcom.ac_enaddr[i]);
+
+#if NBPFILTER > 0
+ /*
+ * Initialize multicast address hashing registers to accept
+ * all multicasts (only used when in promiscuous mode)
+ */
+ for (i = 0; i < 8; ++i)
+ outb(sc->nic_addr + ED_P1_MAR0 + i, 0xff);
+#endif
+
+ /*
+ * Set Current Page pointer to next_packet (initialized above)
+ */
+ outb(sc->nic_addr + ED_P1_CURR, sc->next_packet);
+
+ /*
+ * Set Command Register for page 0, Remote DMA complete,
+ * and interface Start.
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P1_CR, ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P1_CR, ED_CR_RD2|ED_CR_STA);
+ }
+ /*
+ * Take interface out of loopback
+ */
+ outb(sc->nic_addr + ED_P0_TCR, 0);
+
+ /*
+ * If this is a 3Com board, the tranceiver must be software enabled
+ * (there is no settable hardware default).
+ */
+ if (sc->vendor == ED_VENDOR_3COM) {
+ if (ifp->if_flags & IFF_ALTPHYS) {
+ outb(sc->asic_addr + ED_3COM_CR, 0);
+ } else {
+ outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
+ }
+ }
+
+ /*
+ * Set 'running' flag, and clear output active flag.
+ */
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ /*
+ * ...and attempt to start output
+ */
+ ed_start(ifp);
+
+ (void) splx(s);
+}
+
+/*
+ * This routine actually starts the transmission on the interface
+ */
+static inline void ed_xmit(ifp)
+ struct ifnet *ifp;
+{
+ struct ed_softc *sc = &ed_softc[ifp->if_unit];
+ unsigned short len;
+
+ len = sc->txb_len[sc->txb_next_tx];
+
+ /*
+ * Set NIC for page 0 register access
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ }
+ /*
+ * Set TX buffer start page
+ */
+ outb(sc->nic_addr + ED_P0_TPSR, sc->tx_page_start +
+ sc->txb_next_tx * ED_TXBUF_SIZE);
+
+ /*
+ * Set TX length
+ */
+ outb(sc->nic_addr + ED_P0_TBCR0, len);
+ outb(sc->nic_addr + ED_P0_TBCR1, len >> 8);
+
+ /*
+ * Set page 0, Remote DMA complete, Transmit Packet, and *Start*
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_TXP | ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_TXP|ED_CR_STA);
+ }
+ sc->xmit_busy = 1;
+
+ /*
+ * Point to next transmit buffer slot and wrap if necessary.
+ */
+ sc->txb_next_tx++;
+ if (sc->txb_next_tx == sc->txb_cnt)
+ sc->txb_next_tx = 0;
+
+ /*
+ * Set a timer just in case we never hear from the board again
+ */
+ ifp->if_timer = 2;
+}
+
+/*
+ * Start output on interface.
+ * We make two assumptions here:
+ * 1) that the current priority is set to splimp _before_ this code
+ * is called *and* is returned to the appropriate priority after
+ * return
+ * 2) that the IFF_OACTIVE flag is checked before this code is called
+ * (i.e. that the output part of the interface is idle)
+ */
+void
+ed_start(ifp)
+ struct ifnet *ifp;
+{
+ struct ed_softc *sc = &ed_softc[ifp->if_unit];
+ struct mbuf *m0, *m;
+ caddr_t buffer;
+ int len;
+
+outloop:
+ /*
+ * First, see if there are buffered packets and an idle
+ * transmitter - should never happen at this point.
+ */
+ if (sc->txb_inuse && (sc->xmit_busy == 0)) {
+ printf("ed: packets buffers, but transmitter idle\n");
+ ed_xmit(ifp);
+ }
+
+ /*
+ * See if there is room to put another packet in the buffer.
+ */
+ if (sc->txb_inuse == sc->txb_cnt) {
+ /*
+ * No room. Indicate this to the outside world
+ * and exit.
+ */
+ ifp->if_flags |= IFF_OACTIVE;
+ return;
+ }
+
+ IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
+ if (m == 0) {
+ /*
+ * We are using the !OACTIVE flag to indicate to the outside
+ * world that we can accept an additional packet rather than
+ * that the transmitter is _actually_ active. Indeed, the
+ * transmitter may be active, but if we haven't filled all
+ * the buffers with data then we still want to accept more.
+ */
+ ifp->if_flags &= ~IFF_OACTIVE;
+ return;
+ }
+
+ /*
+ * Copy the mbuf chain into the transmit buffer
+ */
+
+ m0 = m;
+
+ /* txb_new points to next open buffer slot */
+ buffer = sc->mem_start + (sc->txb_new * ED_TXBUF_SIZE * ED_PAGE_SIZE);
+
+ if (sc->mem_shared) {
+ /*
+ * Special case setup for 16 bit boards...
+ */
+ if (sc->isa16bit) {
+ switch (sc->vendor) {
+ /*
+ * For 16bit 3Com boards (which have 16k of memory),
+ * we have the xmit buffers in a different page
+ * of memory ('page 0') - so change pages.
+ */
+ case ED_VENDOR_3COM:
+ outb(sc->asic_addr + ED_3COM_GACFR,
+ ED_3COM_GACFR_RSEL);
+ break;
+ /*
+ * Enable 16bit access to shared memory on WD/SMC boards
+ * Don't update wd_laar_proto because we want to restore the
+ * previous state (because an arp reply in the input code
+ * may cause a call-back to ed_start)
+ * XXX - the call-back to 'start' is a bug, IMHO.
+ */
+ case ED_VENDOR_WD_SMC: {
+ outb(sc->asic_addr + ED_WD_LAAR,
+ (sc->wd_laar_proto | ED_WD_LAAR_M16EN));
+ (void) inb(0x84);
+ if (sc->is790) {
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB);
+ (void) inb(0x84);
+ }
+ (void) inb(0x84);
+ break;
+ }
+ }
+ }
+
+ for (len = 0; m != 0; m = m->m_next) {
+ bcopy(mtod(m, caddr_t), buffer, m->m_len);
+ buffer += m->m_len;
+ len += m->m_len;
+ }
+
+ /*
+ * Restore previous shared memory access
+ */
+ if (sc->isa16bit) {
+ switch (sc->vendor) {
+ case ED_VENDOR_3COM:
+ outb(sc->asic_addr + ED_3COM_GACFR,
+ ED_3COM_GACFR_RSEL | ED_3COM_GACFR_MBS0);
+ break;
+ case ED_VENDOR_WD_SMC: {
+ outb(sc->asic_addr + ED_WD_LAAR, sc->wd_laar_proto);
+ (void) inb(0x84);
+ if (sc->is790) {
+ outb(sc->asic_addr + ED_WD_MSR, 0x00);
+ (void) inb(0x84);
+ }
+ break;
+ }
+ }
+ }
+ } else {
+ len = ed_pio_write_mbufs(sc, m, buffer);
+ }
+
+ sc->txb_len[sc->txb_new] = MAX(len, ETHER_MIN_LEN);
+
+ sc->txb_inuse++;
+
+ /*
+ * Point to next buffer slot and wrap if necessary.
+ */
+ sc->txb_new++;
+ if (sc->txb_new == sc->txb_cnt)
+ sc->txb_new = 0;
+
+ if (sc->xmit_busy == 0)
+ ed_xmit(ifp);
+ /*
+ * If there is BPF support in the configuration, tap off here.
+ * The following has support for converting trailer packets
+ * back to normal.
+ * XXX - support for trailer packets in BPF should be moved into
+ * the bpf code proper to avoid code duplication in all of
+ * the drivers.
+ */
+#if NBPFILTER > 0
+ if (sc->bpf) {
+ u_short etype;
+ int off, datasize, resid;
+ struct ether_header *eh;
+ struct trailer_header trailer_header;
+ char ether_packet[ETHER_MAX_LEN];
+ char *ep;
+
+ ep = ether_packet;
+
+ /*
+ * We handle trailers below:
+ * Copy ether header first, then residual data,
+ * then data. Put all this in a temporary buffer
+ * 'ether_packet' and send off to bpf. Since the
+ * system has generated this packet, we assume
+ * that all of the offsets in the packet are
+ * correct; if they're not, the system will almost
+ * certainly crash in m_copydata.
+ * We make no assumptions about how the data is
+ * arranged in the mbuf chain (i.e. how much
+ * data is in each mbuf, if mbuf clusters are
+ * used, etc.), which is why we use m_copydata
+ * to get the ether header rather than assume
+ * that this is located in the first mbuf.
+ */
+ /* copy ether header */
+ m_copydata(m0, 0, sizeof(struct ether_header), ep);
+ eh = (struct ether_header *) ep;
+ ep += sizeof(struct ether_header);
+ etype = ntohs(eh->ether_type);
+ if (etype >= ETHERTYPE_TRAIL &&
+ etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+ datasize = ((etype - ETHERTYPE_TRAIL) << 9);
+ off = datasize + sizeof(struct ether_header);
+
+ /* copy trailer_header into a data structure */
+ m_copydata(m0, off, sizeof(struct trailer_header),
+ (caddr_t)&trailer_header.ether_type);
+
+ /* copy residual data */
+ m_copydata(m0, off+sizeof(struct trailer_header),
+ resid = ntohs(trailer_header.ether_residual) -
+ sizeof(struct trailer_header), ep);
+ ep += resid;
+
+ /* copy data */
+ m_copydata(m0, sizeof(struct ether_header),
+ datasize, ep);
+ ep += datasize;
+
+ /* restore original ether packet type */
+ eh->ether_type = trailer_header.ether_type;
+
+ bpf_tap(sc->bpf, ether_packet, ep - ether_packet);
+ } else
+ bpf_mtap(sc->bpf, m0);
+ }
+#endif
+
+ m_freem(m0);
+
+ /*
+ * Loop back to the top to possibly buffer more packets
+ */
+ goto outloop;
+}
+
+/*
+ * Ethernet interface receiver interrupt.
+ */
+static inline void
+ed_rint(unit)
+ int unit;
+{
+ register struct ed_softc *sc = &ed_softc[unit];
+ u_char boundry, current;
+ u_short len;
+ struct ed_ring packet_hdr;
+ char *packet_ptr;
+
+ /*
+ * Set NIC to page 1 registers to get 'current' pointer
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STA);
+ }
+ /*
+ * 'sc->next_packet' is the logical beginning of the ring-buffer - i.e.
+ * it points to where new data has been buffered. The 'CURR'
+ * (current) register points to the logical end of the ring-buffer
+ * - i.e. it points to where additional new data will be added.
+ * We loop here until the logical beginning equals the logical
+ * end (or in other words, until the ring-buffer is empty).
+ */
+ while (sc->next_packet != inb(sc->nic_addr + ED_P1_CURR)) {
+
+ /* get pointer to this buffer's header structure */
+ packet_ptr = sc->mem_ring +
+ (sc->next_packet - sc->rec_page_start) * ED_PAGE_SIZE;
+
+ /*
+ * The byte count includes the FCS - Frame Check Sequence (a
+ * 32 bit CRC).
+ */
+ if (sc->mem_shared)
+ packet_hdr = *(struct ed_ring *)packet_ptr;
+ else
+ ed_pio_readmem(sc, packet_ptr, (char *) &packet_hdr,
+ sizeof(packet_hdr));
+ len = packet_hdr.count;
+ if ((len >= ETHER_MIN_LEN) && (len <= ETHER_MAX_LEN)) {
+ /*
+ * Go get packet. len - 4 removes CRC from length.
+ */
+ ed_get_packet(sc, packet_ptr + 4, len - 4);
+ ++sc->arpcom.ac_if.if_ipackets;
+ } else {
+ /*
+ * Really BAD...probably indicates that the ring pointers
+ * are corrupted. Also seen on early rev chips under
+ * high load - the byte order of the length gets switched.
+ */
+ log(LOG_ERR,
+ "ed%d: NIC memory corrupt - invalid packet length %d\n",
+ unit, len);
+ ++sc->arpcom.ac_if.if_ierrors;
+ ed_reset(unit, 0);
+ return;
+ }
+
+ /*
+ * Update next packet pointer
+ */
+ sc->next_packet = packet_hdr.next_packet;
+
+ /*
+ * Update NIC boundry pointer - being careful to keep it
+ * one buffer behind. (as recommended by NS databook)
+ */
+ boundry = sc->next_packet - 1;
+ if (boundry < sc->rec_page_start)
+ boundry = sc->rec_page_stop - 1;
+
+ /*
+ * Set NIC to page 0 registers to update boundry register
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ }
+ outb(sc->nic_addr + ED_P0_BNRY, boundry);
+
+ /*
+ * Set NIC to page 1 registers before looping to top (prepare to
+ * get 'CURR' current pointer)
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STA);
+ }
+ }
+}
+
+/*
+ * Ethernet interface interrupt processor
+ */
+void
+edintr(unit)
+ int unit;
+{
+ struct ed_softc *sc = &ed_softc[unit];
+ u_char isr;
+
+ /*
+ * Set NIC to page 0 registers
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ }
+ /*
+ * loop until there are no more new interrupts
+ */
+ while (isr = inb(sc->nic_addr + ED_P0_ISR)) {
+
+ /*
+ * reset all the bits that we are 'acknowledging'
+ * by writing a '1' to each bit position that was set
+ * (writing a '1' *clears* the bit)
+ */
+ outb(sc->nic_addr + ED_P0_ISR, isr);
+
+ /*
+ * Handle transmitter interrupts. Handle these first
+ * because the receiver will reset the board under
+ * some conditions.
+ */
+ if (isr & (ED_ISR_PTX|ED_ISR_TXE)) {
+ u_char collisions = inb(sc->nic_addr + ED_P0_NCR) & 0x0f;
+
+ /*
+ * Check for transmit error. If a TX completed with an
+ * error, we end up throwing the packet away. Really
+ * the only error that is possible is excessive
+ * collisions, and in this case it is best to allow the
+ * automatic mechanisms of TCP to backoff the flow. Of
+ * course, with UDP we're screwed, but this is expected
+ * when a network is heavily loaded.
+ */
+ (void) inb(sc->nic_addr + ED_P0_TSR);
+ if (isr & ED_ISR_TXE) {
+
+ /*
+ * Excessive collisions (16)
+ */
+ if ((inb(sc->nic_addr + ED_P0_TSR) & ED_TSR_ABT)
+ && (collisions == 0)) {
+ /*
+ * When collisions total 16, the
+ * P0_NCR will indicate 0, and the
+ * TSR_ABT is set.
+ */
+ collisions = 16;
+ }
+
+ /*
+ * update output errors counter
+ */
+ ++sc->arpcom.ac_if.if_oerrors;
+ } else {
+ /*
+ * Update total number of successfully
+ * transmitted packets.
+ */
+ ++sc->arpcom.ac_if.if_opackets;
+ }
+
+ /*
+ * reset tx busy and output active flags
+ */
+ sc->xmit_busy = 0;
+ sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+
+ /*
+ * clear watchdog timer
+ */
+ sc->arpcom.ac_if.if_timer = 0;
+
+ /*
+ * Add in total number of collisions on last
+ * transmission.
+ */
+ sc->arpcom.ac_if.if_collisions += collisions;
+
+ /*
+ * Decrement buffer in-use count if not zero (can only
+ * be zero if a transmitter interrupt occured while
+ * not actually transmitting).
+ * If data is ready to transmit, start it transmitting,
+ * otherwise defer until after handling receiver
+ */
+ if (sc->txb_inuse && --sc->txb_inuse)
+ ed_xmit(&sc->arpcom.ac_if);
+ }
+
+ /*
+ * Handle receiver interrupts
+ */
+ if (isr & (ED_ISR_PRX|ED_ISR_RXE|ED_ISR_OVW)) {
+ /*
+ * Overwrite warning. In order to make sure that a lockup
+ * of the local DMA hasn't occurred, we reset and
+ * re-init the NIC. The NSC manual suggests only a
+ * partial reset/re-init is necessary - but some
+ * chips seem to want more. The DMA lockup has been
+ * seen only with early rev chips - Methinks this
+ * bug was fixed in later revs. -DG
+ */
+ if (isr & ED_ISR_OVW) {
+ ++sc->arpcom.ac_if.if_ierrors;
+#ifdef DIAGNOSTIC
+ log(LOG_WARNING,
+ "ed%d: warning - receiver ring buffer overrun\n",
+ unit);
+#endif
+ /*
+ * Stop/reset/re-init NIC
+ */
+ ed_reset(unit, 0);
+ } else {
+
+ /*
+ * Receiver Error. One or more of: CRC error, frame
+ * alignment error FIFO overrun, or missed packet.
+ */
+ if (isr & ED_ISR_RXE) {
+ ++sc->arpcom.ac_if.if_ierrors;
+#ifdef ED_DEBUG
+ printf("ed%d: receive error %x\n", unit,
+ inb(sc->nic_addr + ED_P0_RSR));
+#endif
+ }
+
+ /*
+ * Go get the packet(s)
+ * XXX - Doing this on an error is dubious
+ * because there shouldn't be any data to
+ * get (we've configured the interface to
+ * not accept packets with errors).
+ */
+
+ /*
+ * Enable 16bit access to shared memory first
+ * on WD/SMC boards.
+ */
+ if (sc->isa16bit &&
+ (sc->vendor == ED_VENDOR_WD_SMC)) {
+
+ outb(sc->asic_addr + ED_WD_LAAR,
+ (sc->wd_laar_proto |=
+ ED_WD_LAAR_M16EN));
+ (void) inb(0x84);
+ if (sc->is790) {
+ outb(sc->asic_addr + ED_WD_MSR,
+ ED_WD_MSR_MENB);
+ (void) inb(0x84);
+ }
+ }
+
+ ed_rint (unit);
+
+ /* disable 16bit access */
+ if (sc->isa16bit &&
+ (sc->vendor == ED_VENDOR_WD_SMC)) {
+
+ outb(sc->asic_addr + ED_WD_LAAR,
+ (sc->wd_laar_proto &=
+ ~ED_WD_LAAR_M16EN));
+ (void) inb(0x84);
+ if (sc->is790) {
+ outb(sc->asic_addr + ED_WD_MSR, 0x00);
+ (void) inb(0x84);
+ }
+ }
+ }
+ }
+
+ /*
+ * If it looks like the transmitter can take more data,
+ * attempt to start output on the interface.
+ * This is done after handling the receiver to
+ * give the receiver priority.
+ */
+ if ((sc->arpcom.ac_if.if_flags & IFF_OACTIVE) == 0)
+ ed_start(&sc->arpcom.ac_if);
+
+ /*
+ * return NIC CR to standard state: page 0, remote DMA complete,
+ * start (toggling the TXP bit off, even if was just set
+ * in the transmit routine, is *okay* - it is 'edge'
+ * triggered from low to high)
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ }
+ /*
+ * If the Network Talley Counters overflow, read them to
+ * reset them. It appears that old 8390's won't
+ * clear the ISR flag otherwise - resulting in an
+ * infinite loop.
+ */
+ if (isr & ED_ISR_CNT) {
+ (void) inb(sc->nic_addr + ED_P0_CNTR0);
+ (void) inb(sc->nic_addr + ED_P0_CNTR1);
+ (void) inb(sc->nic_addr + ED_P0_CNTR2);
+ }
+ }
+}
+
+/*
+ * Process an ioctl request. This code needs some work - it looks
+ * pretty ugly.
+ */
+int
+ed_ioctl(ifp, command, data)
+ register struct ifnet *ifp;
+ int command;
+ caddr_t data;
+{
+ register struct ifaddr *ifa = (struct ifaddr *)data;
+ struct ed_softc *sc = &ed_softc[ifp->if_unit];
+ struct ifreq *ifr = (struct ifreq *)data;
+ int s, error = 0;
+
+ s = splimp();
+
+ switch (command) {
+
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ ed_init(ifp->if_unit); /* before arpwhohas */
+ /*
+ * See if another station has *our* IP address.
+ * i.e.: There is an address conflict! If a
+ * conflict exists, a message is sent to the
+ * console.
+ */
+ ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
+ arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
+ break;
+#endif
+#ifdef NS
+ /*
+ * XXX - This code is probably wrong
+ */
+ case AF_NS:
+ {
+ register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+
+ if (ns_nullhost(*ina))
+ ina->x_host =
+ *(union ns_host *)(sc->arpcom.ac_enaddr);
+ else {
+ /*
+ *
+ */
+ bcopy((caddr_t)ina->x_host.c_host,
+ (caddr_t)sc->arpcom.ac_enaddr,
+ sizeof(sc->arpcom.ac_enaddr));
+ }
+ /*
+ * Set new address
+ */
+ ed_init(ifp->if_unit);
+ break;
+ }
+#endif
+ default:
+ ed_init(ifp->if_unit);
+ break;
+ }
+ break;
+
+ case SIOCGIFADDR:
+ {
+ struct sockaddr *sa;
+ sa = (struct sockaddr *)&ifr->ifr_data;
+ bcopy((caddr_t)sc->arpcom.ac_enaddr,
+ (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
+ }
+ break;
+
+ case SIOCSIFFLAGS:
+ /*
+ * If interface is marked down and it is running, then stop it
+ */
+ if (((ifp->if_flags & IFF_UP) == 0) &&
+ (ifp->if_flags & IFF_RUNNING)) {
+ ed_stop(ifp->if_unit);
+ ifp->if_flags &= ~IFF_RUNNING;
+ } else {
+ /*
+ * If interface is marked up and it is stopped, then start it
+ */
+ if ((ifp->if_flags & IFF_UP) &&
+ ((ifp->if_flags & IFF_RUNNING) == 0))
+ ed_init(ifp->if_unit);
+ }
+#if NBPFILTER > 0
+ if (ifp->if_flags & IFF_PROMISC) {
+ /*
+ * Set promiscuous mode on interface.
+ * XXX - for multicasts to work, we would need to
+ * write 1's in all bits of multicast
+ * hashing array. For now we assume that
+ * this was done in ed_init().
+ */
+ outb(sc->nic_addr + ED_P0_RCR,
+ ED_RCR_PRO|ED_RCR_AM|ED_RCR_AB);
+ } else {
+ /*
+ * XXX - for multicasts to work, we would need to
+ * rewrite the multicast hashing array with the
+ * proper hash (would have been destroyed above).
+ */
+ outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB);
+ }
+#endif
+ /*
+ * An unfortunate hack to provide the (required) software control
+ * of the tranceiver for 3Com boards. The ALTPHYS flag disables
+ * the tranceiver if set.
+ */
+ if (sc->vendor == ED_VENDOR_3COM) {
+ if (ifp->if_flags & IFF_ALTPHYS) {
+ outb(sc->asic_addr + ED_3COM_CR, 0);
+ } else {
+ outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
+ }
+ }
+
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ (void) splx(s);
+ return (error);
+}
+
+/*
+ * Macro to calculate a new address within shared memory when given an offset
+ * from an address, taking into account ring-wrap.
+ */
+#define ringoffset(sc, start, off, type) \
+ ((type)( ((caddr_t)(start)+(off) >= (sc)->mem_end) ? \
+ (((caddr_t)(start)+(off))) - (sc)->mem_end \
+ + (sc)->mem_ring: \
+ ((caddr_t)(start)+(off)) ))
+
+/*
+ * Retreive packet from shared memory and send to the next level up via
+ * ether_input(). If there is a BPF listener, give a copy to BPF, too.
+ */
+static void
+ed_get_packet(sc, buf, len)
+ struct ed_softc *sc;
+ char *buf;
+ u_short len;
+{
+ struct ether_header *eh;
+ struct mbuf *m, *head = 0, *ed_ring_to_mbuf();
+ u_short off;
+ int resid;
+ u_short etype;
+ struct trailer_header trailer_header;
+
+ /* Allocate a header mbuf */
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ goto bad;
+ m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
+ m->m_pkthdr.len = len;
+ m->m_len = 0;
+ head = m;
+
+ /* The following sillines is to make NFS happy */
+#define EROUND ((sizeof(struct ether_header) + 3) & ~3)
+#define EOFF (EROUND - sizeof(struct ether_header))
+
+ /*
+ * The following assumes there is room for
+ * the ether header in the header mbuf
+ */
+ head->m_data += EOFF;
+ eh = mtod(head, struct ether_header *);
+
+ if (sc->mem_shared)
+ bcopy(buf, mtod(head, caddr_t), sizeof(struct ether_header));
+ else
+ ed_pio_readmem(sc, buf, mtod(head, caddr_t),
+ sizeof(struct ether_header));
+ buf += sizeof(struct ether_header);
+ head->m_len += sizeof(struct ether_header);
+ len -= sizeof(struct ether_header);
+
+ etype = ntohs((u_short)eh->ether_type);
+
+ /*
+ * Deal with trailer protocol:
+ * If trailer protocol, calculate the datasize as 'off',
+ * which is also the offset to the trailer header.
+ * Set resid to the amount of packet data following the
+ * trailer header.
+ * Finally, copy residual data into mbuf chain.
+ */
+ if (etype >= ETHERTYPE_TRAIL &&
+ etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+
+ off = (etype - ETHERTYPE_TRAIL) << 9;
+ if ((off + sizeof(struct trailer_header)) > len)
+ goto bad; /* insanity */
+
+ /*
+ * If we have shared memory, we can get info directly from the
+ * stored packet, otherwise we must get a local copy
+ * of the trailer header using PIO.
+ */
+ if (sc->mem_shared) {
+ eh->ether_type = *ringoffset(sc, buf, off, u_short *);
+ resid = ntohs(*ringoffset(sc, buf, off+2, u_short *));
+ } else {
+ struct trailer_header trailer_header;
+ ed_pio_readmem(sc,
+ ringoffset(sc, buf, off, caddr_t),
+ (char *) &trailer_header,
+ sizeof(trailer_header));
+ eh->ether_type = trailer_header.ether_type;
+ resid = trailer_header.ether_residual;
+ }
+
+ if ((off + resid) > len) goto bad; /* insanity */
+
+ resid -= sizeof(struct trailer_header);
+ if (resid < 0) goto bad; /* insanity */
+
+ m = ed_ring_to_mbuf(sc, ringoffset(sc, buf, off+4, char *),
+ head, resid);
+ if (m == 0) goto bad;
+
+ len = off;
+ head->m_pkthdr.len -= 4; /* subtract trailer header */
+ }
+
+ /*
+ * Pull packet off interface. Or if this was a trailer packet,
+ * the data portion is appended.
+ */
+ m = ed_ring_to_mbuf(sc, buf, m, len);
+ if (m == 0) goto bad;
+
+#if NBPFILTER > 0
+ /*
+ * Check if there's a BPF listener on this interface.
+ * If so, hand off the raw packet to bpf.
+ */
+ if (sc->bpf) {
+ bpf_mtap(sc->bpf, head);
+
+ /*
+ * Note that the interface cannot be in promiscuous mode if
+ * there are no BPF listeners. And if we are in promiscuous
+ * mode, we have to check if this packet is really ours.
+ *
+ * XXX This test does not support multicasts.
+ */
+ if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) &&
+ bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
+ sizeof(eh->ether_dhost)) != 0 &&
+ bcmp(eh->ether_dhost, etherbroadcastaddr,
+ sizeof(eh->ether_dhost)) != 0) {
+
+ m_freem(head);
+ return;
+ }
+ }
+#endif
+
+ /*
+ * Fix up data start offset in mbuf to point past ether header
+ */
+ m_adj(head, sizeof(struct ether_header));
+
+ /*
+ * silly ether_input routine needs 'type' in host byte order
+ */
+ eh->ether_type = ntohs(eh->ether_type);
+
+ ether_input(&sc->arpcom.ac_if, eh, head);
+ return;
+
+bad: if (head)
+ m_freem(head);
+ return;
+}
+
+/*
+ * Supporting routines
+ */
+
+/*
+ * Given a NIC memory source address and a host memory destination
+ * address, copy 'amount' from NIC to host using Programmed I/O.
+ * The 'amount' is rounded up to a word - okay as long as mbufs
+ * are word sized.
+ * This routine is currently Novell-specific.
+ */
+void
+ed_pio_readmem(sc,src,dst,amount)
+ struct ed_softc *sc;
+ unsigned short src;
+ unsigned char *dst;
+ unsigned short amount;
+{
+ unsigned short tmp_amount;
+
+ /* select page 0 registers */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+
+ /* round up to a word */
+ tmp_amount = amount;
+ if (amount & 1) ++amount;
+
+ /* set up DMA byte count */
+ outb(sc->nic_addr + ED_P0_RBCR0, amount);
+ outb(sc->nic_addr + ED_P0_RBCR1, amount>>8);
+
+ /* set up source address in NIC mem */
+ outb(sc->nic_addr + ED_P0_RSAR0, src);
+ outb(sc->nic_addr + ED_P0_RSAR1, src>>8);
+
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD0 | ED_CR_STA);
+
+ if (sc->isa16bit) {
+ insw(sc->asic_addr + ED_NOVELL_DATA, dst, amount/2);
+ } else
+ insb(sc->asic_addr + ED_NOVELL_DATA, dst, amount);
+
+}
+
+/*
+ * Stripped down routine for writing a linear buffer to NIC memory.
+ * Only used in the probe routine to test the memory. 'len' must
+ * be even.
+ */
+void
+ed_pio_writemem(sc,src,dst,len)
+ struct ed_softc *sc;
+ char *src;
+ unsigned short dst;
+ unsigned short len;
+{
+ int maxwait=100; /* about 120us */
+
+ /* select page 0 registers */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+
+ /* reset remote DMA complete flag */
+ outb(sc->nic_addr + ED_P0_ISR, ED_ISR_RDC);
+
+ /* set up DMA byte count */
+ outb(sc->nic_addr + ED_P0_RBCR0, len);
+ outb(sc->nic_addr + ED_P0_RBCR1, len>>8);
+
+ /* set up destination address in NIC mem */
+ outb(sc->nic_addr + ED_P0_RSAR0, dst);
+ outb(sc->nic_addr + ED_P0_RSAR1, dst>>8);
+
+ /* set remote DMA write */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD1 | ED_CR_STA);
+
+ if (sc->isa16bit)
+ outsw(sc->asic_addr + ED_NOVELL_DATA, src, len/2);
+ else
+ outsb(sc->asic_addr + ED_NOVELL_DATA, src, len);
+ /*
+ * Wait for remote DMA complete. This is necessary because on the
+ * transmit side, data is handled internally by the NIC in bursts
+ * and we can't start another remote DMA until this one completes.
+ * Not waiting causes really bad things to happen - like the NIC
+ * irrecoverably jamming the ISA bus.
+ */
+ while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RDC) != ED_ISR_RDC) && --maxwait);
+}
+
+/*
+ * Write an mbuf chain to the destination NIC memory address using
+ * programmed I/O.
+ */
+u_short
+ed_pio_write_mbufs(sc,m,dst)
+ struct ed_softc *sc;
+ struct mbuf *m;
+ unsigned short dst;
+{
+ unsigned short len, mb_offset;
+ struct mbuf *mp;
+ unsigned char residual[2];
+ int maxwait=100; /* about 120us */
+
+ /* First, count up the total number of bytes to copy */
+ for (len = 0, mp = m; mp; mp = mp->m_next)
+ len += mp->m_len;
+
+ /* select page 0 registers */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+
+ /* reset remote DMA complete flag */
+ outb(sc->nic_addr + ED_P0_ISR, ED_ISR_RDC);
+
+ /* set up DMA byte count */
+ outb(sc->nic_addr + ED_P0_RBCR0, len);
+ outb(sc->nic_addr + ED_P0_RBCR1, len>>8);
+
+ /* set up destination address in NIC mem */
+ outb(sc->nic_addr + ED_P0_RSAR0, dst);
+ outb(sc->nic_addr + ED_P0_RSAR1, dst>>8);
+
+ /* set remote DMA write */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD1 | ED_CR_STA);
+
+ mb_offset = 0;
+ /*
+ * Transfer the mbuf chain to the NIC memory.
+ * The following code isn't too pretty. The problem is that we can only
+ * transfer words to the board, and if an mbuf has an odd number
+ * of bytes in it, this is a problem. It's not a simple matter of
+ * just removing a byte from the next mbuf (adjusting data++ and
+ * len--) because this will hose-over the mbuf chain which might
+ * be needed later for BPF. Instead, we maintain an offset
+ * (mb_offset) which let's us skip over the first byte in the
+ * following mbuf.
+ */
+ while (m) {
+ if (m->m_len - mb_offset) {
+ if (sc->isa16bit) {
+ if ((m->m_len - mb_offset) > 1)
+ outsw(sc->asic_addr + ED_NOVELL_DATA,
+ mtod(m, caddr_t) + mb_offset,
+ (m->m_len - mb_offset) / 2);
+
+ /*
+ * if odd number of bytes, get the odd byte from
+ * the next mbuf with data
+ */
+ if ((m->m_len - mb_offset) & 1) {
+ /* first the last byte in current mbuf */
+ residual[0] = *(mtod(m, caddr_t) +
+ m->m_len - 1);
+
+ /* advance past any empty mbufs */
+ while (m->m_next && (m->m_next->m_len == 0))
+ m = m->m_next;
+
+ if (m->m_next) {
+ /* remove first byte in next mbuf */
+ residual[1] = *(mtod(m->m_next, caddr_t));
+ mb_offset = 1;
+ }
+
+ outw(sc->asic_addr + ED_NOVELL_DATA,
+ *((unsigned short *) residual));
+ } else
+ mb_offset = 0;
+ } else
+ outsb(sc->asic_addr + ED_NOVELL_DATA, m->m_data, m->m_len);
+
+ }
+ m = m->m_next;
+ }
+
+ /*
+ * Wait for remote DMA complete. This is necessary because on the
+ * transmit side, data is handled internally by the NIC in bursts
+ * and we can't start another remote DMA until this one completes.
+ * Not waiting causes really bad things to happen - like the NIC
+ * irrecoverably jamming the ISA bus.
+ */
+ while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RDC) != ED_ISR_RDC) && --maxwait);
+
+ if (!maxwait) {
+ log(LOG_WARNING, "ed%d: remote transmit DMA failed to complete\n",
+ sc->arpcom.ac_if.if_unit);
+ ed_reset(sc->arpcom.ac_if.if_unit, 0);
+ }
+
+ return(len);
+}
+
+/*
+ * Given a source and destination address, copy 'amount' of a packet from
+ * the ring buffer into a linear destination buffer. Takes into account
+ * ring-wrap.
+ */
+static inline char *
+ed_ring_copy(sc,src,dst,amount)
+ struct ed_softc *sc;
+ char *src;
+ char *dst;
+ u_short amount;
+{
+ u_short tmp_amount;
+
+ /* does copy wrap to lower addr in ring buffer? */
+ if (src + amount > sc->mem_end) {
+ tmp_amount = sc->mem_end - src;
+
+ /* copy amount up to end of NIC memory */
+ if (sc->mem_shared)
+ bcopy(src,dst,tmp_amount);
+ else
+ ed_pio_readmem(sc,src,dst,tmp_amount);
+
+ amount -= tmp_amount;
+ src = sc->mem_ring;
+ dst += tmp_amount;
+ }
+
+ if (sc->mem_shared)
+ bcopy(src, dst, amount);
+ else
+ ed_pio_readmem(sc, src, dst, amount);
+
+ return(src + amount);
+}
+
+/*
+ * Copy data from receive buffer to end of mbuf chain
+ * allocate additional mbufs as needed. return pointer
+ * to last mbuf in chain.
+ * sc = ed info (softc)
+ * src = pointer in ed ring buffer
+ * dst = pointer to last mbuf in mbuf chain to copy to
+ * amount = amount of data to copy
+ */
+struct mbuf *
+ed_ring_to_mbuf(sc,src,dst,total_len)
+ struct ed_softc *sc;
+ char *src;
+ struct mbuf *dst;
+ u_short total_len;
+{
+ register struct mbuf *m = dst;
+
+ while (total_len) {
+ register u_short amount = min(total_len, M_TRAILINGSPACE(m));
+
+ if (amount == 0) { /* no more data in this mbuf, alloc another */
+ /*
+ * If there is enough data for an mbuf cluster, attempt
+ * to allocate one of those, otherwise, a regular
+ * mbuf will do.
+ * Note that a regular mbuf is always required, even if
+ * we get a cluster - getting a cluster does not
+ * allocate any mbufs, and one is needed to assign
+ * the cluster to. The mbuf that has a cluster
+ * extension can not be used to contain data - only
+ * the cluster can contain data.
+ */
+ dst = m;
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ return (0);
+
+ if (total_len >= MINCLSIZE)
+ MCLGET(m, M_DONTWAIT);
+
+ m->m_len = 0;
+ dst->m_next = m;
+ amount = min(total_len, M_TRAILINGSPACE(m));
+ }
+
+ src = ed_ring_copy(sc, src, mtod(m, caddr_t) + m->m_len, amount);
+
+ m->m_len += amount;
+ total_len -= amount;
+
+ }
+ return (m);
+}
+#endif
diff --git a/sys/dev/ed/if_edreg.h b/sys/dev/ed/if_edreg.h
new file mode 100644
index 0000000..f75e261
--- /dev/null
+++ b/sys/dev/ed/if_edreg.h
@@ -0,0 +1,962 @@
+/*
+ * National Semiconductor DS8390 NIC register definitions
+ *
+ * $Id: if_edreg.h,v 1.13 1994/02/02 14:05:58 davidg Exp $
+ *
+ * Modification history
+ *
+ * Revision 2.2 1993/11/29 16:33:39 davidg
+ * From Thomas Sandford <t.d.g.sandford@comp.brad.ac.uk>
+ * Add support for the 8013W board type
+ *
+ * Revision 2.1 1993/11/22 10:52:33 davidg
+ * patch to add support for SMC8216 (Elite-Ultra) boards
+ * from Glen H. Lowe
+ *
+ * Revision 2.0 93/09/29 00:37:15 davidg
+ * changed double buffering flag to multi buffering
+ * made changes/additions for 3c503 multi-buffering
+ * ...companion to Rev. 2.0 of 'ed' driver.
+ *
+ * Revision 1.1 93/06/23 03:01:07 davidg
+ * Initial revision
+ *
+ */
+
+/*
+ * Page 0 register offsets
+ */
+#define ED_P0_CR 0x00 /* Command Register */
+
+#define ED_P0_CLDA0 0x01 /* Current Local DMA Addr low (read) */
+#define ED_P0_PSTART 0x01 /* Page Start register (write) */
+
+#define ED_P0_CLDA1 0x02 /* Current Local DMA Addr high (read) */
+#define ED_P0_PSTOP 0x02 /* Page Stop register (write) */
+
+#define ED_P0_BNRY 0x03 /* Boundary Pointer */
+
+#define ED_P0_TSR 0x04 /* Transmit Status Register (read) */
+#define ED_P0_TPSR 0x04 /* Transmit Page Start (write) */
+
+#define ED_P0_NCR 0x05 /* Number of Collisions Reg (read) */
+#define ED_P0_TBCR0 0x05 /* Transmit Byte count, low (write) */
+
+#define ED_P0_FIFO 0x06 /* FIFO register (read) */
+#define ED_P0_TBCR1 0x06 /* Transmit Byte count, high (write) */
+
+#define ED_P0_ISR 0x07 /* Interrupt Status Register */
+
+#define ED_P0_CRDA0 0x08 /* Current Remote DMA Addr low (read) */
+#define ED_P0_RSAR0 0x08 /* Remote Start Address low (write) */
+
+#define ED_P0_CRDA1 0x09 /* Current Remote DMA Addr high (read) */
+#define ED_P0_RSAR1 0x09 /* Remote Start Address high (write) */
+
+#define ED_P0_RBCR0 0x0a /* Remote Byte Count low (write) */
+
+#define ED_P0_RBCR1 0x0b /* Remote Byte Count high (write) */
+
+#define ED_P0_RSR 0x0c /* Receive Status (read) */
+#define ED_P0_RCR 0x0c /* Receive Configuration Reg (write) */
+
+#define ED_P0_CNTR0 0x0d /* frame alignment error counter (read) */
+#define ED_P0_TCR 0x0d /* Transmit Configuration Reg (write) */
+
+#define ED_P0_CNTR1 0x0e /* CRC error counter (read) */
+#define ED_P0_DCR 0x0e /* Data Configuration Reg (write) */
+
+#define ED_P0_CNTR2 0x0f /* missed packet counter (read) */
+#define ED_P0_IMR 0x0f /* Interrupt Mask Register (write) */
+
+/*
+ * Page 1 register offsets
+ */
+#define ED_P1_CR 0x00 /* Command Register */
+#define ED_P1_PAR0 0x01 /* Physical Address Register 0 */
+#define ED_P1_PAR1 0x02 /* Physical Address Register 1 */
+#define ED_P1_PAR2 0x03 /* Physical Address Register 2 */
+#define ED_P1_PAR3 0x04 /* Physical Address Register 3 */
+#define ED_P1_PAR4 0x05 /* Physical Address Register 4 */
+#define ED_P1_PAR5 0x06 /* Physical Address Register 5 */
+#define ED_P1_CURR 0x07 /* Current RX ring-buffer page */
+#define ED_P1_MAR0 0x08 /* Multicast Address Register 0 */
+#define ED_P1_MAR1 0x09 /* Multicast Address Register 1 */
+#define ED_P1_MAR2 0x0a /* Multicast Address Register 2 */
+#define ED_P1_MAR3 0x0b /* Multicast Address Register 3 */
+#define ED_P1_MAR4 0x0c /* Multicast Address Register 4 */
+#define ED_P1_MAR5 0x0d /* Multicast Address Register 5 */
+#define ED_P1_MAR6 0x0e /* Multicast Address Register 6 */
+#define ED_P1_MAR7 0x0f /* Multicast Address Register 7 */
+
+/*
+ * Page 2 register offsets
+ */
+#define ED_P2_CR 0x00 /* Command Register */
+#define ED_P2_PSTART 0x01 /* Page Start (read) */
+#define ED_P2_CLDA0 0x01 /* Current Local DMA Addr 0 (write) */
+#define ED_P2_PSTOP 0x02 /* Page Stop (read) */
+#define ED_P2_CLDA1 0x02 /* Current Local DMA Addr 1 (write) */
+#define ED_P2_RNPP 0x03 /* Remote Next Packet Pointer */
+#define ED_P2_TPSR 0x04 /* Transmit Page Start (read) */
+#define ED_P2_LNPP 0x05 /* Local Next Packet Pointer */
+#define ED_P2_ACU 0x06 /* Address Counter Upper */
+#define ED_P2_ACL 0x07 /* Address Counter Lower */
+#define ED_P2_RCR 0x0c /* Receive Configuration Register (read) */
+#define ED_P2_TCR 0x0d /* Transmit Configuration Register (read) */
+#define ED_P2_DCR 0x0e /* Data Configuration Register (read) */
+#define ED_P2_IMR 0x0f /* Interrupt Mask Register (read) */
+
+/*
+ * Command Register (CR) definitions
+ */
+
+/*
+ * STP: SToP. Software reset command. Takes the controller offline. No
+ * packets will be received or transmitted. Any reception or
+ * transmission in progress will continue to completion before
+ * entering reset state. To exit this state, the STP bit must
+ * reset and the STA bit must be set. The software reset has
+ * executed only when indicated by the RST bit in the ISR being
+ * set.
+ */
+#define ED_CR_STP 0x01
+
+/*
+ * STA: STArt. This bit is used to activate the NIC after either power-up,
+ * or when the NIC has been put in reset mode by software command
+ * or error.
+ */
+#define ED_CR_STA 0x02
+
+/*
+ * TXP: Transmit Packet. This bit must be set to indicate transmission of
+ * a packet. TXP is internally reset either after the transmission is
+ * completed or aborted. This bit should be set only after the Transmit
+ * Byte Count and Transmit Page Start register have been programmed.
+ */
+#define ED_CR_TXP 0x04
+
+/*
+ * RD0, RD1, RD2: Remote DMA Command. These three bits control the operation
+ * of the remote DMA channel. RD2 can be set to abort any remote DMA
+ * command in progress. The Remote Byte Count registers should be cleared
+ * when a remote DMA has been aborted. The Remote Start Addresses are not
+ * restored to the starting address if the remote DMA is aborted.
+ *
+ * RD2 RD1 RD0 function
+ * 0 0 0 not allowed
+ * 0 0 1 remote read
+ * 0 1 0 remote write
+ * 0 1 1 send packet
+ * 1 X X abort
+ */
+#define ED_CR_RD0 0x08
+#define ED_CR_RD1 0x10
+#define ED_CR_RD2 0x20
+
+/*
+ * PS0, PS1: Page Select. The two bits select which register set or 'page' to
+ * access.
+ *
+ * PS1 PS0 page
+ * 0 0 0
+ * 0 1 1
+ * 1 0 2
+ * 1 1 reserved
+ */
+#define ED_CR_PS0 0x40
+#define ED_CR_PS1 0x80
+/* bit encoded aliases */
+#define ED_CR_PAGE_0 0x00 /* (for consistency) */
+#define ED_CR_PAGE_1 0x40
+#define ED_CR_PAGE_2 0x80
+
+/*
+ * Interrupt Status Register (ISR) definitions
+ */
+
+/*
+ * PRX: Packet Received. Indicates packet received with no errors.
+ */
+#define ED_ISR_PRX 0x01
+
+/*
+ * PTX: Packet Transmitted. Indicates packet transmitted with no errors.
+ */
+#define ED_ISR_PTX 0x02
+
+/*
+ * RXE: Receive Error. Indicates that a packet was received with one or more
+ * the following errors: CRC error, frame alignment error, FIFO overrun,
+ * missed packet.
+ */
+#define ED_ISR_RXE 0x04
+
+/*
+ * TXE: Transmission Error. Indicates that an attempt to transmit a packet
+ * resulted in one or more of the following errors: excessive
+ * collisions, FIFO underrun.
+ */
+#define ED_ISR_TXE 0x08
+
+/*
+ * OVW: OverWrite. Indicates a receive ring-buffer overrun. Incoming network
+ * would exceed (has exceeded?) the boundry pointer, resulting in data
+ * that was previously received and not yet read from the buffer to be
+ * overwritten.
+ */
+#define ED_ISR_OVW 0x10
+
+/*
+ * CNT: Counter Overflow. Set when the MSB of one or more of the Network Talley
+ * Counters has been set.
+ */
+#define ED_ISR_CNT 0x20
+
+/*
+ * RDC: Remote Data Complete. Indicates that a Remote DMA operation has completed.
+ */
+#define ED_ISR_RDC 0x40
+
+/*
+ * RST: Reset status. Set when the NIC enters the reset state and cleared when a
+ * Start Command is issued to the CR. This bit is also set when a receive
+ * ring-buffer overrun (OverWrite) occurs and is cleared when one or more
+ * packets have been removed from the ring. This is a read-only bit.
+ */
+#define ED_ISR_RST 0x80
+
+/*
+ * Interrupt Mask Register (IMR) definitions
+ */
+
+/*
+ * PRXE: Packet Received interrupt Enable. If set, a received packet will cause
+ * an interrupt.
+ */
+#define ED_IMR_PRXE 0x01
+
+/*
+ * PTXE: Packet Transmit interrupt Enable. If set, an interrupt is generated when
+ * a packet transmission completes.
+ */
+#define ED_IMR_PTXE 0x02
+
+/*
+ * RXEE: Receive Error interrupt Enable. If set, an interrupt will occur whenever a
+ * packet is received with an error.
+ */
+#define ED_IMR_RXEE 0x04
+
+/*
+ * TXEE: Transmit Error interrupt Enable. If set, an interrupt will occur whenever
+ * a transmission results in an error.
+ */
+#define ED_IMR_TXEE 0x08
+
+/*
+ * OVWE: OverWrite error interrupt Enable. If set, an interrupt is generated whenever
+ * the receive ring-buffer is overrun. i.e. when the boundry pointer is exceeded.
+ */
+#define ED_IMR_OVWE 0x10
+
+/*
+ * CNTE: Counter overflow interrupt Enable. If set, an interrupt is generated whenever
+ * the MSB of one or more of the Network Statistics counters has been set.
+ */
+#define ED_IMR_CNTE 0x20
+
+/*
+ * RDCE: Remote DMA Complete interrupt Enable. If set, an interrupt is generated
+ * when a remote DMA transfer has completed.
+ */
+#define ED_IMR_RDCE 0x40
+
+/*
+ * bit 7 is unused/reserved
+ */
+
+/*
+ * Data Configuration Register (DCR) definitions
+ */
+
+/*
+ * WTS: Word Transfer Select. WTS establishes byte or word transfers for
+ * both remote and local DMA transfers
+ */
+#define ED_DCR_WTS 0x01
+
+/*
+ * BOS: Byte Order Select. BOS sets the byte order for the host.
+ * Should be 0 for 80x86, and 1 for 68000 series processors
+ */
+#define ED_DCR_BOS 0x02
+
+/*
+ * LAS: Long Address Select. When LAS is 1, the contents of the remote
+ * DMA registers RSAR0 and RSAR1 are used to provide A16-A31
+ */
+#define ED_DCR_LAS 0x04
+
+/*
+ * LS: Loopback Select. When 0, loopback mode is selected. Bits D1 and D2
+ * of the TCR must also be programmed for loopback operation.
+ * When 1, normal operation is selected.
+ */
+#define ED_DCR_LS 0x08
+
+/*
+ * AR: Auto-initialize Remote. When 0, data must be removed from ring-buffer
+ * under program control. When 1, remote DMA is automatically initiated
+ * and the boundry pointer is automatically updated
+ */
+#define ED_DCR_AR 0x10
+
+/*
+ * FT0, FT1: Fifo Threshold select.
+ * FT1 FT0 Word-width Byte-width
+ * 0 0 1 word 2 bytes
+ * 0 1 2 words 4 bytes
+ * 1 0 4 words 8 bytes
+ * 1 1 8 words 12 bytes
+ *
+ * During transmission, the FIFO threshold indicates the number of bytes
+ * or words that the FIFO has filled from the local DMA before BREQ is
+ * asserted. The transmission threshold is 16 bytes minus the receiver
+ * threshold.
+ */
+#define ED_DCR_FT0 0x20
+#define ED_DCR_FT1 0x40
+
+/*
+ * bit 7 (0x80) is unused/reserved
+ */
+
+/*
+ * Transmit Configuration Register (TCR) definitions
+ */
+
+/*
+ * CRC: Inhibit CRC. If 0, CRC will be appended by the transmitter, if 0, CRC
+ * is not appended by the transmitter.
+ */
+#define ED_TCR_CRC 0x01
+
+/*
+ * LB0, LB1: Loopback control. These two bits set the type of loopback that is
+ * to be performed.
+ *
+ * LB1 LB0 mode
+ * 0 0 0 - normal operation (DCR_LS = 0)
+ * 0 1 1 - internal loopback (DCR_LS = 0)
+ * 1 0 2 - external loopback (DCR_LS = 1)
+ * 1 1 3 - external loopback (DCR_LS = 0)
+ */
+#define ED_TCR_LB0 0x02
+#define ED_TCR_LB1 0x04
+
+/*
+ * ATD: Auto Transmit Disable. Clear for normal operation. When set, allows
+ * another station to disable the NIC's transmitter by transmitting to
+ * a multicast address hashing to bit 62. Reception of a multicast address
+ * hashing to bit 63 enables the transmitter.
+ */
+#define ED_TCR_ATD 0x08
+
+/*
+ * OFST: Collision Offset enable. This bit when set modifies the backoff
+ * algorithm to allow prioritization of nodes.
+ */
+#define ED_TCR_OFST 0x10
+
+/*
+ * bits 5, 6, and 7 are unused/reserved
+ */
+
+/*
+ * Transmit Status Register (TSR) definitions
+ */
+
+/*
+ * PTX: Packet Transmitted. Indicates successful transmission of packet.
+ */
+#define ED_TSR_PTX 0x01
+
+/*
+ * bit 1 (0x02) is unused/reserved
+ */
+
+/*
+ * COL: Transmit Collided. Indicates that the transmission collided at least
+ * once with another station on the network.
+ */
+#define ED_TSR_COL 0x04
+
+/*
+ * ABT: Transmit aborted. Indicates that the transmission was aborted due to
+ * excessive collisions.
+ */
+#define ED_TSR_ABT 0x08
+
+/*
+ * CRS: Carrier Sense Lost. Indicates that carrier was lost during the
+ * transmission of the packet. (Transmission is not aborted because
+ * of a loss of carrier)
+ */
+#define ED_TSR_CRS 0x10
+
+/*
+ * FU: FIFO Underrun. Indicates that the NIC wasn't able to access bus/
+ * transmission memory before the FIFO emptied. Transmission of the
+ * packet was aborted.
+ */
+#define ED_TSR_FU 0x20
+
+/*
+ * CDH: CD Heartbeat. Indicates that the collision detection circuitry
+ * isn't working correctly during a collision heartbeat test.
+ */
+#define ED_TSR_CDH 0x40
+
+/*
+ * OWC: Out of Window Collision: Indicates that a collision occurred after
+ * a slot time (51.2us). The transmission is rescheduled just as in
+ * normal collisions.
+ */
+#define ED_TSR_OWC 0x80
+
+/*
+ * Receiver Configuration Register (RCR) definitions
+ */
+
+/*
+ * SEP: Save Errored Packets. If 0, error packets are discarded. If set to 1,
+ * packets with CRC and frame errors are not discarded.
+ */
+#define ED_RCR_SEP 0x01
+
+/*
+ * AR: Accept Runt packet. If 0, packet with less than 64 byte are discarded.
+ * If set to 1, packets with less than 64 byte are not discarded.
+ */
+#define ED_RCR_AR 0x02
+
+/*
+ * AB: Accept Broadcast. If set, packets sent to the broadcast address will be
+ * accepted.
+ */
+#define ED_RCR_AB 0x04
+
+/*
+ * AM: Accept Multicast. If set, packets sent to a multicast address are checked
+ * for a match in the hashing array. If clear, multicast packets are ignored.
+ */
+#define ED_RCR_AM 0x08
+
+/*
+ * PRO: Promiscuous Physical. If set, all packets with a physical addresses are
+ * accepted. If clear, a physical destination address must match this
+ * station's address. Note: for full promiscuous mode, RCR_AB and RCR_AM
+ * must also be set. In addition, the multicast hashing array must be set
+ * to all 1's so that all multicast addresses are accepted.
+ */
+#define ED_RCR_PRO 0x10
+
+/*
+ * MON: Monitor Mode. If set, packets will be checked for good CRC and framing,
+ * but are not stored in the ring-buffer. If clear, packets are stored (normal
+ * operation).
+ */
+#define ED_RCR_MON 0x20
+
+/*
+ * bits 6 and 7 are unused/reserved.
+ */
+
+/*
+ * Receiver Status Register (RSR) definitions
+ */
+
+/*
+ * PRX: Packet Received without error.
+ */
+#define ED_RSR_PRX 0x01
+
+/*
+ * CRC: CRC error. Indicates that a packet has a CRC error. Also set for frame
+ * alignment errors.
+ */
+#define ED_RSR_CRC 0x02
+
+/*
+ * FAE: Frame Alignment Error. Indicates that the incoming packet did not end on
+ * a byte boundry and the CRC did not match at the last byte boundry.
+ */
+#define ED_RSR_FAE 0x04
+
+/*
+ * FO: FIFO Overrun. Indicates that the FIFO was not serviced (during local DMA)
+ * causing it to overrun. Reception of the packet is aborted.
+ */
+#define ED_RSR_FO 0x08
+
+/*
+ * MPA: Missed Packet. Indicates that the received packet couldn't be stored in
+ * the ring-buffer because of insufficient buffer space (exceeding the
+ * boundry pointer), or because the transfer to the ring-buffer was inhibited
+ * by RCR_MON - monitor mode.
+ */
+#define ED_RSR_MPA 0x10
+
+/*
+ * PHY: Physical address. If 0, the packet received was sent to a physical address.
+ * If 1, the packet was accepted because of a multicast/broadcast address
+ * match.
+ */
+#define ED_RSR_PHY 0x20
+
+/*
+ * DIS: Receiver Disabled. Set to indicate that the receiver has enetered monitor
+ * mode. Cleared when the receiver exits monitor mode.
+ */
+#define ED_RSR_DIS 0x40
+
+/*
+ * DFR: Deferring. Set to indicate a 'jabber' condition. The CRS and COL inputs
+ * are active, and the transceiver has set the CD line as a result of the
+ * jabber.
+ */
+#define ED_RSR_DFR 0x80
+
+/*
+ * receive ring discriptor
+ *
+ * The National Semiconductor DS8390 Network interface controller uses
+ * the following receive ring headers. The way this works is that the
+ * memory on the interface card is chopped up into 256 bytes blocks.
+ * A contiguous portion of those blocks are marked for receive packets
+ * by setting start and end block #'s in the NIC. For each packet that
+ * is put into the receive ring, one of these headers (4 bytes each) is
+ * tacked onto the front.
+ */
+struct ed_ring {
+ struct edr_status { /* received packet status */
+ u_char rs_prx:1, /* packet received intack */
+ rs_crc:1, /* crc error */
+ rs_fae:1, /* frame alignment error */
+ rs_fo:1, /* fifo overrun */
+ rs_mpa:1, /* packet received intack */
+ rs_phy:1, /* packet received intack */
+ rs_dis:1, /* packet received intack */
+ rs_dfr:1; /* packet received intack */
+ } ed_rcv_status; /* received packet status */
+ u_char next_packet; /* pointer to next packet */
+ u_short count; /* bytes in packet (length + 4) */
+};
+
+/*
+ * Common constants
+ */
+#define ED_PAGE_SIZE 256 /* Size of RAM pages in bytes */
+#define ED_TXBUF_SIZE 6 /* Size of TX buffer in pages */
+
+/*
+ * Vendor types
+ */
+#define ED_VENDOR_WD_SMC 0x00 /* Western Digital/SMC */
+#define ED_VENDOR_3COM 0x01 /* 3Com */
+#define ED_VENDOR_NOVELL 0x02 /* Novell */
+
+/*
+ * Compile-time config flags
+ */
+/*
+ * this sets the default for enabling/disablng the tranceiver
+ */
+#define ED_FLAGS_DISABLE_TRANCEIVER 0x0001
+
+/*
+ * This forces the board to be used in 8/16bit mode even if it
+ * autoconfigs differently
+ */
+#define ED_FLAGS_FORCE_8BIT_MODE 0x0002
+#define ED_FLAGS_FORCE_16BIT_MODE 0x0004
+
+/*
+ * This disables the use of double transmit buffers.
+ */
+#define ED_FLAGS_NO_MULTI_BUFFERING 0x0008
+
+/*
+ * This forces all operations with the NIC memory to use Programmed
+ * I/O (i.e. not via shared memory)
+ */
+#define ED_FLAGS_FORCE_PIO 0x0010
+
+/*
+ * Definitions for Western digital/SMC WD80x3 series ASIC
+ */
+/*
+ * Memory Select Register (MSR)
+ */
+#define ED_WD_MSR 0
+
+/* next three definitions for Toshiba */
+#define ED_WD_MSR_POW 0x02 /* 0 = power save, 1 = normal (R/W) */
+#define ED_WD_MSR_BSY 0x04 /* gate array busy (R) */
+#define ED_WD_MSR_LEN 0x20 /* data bus width, 0 = 16 bits,
+ 1 = 8 bits (R/W) */
+#define ED_WD_MSR_ADDR 0x3f /* Memory decode bits 18-13 */
+#define ED_WD_MSR_MENB 0x40 /* Memory enable */
+#define ED_WD_MSR_RST 0x80 /* Reset board */
+
+/*
+ * Interface Configuration Register (ICR)
+ */
+#define ED_WD_ICR 1
+
+#define ED_WD_ICR_16BIT 0x01 /* 16-bit interface */
+#define ED_WD_ICR_OAR 0x02 /* select register. 0=BIO 1=EAR */
+#define ED_WD_ICR_IR2 0x04 /* high order bit of encoded IRQ */
+#define ED_WD_ICR_MSZ 0x08 /* memory size (0=8k 1=32k) */
+#define ED_WD_ICR_RLA 0x10 /* recall LAN address */
+#define ED_WD_ICR_RX7 0x20 /* recall all but i/o and LAN address */
+#define ED_WD_ICR_RIO 0x40 /* recall i/o address */
+#define ED_WD_ICR_STO 0x80 /* store to non-volatile memory */
+#ifdef TOSH_ETHER
+#define ED_WD_ICR_MEM 0xe0 /* shared mem address A15-A13 (R/W) */
+#define ED_WD_ICR_MSZ1 0x0f /* memory size, 0x08 = 64K, 0x04 = 32K,
+ 0x02 = 16K, 0x01 = 8K */
+ /* 64K can only be used if mem address
+ above 1Mb */
+ /* IAR holds address A23-A16 (R/W) */
+#endif
+
+/*
+ * IO Address Register (IAR)
+ */
+#define ED_WD_IAR 2
+
+/*
+ * EEROM Address Register
+ */
+#define ED_WD_EAR 3
+
+/*
+ * Interrupt Request Register (IRR)
+ */
+#define ED_WD_IRR 4
+
+#define ED_WD_IRR_0WS 0x01 /* use 0 wait-states on 8 bit bus */
+#define ED_WD_IRR_OUT1 0x02 /* WD83C584 pin 1 output */
+#define ED_WD_IRR_OUT2 0x04 /* WD83C584 pin 2 output */
+#define ED_WD_IRR_OUT3 0x08 /* WD83C584 pin 3 output */
+#define ED_WD_IRR_FLASH 0x10 /* Flash RAM is in the ROM socket */
+
+/*
+ * The three bits of the encoded IRQ are decoded as follows:
+ *
+ * IR2 IR1 IR0 IRQ
+ * 0 0 0 2/9
+ * 0 0 1 3
+ * 0 1 0 5
+ * 0 1 1 7
+ * 1 0 0 10
+ * 1 0 1 11
+ * 1 1 0 15
+ * 1 1 1 4
+ */
+#define ED_WD_IRR_IR0 0x20 /* bit 0 of encoded IRQ */
+#define ED_WD_IRR_IR1 0x40 /* bit 1 of encoded IRQ */
+#define ED_WD_IRR_IEN 0x80 /* Interrupt enable */
+
+/*
+ * LA Address Register (LAAR)
+ */
+#define ED_WD_LAAR 5
+
+#define ED_WD_LAAR_ADDRHI 0x1f /* bits 23-19 of RAM address */
+#define ED_WD_LAAR_0WS16 0x20 /* enable 0 wait-states on 16 bit bus */
+#define ED_WD_LAAR_L16EN 0x40 /* enable 16-bit operation */
+#define ED_WD_LAAR_M16EN 0x80 /* enable 16-bit memory access */
+
+/* i/o base offset to station address/card-ID PROM */
+#define ED_WD_PROM 8
+
+/*
+ * 83C790 specific registers
+ */
+/*
+ * Hardware Support Register (HWR) ('790)
+ */
+#define ED_WD790_HWR 4
+
+#define WD_WD790_HWR_NUKE 0x10 /* hardware reset */
+#define ED_WD790_HWR_LPRM 0x40 /* LAN PROM select */
+#define ED_WD790_HWR_SWH 0x80 /* switch register set */
+
+/*
+ * ICR790 Interrupt Control Register for the 83C790
+ */
+#define ED_WD790_ICR 6
+
+#define ED_WD790_ICR_EIL 0x01 /* enable interrupts */
+
+/*
+ * General Control Register (GCR)
+ * Enabled with SWH bit=1 in HWR register
+ */
+#define ED_WD790_GCR 0x0d
+
+#define ED_WD790_GCR_IR0 0x04 /* bit 0 of encoded IRQ */
+#define ED_WD790_GCR_IR1 0x08 /* bit 1 of encoded IRQ */
+#define ED_WD790_GCR_ZWSEN 0x20 /* zero wait state enable */
+#define ED_WD790_GCR_IR2 0x40 /* bit 2 of encoded IRQ */
+/*
+ * The three bits of the encoded IRQ are decoded as follows:
+ *
+ * IR2 IR1 IR0 IRQ
+ * 0 0 0 none
+ * 0 0 1 9
+ * 0 1 0 3
+ * 0 1 1 5
+ * 1 0 0 7
+ * 1 0 1 10
+ * 1 1 0 11
+ * 1 1 1 15
+ */
+
+/* i/o base offset to CARD ID */
+#define ED_WD_CARD_ID ED_WD_PROM+6
+
+/* Board type codes in card ID */
+#define ED_TYPE_WD8003S 0x02
+#define ED_TYPE_WD8003E 0x03
+#define ED_TYPE_WD8013EBT 0x05
+#define ED_TYPE_TOSHIBA1 0x11 /* named PCETA1 */
+#define ED_TYPE_TOSHIBA2 0x12 /* named PCETA2 */
+#define ED_TYPE_TOSHIBA3 0x13 /* named PCETB */
+#define ED_TYPE_TOSHIBA4 0x14 /* named PCETC */
+#define ED_TYPE_WD8003W 0x24
+#define ED_TYPE_WD8003EB 0x25
+#define ED_TYPE_WD8013W 0x26
+#define ED_TYPE_WD8013EP 0x27
+#define ED_TYPE_WD8013WC 0x28
+#define ED_TYPE_WD8013EPC 0x29
+#define ED_TYPE_SMC8216T 0x2a
+#define ED_TYPE_SMC8216C 0x2b
+#define ED_TYPE_WD8013EBP 0x2c
+
+/* Bit definitions in card ID */
+#define ED_WD_REV_MASK 0x1f /* Revision mask */
+#define ED_WD_SOFTCONFIG 0x20 /* Soft config */
+#define ED_WD_LARGERAM 0x40 /* Large RAM */
+#define ED_MICROCHANEL 0x80 /* Microchannel bus (vs. isa) */
+
+/*
+ * Checksum total. All 8 bytes in station address PROM will add up to this
+ */
+#ifdef TOSH_ETHER
+#define ED_WD_ROM_CHECKSUM_TOTAL 0xA5
+#else
+#define ED_WD_ROM_CHECKSUM_TOTAL 0xFF
+#endif
+
+#define ED_WD_NIC_OFFSET 0x10 /* I/O base offset to NIC */
+#define ED_WD_ASIC_OFFSET 0 /* I/O base offset to ASIC */
+#define ED_WD_IO_PORTS 32 /* # of i/o addresses used */
+
+#define ED_WD_PAGE_OFFSET 0 /* page offset for NIC access to mem */
+
+/*
+ * Definitions for 3Com 3c503
+ */
+#define ED_3COM_NIC_OFFSET 0
+#define ED_3COM_ASIC_OFFSET 0x400 /* offset to nic i/o regs */
+
+/*
+ * XXX - The I/O address range is fragmented in the 3c503; this is the
+ * number of regs at iobase.
+ */
+#define ED_3COM_IO_PORTS 16 /* # of i/o addresses used */
+
+/* tx memory starts in second bank on 8bit cards */
+#define ED_3COM_TX_PAGE_OFFSET_8BIT 0x20
+
+/* tx memory starts in first bank on 16bit cards */
+#define ED_3COM_TX_PAGE_OFFSET_16BIT 0x0
+
+/* ...and rx memory starts in second bank */
+#define ED_3COM_RX_PAGE_OFFSET_16BIT 0x20
+
+
+/*
+ * Page Start Register. Must match PSTART in NIC
+ */
+#define ED_3COM_PSTR 0
+
+/*
+ * Page Stop Register. Must match PSTOP in NIC
+ */
+#define ED_3COM_PSPR 1
+
+/*
+ * Drq Timer Register. Determines number of bytes to be transfered during
+ * a DMA burst.
+ */
+#define ED_3COM_DQTR 2
+
+/*
+ * Base Configuration Register. Read-only register which contains the
+ * board-configured I/O base address of the adapter. Bit encoded.
+ */
+#define ED_3COM_BCFR 3
+
+#define ED_3COM_BCFR_2E0 0x01
+#define ED_3COM_BCFR_2A0 0x02
+#define ED_3COM_BCFR_280 0x04
+#define ED_3COM_BCFR_250 0x08
+#define ED_3COM_BCFR_350 0x10
+#define ED_3COM_BCFR_330 0x20
+#define ED_3COM_BCFR_310 0x40
+#define ED_3COM_BCFR_300 0x80
+
+/*
+ * EPROM Configuration Register. Read-only register which contains the
+ * board-configured memory base address. Bit encoded.
+ */
+#define ED_3COM_PCFR 4
+
+#define ED_3COM_PCFR_C8000 0x10
+#define ED_3COM_PCFR_CC000 0x20
+#define ED_3COM_PCFR_D8000 0x40
+#define ED_3COM_PCFR_DC000 0x80
+
+/*
+ * GA Configuration Register. Gate-Array Configuration Register.
+ */
+#define ED_3COM_GACFR 5
+
+/*
+ * mbs2 mbs1 mbs0 start address
+ * 0 0 0 0x0000
+ * 0 0 1 0x2000
+ * 0 1 0 0x4000
+ * 0 1 1 0x6000
+ *
+ * Note that with adapters with only 8K, the setting for 0x2000 must
+ * always be used.
+ */
+#define ED_3COM_GACFR_MBS0 0x01
+#define ED_3COM_GACFR_MBS1 0x02
+#define ED_3COM_GACFR_MBS2 0x04
+
+#define ED_3COM_GACFR_RSEL 0x08 /* enable shared memory */
+#define ED_3COM_GACFR_TEST 0x10 /* for GA testing */
+#define ED_3COM_GACFR_OWS 0x20 /* select 0WS access to GA */
+#define ED_3COM_GACFR_TCM 0x40 /* Mask DMA interrupts */
+#define ED_3COM_GACFR_NIM 0x80 /* Mask NIC interrupts */
+
+/*
+ * Control Register. Miscellaneous control functions.
+ */
+#define ED_3COM_CR 6
+
+#define ED_3COM_CR_RST 0x01 /* Reset GA and NIC */
+#define ED_3COM_CR_XSEL 0x02 /* Transceiver select. BNC=1(def) AUI=0 */
+#define ED_3COM_CR_EALO 0x04 /* window EA PROM 0-15 to I/O base */
+#define ED_3COM_CR_EAHI 0x08 /* window EA PROM 16-31 to I/O base */
+#define ED_3COM_CR_SHARE 0x10 /* select interrupt sharing option */
+#define ED_3COM_CR_DBSEL 0x20 /* Double buffer select */
+#define ED_3COM_CR_DDIR 0x40 /* DMA direction select */
+#define ED_3COM_CR_START 0x80 /* Start DMA controller */
+
+/*
+ * Status Register. Miscellaneous status information.
+ */
+#define ED_3COM_STREG 7
+
+#define ED_3COM_STREG_REV 0x07 /* GA revision */
+#define ED_3COM_STREG_DIP 0x08 /* DMA in progress */
+#define ED_3COM_STREG_DTC 0x10 /* DMA terminal count */
+#define ED_3COM_STREG_OFLW 0x20 /* Overflow */
+#define ED_3COM_STREG_UFLW 0x40 /* Underflow */
+#define ED_3COM_STREG_DPRDY 0x80 /* Data port ready */
+
+/*
+ * Interrupt/DMA Configuration Register
+ */
+#define ED_3COM_IDCFR 8
+
+#define ED_3COM_IDCFR_DRQ0 0x01 /* DMA request 1 select */
+#define ED_3COM_IDCFR_DRQ1 0x02 /* DMA request 2 select */
+#define ED_3COM_IDCFR_DRQ2 0x04 /* DMA request 3 select */
+#define ED_3COM_IDCFR_UNUSED 0x08 /* not used */
+#define ED_3COM_IDCFR_IRQ2 0x10 /* Interrupt request 2 select */
+#define ED_3COM_IDCFR_IRQ3 0x20 /* Interrupt request 3 select */
+#define ED_3COM_IDCFR_IRQ4 0x40 /* Interrupt request 4 select */
+#define ED_3COM_IDCFR_IRQ5 0x80 /* Interrupt request 5 select */
+
+/*
+ * DMA Address Register MSB
+ */
+#define ED_3COM_DAMSB 9
+
+/*
+ * DMA Address Register LSB
+ */
+#define ED_3COM_DALSB 0x0a
+
+/*
+ * Vector Pointer Register 2
+ */
+#define ED_3COM_VPTR2 0x0b
+
+/*
+ * Vector Pointer Register 1
+ */
+#define ED_3COM_VPTR1 0x0c
+
+/*
+ * Vector Pointer Register 0
+ */
+#define ED_3COM_VPTR0 0x0d
+
+/*
+ * Register File Access MSB
+ */
+#define ED_3COM_RFMSB 0x0e
+
+/*
+ * Register File Access LSB
+ */
+#define ED_3COM_RFLSB 0x0f
+
+/*
+ * Definitions for Novell NE1000/2000 boards
+ */
+
+/*
+ * Board type codes
+ */
+#define ED_TYPE_NE1000 0x01
+#define ED_TYPE_NE2000 0x02
+
+/*
+ * Register offsets/total
+ */
+#define ED_NOVELL_NIC_OFFSET 0x00
+#define ED_NOVELL_ASIC_OFFSET 0x10
+#define ED_NOVELL_IO_PORTS 32
+
+/*
+ * Remote DMA data register; for reading or writing to the NIC mem
+ * via programmed I/O (offset from ASIC base)
+ */
+#define ED_NOVELL_DATA 0x00
+
+/*
+ * Reset register; reading from this register causes a board reset
+ */
+#define ED_NOVELL_RESET 0x0f
diff --git a/sys/dev/ep/if_ep.c b/sys/dev/ep/if_ep.c
new file mode 100644
index 0000000..e8d3112
--- /dev/null
+++ b/sys/dev/ep/if_ep.c
@@ -0,0 +1,994 @@
+/*
+ * Copyright (c) 1993 Herb Peyerl <hpeyerl@novatel.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * From: if_ep.c,v 1.9 1994/01/25 10:46:29 deraadt Exp $
+ * $Id: if_ep.c,v 1.8 1994/03/15 01:58:22 wollman Exp $
+ */
+
+#include "ep.h"
+#if NEP > 0
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#if defined(__FreeBSD__)
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#endif
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+#if defined(__NetBSD__)
+#include <sys/select.h>
+#endif
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#endif
+
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+#include <machine/pio.h>
+
+#include <i386/isa/isa.h>
+#include <i386/isa/isa_device.h>
+#include <i386/isa/icu.h>
+#include <i386/isa/if_epreg.h>
+
+#define ETHER_MIN_LEN 64
+#define ETHER_MAX_LEN 1518
+#define ETHER_ADDR_LEN 6
+
+/*
+ * Ethernet software status per interface.
+ */
+struct ep_softc {
+ struct arpcom arpcom; /* Ethernet common part */
+ short ep_io_addr; /* i/o bus address */
+ char ep_connectors; /* Connectors on this card. */
+#define MAX_MBS 8 /* # of mbufs we keep around */
+ struct mbuf *mb[MAX_MBS]; /* spare mbuf storage. */
+ int next_mb; /* Which mbuf to use next. */
+ int last_mb; /* Last mbuf. */
+ int tx_start_thresh; /* Current TX_start_thresh. */
+ caddr_t bpf; /* BPF "magic cookie" */
+ char bus32bit; /* 32bit access possible */
+} ep_softc[NEP];
+
+static int epprobe __P((struct isa_device *));
+static int epattach __P((struct isa_device *));
+static int epioctl __P((struct ifnet * ifp, int, caddr_t));
+
+void epinit __P((int));
+void epintr __P((int));
+void epmbuffill __P((caddr_t, int));
+void epmbufempty __P((struct ep_softc *));
+void epread __P((struct ep_softc *));
+void epreset __P((int));
+void epstart __P((struct ifnet *));
+void epstop __P((int));
+void epwatchdog __P((int));
+
+struct isa_driver epdriver = {
+ epprobe,
+ epattach,
+ "ep"
+};
+
+static int send_ID_sequence __P((u_short));
+static u_short get_eeprom_data __P((int, int));
+static int is_eeprom_busy __P((struct isa_device *));
+
+/*
+ * Rudimentary support for multiple cards is here but is not
+ * currently handled. In the future we will have to add code
+ * for tagging the cards for later activation. We wanna do something
+ * about the id_port. We're limited due to current config procedure.
+ * Magnum config holds promise of a fix but we'll have to wait a bit.
+ */
+int
+epprobe(is)
+ struct isa_device *is;
+{
+ struct ep_softc *sc = &ep_softc[is->id_unit];
+ u_short k;
+ int id_port = 0x100; /* XXX */
+
+ outw(BASE + EP_COMMAND, GLOBAL_RESET);
+ DELAY(1000);
+ outb(id_port, 0xc0); /* Global reset to id_port. */
+ DELAY(1000);
+ send_ID_sequence(id_port);
+ DELAY(1000);
+
+ /*
+ * MFG_ID should have 0x6d50.
+ * PROD_ID should be 0x9[0-f]50
+ */
+ k = get_eeprom_data(id_port, EEPROM_MFG_ID);
+ if (k != MFG_ID)
+ return (0);
+ k = get_eeprom_data(id_port, EEPROM_PROD_ID);
+ if ((k & 0xf0ff) != (PROD_ID & 0xf0ff))
+ return (0);
+
+ k = get_eeprom_data(id_port, EEPROM_ADDR_CFG); /* get addr cfg */
+ k = (k & 0x1f) * 0x10 + 0x200; /* decode base addr. */
+ if (k != (u_short)is->id_iobase)
+ return (0);
+
+ k = get_eeprom_data(id_port, EEPROM_RESOURCE_CFG);
+ k >>= 12;
+ if (is->id_irq != (1 << ((k == 2) ? 9 : k)))
+ return (0);
+
+ outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG);
+
+ return (0x10); /* 16 bytes of I/O space used. */
+}
+
+static int
+epattach(is)
+ struct isa_device *is;
+{
+ struct ep_softc *sc = &ep_softc[is->id_unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ u_short i;
+ struct ifaddr *ifa;
+ struct sockaddr_dl *sdl;
+
+ sc->ep_io_addr = is->id_iobase;
+
+ printf("ep%d: ", is->id_unit);
+
+ sc->ep_connectors = 0;
+ i = inw(is->id_iobase + EP_W0_CONFIG_CTRL);
+ if (i & IS_AUI) {
+ printf("aui");
+ sc->ep_connectors |= AUI;
+ }
+ if (i & IS_BNC) {
+ if (sc->ep_connectors)
+ printf("/");
+ printf("bnc");
+ sc->ep_connectors |= BNC;
+ }
+ if (i & IS_UTP) {
+ if (sc->ep_connectors)
+ printf("/");
+ printf("utp");
+ sc->ep_connectors |= UTP;
+ }
+ if (!sc->ep_connectors)
+ printf("no connectors!");
+
+ /*
+ * Read the station address from the eeprom
+ */
+ for (i = 0; i < 3; i++) {
+ u_short *p;
+ GO_WINDOW(0);
+ if (is_eeprom_busy(is))
+ return(0);
+ outw(BASE + EP_W0_EEPROM_COMMAND, READ_EEPROM | i);
+ if (is_eeprom_busy(is))
+ return(0);
+ p =(u_short *)&sc->arpcom.ac_enaddr[i*2];
+ *p = htons(inw(BASE + EP_W0_EEPROM_DATA));
+ GO_WINDOW(2);
+ outw(BASE + EP_W2_ADDR_0 + (i * 2), ntohs(*p));
+ }
+ printf(" address %s\n", ether_sprintf(sc->arpcom.ac_enaddr));
+
+ ifp->if_unit = is->id_unit;
+ ifp->if_name = "ep";
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
+ ifp->if_init = epinit;
+ ifp->if_output = ether_output;
+ ifp->if_start = epstart;
+ ifp->if_ioctl = epioctl;
+ ifp->if_watchdog = epwatchdog;
+
+ if_attach(ifp);
+
+ /*
+ * Fill the hardware address into ifa_addr if we find an
+ * AF_LINK entry. We need to do this so bpf's can get the hardware
+ * addr of this card. netstat likes this too!
+ */
+ ifa = ifp->if_addrlist;
+ while ((ifa != 0) && (ifa->ifa_addr != 0) &&
+ (ifa->ifa_addr->sa_family != AF_LINK))
+ ifa = ifa->ifa_next;
+
+ if ((ifa != 0) && (ifa->ifa_addr != 0)) {
+ sdl = (struct sockaddr_dl *) ifa->ifa_addr;
+ sdl->sdl_type = IFT_ETHER;
+ sdl->sdl_alen = ETHER_ADDR_LEN;
+ sdl->sdl_slen = 0;
+ bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN);
+ }
+#if NBPFILTER > 0
+ bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+ return 1;
+}
+
+
+/*
+ * The order in here seems important. Otherwise we may not receive
+ * interrupts. ?!
+ */
+void
+epinit(unit)
+ int unit;
+{
+ register struct ep_softc *sc = &ep_softc[unit];
+ register struct ifnet *ifp = &sc->arpcom.ac_if;
+ int s, i;
+
+ if (ifp->if_addrlist == (struct ifaddr *) 0)
+ return;
+
+ s = splimp();
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+ ;
+
+ GO_WINDOW(0);
+
+ /* Disable the card */
+ outw(BASE + EP_W0_CONFIG_CTRL, 0);
+
+ /* Enable the card */
+ outw(BASE + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ);
+
+ GO_WINDOW(2);
+
+ /* Reload the ether_addr. */
+ for (i = 0; i < 6; i++)
+ outb(BASE + EP_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]);
+
+ outw(BASE + EP_COMMAND, RX_RESET);
+ outw(BASE + EP_COMMAND, TX_RESET);
+
+ /* Window 1 is operating window */
+ GO_WINDOW(1);
+ for (i = 0; i < 31; i++)
+ inb(BASE + EP_W1_TX_STATUS);
+
+ /* get rid of stray intr's */
+ outw(BASE + EP_COMMAND, ACK_INTR | 0xff);
+
+ outw(BASE + EP_COMMAND, SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
+ S_TX_COMPLETE | S_TX_AVAIL);
+ outw(BASE + EP_COMMAND, SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
+ S_TX_COMPLETE | S_TX_AVAIL);
+
+ outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
+ FIL_GROUP | FIL_BRDCST);
+
+ /*
+ * you can `ifconfig (link0|-link0) ep0' to get the following
+ * behaviour:
+ * -link0 disable AUI/UTP. enable BNC.
+ * link0 disable BNC. enable AUI. if the card has a UTP
+ * connector, that is enabled too. not sure, but it
+ * seems you have to be careful to not plug things
+ * into both AUI & UTP.
+ */
+#if defined(__NetBSD__)
+ if (!(ifp->if_flags & IFF_LINK0) && (sc->ep_connectors & BNC)) {
+#else
+ if (!(ifp->if_flags & IFF_ALTPHYS) && (sc->ep_connectors & BNC)) {
+#endif
+ outw(BASE + EP_COMMAND, START_TRANSCEIVER);
+ DELAY(1000);
+ }
+#if defined(__NetBSD__)
+ if ((ifp->if_flags & IFF_LINK0) && (sc->ep_connectors & UTP)) {
+#else
+ if ((ifp->if_flags & IFF_ALTPHYS) && (sc->ep_connectors & UTP)) {
+#endif
+ GO_WINDOW(4);
+ outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP);
+ GO_WINDOW(1);
+ }
+
+ outw(BASE + EP_COMMAND, RX_ENABLE);
+ outw(BASE + EP_COMMAND, TX_ENABLE);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE; /* just in case */
+ sc->tx_start_thresh = 20; /* probably a good starting point. */
+ /*
+ * Store up a bunch of mbuf's for use later. (MAX_MBS). First we
+ * free up any that we had in case we're being called from intr or
+ * somewhere else.
+ */
+ sc->last_mb = 0;
+ sc->next_mb = 0;
+ epmbuffill((caddr_t)sc, 0);
+
+ epstart(ifp);
+
+ splx(s);
+}
+
+static const char padmap[] = {0, 3, 2, 1};
+
+void
+epstart(ifp)
+ struct ifnet *ifp;
+{
+ register struct ep_softc *sc = &ep_softc[ifp->if_unit];
+ struct mbuf *m, *top;
+ int s, len, pad;
+
+ s = splimp();
+ if (sc->arpcom.ac_if.if_flags & IFF_OACTIVE) {
+ splx(s);
+ return;
+ }
+
+startagain:
+ /* Sneak a peek at the next packet */
+ m = sc->arpcom.ac_if.if_snd.ifq_head;
+ if (m == 0) {
+ splx(s);
+ return;
+ }
+#if 0
+ len = m->m_pkthdr.len;
+#else
+ for (len = 0, top = m; m; m = m->m_next)
+ len += m->m_len;
+#endif
+
+ pad = padmap[len & 3];
+
+ /*
+ * The 3c509 automatically pads short packets to minimum ethernet
+ * length, but we drop packets that are too large. Perhaps we should
+ * truncate them instead?
+ */
+ if (len + pad > ETHER_MAX_LEN) {
+ /* packet is obviously too large: toss it */
+ ++sc->arpcom.ac_if.if_oerrors;
+ IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
+ m_freem(m);
+ goto readcheck;
+ }
+
+ if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) {
+ /* no room in FIFO */
+ outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | (len + pad + 4));
+ sc->arpcom.ac_if.if_flags |= IFF_OACTIVE;
+ splx(s);
+ return;
+ }
+ IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
+ if (m == 0) { /* not really needed */
+ splx(s);
+ return;
+ }
+ outw(BASE + EP_COMMAND, SET_TX_START_THRESH |
+ (len / 4 + sc->tx_start_thresh));
+
+ outw(BASE + EP_W1_TX_PIO_WR_1, len);
+ outw(BASE + EP_W1_TX_PIO_WR_1, 0xffff); /* Second dword meaningless */
+
+ for (top = m; m != 0; m = m->m_next) {
+ if (sc->bus32bit) {
+ outsl(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t),
+ m->m_len/4);
+ if (m->m_len & 3)
+ outsb(BASE + EP_W1_TX_PIO_WR_1,
+ mtod(m, caddr_t) + m->m_len/4,
+ m->m_len & 3);
+ } else {
+ outsw(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len/2);
+ if (m->m_len & 1)
+ outb(BASE + EP_W1_TX_PIO_WR_1,
+ *(mtod(m, caddr_t) + m->m_len - 1));
+ }
+ }
+ while (pad--)
+ outb(BASE + EP_W1_TX_PIO_WR_1, 0); /* Padding */
+
+#if NBPFILTER > 0
+ if (sc->bpf) {
+ u_short etype;
+ int off, datasize, resid;
+ struct ether_header *eh;
+ struct trailer_header {
+ u_short ether_type;
+ u_short ether_residual;
+ } trailer_header;
+ char ether_packet[ETHER_MAX_LEN];
+ char *ep;
+
+ ep = ether_packet;
+
+ /*
+ * We handle trailers below:
+ * Copy ether header first, then residual data,
+ * then data. Put all this in a temporary buffer
+ * 'ether_packet' and send off to bpf. Since the
+ * system has generated this packet, we assume
+ * that all of the offsets in the packet are
+ * correct; if they're not, the system will almost
+ * certainly crash in m_copydata.
+ * We make no assumptions about how the data is
+ * arranged in the mbuf chain (i.e. how much
+ * data is in each mbuf, if mbuf clusters are
+ * used, etc.), which is why we use m_copydata
+ * to get the ether header rather than assume
+ * that this is located in the first mbuf.
+ */
+ /* copy ether header */
+ m_copydata(top, 0, sizeof(struct ether_header), ep);
+ eh = (struct ether_header *) ep;
+ ep += sizeof(struct ether_header);
+ eh->ether_type = etype = ntohs(eh->ether_type);
+ if (etype >= ETHERTYPE_TRAIL &&
+ etype < ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER) {
+ datasize = ((etype - ETHERTYPE_TRAIL) << 9);
+ off = datasize + sizeof(struct ether_header);
+
+ /* copy trailer_header into a data structure */
+ m_copydata(top, off, sizeof(struct trailer_header),
+ (caddr_t)&trailer_header.ether_type);
+
+ /* copy residual data */
+ resid = trailer_header.ether_residual -
+ sizeof(struct trailer_header);
+ resid = ntohs(resid);
+ m_copydata(top, off + sizeof(struct trailer_header),
+ resid, ep);
+ ep += resid;
+
+ /* copy data */
+ m_copydata(top, sizeof(struct ether_header),
+ datasize, ep);
+ ep += datasize;
+
+ /* restore original ether packet type */
+ eh->ether_type = trailer_header.ether_type;
+
+ bpf_tap(sc->bpf, ether_packet, ep - ether_packet);
+ } else
+ bpf_mtap(sc->bpf, top);
+ }
+#endif
+
+ m_freem(top);
+ ++sc->arpcom.ac_if.if_opackets;
+
+ /*
+ * Is another packet coming in? We don't want to overflow the
+ * tiny RX fifo.
+ */
+readcheck:
+ if (inw(BASE + EP_W1_RX_STATUS) & RX_BYTES_MASK) {
+ splx(s);
+ return;
+ }
+ goto startagain;
+}
+
+void
+epintr(unit)
+ int unit;
+{
+ int status, i;
+ register struct ep_softc *sc = &ep_softc[unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mbuf *m;
+
+ status = 0;
+checkintr:
+ status = inw(BASE + EP_STATUS) &
+ (S_TX_COMPLETE | S_TX_AVAIL | S_RX_COMPLETE | S_CARD_FAILURE);
+ if (status == 0) {
+ /* No interrupts. */
+ outw(BASE + EP_COMMAND, C_INTR_LATCH);
+ return;
+ }
+ /* important that we do this first. */
+ outw(BASE + EP_COMMAND, ACK_INTR | status);
+
+ if (status & S_TX_AVAIL) {
+ status &= ~S_TX_AVAIL;
+ inw(BASE + EP_W1_FREE_TX);
+ sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+ epstart(&sc->arpcom.ac_if);
+ }
+ if (status & S_RX_COMPLETE) {
+ status &= ~S_RX_COMPLETE;
+ epread(sc);
+ }
+ if (status & S_CARD_FAILURE) {
+ printf("ep%d: reset (status: %x)\n", unit, status);
+ outw(BASE + EP_COMMAND, C_INTR_LATCH);
+ epinit(unit);
+ return;
+ }
+ if (status & S_TX_COMPLETE) {
+ status &= ~S_TX_COMPLETE;
+ /*
+ * We need to read TX_STATUS until we get a 0 status in
+ * order to turn off the interrupt flag.
+ */
+ while ((i = inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE) {
+ outw(BASE + EP_W1_TX_STATUS, 0x0);
+ if (i & (TXS_MAX_COLLISION | TXS_JABBER | TXS_UNDERRUN)) {
+ if (i & TXS_MAX_COLLISION)
+ ++sc->arpcom.ac_if.if_collisions;
+ if (i & (TXS_JABBER | TXS_UNDERRUN)) {
+ outw(BASE + EP_COMMAND, TX_RESET);
+ if (i & TXS_UNDERRUN) {
+ if (sc->tx_start_thresh < ETHER_MAX_LEN) {
+ sc->tx_start_thresh += 20;
+ outw(BASE + EP_COMMAND,
+ SET_TX_START_THRESH |
+ sc->tx_start_thresh);
+ }
+ }
+ }
+ outw(BASE + EP_COMMAND, TX_ENABLE);
+ ++sc->arpcom.ac_if.if_oerrors;
+ }
+ }
+ epstart(ifp);
+ }
+ goto checkintr;
+}
+
+void
+epread(sc)
+ register struct ep_softc *sc;
+{
+ struct ether_header *eh;
+ struct mbuf *mcur, *m, *m0, *top;
+ int totlen, lenthisone;
+ int save_totlen;
+ u_short etype;
+ int off, resid;
+ int count, spinwait;
+ int i;
+
+ totlen = inw(BASE + EP_W1_RX_STATUS);
+ off = 0;
+ top = 0;
+
+ if (totlen & ERR_RX) {
+ ++sc->arpcom.ac_if.if_ierrors;
+ goto out;
+ }
+ save_totlen = totlen &= RX_BYTES_MASK; /* Lower 11 bits = RX bytes. */
+
+ m = sc->mb[sc->next_mb];
+ sc->mb[sc->next_mb] = 0;
+
+ if (m == 0) {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ goto out;
+ } else {
+ /* Convert one of our saved mbuf's */
+ sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
+ m->m_data = m->m_pktdat;
+ m->m_flags = M_PKTHDR;
+ }
+
+ top = m0 = m; /* We assign top so we can "goto out" */
+#define EROUND ((sizeof(struct ether_header) + 3) & ~3)
+#define EOFF (EROUND - sizeof(struct ether_header))
+ m0->m_data += EOFF;
+ /* Read what should be the header. */
+ insw(BASE + EP_W1_RX_PIO_RD_1,
+ mtod(m0, caddr_t), sizeof(struct ether_header) / 2);
+ m->m_len = sizeof(struct ether_header);
+ totlen -= sizeof(struct ether_header);
+ /*
+ * mostly deal with trailer here. (untested)
+ * We do this in a couple of parts. First we check for a trailer, if
+ * we have one we convert the mbuf back to a regular mbuf and set the offset and
+ * subtract sizeof(struct ether_header) from the pktlen.
+ * After we've read the packet off the interface (all except for the trailer
+ * header, we then get a header mbuf, read the trailer into it, and fix up
+ * the mbuf pointer chain.
+ */
+ eh = mtod(m, struct ether_header *);
+ eh->ether_type = etype = ntohs((u_short) eh->ether_type);
+ if (etype >= ETHERTYPE_TRAIL &&
+ etype < ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER) {
+ m->m_data = m->m_dat; /* Convert back to regular mbuf. */
+ m->m_flags = 0; /* This sucks but non-trailers are the norm */
+ off = (etype - ETHERTYPE_TRAIL) * 512;
+ if (off >= ETHERMTU) {
+ m_freem(m);
+ return; /* sanity */
+ }
+ totlen -= sizeof(struct ether_header); /* We don't read the trailer */
+ m->m_data += 2 * sizeof(u_short); /* Get rid of type & len */
+ }
+ while (totlen > 0) {
+ lenthisone = min(totlen, M_TRAILINGSPACE(m));
+ if (lenthisone == 0) { /* no room in this one */
+ mcur = m;
+ m = sc->mb[sc->next_mb];
+ sc->mb[sc->next_mb] = 0;
+ if (!m) {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ goto out;
+ } else {
+ timeout(epmbuffill, (caddr_t)sc, 0);
+ sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
+ }
+ if (totlen >= MINCLSIZE)
+ MCLGET(m, M_DONTWAIT);
+ m->m_len = 0;
+ mcur->m_next = m;
+ lenthisone = min(totlen, M_TRAILINGSPACE(m));
+ }
+ if (sc->bus32bit) {
+ insl(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
+ lenthisone / 4);
+ m->m_len += (lenthisone & ~3);
+ if (lenthisone & 3)
+ insb(BASE + EP_W1_RX_PIO_RD_1,
+ mtod(m, caddr_t) + m->m_len,
+ lenthisone & 3);
+ m->m_len += (lenthisone & 3);
+ } else {
+ insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
+ lenthisone / 2);
+ m->m_len += lenthisone;
+ if (lenthisone & 1)
+ *(mtod(m, caddr_t) + m->m_len - 1) = inb(BASE + EP_W1_RX_PIO_RD_1);
+ }
+ totlen -= lenthisone;
+ }
+ if (off) {
+ top = sc->mb[sc->next_mb];
+ sc->mb[sc->next_mb] = 0;
+ if (top == 0) {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (top == 0) {
+ top = m0;
+ goto out;
+ }
+ } else {
+ /* Convert one of our saved mbuf's */
+ sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
+ top->m_data = top->m_pktdat;
+ top->m_flags = M_PKTHDR;
+ }
+ insw(BASE + EP_W1_RX_PIO_RD_1, mtod(top, caddr_t),
+ sizeof(struct ether_header));
+ top->m_next = m0;
+ top->m_len = sizeof(struct ether_header);
+ /* XXX Accomodate for type and len from beginning of trailer */
+ top->m_pkthdr.len = save_totlen - (2 * sizeof(u_short));
+ } else {
+ top = m0;
+ top->m_pkthdr.len = save_totlen;
+ }
+
+ top->m_pkthdr.rcvif = &sc->arpcom.ac_if;
+ outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+ ;
+ ++sc->arpcom.ac_if.if_ipackets;
+#if NBPFILTER > 0
+ if (sc->bpf) {
+ bpf_mtap(sc->bpf, top);
+
+ /*
+ * Note that the interface cannot be in promiscuous mode if
+ * there are no BPF listeners. And if we are in promiscuous
+ * mode, we have to check if this packet is really ours.
+ */
+ if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) &&
+ (eh->ether_dhost[0] & 1) == 0 &&
+ bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
+ sizeof(eh->ether_dhost)) != 0 &&
+ bcmp(eh->ether_dhost, etherbroadcastaddr,
+ sizeof(eh->ether_dhost)) != 0) {
+ m_freem(top);
+ return;
+ }
+ }
+#endif
+ m_adj(top, sizeof(struct ether_header));
+ ether_input(&sc->arpcom.ac_if, eh, top);
+ return;
+
+out: outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+ ;
+ if (top)
+ m_freem(top);
+
+}
+
+
+/*
+ * Look familiar?
+ */
+static int
+epioctl(ifp, cmd, data)
+ register struct ifnet *ifp;
+ int cmd;
+ caddr_t data;
+{
+ register struct ifaddr *ifa = (struct ifaddr *) data;
+ struct ep_softc *sc = &ep_softc[ifp->if_unit];
+ struct ifreq *ifr = (struct ifreq *) data;
+ int s, error = 0;
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ epinit(ifp->if_unit); /* before arpwhohas */
+ ((struct arpcom *) ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
+ arpwhohas((struct arpcom *) ifp, &IA_SIN(ifa)->sin_addr);
+ break;
+#endif
+#ifdef NS
+ case AF_NS:
+ {
+ register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+
+ if (ns_nullhost(*ina))
+ ina->x_host =
+ *(union ns_host *)(sc->arpcom.ac_enaddr);
+ else {
+ ifp->if_flags &= ~IFF_RUNNING;
+ bcopy((caddr_t) ina->x_host.c_host,
+ (caddr_t)sc->arpcom.ac_enaddr,
+ sizeof(sc->arpcom.ac_enaddr));
+ }
+ epinit(ifp->if_unit);
+ break;
+ }
+#endif
+ default:
+ epinit(ifp->if_unit);
+ break;
+ }
+ break;
+ case SIOCSIFFLAGS:
+ if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) {
+ ifp->if_flags &= ~IFF_RUNNING;
+ epstop(ifp->if_unit);
+ epmbufempty(sc);
+ break;
+ }
+ if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0)
+ epinit(ifp->if_unit);
+ break;
+#ifdef notdef
+ case SIOCGHWADDR:
+ bcopy((caddr_t) sc->sc_addr, (caddr_t) &ifr->ifr_data,
+ sizeof(sc->sc_addr));
+ break;
+#endif
+ default:
+ error = EINVAL;
+ }
+ return (error);
+}
+
+void
+epreset(unit)
+ int unit;
+{
+ int s = splimp();
+
+ epstop(unit);
+ epinit(unit);
+ splx(s);
+}
+
+void
+epwatchdog(unit)
+ int unit;
+{
+ struct ep_softc *sc = &ep_softc[unit];
+
+ log(LOG_ERR, "ep%d: watchdog\n", unit);
+ ++sc->arpcom.ac_if.if_oerrors;
+
+ epreset(unit);
+}
+
+void
+epstop(unit)
+ int unit;
+{
+ struct ep_softc *sc = &ep_softc[unit];
+
+ outw(BASE + EP_COMMAND, RX_DISABLE);
+ outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+ ;
+ outw(BASE + EP_COMMAND, TX_DISABLE);
+ outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);
+ outw(BASE + EP_COMMAND, RX_RESET);
+ outw(BASE + EP_COMMAND, TX_RESET);
+ outw(BASE + EP_COMMAND, C_INTR_LATCH);
+ outw(BASE + EP_COMMAND, SET_RD_0_MASK);
+ outw(BASE + EP_COMMAND, SET_INTR_MASK);
+ outw(BASE + EP_COMMAND, SET_RX_FILTER);
+}
+
+
+/*
+ * This is adapted straight from the book. There's probably a better way.
+ */
+static int
+send_ID_sequence(port)
+ u_short port;
+{
+ char cx, al;
+
+ cx = 0x0ff;
+ al = 0x0ff;
+
+ outb(port, 0x0);
+ DELAY(1000);
+ outb(port, 0x0);
+ DELAY(1000);
+
+loop1: cx--;
+ outb(port, al);
+ if (!(al & 0x80)) {
+ al = al << 1;
+ goto loop1;
+ }
+ al = al << 1;
+ al ^= 0xcf;
+ if (cx)
+ goto loop1;
+
+ return(1);
+}
+
+
+/*
+ * We get eeprom data from the id_port given an offset into the
+ * eeprom. Basically; after the ID_sequence is sent to all of
+ * the cards; they enter the ID_CMD state where they will accept
+ * command requests. 0x80-0xbf loads the eeprom data. We then
+ * read the port 16 times and with every read; the cards check
+ * for contention (ie: if one card writes a 0 bit and another
+ * writes a 1 bit then the host sees a 0. At the end of the cycle;
+ * each card compares the data on the bus; if there is a difference
+ * then that card goes into ID_WAIT state again). In the meantime;
+ * one bit of data is returned in the AX register which is conveniently
+ * returned to us by inb(). Hence; we read 16 times getting one
+ * bit of data with each read.
+ */
+static u_short
+get_eeprom_data(id_port, offset)
+ int id_port;
+ int offset;
+{
+ int i, data = 0;
+ outb(id_port, 0x80 + offset);
+ DELAY(1000);
+ for (i = 0; i < 16; i++)
+ data = (data << 1) | (inw(id_port) & 1);
+ return (data);
+}
+
+static int
+is_eeprom_busy(is)
+ struct isa_device *is;
+{
+ int i = 0, j;
+ register struct ep_softc *sc = &ep_softc[is->id_unit];
+
+ while (i++ < 100) {
+ j = inw(BASE + EP_W0_EEPROM_COMMAND);
+ if (j & EEPROM_BUSY)
+ DELAY(100);
+ else
+ break;
+ }
+ if (i >= 100) {
+ printf("\nep%d: eeprom failed to come ready.\n", is->id_unit);
+ return (1);
+ }
+ if (j & EEPROM_TST_MODE) {
+ printf("\nep%d: 3c509 in test mode. Erase pencil mark!\n", is->id_unit);
+ return (1);
+ }
+ return (0);
+}
+
+void
+epmbuffill(sp, dummy_arg)
+ caddr_t sp;
+ int dummy_arg;
+{
+ struct ep_softc *sc = (struct ep_softc *)sp;
+ int s, i;
+
+ s = splimp();
+ i = sc->last_mb;
+ do {
+ if(sc->mb[i] == NULL)
+ MGET(sc->mb[i], M_DONTWAIT, MT_DATA);
+ if(sc->mb[i] == NULL)
+ break;
+ i = (i + 1) % MAX_MBS;
+ } while (i != sc->next_mb);
+ sc->last_mb = i;
+ splx(s);
+}
+
+static void
+epmbufempty(sc)
+ struct ep_softc *sc;
+{
+ int s, i;
+
+ s = splimp();
+ for (i = 0; i<MAX_MBS; i++) {
+ if (sc->mb[i]) {
+ m_freem(sc->mb[i]);
+ sc->mb[i] = NULL;
+ }
+ }
+ sc->last_mb = sc->next_mb = 0;
+ untimeout(epmbuffill, sc);
+ splx(s);
+}
+
+#endif /* NEP > 0 */
diff --git a/sys/dev/ep/if_epreg.h b/sys/dev/ep/if_epreg.h
new file mode 100644
index 0000000..f0b4cd9
--- /dev/null
+++ b/sys/dev/ep/if_epreg.h
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 1993 Herb Peyerl (hpeyerl@novatel.ca)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: if_epreg.h,v 1.1 1993/12/14 04:26:47 hpeyerl Exp $
+ */
+/**************************************************************************
+ * *
+ * These define the EEPROM data structure. They are used in the probe
+ * function to verify the existance of the adapter after having sent
+ * the ID_Sequence.
+ *
+ * There are others but only the ones we use are defined here.
+ *
+ **************************************************************************/
+
+#define EEPROM_NODE_ADDR_0 0x0 /* Word */
+#define EEPROM_NODE_ADDR_1 0x1 /* Word */
+#define EEPROM_NODE_ADDR_2 0x2 /* Word */
+#define EEPROM_PROD_ID 0x3 /* 0x9[0-f]50 */
+#define EEPROM_MFG_ID 0x7 /* 0x6d50 */
+#define EEPROM_ADDR_CFG 0x8 /* Base addr */
+#define EEPROM_RESOURCE_CFG 0x9 /* IRQ. Bits 12-15 */
+
+/**************************************************************************
+ * *
+ * These are the registers for the 3Com 3c509 and their bit patterns when *
+ * applicable. They have been taken out the the "EtherLink III Parallel *
+ * Tasking EISA and ISA Technical Reference" "Beta Draft 10/30/92" manual *
+ * from 3com. *
+ * *
+ **************************************************************************/
+
+#define EP_COMMAND 0x0e /* Write. BASE+0x0e is always a command reg. */
+#define EP_STATUS 0x0e /* Read. BASE+0x0e is always status reg. */
+#define EP_WINDOW 0x0f /* Read. BASE+0x0f is always window reg. */
+/*
+ * Window 0 registers. Setup.
+ */
+ /* Write */
+#define EP_W0_EEPROM_DATA 0x0c
+#define EP_W0_EEPROM_COMMAND 0x0a
+#define EP_W0_RESOURCE_CFG 0x08
+#define EP_W0_ADDRESS_CFG 0x06
+#define EP_W0_CONFIG_CTRL 0x04
+ /* Read */
+#define EP_W0_PRODUCT_ID 0x02
+#define EP_W0_MFG_ID 0x00
+
+/*
+ * Window 1 registers. Operating Set.
+ */
+ /* Write */
+#define EP_W1_TX_PIO_WR_2 0x02
+#define EP_W1_TX_PIO_WR_1 0x00
+ /* Read */
+#define EP_W1_FREE_TX 0x0c
+#define EP_W1_TX_STATUS 0x0b /* byte */
+#define EP_W1_TIMER 0x0a /* byte */
+#define EP_W1_RX_STATUS 0x08
+#define EP_W1_RX_PIO_RD_2 0x02
+#define EP_W1_RX_PIO_RD_1 0x00
+
+/*
+ * Window 2 registers. Station Address Setup/Read
+ */
+ /* Read/Write */
+#define EP_W2_ADDR_5 0x05
+#define EP_W2_ADDR_4 0x04
+#define EP_W2_ADDR_3 0x03
+#define EP_W2_ADDR_2 0x02
+#define EP_W2_ADDR_1 0x01
+#define EP_W2_ADDR_0 0x00
+
+/*
+ * Window 3 registers. FIFO Management.
+ */
+ /* Read */
+#define EP_W3_FREE_TX 0x0c
+#define EP_W3_FREE_RX 0x0a
+
+/*
+ * Window 4 registers. Diagnostics.
+ */
+ /* Read/Write */
+#define EP_W4_MEDIA_TYPE 0x0a
+#define EP_W4_CTRLR_STATUS 0x08
+#define EP_W4_NET_DIAG 0x06
+#define EP_W4_FIFO_DIAG 0x04
+#define EP_W4_HOST_DIAG 0x02
+#define EP_W4_TX_DIAG 0x00
+
+/*
+ * Window 5 Registers. Results and Internal status.
+ */
+ /* Read */
+#define EP_W5_READ_0_MASK 0x0c
+#define EP_W5_INTR_MASK 0x0a
+#define EP_W5_RX_FILTER 0x08
+#define EP_W5_RX_EARLY_THRESH 0x06
+#define EP_W5_TX_AVAIL_THRESH 0x02
+#define EP_W5_TX_START_THRESH 0x00
+
+/*
+ * Window 6 registers. Statistics.
+ */
+ /* Read/Write */
+#define TX_TOTAL_OK 0x0c
+#define RX_TOTAL_OK 0x0a
+#define TX_DEFERRALS 0x08
+#define RX_FRAMES_OK 0x07
+#define TX_FRAMES_OK 0x06
+#define RX_OVERRUNS 0x05
+#define TX_COLLISIONS 0x04
+#define TX_AFTER_1_COLLISION 0x03
+#define TX_AFTER_X_COLLISIONS 0x02
+#define TX_NO_SQE 0x01
+#define TX_CD_LOST 0x00
+
+/****************************************
+ *
+ * Register definitions.
+ *
+ ****************************************/
+
+/*
+ * Command register. All windows.
+ *
+ * 16 bit register.
+ * 15-11: 5-bit code for command to be executed.
+ * 10-0: 11-bit arg if any. For commands with no args;
+ * this can be set to anything.
+ */
+#define GLOBAL_RESET (u_short) 0x0000 /* Wait at least 1ms after issuing */
+#define WINDOW_SELECT (u_short) (0x1<<11)
+#define START_TRANSCEIVER (u_short) (0x2<<11) /* Read ADDR_CFG reg to determine
+ whether this is needed. If so;
+ wait 800 uSec before using trans-
+ ceiver. */
+#define RX_DISABLE (u_short) (0x3<<11) /* state disabled on power-up */
+#define RX_ENABLE (u_short) (0x4<<11)
+#define RX_RESET (u_short) (0x5<<11)
+#define RX_DISCARD_TOP_PACK (u_short) (0x8<<11)
+#define TX_ENABLE (u_short) (0x9<<11)
+#define TX_DISABLE (u_short) (0xa<<11)
+#define TX_RESET (u_short) (0xb<<11)
+#define REQ_INTR (u_short) (0xc<<11)
+ /*
+ * The following C_* acknowledge the various interrupts.
+ * Some of them don't do anything. See the manual.
+ */
+#define ACK_INTR (u_short) (0x6800)
+# define C_INTR_LATCH (u_short) (ACK_INTR|0x1)
+# define C_CARD_FAILURE (u_short) (ACK_INTR|0x2)
+# define C_TX_COMPLETE (u_short) (ACK_INTR|0x4)
+# define C_TX_AVAIL (u_short) (ACK_INTR|0x8)
+# define C_RX_COMPLETE (u_short) (ACK_INTR|0x10)
+# define C_RX_EARLY (u_short) (ACK_INTR|0x20)
+# define C_INT_RQD (u_short) (ACK_INTR|0x40)
+# define C_UPD_STATS (u_short) (ACK_INTR|0x80)
+#define SET_INTR_MASK (u_short) (0xe<<11)
+#define SET_RD_0_MASK (u_short) (0xf<<11)
+#define SET_RX_FILTER (u_short) (0x10<<11)
+# define FIL_INDIVIDUAL (u_short) (0x1)
+# define FIL_GROUP (u_short) (0x2)
+# define FIL_BRDCST (u_short) (0x4)
+# define FIL_ALL (u_short) (0x8)
+#define SET_RX_EARLY_THRESH (u_short) (0x11<<11)
+#define SET_TX_AVAIL_THRESH (u_short) (0x12<<11)
+#define SET_TX_START_THRESH (u_short) (0x13<<11)
+#define STATS_ENABLE (u_short) (0x15<<11)
+#define STATS_DISABLE (u_short) (0x16<<11)
+#define STOP_TRANSCEIVER (u_short) (0x17<<11)
+
+/*
+ * Status register. All windows.
+ *
+ * 15-13: Window number(0-7).
+ * 12: Command_in_progress.
+ * 11: reserved.
+ * 10: reserved.
+ * 9: reserved.
+ * 8: reserved.
+ * 7: Update Statistics.
+ * 6: Interrupt Requested.
+ * 5: RX Early.
+ * 4: RX Complete.
+ * 3: TX Available.
+ * 2: TX Complete.
+ * 1: Adapter Failure.
+ * 0: Interrupt Latch.
+ */
+#define S_INTR_LATCH (u_short) (0x1)
+#define S_CARD_FAILURE (u_short) (0x2)
+#define S_TX_COMPLETE (u_short) (0x4)
+#define S_TX_AVAIL (u_short) (0x8)
+#define S_RX_COMPLETE (u_short) (0x10)
+#define S_RX_EARLY (u_short) (0x20)
+#define S_INT_RQD (u_short) (0x40)
+#define S_UPD_STATS (u_short) (0x80)
+#define S_COMMAND_IN_PROGRESS (u_short) (0x1000)
+
+/*
+ * FIFO Registers. RX Status.
+ *
+ * 15: Incomplete or FIFO empty.
+ * 14: 1: Error in RX Packet 0: Incomplete or no error.
+ * 13-11: Type of error.
+ * 1000 = Overrun.
+ * 1011 = Run Packet Error.
+ * 1100 = Alignment Error.
+ * 1101 = CRC Error.
+ * 1001 = Oversize Packet Error (>1514 bytes)
+ * 0010 = Dribble Bits.
+ * (all other error codes, no errors.)
+ *
+ * 10-0: RX Bytes (0-1514)
+ */
+#define ERR_INCOMPLETE (u_short) (0x8000)
+#define ERR_RX (u_short) (0x4000)
+#define ERR_RX_PACKET (u_short) (0x2000)
+#define ERR_OVERRUN (u_short) (0x1000)
+#define ERR_RUNT (u_short) (0x1300)
+#define ERR_ALIGNMENT (u_short) (0x1400)
+#define ERR_CRC (u_short) (0x1500)
+#define ERR_OVERSIZE (u_short) (0x1100)
+#define ERR_DRIBBLE (u_short) (0x200)
+
+/*
+ * TX Status
+ *
+ * Reports the transmit status of a completed transmission. Writing this
+ * register pops the transmit completion stack.
+ *
+ * Window 1/Port 0x0b.
+ *
+ * 7: Complete
+ * 6: Interrupt on successful transmission requested.
+ * 5: Jabber Error (TP Only, TX Reset required. )
+ * 4: Underrun (TX Reset required. )
+ * 3: Maximum Collisions.
+ * 2: TX Status Overflow.
+ * 1-0: Undefined.
+ *
+ */
+#define TXS_COMPLETE 0x80
+#define TXS_INTR_REQ 0x40
+#define TXS_JABBER 0x20
+#define TXS_UNDERRUN 0x10
+#define TXS_MAX_COLLISION 0x8
+#define TXS_STATUS_OVERFLOW 0x4
+
+/*
+ * Misc defines for various things.
+ */
+#define TAG_ADAPTER_0 0xd0
+#define ACTIVATE_ADAPTER_TO_CONFIG 0xff
+#define ENABLE_DRQ_IRQ 0x0001
+#define MFG_ID 0x6d50
+#define PROD_ID 0x9150
+#define BASE sc->ep_io_addr
+#define GO_WINDOW(x) outw(BASE+EP_COMMAND, WINDOW_SELECT|x)
+#define AUI 0x1
+#define BNC 0x2
+#define UTP 0x4
+#define IS_AUI (1<<13)
+#define IS_BNC (1<<12)
+#define IS_UTP (1<<9)
+#define EEPROM_BUSY (1<<15)
+#define EEPROM_TST_MODE (1<<14)
+#define READ_EEPROM (1<<7)
+#define ETHER_ADDR_LEN 6
+#define ETHER_MAX 1536
+#define ENABLE_UTP 0xc0
+#define DISABLE_UTP 0x0
+#define RX_BYTES_MASK (u_short) (0x07ff)
diff --git a/sys/dev/fdc/fdc.c b/sys/dev/fdc/fdc.c
new file mode 100644
index 0000000..d05c361
--- /dev/null
+++ b/sys/dev/fdc/fdc.c
@@ -0,0 +1,1255 @@
+/*#define DEBUG 1*/
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)fd.c 7.4 (Berkeley) 5/25/91
+ * $Id: fd.c,v 1.24 1994/03/08 16:25:29 nate Exp $
+ *
+ */
+
+#include "ft.h"
+#if NFT < 1
+#undef NFDC
+#endif
+#include "fd.h"
+
+#if NFDC > 0
+
+#include <sys/param.h>
+#include <sys/dkbad.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <machine/ioctl_fd.h>
+#include <sys/disklabel.h>
+#include <sys/buf.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+#include <sys/syslog.h>
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/fdreg.h"
+#include "i386/isa/fdc.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/rtc.h"
+
+#if NFT > 0
+extern int ftopen(), ftintr(), ftattach(), ftclose(), ftioctl();
+#endif
+
+#define b_cylin b_resid
+#define FDBLK 512
+
+/* misuse a flag to identify format operation */
+#define B_FORMAT B_XXX
+
+#define NUMTYPES 14
+#define NUMDENS (NUMTYPES - 6)
+
+/* This defines (-1) must match index for fd_types */
+#define F_TAPE_TYPE 0x020 /* bit for fd_types to indicate tape */
+#define NO_TYPE 0 /* must match NO_TYPE in ft.c */
+#define FD_1720 1
+#define FD_1480 2
+#define FD_1440 3
+#define FD_1200 4
+#define FD_820 5
+#define FD_800 6
+#define FD_720 7
+#define FD_360 8
+
+#define FD_1480in5_25 9
+#define FD_1440in5_25 10
+#define FD_820in5_25 11
+#define FD_800in5_25 12
+#define FD_720in5_25 13
+#define FD_360in5_25 14
+
+
+struct fd_type fd_types[NUMTYPES] =
+{
+{ 21,2,0xFF,0x04,82,3444,1,FDC_500KBPS,2,0x0C,2 }, /* 1.72M in HD 3.5in */
+{ 18,2,0xFF,0x1B,82,2952,1,FDC_500KBPS,2,0x6C,1 }, /* 1.48M in HD 3.5in */
+{ 18,2,0xFF,0x1B,80,2880,1,FDC_500KBPS,2,0x6C,1 }, /* 1.44M in HD 3.5in */
+{ 15,2,0xFF,0x1B,80,2400,1,FDC_500KBPS,2,0x54,1 }, /* 1.2M in HD 5.25/3.5 */
+{ 10,2,0xFF,0x10,82,1640,1,FDC_250KBPS,2,0x2E,1 }, /* 820K in HD 3.5in */
+{ 10,2,0xFF,0x10,80,1600,1,FDC_250KBPS,2,0x2E,1 }, /* 800K in HD 3.5in */
+{ 9,2,0xFF,0x20,80,1440,1,FDC_250KBPS,2,0x50,1 }, /* 720K in HD 3.5in */
+{ 9,2,0xFF,0x2A,40, 720,1,FDC_250KBPS,2,0x50,1 }, /* 360K in DD 5.25in */
+
+{ 18,2,0xFF,0x02,82,2952,1,FDC_500KBPS,2,0x02,2 }, /* 1.48M in HD 5.25in */
+{ 18,2,0xFF,0x02,80,2880,1,FDC_500KBPS,2,0x02,2 }, /* 1.44M in HD 5.25in */
+{ 10,2,0xFF,0x10,82,1640,1,FDC_300KBPS,2,0x2E,1 }, /* 820K in HD 5.25in */
+{ 10,2,0xFF,0x10,80,1600,1,FDC_300KBPS,2,0x2E,1 }, /* 800K in HD 5.25in */
+{ 9,2,0xFF,0x20,80,1440,1,FDC_300KBPS,2,0x50,1 }, /* 720K in HD 5.25in */
+{ 9,2,0xFF,0x23,40, 720,2,FDC_300KBPS,2,0x50,1 }, /* 360K in HD 5.25in */
+};
+
+#define DRVS_PER_CTLR 2 /* 2 floppies */
+/***********************************************************************\
+* Per controller structure. *
+\***********************************************************************/
+struct fdc_data fdc_data[NFDC];
+
+/***********************************************************************\
+* Per drive structure. *
+* N per controller (DRVS_PER_CTLR) *
+\***********************************************************************/
+struct fd_data {
+ struct fdc_data *fdc; /* pointer to controller structure */
+ int fdsu; /* this units number on this controller */
+ int type; /* Drive type (HD, DD */
+ struct fd_type *ft; /* pointer to the type descriptor */
+ int flags;
+#define FD_OPEN 0x01 /* it's open */
+#define FD_ACTIVE 0x02 /* it's active */
+#define FD_MOTOR 0x04 /* motor should be on */
+#define FD_MOTOR_WAIT 0x08 /* motor coming up */
+ int skip;
+ int hddrv;
+ int track; /* where we think the head is */
+} fd_data[NFD];
+
+/***********************************************************************\
+* Throughout this file the following conventions will be used: *
+* fd is a pointer to the fd_data struct for the drive in question *
+* fdc is a pointer to the fdc_data struct for the controller *
+* fdu is the floppy drive unit number *
+* fdcu is the floppy controller unit number *
+* fdsu is the floppy drive unit number on that controller. (sub-unit) *
+\***********************************************************************/
+
+#define id_physid id_scsiid /* this biotab field doubles as a field */
+ /* for the physical unit number on the controller */
+
+static int retrier(fdcu_t);
+
+#define DEVIDLE 0
+#define FINDWORK 1
+#define DOSEEK 2
+#define SEEKCOMPLETE 3
+#define IOCOMPLETE 4
+#define RECALCOMPLETE 5
+#define STARTRECAL 6
+#define RESETCTLR 7
+#define SEEKWAIT 8
+#define RECALWAIT 9
+#define MOTORWAIT 10
+#define IOTIMEDOUT 11
+
+#ifdef DEBUG
+char *fdstates[] =
+{
+"DEVIDLE",
+"FINDWORK",
+"DOSEEK",
+"SEEKCOMPLETE",
+"IOCOMPLETE",
+"RECALCOMPLETE",
+"STARTRECAL",
+"RESETCTLR",
+"SEEKWAIT",
+"RECALWAIT",
+"MOTORWAIT",
+"IOTIMEDOUT"
+};
+
+
+int fd_debug = 1;
+#define TRACE0(arg) if(fd_debug) printf(arg)
+#define TRACE1(arg1,arg2) if(fd_debug) printf(arg1,arg2)
+#else /* DEBUG */
+#define TRACE0(arg)
+#define TRACE1(arg1,arg2)
+#endif /* DEBUG */
+
+static void fdstart(fdcu_t);
+void fdintr(fdcu_t);
+static void fd_turnoff(caddr_t, int);
+
+/****************************************************************************/
+/* autoconfiguration stuff */
+/****************************************************************************/
+static int fdprobe(struct isa_device *);
+static int fdattach(struct isa_device *);
+
+struct isa_driver fdcdriver = {
+ fdprobe, fdattach, "fdc",
+};
+
+/*
+ * probe for existance of controller
+ */
+int
+fdprobe(dev)
+ struct isa_device *dev;
+{
+ fdcu_t fdcu = dev->id_unit;
+ if(fdc_data[fdcu].flags & FDC_ATTACHED)
+ {
+ printf("fdc: same unit (%d) used multiple times\n",fdcu);
+ return 0;
+ }
+
+ fdc_data[fdcu].baseport = dev->id_iobase;
+
+ /* First - lets reset the floppy controller */
+
+ outb(dev->id_iobase+fdout,0);
+ DELAY(100);
+ outb(dev->id_iobase+fdout,FDO_FRST);
+
+ /* see if it can handle a command */
+ if (out_fdc(fdcu,NE7CMD_SPECIFY) < 0)
+ {
+ return(0);
+ }
+ out_fdc(fdcu,0xDF);
+ out_fdc(fdcu,2);
+ return (IO_FDCSIZE);
+}
+
+/*
+ * wire controller into system, look for floppy units
+ */
+int
+fdattach(dev)
+ struct isa_device *dev;
+{
+ unsigned fdt,st0, cyl;
+ int hdr;
+ fdu_t fdu;
+ fdcu_t fdcu = dev->id_unit;
+ fdc_p fdc = fdc_data + fdcu;
+ fd_p fd;
+ int fdsu;
+ struct isa_device *fdup;
+
+ fdc->fdcu = fdcu;
+ fdc->flags |= FDC_ATTACHED;
+ fdc->dmachan = dev->id_drq;
+ fdc->state = DEVIDLE;
+ hdr = 0;
+ printf("fdc%d:", fdcu);
+
+ /* check for each floppy drive */
+ for (fdup = isa_biotab_fdc; fdup->id_driver != 0; fdup++) {
+ if (fdup->id_iobase != dev->id_iobase)
+ continue;
+ fdu = fdup->id_unit;
+ fd = &fd_data[fdu];
+ if (fdu >= (NFD+NFT))
+ continue;
+ fdsu = fdup->id_physid;
+ /* look up what bios thinks we have */
+ switch (fdu) {
+ case 0: fdt = (rtcin(RTC_FDISKETTE) & 0xf0);
+ break;
+ case 1: fdt = ((rtcin(RTC_FDISKETTE) << 4) & 0xf0);
+ break;
+ default: fdt = RTCFDT_NONE;
+ break;
+ }
+ /* is there a unit? */
+ if ((fdt == RTCFDT_NONE)
+#if NFT > 0
+ || (fdsu >= DRVS_PER_CTLR)) {
+#else
+ ) {
+ fd->type = NO_TYPE;
+#endif
+#if NFT > 0
+ /* If BIOS says no floppy, or > 2nd device */
+ /* Probe for and attach a floppy tape. */
+ if (ftattach(dev, fdup))
+ continue;
+ if (fdsu < DRVS_PER_CTLR)
+ fd->type = NO_TYPE;
+#endif
+ continue;
+ }
+
+#ifdef notyet
+ /* select it */
+ fd_turnon1(fdu);
+ spinwait(1000); /* 1 sec */
+ out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
+ out_fdc(fdcu,fdsu);
+ spinwait(1000); /* 1 sec */
+
+ /* anything responding */
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (st0 & 0xd0)
+ continue;
+
+#endif
+ fd->track = -2;
+ fd->fdc = fdc;
+ fd->fdsu = fdsu;
+ printf(" [%d: fd%d: ", fdsu, fdu);
+
+ switch (fdt) {
+ case RTCFDT_12M:
+ printf("1.2MB 5.25in]");
+ fd->type = FD_1200;
+ break;
+ case RTCFDT_144M:
+ printf("1.44MB 3.5in]");
+ fd->type = FD_1440;
+ break;
+ case RTCFDT_360K:
+ printf("360KB 5.25in]");
+ fd->type = FD_360;
+ break;
+ case RTCFDT_720K:
+ printf("720KB 3.5in]");
+ fd->type = FD_720;
+ break;
+ default:
+ printf("unknown]");
+ fd->type = NO_TYPE;
+ break;
+ }
+
+ fd_turnoff((caddr_t)fdu, 0);
+ hdr = 1;
+ }
+ printf("\n");
+
+ /* Set transfer to 500kbps */
+ outb(fdc->baseport+fdctl,0); /*XXX*/
+ return 1;
+}
+
+int
+fdsize(dev)
+ dev_t dev;
+{
+ return(0);
+}
+
+/****************************************************************************/
+/* fdstrategy */
+/****************************************************************************/
+void fdstrategy(struct buf *bp)
+{
+ register struct buf *dp,*dp0,*dp1;
+ long nblocks,blknum;
+ int s;
+ fdcu_t fdcu;
+ fdu_t fdu;
+ fdc_p fdc;
+ fd_p fd;
+
+ fdu = FDUNIT(minor(bp->b_dev));
+ fd = &fd_data[fdu];
+ fdc = fd->fdc;
+ fdcu = fdc->fdcu;
+
+#if NFT > 0
+ /* check for controller already busy with tape */
+ if (fdc->flags & FDC_TAPE_BUSY) {
+ bp->b_error = EBUSY;
+ bp->b_flags |= B_ERROR;
+ return;
+ }
+#endif
+ if ((fdu >= NFD) || (bp->b_blkno < 0)) {
+ printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n",
+ fdu, bp->b_blkno, bp->b_bcount);
+ pg("fd:error in fdstrategy");
+ bp->b_error = EINVAL;
+ bp->b_flags |= B_ERROR;
+ goto bad;
+ }
+ /*
+ * Set up block calculations.
+ */
+ blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK;
+ nblocks = fd->ft->size;
+ if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
+ if (blknum == nblocks) {
+ bp->b_resid = bp->b_bcount;
+ } else {
+ bp->b_error = ENOSPC;
+ bp->b_flags |= B_ERROR;
+ }
+ goto bad;
+ }
+ bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads);
+ bp->b_pblkno = bp->b_blkno;
+ dp = &(fdc->head);
+ s = splbio();
+ disksort(dp, bp);
+ untimeout(fd_turnoff, (caddr_t)fdu); /* a good idea */
+ fdstart(fdcu);
+ splx(s);
+ return;
+
+bad:
+ biodone(bp);
+ return;
+}
+
+/****************************************************************************/
+/* motor control stuff */
+/* remember to not deselect the drive we're working on */
+/****************************************************************************/
+void
+set_motor(fdcu, fdu, reset)
+ fdcu_t fdcu;
+ fdu_t fdu;
+ int reset;
+{
+ int m0,m1;
+ int selunit;
+ fd_p fd;
+ if(fd = fdc_data[fdcu].fd)/* yes an assign! */
+ {
+ selunit = fd->fdsu;
+ }
+ else
+ {
+ selunit = 0;
+ }
+ m0 = fd_data[fdcu * DRVS_PER_CTLR + 0].flags & FD_MOTOR;
+ m1 = fd_data[fdcu * DRVS_PER_CTLR + 1].flags & FD_MOTOR;
+ outb(fdc_data[fdcu].baseport+fdout,
+ selunit
+ | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
+ | (m0 ? FDO_MOEN0 : 0)
+ | (m1 ? FDO_MOEN1 : 0));
+ TRACE1("[0x%x->fdout]",(
+ selunit
+ | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
+ | (m0 ? FDO_MOEN0 : 0)
+ | (m1 ? FDO_MOEN1 : 0)));
+}
+
+static void
+fd_turnoff(caddr_t arg1, int arg2)
+{
+ fdu_t fdu = (fdu_t)arg1;
+ int s;
+
+ fd_p fd = fd_data + fdu;
+ s = splbio();
+ fd->flags &= ~FD_MOTOR;
+ set_motor(fd->fdc->fdcu,fd->fdsu,0);
+ splx(s);
+}
+
+void
+fd_motor_on(caddr_t arg1, int arg2)
+{
+ fdu_t fdu = (fdu_t)arg1;
+ int s;
+
+ fd_p fd = fd_data + fdu;
+ s = splbio();
+ fd->flags &= ~FD_MOTOR_WAIT;
+ if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT))
+ {
+ fdintr(fd->fdc->fdcu);
+ }
+ splx(s);
+}
+
+static void fd_turnon1(fdu_t);
+
+void
+fd_turnon(fdu)
+ fdu_t fdu;
+{
+ fd_p fd = fd_data + fdu;
+ if(!(fd->flags & FD_MOTOR))
+ {
+ fd_turnon1(fdu);
+ fd->flags |= FD_MOTOR_WAIT;
+ timeout(fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */
+ }
+}
+
+static void
+fd_turnon1(fdu_t fdu)
+{
+ fd_p fd = fd_data + fdu;
+ fd->flags |= FD_MOTOR;
+ set_motor(fd->fdc->fdcu,fd->fdsu,0);
+}
+
+/****************************************************************************/
+/* fdc in/out */
+/****************************************************************************/
+int
+in_fdc(fdcu)
+ fdcu_t fdcu;
+{
+ int baseport = fdc_data[fdcu].baseport;
+ int i, j = 100000;
+ while ((i = inb(baseport+fdsts) & (NE7_DIO|NE7_RQM))
+ != (NE7_DIO|NE7_RQM) && j-- > 0)
+ if (i == NE7_RQM) return -1;
+ if (j <= 0)
+ return(-1);
+#ifdef DEBUG
+ i = inb(baseport+fddata);
+ TRACE1("[fddata->0x%x]",(unsigned char)i);
+ return(i);
+#else
+ return inb(baseport+fddata);
+#endif
+}
+
+int
+out_fdc(fdcu, x)
+ fdcu_t fdcu;
+ int x;
+{
+ int baseport = fdc_data[fdcu].baseport;
+ int i;
+
+ /* Check that the direction bit is set */
+ i = 100000;
+ while ((inb(baseport+fdsts) & NE7_DIO) && i-- > 0);
+ if (i <= 0) return (-1); /* Floppy timed out */
+
+ /* Check that the floppy controller is ready for a command */
+ i = 100000;
+ while ((inb(baseport+fdsts) & NE7_RQM) == 0 && i-- > 0);
+ if (i <= 0) return (-1); /* Floppy timed out */
+
+ /* Send the command and return */
+ outb(baseport+fddata,x);
+ TRACE1("[0x%x->fddata]",x);
+ return (0);
+}
+
+/****************************************************************************/
+/* fdopen/fdclose */
+/****************************************************************************/
+int
+Fdopen(dev, flags)
+ dev_t dev;
+ int flags;
+{
+ fdu_t fdu = FDUNIT(minor(dev));
+ int type = FDTYPE(minor(dev));
+ fdc_p fdc;
+
+#if NFT > 0
+ /* check for a tape open */
+ if (type & F_TAPE_TYPE)
+ return(ftopen(dev, flags));
+#endif
+ /* check bounds */
+ if (fdu >= NFD)
+ return(ENXIO);
+ fdc = fd_data[fdu].fdc;
+ if ((fdc == NULL) || (fd_data[fdu].type == NO_TYPE))
+ return(ENXIO);
+ if (type > NUMDENS)
+ return(ENXIO);
+ if (type == 0)
+ type = fd_data[fdu].type;
+ else {
+ if (type != fd_data[fdu].type) {
+ switch (fd_data[fdu].type) {
+ case FD_360:
+ return(ENXIO);
+ case FD_720:
+ if ( type != FD_820
+ && type != FD_800
+ )
+ return(ENXIO);
+ break;
+ case FD_1200:
+ switch (type) {
+ case FD_1480:
+ type = FD_1480in5_25;
+ break;
+ case FD_1440:
+ type = FD_1440in5_25;
+ break;
+ case FD_820:
+ type = FD_820in5_25;
+ break;
+ case FD_800:
+ type = FD_800in5_25;
+ break;
+ case FD_720:
+ type = FD_720in5_25;
+ break;
+ case FD_360:
+ type = FD_360in5_25;
+ break;
+ default:
+ return(ENXIO);
+ }
+ break;
+ case FD_1440:
+ if ( type != FD_1720
+ && type != FD_1480
+ && type != FD_1200
+ && type != FD_820
+ && type != FD_800
+ && type != FD_720
+ )
+ return(ENXIO);
+ break;
+ }
+ }
+ }
+ fd_data[fdu].ft = fd_types + type - 1;
+ fd_data[fdu].flags |= FD_OPEN;
+
+ return 0;
+}
+
+int
+fdclose(dev, flags)
+ dev_t dev;
+ int flags;
+{
+ fdu_t fdu = FDUNIT(minor(dev));
+ int type = FDTYPE(minor(dev));
+
+#if NFT > 0
+ if (type & F_TAPE_TYPE)
+ return ftclose(0);
+#endif
+ fd_data[fdu].flags &= ~FD_OPEN;
+ return(0);
+}
+
+
+/***************************************************************\
+* fdstart *
+* We have just queued something.. if the controller is not busy *
+* then simulate the case where it has just finished a command *
+* So that it (the interrupt routine) looks on the queue for more*
+* work to do and picks up what we just added. *
+* If the controller is already busy, we need do nothing, as it *
+* will pick up our work when the present work completes *
+\***************************************************************/
+static void
+fdstart(fdcu)
+ fdcu_t fdcu;
+{
+ register struct buf *dp,*bp;
+ int s;
+ fdu_t fdu;
+
+ s = splbio();
+ if(fdc_data[fdcu].state == DEVIDLE)
+ {
+ fdintr(fdcu);
+ }
+ splx(s);
+}
+
+static void
+fd_timeout(caddr_t arg1, int arg2)
+{
+ fdcu_t fdcu = (fdcu_t)arg1;
+ fdu_t fdu = fdc_data[fdcu].fdu;
+ int st0, st3, cyl;
+ struct buf *dp,*bp;
+ int s;
+
+ dp = &fdc_data[fdcu].head;
+ s = splbio();
+ bp = dp->b_actf;
+
+ out_fdc(fdcu,NE7CMD_SENSED);
+ out_fdc(fdcu,fd_data[fdu].hddrv);
+ st3 = in_fdc(fdcu);
+
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ printf("fd%d: Operation timeout ST0 %b cyl %d ST3 %b\n",
+ fdu,
+ st0,
+ NE7_ST0BITS,
+ cyl,
+ st3,
+ NE7_ST3BITS);
+
+ if (bp)
+ {
+ retrier(fdcu);
+ fdc_data[fdcu].status[0] = 0xc0;
+ fdc_data[fdcu].state = IOTIMEDOUT;
+ if( fdc_data[fdcu].retry < 6)
+ fdc_data[fdcu].retry = 6;
+ }
+ else
+ {
+ fdc_data[fdcu].fd = (fd_p) 0;
+ fdc_data[fdcu].fdu = -1;
+ fdc_data[fdcu].state = DEVIDLE;
+ }
+ fdintr(fdcu);
+ splx(s);
+}
+
+/* just ensure it has the right spl */
+static void
+fd_pseudointr(caddr_t arg1, int arg2)
+{
+ fdcu_t fdcu = (fdcu_t)arg1;
+ int s;
+ s = splbio();
+ fdintr(fdcu);
+ splx(s);
+}
+
+/***********************************************************************\
+* fdintr *
+* keep calling the state machine until it returns a 0 *
+* ALWAYS called at SPLBIO *
+\***********************************************************************/
+void
+fdintr(fdcu_t fdcu)
+{
+ fdc_p fdc = fdc_data + fdcu;
+#if NFT > 0
+ fdu_t fdu = fdc->fdu;
+
+ if (fdc->flags & FDC_TAPE_BUSY)
+ (ftintr(fdu));
+ else
+#endif
+ while(fdstate(fdcu, fdc))
+ ;
+}
+
+/***********************************************************************\
+* The controller state machine. *
+* if it returns a non zero value, it should be called again immediatly *
+\***********************************************************************/
+int
+fdstate(fdcu, fdc)
+ fdcu_t fdcu;
+ fdc_p fdc;
+{
+ int read, format, head, trac, sec = 0, i = 0, s, sectrac, cyl, st0;
+ unsigned long blknum;
+ fdu_t fdu = fdc->fdu;
+ fd_p fd;
+ register struct buf *dp,*bp;
+ struct fd_formb *finfo = NULL;
+
+ dp = &(fdc->head);
+ bp = dp->b_actf;
+ if(!bp)
+ {
+ /***********************************************\
+ * nothing left for this controller to do *
+ * Force into the IDLE state, *
+ \***********************************************/
+ fdc->state = DEVIDLE;
+ if(fdc->fd)
+ {
+ printf("unexpected valid fd pointer (fdu = %d)\n"
+ ,fdc->fdu);
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ }
+ TRACE1("[fdc%d IDLE]",fdcu);
+ return(0);
+ }
+ fdu = FDUNIT(minor(bp->b_dev));
+ fd = fd_data + fdu;
+ if (fdc->fd && (fd != fdc->fd))
+ {
+ printf("confused fd pointers\n");
+ }
+ read = bp->b_flags & B_READ;
+ format = bp->b_flags & B_FORMAT;
+ if(format)
+ finfo = (struct fd_formb *)bp->b_un.b_addr;
+ TRACE1("fd%d",fdu);
+ TRACE1("[%s]",fdstates[fdc->state]);
+ TRACE1("(0x%x)",fd->flags);
+ untimeout(fd_turnoff, (caddr_t)fdu);
+ timeout(fd_turnoff, (caddr_t)fdu, 4 * hz);
+ switch (fdc->state)
+ {
+ case DEVIDLE:
+ case FINDWORK: /* we have found new work */
+ fdc->retry = 0;
+ fd->skip = 0;
+ fdc->fd = fd;
+ fdc->fdu = fdu;
+ outb(fdc->baseport+fdctl, fd->ft->trans);
+ /*******************************************************\
+ * If the next drive has a motor startup pending, then *
+ * it will start up in it's own good time *
+ \*******************************************************/
+ if(fd->flags & FD_MOTOR_WAIT)
+ {
+ fdc->state = MOTORWAIT;
+ return(0); /* come back later */
+ }
+ /*******************************************************\
+ * Maybe if it's not starting, it SHOULD be starting *
+ \*******************************************************/
+ if (!(fd->flags & FD_MOTOR))
+ {
+ fdc->state = MOTORWAIT;
+ fd_turnon(fdu);
+ return(0);
+ }
+ else /* at least make sure we are selected */
+ {
+ set_motor(fdcu,fd->fdsu,0);
+ }
+ fdc->state = DOSEEK;
+ break;
+ case DOSEEK:
+ if (bp->b_cylin == fd->track)
+ {
+ fdc->state = SEEKCOMPLETE;
+ break;
+ }
+ out_fdc(fdcu,NE7CMD_SEEK); /* Seek function */
+ out_fdc(fdcu,fd->fdsu); /* Drive number */
+ out_fdc(fdcu,bp->b_cylin * fd->ft->steptrac);
+ fd->track = -2;
+ fdc->state = SEEKWAIT;
+ timeout(fd_timeout, (caddr_t)fdcu, 2 * hz);
+ return(0); /* will return later */
+ case SEEKWAIT:
+ untimeout(fd_timeout, (caddr_t)fdcu);
+ /* allow heads to settle */
+ timeout(fd_pseudointr, (caddr_t)fdcu, hz / 50);
+ fdc->state = SEEKCOMPLETE;
+ return(0); /* will return later */
+ break;
+
+ case SEEKCOMPLETE : /* SEEK DONE, START DMA */
+ /* Make sure seek really happened*/
+ if(fd->track == -2)
+ {
+ int descyl = bp->b_cylin * fd->ft->steptrac;
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ i = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (cyl != descyl)
+ {
+ printf("fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n",
+ fdu, descyl, cyl, i, NE7_ST0BITS);
+ return(retrier(fdcu));
+ }
+ }
+
+ fd->track = bp->b_cylin;
+ if(format)
+ fd->skip = (char *)&(finfo->fd_formb_cylno(0))
+ - (char *)finfo;
+ isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip,
+ format ? bp->b_bcount : FDBLK, fdc->dmachan);
+ blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
+ + fd->skip/FDBLK;
+ sectrac = fd->ft->sectrac;
+ sec = blknum % (sectrac * fd->ft->heads);
+ head = sec / sectrac;
+ sec = sec % sectrac + 1;
+/*XXX*/ fd->hddrv = ((head&1)<<2)+fdu;
+
+ if(format)
+ {
+ /* formatting */
+ out_fdc(fdcu,/* NE7CMD_FORMAT */ 0x4d);
+ out_fdc(fdcu,head << 2 | fdu);
+ out_fdc(fdcu,finfo->fd_formb_secshift);
+ out_fdc(fdcu,finfo->fd_formb_nsecs);
+ out_fdc(fdcu,finfo->fd_formb_gaplen);
+ out_fdc(fdcu,finfo->fd_formb_fillbyte);
+ }
+ else
+ {
+ if (read)
+ {
+ out_fdc(fdcu,NE7CMD_READ); /* READ */
+ }
+ else
+ {
+ out_fdc(fdcu,NE7CMD_WRITE); /* WRITE */
+ }
+ out_fdc(fdcu,head << 2 | fdu); /* head & unit */
+ out_fdc(fdcu,fd->track); /* track */
+ out_fdc(fdcu,head);
+ out_fdc(fdcu,sec); /* sector XXX +1? */
+ out_fdc(fdcu,fd->ft->secsize); /* sector size */
+ out_fdc(fdcu,sectrac); /* sectors/track */
+ out_fdc(fdcu,fd->ft->gap); /* gap size */
+ out_fdc(fdcu,fd->ft->datalen); /* data length */
+ }
+ fdc->state = IOCOMPLETE;
+ timeout(fd_timeout, (caddr_t)fdcu, 2 * hz);
+ return(0); /* will return later */
+ case IOCOMPLETE: /* IO DONE, post-analyze */
+ untimeout(fd_timeout, (caddr_t)fdcu);
+ for(i=0;i<7;i++)
+ {
+ fdc->status[i] = in_fdc(fdcu);
+ }
+ case IOTIMEDOUT: /*XXX*/
+ isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip,
+ format ? bp->b_bcount : FDBLK, fdc->dmachan);
+ if (fdc->status[0]&0xF8)
+ {
+ if (fdc->status[1] & 0x10) {
+ /*
+ * Operation not completed in reasonable time.
+ * Just restart it, don't increment retry count.
+ * (vak)
+ */
+ fdc->state = SEEKCOMPLETE;
+ return (1);
+ }
+ return(retrier(fdcu));
+ }
+ /* All OK */
+ fd->skip += FDBLK;
+ if (!format && fd->skip < bp->b_bcount)
+ {
+ /* set up next transfer */
+ blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
+ + fd->skip/FDBLK;
+ bp->b_cylin = (blknum / (fd->ft->sectrac * fd->ft->heads));
+ fdc->state = DOSEEK;
+ }
+ else
+ {
+ /* ALL DONE */
+ fd->skip = 0;
+ bp->b_resid = 0;
+ dp->b_actf = bp->av_forw;
+ biodone(bp);
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ fdc->state = FINDWORK;
+ }
+ return(1);
+ case RESETCTLR:
+ /* Try a reset, keep motor on */
+ set_motor(fdcu,fd->fdsu,1);
+ DELAY(100);
+ set_motor(fdcu,fd->fdsu,0);
+ outb(fdc->baseport+fdctl,fd->ft->trans);
+ TRACE1("[0x%x->fdctl]",fd->ft->trans);
+ fdc->retry++;
+ fdc->state = STARTRECAL;
+ break;
+ case STARTRECAL:
+ out_fdc(fdcu,NE7CMD_SPECIFY); /* specify command */
+ out_fdc(fdcu,0xDF);
+ out_fdc(fdcu,2);
+ out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
+ out_fdc(fdcu,fdu);
+ fdc->state = RECALWAIT;
+ return(0); /* will return later */
+ case RECALWAIT:
+ /* allow heads to settle */
+ timeout(fd_pseudointr, (caddr_t)fdcu, hz / 30);
+ fdc->state = RECALCOMPLETE;
+ return(0); /* will return later */
+ case RECALCOMPLETE:
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (cyl != 0)
+ {
+ printf("fd%d: recal failed ST0 %b cyl %d\n", fdu,
+ st0, NE7_ST0BITS, cyl);
+ return(retrier(fdcu));
+ }
+ fd->track = 0;
+ /* Seek (probably) necessary */
+ fdc->state = DOSEEK;
+ return(1); /* will return immediatly */
+ case MOTORWAIT:
+ if(fd->flags & FD_MOTOR_WAIT)
+ {
+ return(0); /* time's not up yet */
+ }
+ fdc->state = DOSEEK;
+ return(1); /* will return immediatly */
+ default:
+ printf("Unexpected FD int->");
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ printf("ST0 = %lx, PCN = %lx\n",i,sec);
+ out_fdc(fdcu,0x4A);
+ out_fdc(fdcu,fd->fdsu);
+ for(i=0;i<7;i++) {
+ fdc->status[i] = in_fdc(fdcu);
+ }
+ printf("intr status :%lx %lx %lx %lx %lx %lx %lx ",
+ fdc->status[0],
+ fdc->status[1],
+ fdc->status[2],
+ fdc->status[3],
+ fdc->status[4],
+ fdc->status[5],
+ fdc->status[6] );
+ return(0);
+ }
+ return(1); /* Come back immediatly to new state */
+}
+
+static int
+retrier(fdcu)
+ fdcu_t fdcu;
+{
+ fdc_p fdc = fdc_data + fdcu;
+ register struct buf *dp,*bp;
+
+ dp = &(fdc->head);
+ bp = dp->b_actf;
+
+ switch(fdc->retry)
+ {
+ case 0: case 1: case 2:
+ fdc->state = SEEKCOMPLETE;
+ break;
+ case 3: case 4: case 5:
+ fdc->state = STARTRECAL;
+ break;
+ case 6:
+ fdc->state = RESETCTLR;
+ break;
+ case 7:
+ break;
+ default:
+ {
+ dev_t sav_b_dev = bp->b_dev;
+ /* Trick diskerr */
+ bp->b_dev = makedev(major(bp->b_dev), (FDUNIT(minor(bp->b_dev))<<3)|3);
+ diskerr(bp, "fd", "hard error", LOG_PRINTF,
+ fdc->fd->skip, (struct disklabel *)NULL);
+ bp->b_dev = sav_b_dev;
+ printf(" (ST0 %b ", fdc->status[0], NE7_ST0BITS);
+ printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS);
+ printf(" ST2 %b ", fdc->status[2], NE7_ST2BITS);
+ printf("cyl %d hd %d sec %d)\n",
+ fdc->status[3], fdc->status[4], fdc->status[5]);
+ }
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ bp->b_resid = bp->b_bcount - fdc->fd->skip;
+ dp->b_actf = bp->av_forw;
+ fdc->fd->skip = 0;
+ biodone(bp);
+ fdc->state = FINDWORK;
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ /* XXX abort current command, if any. */
+ return(1);
+ }
+ fdc->retry++;
+ return(1);
+}
+
+static int
+fdformat(dev, finfo, p)
+ dev_t dev;
+ struct fd_formb *finfo;
+ struct proc *p;
+{
+ fdu_t fdu;
+ fd_p fd;
+
+ struct buf *bp;
+ int rv = 0, s;
+
+ fdu = FDUNIT(minor(dev));
+ fd = &fd_data[fdu];
+
+ /* set up a buffer header for fdstrategy() */
+ bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
+ if(bp == 0)
+ return ENOBUFS;
+ bzero((void *)bp, sizeof(struct buf));
+ bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
+ bp->b_proc = p;
+ bp->b_dev = dev;
+
+ /*
+ * calculate a fake blkno, so fdstrategy() would initiate a
+ * seek to the requested cylinder
+ */
+ bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads)
+ + finfo->head * fd->ft->sectrac) * FDBLK / DEV_BSIZE;
+
+ bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
+ bp->b_un.b_addr = (caddr_t)finfo;
+
+ /* now do the format */
+ fdstrategy(bp);
+
+ /* ...and wait for it to complete */
+ s = splbio();
+ while(!(bp->b_flags & B_DONE))
+ {
+ rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
+ if(rv == EWOULDBLOCK)
+ break;
+ }
+ splx(s);
+
+ if(rv == EWOULDBLOCK)
+ {
+ /* timed out */
+ biodone(bp);
+ rv = EIO;
+ }
+ free(bp, M_TEMP);
+ return rv;
+}
+
+/*
+ * fdioctl() from jc@irbs.UUCP (John Capo)
+ * i386/i386/conf.c needs to have fdioctl() declared and remove the line that
+ * defines fdioctl to be enxio.
+ *
+ * TODO: Reformat.
+ * Think about allocating buffer off stack.
+ * Don't pass uncast 0's and NULL's to read/write/setdisklabel().
+ * Watch out for NetBSD's different *disklabel() interface.
+ *
+ * Added functionality for floppy formatting
+ * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
+ */
+
+int
+fdioctl (dev, cmd, addr, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t addr;
+ int flag;
+ struct proc *p;
+{
+ struct fd_type *fdt;
+ struct disklabel *dl;
+ char buffer[DEV_BSIZE];
+ int error;
+
+#if NFT > 0
+ int type = FDTYPE(minor(dev));
+
+ /* check for a tape ioctl */
+ if (type & F_TAPE_TYPE)
+ return ftioctl(dev, cmd, addr, flag, p);
+#endif
+
+ error = 0;
+
+ switch (cmd)
+ {
+ case DIOCGDINFO:
+ bzero(buffer, sizeof (buffer));
+ dl = (struct disklabel *)buffer;
+ dl->d_secsize = FDBLK;
+ fdt = fd_data[FDUNIT(minor(dev))].ft;
+ dl->d_secpercyl = fdt->size / fdt->tracks;
+ dl->d_type = DTYPE_FLOPPY;
+
+ if (readdisklabel(dev, fdstrategy, dl, NULL, 0, 0) == NULL)
+ error = 0;
+ else
+ error = EINVAL;
+
+ *(struct disklabel *)addr = *dl;
+ break;
+
+ case DIOCSDINFO:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ break;
+
+ case DIOCWLABEL:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ break;
+
+ case DIOCWDINFO:
+ if ((flag & FWRITE) == 0)
+ {
+ error = EBADF;
+ break;
+ }
+
+ dl = (struct disklabel *)addr;
+
+ if (error = setdisklabel ((struct disklabel *)buffer,
+ dl, 0, NULL))
+ break;
+
+ error = writedisklabel(dev, fdstrategy,
+ (struct disklabel *)buffer, NULL);
+ break;
+
+ case FD_FORM:
+ if((flag & FWRITE) == 0)
+ error = EBADF; /* must be opened for writing */
+ else if(((struct fd_formb *)addr)->format_version !=
+ FD_FORMAT_VERSION)
+ error = EINVAL; /* wrong version of formatting prog */
+ else
+ error = fdformat(dev, (struct fd_formb *)addr, p);
+ break;
+
+ case FD_GTYPE: /* get drive type */
+ *(struct fd_type *)addr = *fd_data[FDUNIT(minor(dev))].ft;
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ return (error);
+}
+
+#endif
diff --git a/sys/dev/fdc/fdcreg.h b/sys/dev/fdc/fdcreg.h
new file mode 100644
index 0000000..5deb02c
--- /dev/null
+++ b/sys/dev/fdc/fdcreg.h
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)fdreg.h 7.1 (Berkeley) 5/9/91
+ * $Id: fdreg.h,v 1.3 1994/02/07 04:27:10 alm Exp $
+ */
+
+/*
+ * AT floppy controller registers and bitfields
+ */
+
+/* uses NEC765 controller */
+#include "../i386/isa/ic/nec765.h"
+
+/* registers */
+#define fdout 2 /* Digital Output Register (W) */
+#define FDO_FDSEL 0x03 /* floppy device select */
+#define FDO_FRST 0x04 /* floppy controller reset */
+#define FDO_FDMAEN 0x08 /* enable floppy DMA and Interrupt */
+#define FDO_MOEN0 0x10 /* motor enable drive 0 */
+#define FDO_MOEN1 0x20 /* motor enable drive 1 */
+#define FDO_MOEN2 0x30 /* motor enable drive 2 */
+#define FDO_MOEN3 0x40 /* motor enable drive 3 */
+
+#define fdsts 4 /* NEC 765 Main Status Register (R) */
+#define fddata 5 /* NEC 765 Data Register (R/W) */
+
+#define fdctl 7 /* Control Register (W) */
+#define FDC_500KBPS 0x00 /* 500KBPS MFM drive transfer rate */
+#define FDC_300KBPS 0x01 /* 300KBPS MFM drive transfer rate */
+#define FDC_250KBPS 0x02 /* 250KBPS MFM drive transfer rate */
+#define FDC_125KBPS 0x03 /* 125KBPS FM drive transfer rate */
+
+#define fdin 7 /* Digital Input Register (R) */
+#define FDI_DCHG 0x80 /* diskette has been changed */
+
diff --git a/sys/dev/ic/i8237.h b/sys/dev/ic/i8237.h
new file mode 100644
index 0000000..2199e73
--- /dev/null
+++ b/sys/dev/ic/i8237.h
@@ -0,0 +1,11 @@
+/*
+ * Intel 8237 DMA Controller
+ *
+ * $Id$
+ */
+
+#define DMA37MD_SINGLE 0x40 /* single pass mode */
+#define DMA37MD_CASCADE 0xc0 /* cascade mode */
+#define DMA37MD_WRITE 0x04 /* read the device, write memory operation */
+#define DMA37MD_READ 0x08 /* write the device, read memory operation */
+
diff --git a/sys/dev/ic/i82586.h b/sys/dev/ic/i82586.h
new file mode 100644
index 0000000..577313d
--- /dev/null
+++ b/sys/dev/ic/i82586.h
@@ -0,0 +1,325 @@
+/*-
+ * Copyright (c) 1992, University of Vermont and State Agricultural College.
+ * Copyright (c) 1992, Garrett A. Wollman.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * Vermont and State Agricultural College and Garrett A. Wollman.
+ * 4. Neither the name of the University nor the name of the author
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR AUTHOR BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+/*
+ * Intel 82586 Ethernet chip
+ * Register, bit, and structure definitions.
+ *
+ * Written by GAW with reference to the Clarkson Packet Driver code for this
+ * chip written by Russ Nelson and others.
+ */
+
+struct ie_en_addr {
+ u_char data[6];
+};
+
+/*
+ * This is the master configuration block. It tells the hardware where all
+ * the rest of the stuff is.
+ */
+struct ie_sys_conf_ptr {
+ u_short mbz; /* must be zero */
+ u_char ie_bus_use; /* true if 8-bit only */
+ u_char mbz2[5]; /* must be zero */
+ caddr_t ie_iscp_ptr; /* 24-bit physaddr of ISCP */
+};
+
+/*
+ * Note that this is wired in hardware; the SCP is always located here, no
+ * matter what.
+ */
+#define IE_SCP_ADDR 0xfffff4
+
+/*
+ * The tells the hardware where all the rest of the stuff is, too.
+ * FIXME: some of these should be re-commented after we figure out their
+ * REAL function.
+ */
+struct ie_int_sys_conf_ptr {
+ u_char ie_busy; /* zeroed after init */
+ u_char mbz;
+ u_short ie_scb_offset; /* 16-bit physaddr of next struct */
+ caddr_t ie_base; /* 24-bit physaddr for all 16-bit vars */
+};
+
+/*
+ * This FINALLY tells the hardware what to do and where to put it.
+ */
+struct ie_sys_ctl_block {
+ u_short ie_status; /* status word */
+ u_short ie_command; /* command word */
+ u_short ie_command_list; /* 16-pointer to command block list */
+ u_short ie_recv_list; /* 16-pointer to receive frame list */
+ u_short ie_err_crc; /* CRC errors */
+ u_short ie_err_align; /* Alignment errors */
+ u_short ie_err_resource; /* Resource errors */
+ u_short ie_err_overrun; /* Overrun errors */
+};
+
+/* Command values */
+#define IE_RU_COMMAND 0x0070 /* mask for RU command */
+#define IE_RU_NOP 0 /* for completeness */
+#define IE_RU_START 0x0010 /* start receive unit command */
+#define IE_RU_ENABLE 0x0020 /* enable receiver command */
+#define IE_RU_DISABLE 0x0030 /* disable receiver command */
+#define IE_RU_ABORT 0x0040 /* abort current receive operation */
+
+#define IE_CU_COMMAND 0x0700 /* mask for CU command */
+#define IE_CU_NOP 0 /* included for completeness */
+#define IE_CU_START 0x0100 /* do-command command */
+#define IE_CU_RESUME 0x0200 /* resume a suspended cmd list */
+#define IE_CU_STOP 0x0300 /* SUSPEND was already taken */
+#define IE_CU_ABORT 0x0400 /* abort current command */
+
+#define IE_ACK_COMMAND 0xf000 /* mask for ACK command */
+#define IE_ACK_CX 0x8000 /* ack IE_ST_DONE */
+#define IE_ACK_FR 0x4000 /* ack IE_ST_RECV */
+#define IE_ACK_CNA 0x2000 /* ack IE_ST_ALLDONE */
+#define IE_ACK_RNR 0x1000 /* ack IE_ST_RNR */
+
+#define IE_ACTION_COMMAND(x) (((x) & IE_CU_COMMAND) == IE_CU_START)
+ /* is this command an action command? */
+
+/* Status values */
+#define IE_ST_WHENCE 0xf000 /* mask for cause of interrupt */
+#define IE_ST_DONE 0x8000 /* command with I bit completed */
+#define IE_ST_RECV 0x4000 /* frame received */
+#define IE_ST_ALLDONE 0x2000 /* all commands completed */
+#define IE_ST_RNR 0x1000 /* receive not ready */
+
+#define IE_CU_STATUS 0x700 /* mask for command unit status */
+#define IE_CU_ACTIVE 0x200 /* command unit is active */
+#define IE_CU_SUSPEND 0x100 /* command unit is suspended */
+
+#define IE_RU_STATUS 0x70 /* mask for receiver unit status */
+#define IE_RU_SUSPEND 0x10 /* receiver is suspended */
+#define IE_RU_NOSPACE 0x20 /* receiver has no resources */
+#define IE_RU_READY 0x40 /* reveiver is ready */
+
+/*
+ * This is filled in partially by the chip, partially by us.
+ */
+struct ie_recv_frame_desc {
+ u_short ie_fd_status; /* status for this frame */
+ u_short ie_fd_last; /* end of frame list flag */
+ u_short ie_fd_next; /* 16-pointer to next RFD */
+ u_short ie_fd_buf_desc; /* 16-pointer to list of buffer desc's */
+ struct ie_en_addr dest; /* destination ether */
+ struct ie_en_addr src; /* source ether */
+ u_short ie_length; /* 802 length/Ether type */
+ u_short mbz; /* must be zero */
+};
+
+#define IE_FD_LAST 0x8000 /* last rfd in list */
+#define IE_FD_SUSP 0x4000 /* suspend RU after receipt */
+
+#define IE_FD_COMPLETE 0x8000 /* frame is complete */
+#define IE_FD_BUSY 0x4000 /* frame is busy */
+#define IE_FD_OK 0x2000 /* frame is bad */
+#define IE_FD_RNR 0x0200 /* receiver out of resources here */
+
+/*
+ * linked list of buffers...
+ */
+struct ie_recv_buf_desc {
+ u_short ie_rbd_actual; /* status for this buffer */
+ u_short ie_rbd_next; /* 16-pointer to next RBD */
+ caddr_t ie_rbd_buffer; /* 24-pointer to buffer for this RBD */
+ u_short ie_rbd_length; /* length of the buffer */
+ u_short mbz; /* must be zero */
+};
+
+#define IE_RBD_LAST 0x8000 /* last buffer */
+#define IE_RBD_USED 0x4000 /* this buffer has data */
+/*
+ * All commands share this in common.
+ */
+struct ie_cmd_common {
+ u_short ie_cmd_status; /* status of this command */
+ u_short ie_cmd_cmd; /* command word */
+ u_short ie_cmd_link; /* link to next command */
+};
+
+#define IE_STAT_COMPL 0x8000 /* command is completed */
+#define IE_STAT_BUSY 0x4000 /* command is running now */
+#define IE_STAT_OK 0x2000 /* command completed successfully */
+
+#define IE_CMD_NOP 0x0000 /* NOP */
+#define IE_CMD_IASETUP 0x0001 /* initial address setup */
+#define IE_CMD_CONFIG 0x0002 /* configure command */
+#define IE_CMD_MCAST 0x0003 /* multicast setup command */
+#define IE_CMD_XMIT 0x0004 /* transmit command */
+#define IE_CMD_TDR 0x0005 /* time-domain reflectometer command */
+#define IE_CMD_DUMP 0x0006 /* dump command */
+#define IE_CMD_DIAGNOSE 0x0007 /* diagnostics command */
+
+#define IE_CMD_LAST 0x8000 /* this is the last command in the list */
+#define IE_CMD_SUSPEND 0x4000 /* suspend CU after this command */
+#define IE_CMD_INTR 0x2000 /* post an interrupt after completion */
+
+/*
+ * This is the command to transmit a frame.
+ */
+struct ie_xmit_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_xmit_status com.ie_cmd_status
+
+ u_short ie_xmit_desc; /* 16-pointer to buffer descriptor */
+ struct ie_en_addr ie_xmit_addr; /* destination address */
+
+ u_short ie_xmit_length; /* 802.3 length/Ether type field */
+};
+
+#define IE_XS_MAXCOLL 0x000f /* number of collisions during transmit */
+#define IE_XS_EXCMAX 0x0020 /* exceeded maximum number of collisions */
+#define IE_XS_SQE 0x0040 /* SQE positive */
+#define IE_XS_DEFERRED 0x0080 /* transmission deferred */
+#define IE_XS_UNDERRUN 0x0100 /* DMA underrun */
+#define IE_XS_LOSTCTS 0x0200 /* Lost CTS */
+#define IE_XS_NOCARRIER 0x0400 /* No Carrier */
+#define IE_XS_LATECOLL 0x0800 /* Late collision */
+
+/*
+ * This is a buffer descriptor for a frame to be transmitted.
+ */
+
+struct ie_xmit_buf {
+ u_short ie_xmit_flags; /* see below */
+ u_short ie_xmit_next; /* 16-pointer to next desc. */
+ caddr_t ie_xmit_buf; /* 24-pointer to the actual buffer */
+};
+
+#define IE_XMIT_LAST 0x8000 /* this TBD is the last one */
+/* The rest of the `flags' word is actually the length. */
+
+/*
+ * Multicast setup command.
+ */
+
+#define MAXMCAST 50 /* must fit in transmit buffer */
+
+struct ie_mcast_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_mcast_status com.ie_cmd_status
+
+ u_short ie_mcast_bytes; /* size (in bytes) of multicast addresses */
+ struct ie_en_addr ie_mcast_addrs[MAXMCAST + 1]; /* space for them */
+};
+
+/*
+ * Time Domain Reflectometer command.
+ */
+
+struct ie_tdr_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_tdr_status com.ie_cmd_status
+
+ u_short ie_tdr_time; /* error bits and time */
+};
+
+#define IE_TDR_SUCCESS 0x8000 /* TDR succeeded without error */
+#define IE_TDR_XCVR 0x4000 /* detected a transceiver problem */
+#define IE_TDR_OPEN 0x2000 /* detected an open */
+#define IE_TDR_SHORT 0x1000 /* TDR detected a short */
+#define IE_TDR_TIME 0x07ff /* mask for reflection time */
+
+/*
+ * Initial Address Setup command
+ */
+struct ie_iasetup_cmd {
+ struct ie_cmd_common com;
+#define ie_iasetup_status com.ie_cmd_status
+
+ struct ie_en_addr ie_address;
+};
+
+/*
+ * Configuration command
+ */
+struct ie_config_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_config_status com.ie_cmd_status
+
+ u_char ie_config_count; /* byte count (0x0c) */
+ u_char ie_fifo; /* fifo (8) */
+ u_char ie_save_bad; /* save bad frames (0x40) */
+ u_char ie_addr_len; /* address length (0x2e) (AL-LOC == 1) */
+ u_char ie_priority; /* priority and backoff (0x0) */
+ u_char ie_ifs; /* inter-frame spacing (0x60) */
+ u_char ie_slot_low; /* slot time, LSB (0x0) */
+ u_char ie_slot_high; /* slot time, MSN, and retries (0xf2) */
+ u_char ie_promisc; /* 1 if promiscuous, else 0 */
+ u_char ie_crs_cdt; /* CSMA/CD parameters (0x0) */
+ u_char ie_min_len; /* min frame length (0x40) */
+ u_char ie_junk; /* stuff for 82596 (0xff) */
+};
+
+/*
+ * Here are a few useful functions. We could have done these as macros,
+ * but since we have the inline facility, it makes sense to use that
+ * instead.
+ */
+inline void
+ie_setup_config(volatile struct ie_config_cmd *cmd,
+ int promiscuous, int manchester) {
+ cmd->ie_config_count = 0x0c;
+ cmd->ie_fifo = 8;
+ cmd->ie_save_bad = 0x40;
+ cmd->ie_addr_len = 0x2e;
+ cmd->ie_priority = 0;
+ cmd->ie_ifs = 0x60;
+ cmd->ie_slot_low = 0;
+ cmd->ie_slot_high = 0xf2;
+ cmd->ie_promisc = !!promiscuous | manchester << 2;
+ cmd->ie_crs_cdt = 0;
+ cmd->ie_min_len = 64;
+ cmd->ie_junk = 0xff;
+}
+
+inline caddr_t
+Align(caddr_t ptr) {
+ unsigned long l = (unsigned long)ptr;
+ l = (l + 3) & ~3L;
+ return (caddr_t)l;
+}
+
+inline void
+ie_ack(volatile struct ie_sys_ctl_block *scb,
+ u_int mask, int unit,
+ void (*ca)(int)) {
+ scb->ie_command = scb->ie_status & mask;
+ (*ca)(unit);
+}
diff --git a/sys/dev/ic/nec765.h b/sys/dev/ic/nec765.h
new file mode 100644
index 0000000..1895db7
--- /dev/null
+++ b/sys/dev/ic/nec765.h
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)nec765.h 7.1 (Berkeley) 5/9/91
+ * $Id$
+ */
+
+/*
+ * Nec 765 floppy disc controller definitions
+ */
+
+/* Main status register */
+#define NE7_DAB 0x01 /* Diskette drive A is seeking, thus busy */
+#define NE7_DBB 0x02 /* Diskette drive B is seeking, thus busy */
+#define NE7_CB 0x10 /* Diskette Controller Busy */
+#define NE7_NDM 0x20 /* Diskette Controller in Non Dma Mode */
+#define NE7_DIO 0x40 /* Diskette Controller Data register I/O */
+#define NE7_RQM 0x80 /* Diskette Controller ReQuest for Master */
+
+/* Status register ST0 */
+#define NE7_ST0BITS "\020\010invld\007abnrml\006seek_cmplt\005drv_chck\004drive_rdy\003top_head"
+
+/* Status register ST1 */
+#define NE7_ST1BITS "\020\010end_of_cyl\006bad_crc\005data_overrun\003sec_not_fnd\002write_protect\001no_am"
+
+/* Status register ST2 */
+#define NE7_ST2BITS "\020\007ctrl_mrk\006bad_crc\005wrong_cyl\004scn_eq\003scn_not_fnd\002bad_cyl\001no_dam"
+
+/* Status register ST3 */
+#define NE7_ST3BITS "\020\010fault\007write_protect\006drdy\005tk0\004two_side\003side_sel\002"
+
+/* Commands */
+#define NE7CMD_SPECIFY 3 /* specify drive parameters - requires unit
+ parameters byte */
+#define NE7CMD_SENSED 4 /* sense drive - requires unit select byte */
+#define NE7CMD_WRITE 0xc5 /* write - requires eight additional bytes */
+#define NE7CMD_READ 0xe6 /* read - requires eight additional bytes */
+#define NE7CMD_FORMAT 0x4c /* format - requires five additional bytes */
+#define NE7CMD_RECAL 7 /* recalibrate drive - requires
+ unit select byte */
+#define NE7CMD_SENSEI 8 /* sense controller interrupt status */
+#define NE7CMD_SEEK 15 /* seek drive - requires unit select byte
+ and new cyl byte */
diff --git a/sys/dev/ic/ns16550.h b/sys/dev/ic/ns16550.h
new file mode 100644
index 0000000..ff59757
--- /dev/null
+++ b/sys/dev/ic/ns16550.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)ns16550.h 7.1 (Berkeley) 5/9/91
+ * $Id$
+ */
+
+/*
+ * NS16550 UART registers
+ */
+
+#define com_data 0 /* data register (R/W) */
+#define com_dlbl 0 /* divisor latch low (W) */
+#define com_dlbh 1 /* divisor latch high (W) */
+#define com_ier 1 /* interrupt enable (W) */
+#define com_iir 2 /* interrupt identification (R) */
+#define com_fifo 2 /* FIFO control (W) */
+#define com_lctl 3 /* line control register (R/W) */
+#define com_cfcr 3 /* line control register (R/W) */
+#define com_mcr 4 /* modem control register (R/W) */
+#define com_lsr 5 /* line status register (R/W) */
+#define com_msr 6 /* modem status register (R/W) */
diff --git a/sys/dev/ie/if_ie.c b/sys/dev/ie/if_ie.c
new file mode 100644
index 0000000..95095bd
--- /dev/null
+++ b/sys/dev/ie/if_ie.c
@@ -0,0 +1,1802 @@
+/*-
+ * Copyright (c) 1992, 1993, University of Vermont and State
+ * Agricultural College.
+ * Copyright (c) 1992, 1993, Garrett A. Wollman.
+ *
+ * Portions:
+ * Copyright (c) 1990, 1991, William F. Jolitz
+ * Copyright (c) 1990, The Regents of the University of California
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * Vermont and State Agricultural College and Garrett A. Wollman,
+ * by William F. Jolitz, by the University of California,
+ * Berkeley, by Larwence Berkeley Laboratory, and its contributors.
+ * 4. Neither the names of the Universities nor the names of the authors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR AUTHORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: if_ie.c,v 1.2 1993/11/25 01:31:36 wollman Exp $
+ */
+
+/*
+ * Intel 82586 Ethernet chip
+ * Register, bit, and structure definitions.
+ *
+ * Written by GAW with reference to the Clarkson Packet Driver code for this
+ * chip written by Russ Nelson and others.
+ *
+ * BPF support code stolen directly from hpdev/if_le.c, supplied with
+ * tcpdump.
+ */
+
+/*
+ * The i82586 is a very versatile chip, found in many implementations.
+ * Programming this chip is mostly the same, but certain details differ
+ * from card to card. This driver is written so that different cards
+ * can be automatically detected at run-time. Currently, only the
+ * AT&T EN100/StarLAN 10 series are supported.
+ */
+
+/*
+Mode of operation:
+
+We run the 82586 in a standard Ethernet mode. We keep NFRAMES received
+frame descriptors around for the receiver to use, and NBUFFS associated
+receive buffer descriptors, both in a circular list. Whenever a frame is
+received, we rotate both lists as necessary. (The 586 treats both lists
+as a simple queue.) We also keep a transmit command around so that packets
+can be sent off quickly.
+
+We configure the adapter in AL-LOC = 1 mode, which means that the
+Ethernet/802.3 MAC header is placed at the beginning of the receive buffer
+rather than being split off into various fields in the RFD. This also
+means that we must include this header in the transmit buffer as well.
+
+By convention, all transmit commands, and only transmit commands, shall
+have the I (IE_CMD_INTR) bit set in the command. This way, when an
+interrupt arrives at ieintr(), it is immediately possible to tell
+what precisely caused it. ANY OTHER command-sending routines should
+run at splimp(), and should post an acknowledgement to every interrupt
+they generate.
+
+The 82586 has a 24-bit address space internally, and the adaptor's
+memory is located at the top of this region. However, the value we are
+given in configuration is normally the *bottom* of the adaptor RAM. So,
+we must go through a few gyrations to come up with a kernel virtual address
+which represents the actual beginning of the 586 address space. First,
+we autosize the RAM by running through several possible sizes and trying
+to initialize the adapter under the assumption that the selected size
+is correct. Then, knowing the correct RAM size, we set up our pointers
+in ie_softc[unit]. `iomem' represents the computed base of the 586
+address space. `iomembot' represents the actual configured base
+of adapter RAM. Finally, `iosize' represents the calculated size
+of 586 RAM. Then, when laying out commands, we use the interval
+[iomembot, iomembot + iosize); to make 24-pointers, we subtract
+iomem, and to make 16-pointers, we subtract iomem and and with 0xffff.
+
+*/
+
+#include "ie.h"
+#if NIE > 0
+
+#include "param.h"
+#include "systm.h"
+#include "mbuf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "ioctl.h"
+#include "errno.h"
+#include "syslog.h"
+
+#include "net/if.h"
+#include "net/if_types.h"
+#include "net/if_dl.h"
+#include "net/route.h"
+
+#include "bpfilter.h"
+
+#ifdef INET
+#include "netinet/in.h"
+#include "netinet/in_systm.h"
+#include "netinet/in_var.h"
+#include "netinet/ip.h"
+#include "netinet/if_ether.h"
+#endif
+
+#ifdef NS
+#include "netns/ns.h"
+#include "netns/ns_if.h"
+#endif
+
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/ic/i82586.h"
+#include "i386/isa/if_iereg.h"
+#include "i386/isa/icu.h"
+
+#include "vm/vm.h"
+
+#if NBPFILTER > 0
+#include "net/bpf.h"
+#include "net/bpfdesc.h"
+#endif
+
+#if (NBPFILTER > 0) || defined(MULTICAST)
+#define FILTER
+static struct mbuf *last_not_for_us;
+#endif
+
+#ifdef DEBUG
+#define IED_RINT 1
+#define IED_TINT 2
+#define IED_RNR 4
+#define IED_CNA 8
+#define IED_READFRAME 16
+int ie_debug = IED_RNR;
+#endif
+
+#ifndef ETHERMINLEN
+#define ETHERMINLEN 60
+#endif
+
+#define IE_BUF_LEN 1512 /* length of transmit buffer */
+
+/* Forward declaration */
+struct ie_softc;
+
+static int ieprobe(struct isa_device *dvp);
+static int ieattach(struct isa_device *dvp);
+static void ieinit(int unit);
+static int ieioctl(struct ifnet *ifp, int command, caddr_t data);
+static void iestart(struct ifnet *ifp);
+static void sl_reset_586(int unit);
+static void sl_chan_attn(int unit);
+static void iereset(int unit, int dummy);
+static void ie_readframe(int unit, struct ie_softc *ie, int bufno);
+static void ie_drop_packet_buffer(int unit, struct ie_softc *ie);
+static void sl_read_ether(int unit, unsigned char addr[6]);
+static void find_ie_mem_size(int unit);
+static int command_and_wait(int unit, int command, void volatile *pcmd, int);
+static int ierint(int unit, struct ie_softc *ie);
+static int ietint(int unit, struct ie_softc *ie);
+static int iernr(int unit, struct ie_softc *ie);
+static void start_receiver(int unit);
+static int ieget(int, struct ie_softc *, struct mbuf **,
+ struct ether_header *, int *);
+static caddr_t setup_rfa(caddr_t ptr, struct ie_softc *ie);
+static int mc_setup(int, caddr_t, volatile struct ie_sys_ctl_block *);
+#ifdef MULTICAST
+static void ie_mc_reset(int unit);
+#endif
+
+#ifdef DEBUG
+void print_rbd(volatile struct ie_recv_buf_desc *rbd);
+
+int in_ierint = 0;
+int in_ietint = 0;
+#endif
+
+/*
+ * This tells the autoconf code how to set us up.
+ */
+struct isa_driver iedriver = {
+ ieprobe, ieattach, "ie",
+};
+
+enum ie_hardware {
+ IE_STARLAN10,
+ IE_EN100,
+ IE_SLFIBER,
+ IE_UNKNOWN
+};
+
+const char *ie_hardware_names[] = {
+ "StarLAN 10",
+ "EN100",
+ "StarLAN Fiber",
+ "Unknown"
+};
+
+/*
+sizeof(iscp) == 1+1+2+4 == 8
+sizeof(scb) == 2+2+2+2+2+2+2+2 == 16
+NFRAMES * sizeof(rfd) == NFRAMES*(2+2+2+2+6+6+2+2) == NFRAMES*24 == 384
+sizeof(xmit_cmd) == 2+2+2+2+6+2 == 18
+sizeof(transmit buffer) == 1512
+sizeof(transmit buffer desc) == 8
+-----
+1946
+
+NBUFFS * sizeof(rbd) == NBUFFS*(2+2+4+2+2) == NBUFFS*12
+NBUFFS * IE_RBUF_SIZE == NBUFFS*256
+
+NBUFFS should be (16384 - 1946) / (256 + 12) == 14438 / 268 == 53
+
+With NBUFFS == 48, this leaves us 1574 bytes for another command or
+more buffers. Another transmit command would be 18+8+1512 == 1538
+---just barely fits!
+
+Obviously all these would have to be reduced for smaller memory sizes.
+With a larger memory, it would be possible to roughly double the number of
+both transmit and receive buffers.
+*/
+
+#define NFRAMES 16 /* number of frames to allow for receive */
+#define NBUFFS 48 /* number of buffers to allocate */
+#define IE_RBUF_SIZE 256 /* size of each buffer, MUST BE POWER OF TWO */
+
+/*
+ * Ethernet status, per interface.
+ */
+struct ie_softc {
+ struct arpcom arpcom;
+ void (*ie_reset_586)(int);
+ void (*ie_chan_attn)(int);
+ enum ie_hardware hard_type;
+ int hard_vers;
+
+ u_short port;
+ caddr_t iomem;
+ caddr_t iomembot;
+ unsigned iosize;
+
+ int want_mcsetup;
+ int promisc;
+ volatile struct ie_int_sys_conf_ptr *iscp;
+ volatile struct ie_sys_ctl_block *scb;
+ volatile struct ie_recv_frame_desc *rframes[NFRAMES];
+ volatile struct ie_recv_buf_desc *rbuffs[NBUFFS];
+ volatile char *cbuffs[NBUFFS];
+ int rfhead, rftail, rbhead, rbtail;
+
+ volatile struct ie_xmit_cmd *xmit_cmds[2];
+ volatile struct ie_xmit_buf *xmit_buffs[2];
+ int xmit_count;
+ u_char *xmit_cbuffs[2];
+
+ struct ie_en_addr mcast_addrs[MAXMCAST + 1];
+ int mcast_count;
+
+#if NBPFILTER > 0
+ caddr_t ie_bpf;
+#endif
+
+} ie_softc[NIE];
+
+#define MK_24(base, ptr) ((caddr_t)((u_long)ptr - (u_long)base))
+#define MK_16(base, ptr) ((u_short)(u_long)MK_24(base, ptr))
+
+#define PORT ie_softc[unit].port
+#define MEM ie_softc[unit].iomem
+
+
+int ieprobe(dvp)
+ struct isa_device *dvp;
+{
+ int unit = dvp->id_unit;
+ u_char c;
+
+ ie_softc[unit].port = dvp->id_iobase;
+ ie_softc[unit].iomembot = dvp->id_maddr;
+ ie_softc[unit].iomem = 0;
+
+ c = inb(PORT + IEATT_REVISION);
+ switch(SL_BOARD(c)) {
+ case SL10_BOARD:
+ ie_softc[unit].hard_type = IE_STARLAN10;
+ ie_softc[unit].ie_reset_586 = sl_reset_586;
+ ie_softc[unit].ie_chan_attn = sl_chan_attn;
+ break;
+ case EN100_BOARD:
+ ie_softc[unit].hard_type = IE_EN100;
+ ie_softc[unit].ie_reset_586 = sl_reset_586;
+ ie_softc[unit].ie_chan_attn = sl_chan_attn;
+ break;
+ case SLFIBER_BOARD:
+ ie_softc[unit].hard_type = IE_SLFIBER;
+ ie_softc[unit].ie_reset_586 = sl_reset_586;
+ ie_softc[unit].ie_chan_attn = sl_chan_attn;
+ break;
+
+ /*
+ * Anything else is not recognized or cannot be used.
+ */
+ default:
+ return 0;
+ }
+
+ ie_softc[unit].hard_vers = SL_REV(c);
+
+ /*
+ * Divine memory size on-board the card. Ususally 16k.
+ */
+ find_ie_mem_size(unit);
+
+ if(!ie_softc[unit].iosize) {
+ return 0;
+ }
+
+ dvp->id_msize = ie_softc[unit].iosize;
+
+ switch(ie_softc[unit].hard_type) {
+ case IE_EN100:
+ case IE_STARLAN10:
+ case IE_SLFIBER:
+ sl_read_ether(unit, ie_softc[unit].arpcom.ac_enaddr);
+ break;
+
+ default:
+ printf("ie%d: unknown AT&T board type code %d\n", unit,
+ ie_softc[unit].hard_type);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Taken almost exactly from Bill's if_is.c, then modified beyond recognition.
+ */
+int
+ieattach(dvp)
+ struct isa_device *dvp;
+{
+ int unit = dvp->id_unit;
+ struct ie_softc *ie = &ie_softc[unit];
+ struct ifnet *ifp = &ie->arpcom.ac_if;
+
+ ifp->if_unit = unit;
+ ifp->if_name = iedriver.name;
+ ifp->if_mtu = ETHERMTU;
+ printf("<%s R%d> ethernet address %s",
+ ie_hardware_names[ie_softc[unit].hard_type],
+ ie_softc[unit].hard_vers + 1,
+ ether_sprintf(ie->arpcom.ac_enaddr));
+
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
+#ifdef MULTICAST
+ ifp->if_flags |= IFF_MULTICAST;
+#endif /* MULTICAST */
+
+ ifp->if_init = ieinit;
+ ifp->if_output = ether_output;
+ ifp->if_start = iestart;
+ ifp->if_ioctl = ieioctl;
+ ifp->if_reset = iereset;
+ ifp->if_type = IFT_ETHER;
+ ifp->if_addrlen = 6;
+ ifp->if_hdrlen = 14;
+
+#if NBPFILTER > 0
+ printf("\n");
+ bpfattach(&ie_softc[unit].ie_bpf, ifp, DLT_EN10MB,
+ sizeof(struct ether_header));
+#endif
+
+ if_attach(ifp);
+ {
+ struct ifaddr *ifa = ifp->if_addrlist;
+ struct sockaddr_dl *sdl;
+ while(ifa && ifa->ifa_addr && ifa->ifa_addr->sa_family != AF_LINK)
+ ifa = ifa->ifa_next;
+
+ if(!ifa || !ifa->ifa_addr) return 1;
+
+ /* Provide our ether address to the higher layers */
+ sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ sdl->sdl_type = IFT_ETHER;
+ sdl->sdl_alen = 6;
+ sdl->sdl_slen = 0;
+ bcopy(ie->arpcom.ac_enaddr, LLADDR(sdl), 6);
+ return 1;
+ }
+}
+
+/*
+ * What to do upon receipt of an interrupt.
+ */
+int ieintr(unit)
+ int unit;
+{
+ register struct ie_softc *ie = &ie_softc[unit];
+ register u_short status;
+
+ status = ie->scb->ie_status;
+
+loop:
+ if(status & (IE_ST_RECV | IE_ST_RNR)) {
+#ifdef DEBUG
+ in_ierint++;
+ if(ie_debug & IED_RINT)
+ printf("ie%d: rint\n", unit);
+#endif
+ ierint(unit, ie);
+#ifdef DEBUG
+ in_ierint--;
+#endif
+ }
+
+ if(status & IE_ST_DONE) {
+#ifdef DEBUG
+ in_ietint++;
+ if(ie_debug & IED_TINT)
+ printf("ie%d: tint\n", unit);
+#endif
+ ietint(unit, ie);
+#ifdef DEBUG
+ in_ietint--;
+#endif
+ }
+
+ if(status & IE_ST_RNR) {
+#ifdef DEBUG
+ if(ie_debug & IED_RNR)
+ printf("ie%d: rnr\n", unit);
+#endif
+ iernr(unit, ie);
+ }
+
+#ifdef DEBUG
+ if((status & IE_ST_ALLDONE)
+ && (ie_debug & IED_CNA))
+ printf("ie%d: cna\n", unit);
+#endif
+
+ /* Don't ack interrupts which we didn't receive */
+ ie_ack(ie->scb, IE_ST_WHENCE & status, unit, ie->ie_chan_attn);
+
+ if((status = ie->scb->ie_status) & IE_ST_WHENCE)
+ goto loop;
+
+ return unit;
+}
+
+/*
+ * Process a received-frame interrupt.
+ */
+static int ierint(unit, ie)
+ int unit;
+ struct ie_softc *ie;
+{
+ int i, status;
+ static int timesthru = 1024;
+
+ i = ie->rfhead;
+ while(1) {
+ status = ie->rframes[i]->ie_fd_status;
+
+ if((status & IE_FD_COMPLETE) && (status & IE_FD_OK)) {
+ ie->arpcom.ac_if.if_ipackets++;
+ if(!--timesthru) {
+ ie->arpcom.ac_if.if_ierrors += ie->scb->ie_err_crc + ie->scb->ie_err_align +
+ ie->scb->ie_err_resource + ie->scb->ie_err_overrun;
+ ie->scb->ie_err_crc = 0;
+ ie->scb->ie_err_align = 0;
+ ie->scb->ie_err_resource = 0;
+ ie->scb->ie_err_overrun = 0;
+ timesthru = 1024;
+ }
+ ie_readframe(unit, ie, i);
+ } else {
+ if(status & IE_FD_RNR) {
+ if(!(ie->scb->ie_status & IE_RU_READY)) {
+ ie->rframes[0]->ie_fd_next = MK_16(MEM, ie->rbuffs[0]);
+ ie->scb->ie_recv_list = MK_16(MEM, ie->rframes[0]);
+ command_and_wait(unit, IE_RU_START, 0, 0);
+ }
+ }
+ break;
+ }
+ i = (i + 1) % NFRAMES;
+ }
+ return 0;
+}
+
+/*
+ * Process a command-complete interrupt. These are only generated by
+ * the transmission of frames. This routine is deceptively simple, since
+ * most of the real work is done by iestart().
+ */
+static int ietint(unit, ie)
+ int unit;
+ struct ie_softc *ie;
+{
+ int status;
+ int i;
+
+ ie->arpcom.ac_if.if_timer = 0;
+ ie->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+
+ for(i = 0; i < ie->xmit_count; i++) {
+ status = ie->xmit_cmds[i]->ie_xmit_status;
+
+ if(status & IE_XS_LATECOLL) {
+ printf("ie%d: late collision\n", unit);
+ ie->arpcom.ac_if.if_collisions++;
+ ie->arpcom.ac_if.if_oerrors++;
+ } else if(status & IE_XS_NOCARRIER) {
+ printf("ie%d: no carrier\n", unit);
+ ie->arpcom.ac_if.if_oerrors++;
+ } else if(status & IE_XS_LOSTCTS) {
+ printf("ie%d: lost CTS\n", unit);
+ ie->arpcom.ac_if.if_oerrors++;
+ } else if(status & IE_XS_UNDERRUN) {
+ printf("ie%d: DMA underrun\n", unit);
+ ie->arpcom.ac_if.if_oerrors++;
+ } else if(status & IE_XS_EXCMAX) {
+ printf("ie%d: too many collisions\n", unit);
+ ie->arpcom.ac_if.if_collisions += 16;
+ ie->arpcom.ac_if.if_oerrors++;
+ } else {
+ ie->arpcom.ac_if.if_opackets++;
+ ie->arpcom.ac_if.if_collisions += status & IE_XS_MAXCOLL;
+ }
+ }
+ ie->xmit_count = 0;
+
+ /*
+ * If multicast addresses were added or deleted while we were transmitting,
+ * ie_mc_reset() set the want_mcsetup flag indicating that we should do it.
+ */
+ if(ie->want_mcsetup) {
+ mc_setup(unit, (caddr_t)ie->xmit_cbuffs[0], ie->scb);
+ ie->want_mcsetup = 0;
+ }
+
+ /* Wish I knew why this seems to be necessary... */
+ ie->xmit_cmds[0]->ie_xmit_status |= IE_STAT_COMPL;
+
+ iestart(&ie->arpcom.ac_if);
+ return 0; /* shouldn't be necessary */
+}
+
+/*
+ * Process a receiver-not-ready interrupt. I believe that we get these
+ * when there aren't enough buffers to go around. For now (FIXME), we
+ * just restart the receiver, and hope everything's ok.
+ */
+static int iernr(unit, ie)
+ int unit;
+ struct ie_softc *ie;
+{
+#ifdef doesnt_work
+ setup_rfa((caddr_t)ie->rframes[0], ie);
+
+ ie->scb->ie_recv_list = MK_16(MEM, ie_softc[unit].rframes[0]);
+ command_and_wait(unit, IE_RU_START, 0, 0);
+#else
+ /* This doesn't work either, but it doesn't hang either. */
+ command_and_wait(unit, IE_RU_DISABLE, 0, 0); /* just in case */
+ setup_rfa((caddr_t)ie->rframes[0], ie); /* ignore cast-qual */
+
+ ie->scb->ie_recv_list = MK_16(MEM, ie_softc[unit].rframes[0]);
+ command_and_wait(unit, IE_RU_START, 0, 0); /* was ENABLE */
+
+#endif
+ ie_ack(ie->scb, IE_ST_WHENCE, unit, ie->ie_chan_attn);
+
+ ie->arpcom.ac_if.if_ierrors++;
+ return 0;
+}
+
+#ifdef FILTER
+/*
+ * Compare two Ether/802 addresses for equality, inlined and
+ * unrolled for speed. I'd love to have an inline assembler
+ * version of this...
+ */
+static inline int ether_equal(u_char *one, u_char *two) {
+ if(one[0] != two[0]) return 0;
+ if(one[1] != two[1]) return 0;
+ if(one[2] != two[2]) return 0;
+ if(one[3] != two[3]) return 0;
+ if(one[4] != two[4]) return 0;
+ if(one[5] != two[5]) return 0;
+ return 1;
+}
+
+/*
+ * Check for a valid address. to_bpf is filled in with one of the following:
+ * 0 -> BPF doesn't get this packet
+ * 1 -> BPF does get this packet
+ * 2 -> BPF does get this packet, but we don't
+ * Return value is true if the packet is for us, and false otherwise.
+ *
+ * This routine is a mess, but it's also critical that it be as fast
+ * as possible. It could be made cleaner if we can assume that the
+ * only client which will fiddle with IFF_PROMISC is BPF. This is
+ * probably a good assumption, but we do not make it here. (Yet.)
+ */
+static inline int check_eh(struct ie_softc *ie,
+ struct ether_header *eh,
+ int *to_bpf) {
+ int i;
+
+ switch(ie->promisc) {
+ case IFF_ALLMULTI:
+ /*
+ * Receiving all multicasts, but no unicasts except those destined for us.
+ */
+#if NBPFILTER > 0
+ *to_bpf = (ie->ie_bpf != 0); /* BPF gets this packet if anybody cares */
+#endif
+ if(eh->ether_dhost[0] & 1) {
+ return 1;
+ }
+ if(ether_equal(eh->ether_dhost, ie->arpcom.ac_enaddr)) return 1;
+ return 0;
+
+ case IFF_PROMISC:
+ /*
+ * Receiving all packets. These need to be passed on to BPF.
+ */
+#if NBPFILTER > 0
+ *to_bpf = (ie->ie_bpf != 0);
+#endif
+ /* If for us, accept and hand up to BPF */
+ if(ether_equal(eh->ether_dhost, ie->arpcom.ac_enaddr)) return 1;
+
+#if NBPFILTER > 0
+ if(*to_bpf) *to_bpf = 2; /* we don't need to see it */
+#endif
+
+#ifdef MULTICAST
+ /*
+ * Not a multicast, so BPF wants to see it but we don't.
+ */
+ if(!(eh->ether_dhost[0] & 1)) return 1;
+
+ /*
+ * If it's one of our multicast groups, accept it and pass it
+ * up.
+ */
+ for(i = 0; i < ie->mcast_count; i++) {
+ if(ether_equal(eh->ether_dhost, (u_char *)&ie->mcast_addrs[i])) {
+#if NBPFILTER > 0
+ if(*to_bpf) *to_bpf = 1;
+#endif
+ return 1;
+ }
+ }
+#endif /* MULTICAST */
+ return 1;
+
+ case IFF_ALLMULTI | IFF_PROMISC:
+ /*
+ * Acting as a multicast router, and BPF running at the same time.
+ * Whew! (Hope this is a fast machine...)
+ */
+#if NBPFILTER > 0
+ *to_bpf = (ie->ie_bpf != 0);
+#endif
+ /* We want to see multicasts. */
+ if(eh->ether_dhost[0] & 1) return 1;
+
+ /* We want to see our own packets */
+ if(ether_equal(eh->ether_dhost, ie->arpcom.ac_enaddr)) return 1;
+
+ /* Anything else goes to BPF but nothing else. */
+#if NBPFILTER > 0
+ if(*to_bpf) *to_bpf = 2;
+#endif
+ return 1;
+
+ default:
+ /*
+ * Only accept unicast packets destined for us, or multicasts
+ * for groups that we belong to. For now, we assume that the
+ * '586 will only return packets that we asked it for. This
+ * isn't strictly true (it uses hashing for the multicast filter),
+ * but it will do in this case, and we want to get out of here
+ * as quickly as possible.
+ */
+#if NBPFILTER > 0
+ *to_bpf = (ie->ie_bpf != 0);
+#endif
+ return 1;
+ }
+ return 0;
+}
+#endif /* FILTER */
+
+/*
+ * We want to isolate the bits that have meaning... This assumes that
+ * IE_RBUF_SIZE is an even power of two. If somehow the act_len exceeds
+ * the size of the buffer, then we are screwed anyway.
+ */
+static inline int ie_buflen(struct ie_softc *ie, int head) {
+ return (ie->rbuffs[head]->ie_rbd_actual
+ & (IE_RBUF_SIZE | (IE_RBUF_SIZE - 1)));
+}
+
+static inline int ie_packet_len(int unit, struct ie_softc *ie) {
+ int i;
+ int head = ie->rbhead;
+ int acc = 0;
+
+ do {
+ if(!(ie->rbuffs[ie->rbhead]->ie_rbd_actual & IE_RBD_USED)) {
+#ifdef DEBUG
+ print_rbd(ie->rbuffs[ie->rbhead]);
+#endif
+ log(LOG_ERR, "ie%d: receive descriptors out of sync at %d\n",
+ unit, ie->rbhead);
+ iereset(unit, 0);
+ return -1;
+ }
+
+ i = ie->rbuffs[head]->ie_rbd_actual & IE_RBD_LAST;
+
+ acc += ie_buflen(ie, head);
+ head = (head + 1) % NBUFFS;
+ } while(!i);
+
+ return acc;
+}
+
+/*
+ * Read data off the interface, and turn it into an mbuf chain.
+ *
+ * This code is DRAMATICALLY different from the previous version; this
+ * version tries to allocate the entire mbuf chain up front, given the
+ * length of the data available. This enables us to allocate mbuf
+ * clusters in many situations where before we would have had a long
+ * chain of partially-full mbufs. This should help to speed up the
+ * operation considerably. (Provided that it works, of course.)
+ */
+static inline int ieget(unit, ie, mp, ehp, to_bpf)
+ int unit;
+ struct ie_softc *ie;
+ struct mbuf **mp;
+ struct ether_header *ehp;
+ int *to_bpf;
+{
+ struct mbuf *m, *top, **mymp;
+ int i;
+ int offset;
+ int totlen, resid;
+ int thismboff;
+ int head;
+
+ totlen = ie_packet_len(unit, ie);
+ if(totlen <= 0) return -1;
+
+ i = ie->rbhead;
+
+ /*
+ * Snarf the Ethernet header.
+ */
+ bcopy((caddr_t)ie->cbuffs[i], (caddr_t)ehp, sizeof *ehp);
+ /* ignore cast-qual warning here */
+
+ /*
+ * As quickly as possible, check if this packet is for us.
+ * If not, don't waste a single cycle copying the rest of the
+ * packet in.
+ * This is only a consideration when FILTER is defined; i.e., when
+ * we are either running BPF or doing multicasting.
+ */
+#ifdef FILTER
+ if(!check_eh(ie, ehp, to_bpf)) {
+ ie_drop_packet_buffer(unit, ie);
+ ie->arpcom.ac_if.if_ierrors--; /* just this case, it's not an error */
+ return -1;
+ }
+#endif
+ totlen -= (offset = sizeof *ehp);
+
+ MGETHDR(*mp, M_DONTWAIT, MT_DATA);
+ if(!*mp) {
+ ie_drop_packet_buffer(unit, ie);
+ return -1;
+ }
+
+ m = *mp;
+ m->m_pkthdr.rcvif = &ie->arpcom.ac_if;
+ m->m_len = MHLEN;
+ resid = m->m_pkthdr.len = totlen;
+ top = 0;
+ mymp = &top;
+
+ /*
+ * This loop goes through and allocates mbufs for all the data we will
+ * be copying in. It does not actually do the copying yet.
+ */
+ do { /* while(resid > 0) */
+ /*
+ * Try to allocate an mbuf to hold the data that we have. If we
+ * already allocated one, just get another one and stick it on the
+ * end (eventually). If we don't already have one, try to allocate
+ * an mbuf cluster big enough to hold the whole packet, if we think it's
+ * reasonable, or a single mbuf which may or may not be big enough.
+ * Got that?
+ */
+ if(top) {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if(!m) {
+ m_freem(top);
+ ie_drop_packet_buffer(unit, ie);
+ return -1;
+ }
+ m->m_len = MLEN;
+ }
+
+ if(resid >= MINCLSIZE) {
+ MCLGET(m, M_DONTWAIT);
+ if(m->m_flags & M_EXT)
+ m->m_len = min(resid, MCLBYTES);
+ } else {
+ if(resid < m->m_len) {
+ if(!top && resid + max_linkhdr <= m->m_len)
+ m->m_data += max_linkhdr;
+ m->m_len = resid;
+ }
+ }
+ resid -= m->m_len;
+ *mymp = m;
+ mymp = &m->m_next;
+ } while(resid > 0);
+
+ resid = totlen;
+ m = top;
+ thismboff = 0;
+ head = ie->rbhead;
+
+ /*
+ * Now we take the mbuf chain (hopefully only one mbuf most of the
+ * time) and stuff the data into it. There are no possible failures
+ * at or after this point.
+ */
+ while(resid > 0) { /* while there's stuff left */
+ int thislen = ie_buflen(ie, head) - offset;
+
+ /*
+ * If too much data for the current mbuf, then fill the current one
+ * up, go to the next one, and try again.
+ */
+ if(thislen > m->m_len - thismboff) {
+ int newlen = m->m_len - thismboff;
+ bcopy((caddr_t)(ie->cbuffs[head] + offset),
+ mtod(m, caddr_t) + thismboff, (unsigned)newlen);
+ /* ignore cast-qual warning */
+ m = m->m_next;
+ thismboff = 0; /* new mbuf, so no offset */
+ offset += newlen; /* we are now this far into the packet */
+ resid -= newlen; /* so there is this much left to get */
+ continue;
+ }
+
+ /*
+ * If there is more than enough space in the mbuf to hold the
+ * contents of this buffer, copy everything in, advance pointers,
+ * and so on.
+ */
+ if(thislen < m->m_len - thismboff) {
+ bcopy((caddr_t)(ie->cbuffs[head] + offset), /* ignore warning */
+ mtod(m, caddr_t) + thismboff, (unsigned)thislen);
+ thismboff += thislen; /* we are this far into the mbuf */
+ resid -= thislen; /* and this much is left */
+ goto nextbuf;
+ }
+
+ /*
+ * Otherwise, there is exactly enough space to put this buffer's
+ * contents into the current mbuf. Do the combination of the above
+ * actions.
+ */
+ bcopy((caddr_t)(ie->cbuffs[head] + offset), /* ignore warning */
+ mtod(m, caddr_t) + thismboff, (unsigned)thislen);
+ m = m->m_next;
+ thismboff = 0; /* new mbuf, start at the beginning */
+ resid -= thislen; /* and we are this far through */
+
+ /*
+ * Advance all the pointers. We can get here from either of the
+ * last two cases, but never the first.
+ */
+nextbuf:
+ offset = 0;
+ ie->rbuffs[head]->ie_rbd_actual = 0;
+ ie->rbuffs[head]->ie_rbd_length |= IE_RBD_LAST;
+ ie->rbhead = head = (head + 1) % NBUFFS;
+ ie->rbuffs[ie->rbtail]->ie_rbd_length &= ~IE_RBD_LAST;
+ ie->rbtail = (ie->rbtail + 1) % NBUFFS;
+ }
+
+ /*
+ * Unless something changed strangely while we were doing the copy,
+ * we have now copied everything in from the shared memory.
+ * This means that we are done.
+ */
+ return 0;
+}
+
+/*
+ * Read frame NUM from unit UNIT (pre-cached as IE).
+ *
+ * This routine reads the RFD at NUM, and copies in the buffers from
+ * the list of RBD, then rotates the RBD and RFD lists so that the receiver
+ * doesn't start complaining. Trailers are DROPPED---there's no point
+ * in wasting time on confusing code to deal with them. Hopefully,
+ * this machine will never ARP for trailers anyway.
+ */
+static void ie_readframe(unit, ie, num)
+ int unit;
+ struct ie_softc *ie;
+ int num; /* frame number to read */
+{
+ struct ie_recv_frame_desc rfd;
+ struct mbuf *m = 0;
+ struct ether_header eh;
+#if NBPFILTER > 0
+ int bpf_gets_it = 0;
+#endif
+
+ bcopy((caddr_t)(ie->rframes[num]), &rfd, sizeof(struct ie_recv_frame_desc));
+
+ /* Immediately advance the RFD list, since we we have copied ours now. */
+ ie->rframes[num]->ie_fd_status = 0;
+ ie->rframes[num]->ie_fd_last |= IE_FD_LAST;
+ ie->rframes[ie->rftail]->ie_fd_last &= ~IE_FD_LAST;
+ ie->rftail = (ie->rftail + 1) % NFRAMES;
+ ie->rfhead = (ie->rfhead + 1) % NFRAMES;
+
+ if(rfd.ie_fd_status & IE_FD_OK) {
+ if(
+#if NBPFILTER > 0
+ ieget(unit, ie, &m, &eh, &bpf_gets_it)
+#else
+ ieget(unit, ie, &m, &eh, (int *)0)
+#endif
+ ) {
+ ie->arpcom.ac_if.if_ierrors++; /* this counts as an error */
+ return;
+ }
+ }
+
+#ifdef DEBUG
+ if(ie_debug & IED_READFRAME) {
+ printf("ie%d: frame from ether %s type %x\n", unit,
+ ether_sprintf(eh.ether_shost), (unsigned)eh.ether_type);
+ }
+ if(ntohs(eh.ether_type) > ETHERTYPE_TRAIL
+ && ntohs(eh.ether_type) < (ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER))
+ printf("received trailer!\n");
+#endif
+
+ if(!m) return;
+
+#ifdef FILTER
+ if(last_not_for_us) {
+ m_freem(last_not_for_us);
+ last_not_for_us = 0;
+ }
+
+#if NBPFILTER > 0
+ /*
+ * Check for a BPF filter; if so, hand it up.
+ * Note that we have to stick an extra mbuf up front, because
+ * bpf_mtap expects to have the ether header at the front.
+ * It doesn't matter that this results in an ill-formatted mbuf chain,
+ * since BPF just looks at the data. (It doesn't try to free the mbuf,
+ * tho' it will make a copy for tcpdump.)
+ */
+ if(bpf_gets_it) {
+ struct mbuf m0;
+ m0.m_len = sizeof eh;
+ m0.m_data = (caddr_t)&eh;
+ m0.m_next = m;
+
+ /* Pass it up */
+ bpf_mtap(ie->ie_bpf, &m0);
+ }
+ /*
+ * A signal passed up from the filtering code indicating that the
+ * packet is intended for BPF but not for the protocol machinery.
+ * We can save a few cycles by not handing it off to them.
+ */
+ if(bpf_gets_it == 2) {
+ last_not_for_us = m;
+ return;
+ }
+#endif /* NBPFILTER > 0 */
+ /*
+ * In here there used to be code to check destination addresses upon
+ * receipt of a packet. We have deleted that code, and replaced it
+ * with code to check the address much earlier in the cycle, before
+ * copying the data in; this saves us valuable cycles when operating
+ * as a multicast router or when using BPF.
+ */
+#endif /* FILTER */
+
+ eh.ether_type = ntohs(eh.ether_type);
+
+ /*
+ * Finally pass this packet up to higher layers.
+ */
+ ether_input(&ie->arpcom.ac_if, &eh, m);
+}
+
+static void ie_drop_packet_buffer(int unit, struct ie_softc *ie) {
+ int i;
+
+ do {
+ /*
+ * This means we are somehow out of sync. So, we reset the
+ * adapter.
+ */
+ if(!(ie->rbuffs[ie->rbhead]->ie_rbd_actual & IE_RBD_USED)) {
+#ifdef DEBUG
+ print_rbd(ie->rbuffs[ie->rbhead]);
+#endif
+ log(LOG_ERR, "ie%d: receive descriptors out of sync at %d\n",
+ unit, ie->rbhead);
+ iereset(unit, 0);
+ return;
+ }
+
+ i = ie->rbuffs[ie->rbhead]->ie_rbd_actual & IE_RBD_LAST;
+
+ ie->rbuffs[ie->rbhead]->ie_rbd_length |= IE_RBD_LAST;
+ ie->rbuffs[ie->rbhead]->ie_rbd_actual = 0;
+ ie->rbhead = (ie->rbhead + 1) % NBUFFS;
+ ie->rbuffs[ie->rbtail]->ie_rbd_length &= ~IE_RBD_LAST;
+ ie->rbtail = (ie->rbtail + 1) % NBUFFS;
+ } while(!i);
+}
+
+
+/*
+ * Start transmission on an interface.
+ */
+static void
+iestart(ifp)
+ struct ifnet *ifp;
+{
+ struct ie_softc *ie = &ie_softc[ifp->if_unit];
+ struct mbuf *m0, *m;
+ unsigned char *buffer;
+ u_short len;
+ /* This is not really volatile, in this routine, but it makes gcc happy. */
+ volatile u_short *bptr = &ie->scb->ie_command_list;
+
+ if(!(ifp->if_flags & IFF_RUNNING))
+ return;
+ if(ifp->if_flags & IFF_OACTIVE)
+ return;
+
+ do {
+ IF_DEQUEUE(&ie->arpcom.ac_if.if_snd, m);
+ if(!m)
+ break;
+
+ buffer = ie->xmit_cbuffs[ie->xmit_count];
+ len = 0;
+
+ for(m0 = m; m && len < IE_BUF_LEN; m = m->m_next) {
+ bcopy(mtod(m, caddr_t), buffer, m->m_len);
+ buffer += m->m_len;
+ len += m->m_len;
+ }
+
+ m_freem(m0);
+ len = MAX(len, ETHERMINLEN);
+
+#if NBPFILTER > 0
+ /*
+ * See if bpf is listening on this interface, let it see the packet
+ * before we commit it to the wire.
+ */
+ if(ie->ie_bpf)
+ bpf_tap(ie->ie_bpf, ie->xmit_cbuffs[ie->xmit_count], len);
+#endif
+
+ ie->xmit_buffs[ie->xmit_count]->ie_xmit_flags = IE_XMIT_LAST | len;
+ ie->xmit_buffs[ie->xmit_count]->ie_xmit_next = 0xffff;
+ ie->xmit_buffs[ie->xmit_count]->ie_xmit_buf =
+ MK_24(ie->iomem, ie->xmit_cbuffs[ie->xmit_count]);
+
+ ie->xmit_cmds[ie->xmit_count]->com.ie_cmd_cmd = IE_CMD_XMIT;
+ ie->xmit_cmds[ie->xmit_count]->ie_xmit_status = 0;
+ ie->xmit_cmds[ie->xmit_count]->ie_xmit_desc =
+ MK_16(ie->iomem, ie->xmit_buffs[ie->xmit_count]);
+
+ *bptr = MK_16(ie->iomem, ie->xmit_cmds[ie->xmit_count]);
+ bptr = &ie->xmit_cmds[ie->xmit_count]->com.ie_cmd_link;
+ ie->xmit_count++;
+ } while(ie->xmit_count < 2);
+
+ /*
+ * If we queued up anything for transmission, send it.
+ */
+ if(ie->xmit_count) {
+ ie->xmit_cmds[ie->xmit_count - 1]->com.ie_cmd_cmd |=
+ IE_CMD_LAST | IE_CMD_INTR;
+
+ /*
+ * By passing the command pointer as a null, we tell
+ * command_and_wait() to pretend that this isn't an action
+ * command. I wish I understood what was happening here.
+ */
+ command_and_wait(ifp->if_unit, IE_CU_START, 0, 0);
+ ifp->if_flags |= IFF_OACTIVE;
+ }
+
+ return;
+}
+
+/*
+ * Check to see if there's an 82586 out there.
+ */
+int check_ie_present(unit, where, size)
+ int unit;
+ caddr_t where;
+ unsigned size;
+{
+ volatile struct ie_sys_conf_ptr *scp;
+ volatile struct ie_int_sys_conf_ptr *iscp;
+ volatile struct ie_sys_ctl_block *scb;
+ u_long realbase;
+ int s;
+
+ s = splimp();
+
+ realbase = (u_long)where + size - (1 << 24);
+
+ scp = (volatile struct ie_sys_conf_ptr *)(realbase + IE_SCP_ADDR);
+ bzero((char *)scp, sizeof *scp); /* ignore cast-qual */
+
+ /*
+ * First we put the ISCP at the bottom of memory; this tests to make
+ * sure that our idea of the size of memory is the same as the controller's.
+ * This is NOT where the ISCP will be in normal operation.
+ */
+ iscp = (volatile struct ie_int_sys_conf_ptr *)where;
+ bzero((char *)iscp, sizeof *iscp); /* ignore cast-qual */
+
+ scb = (volatile struct ie_sys_ctl_block *)where;
+ bzero((char *)scb, sizeof *scb); /* ignore cast-qual */
+
+ scp->ie_bus_use = 0; /* 16-bit */
+ scp->ie_iscp_ptr = (caddr_t)((volatile caddr_t)iscp - /* ignore cast-qual */
+ (volatile caddr_t)realbase);
+
+ iscp->ie_busy = 1;
+ iscp->ie_scb_offset = MK_16(realbase, scb) + 256;
+
+ (*ie_softc[unit].ie_reset_586)(unit);
+ (*ie_softc[unit].ie_chan_attn)(unit);
+
+ DELAY(100); /* wait a while... */
+
+ if(iscp->ie_busy) {
+ splx(s);
+ return 0;
+ }
+
+ /*
+ * Now relocate the ISCP to its real home, and reset the controller
+ * again.
+ */
+ iscp = (void *)Align((caddr_t)(realbase + IE_SCP_ADDR -
+ sizeof(struct ie_int_sys_conf_ptr)));
+ bzero((char *)iscp, sizeof *iscp); /* ignore cast-qual */
+
+ scp->ie_iscp_ptr = (caddr_t)((caddr_t)iscp - (caddr_t)realbase);
+ /* ignore cast-qual */
+
+ iscp->ie_busy = 1;
+ iscp->ie_scb_offset = MK_16(realbase, scb);
+
+ (*ie_softc[unit].ie_reset_586)(unit);
+ (*ie_softc[unit].ie_chan_attn)(unit);
+
+ DELAY(100);
+
+ if(iscp->ie_busy) {
+ splx(s);
+ return 0;
+ }
+
+ ie_softc[unit].iosize = size;
+ ie_softc[unit].iomem = (caddr_t)realbase;
+
+ ie_softc[unit].iscp = iscp;
+ ie_softc[unit].scb = scb;
+
+ /*
+ * Acknowledge any interrupts we may have caused...
+ */
+ ie_ack(scb, IE_ST_WHENCE, unit, ie_softc[unit].ie_chan_attn);
+ splx(s);
+
+ return 1;
+}
+
+/*
+ * Divine the memory size of ie board UNIT.
+ * Better hope there's nothing important hiding just below the ie card...
+ */
+static void find_ie_mem_size(unit)
+ int unit;
+{
+ unsigned size;
+
+ ie_softc[unit].iosize = 0;
+
+ for(size = 65536; size >= 16384; size -= 16384) {
+ if(check_ie_present(unit, ie_softc[unit].iomembot, size)) {
+ return;
+ }
+ }
+
+ return;
+}
+
+void sl_reset_586(unit)
+ int unit;
+{
+ outb(PORT + IEATT_RESET, 0);
+}
+
+void sl_chan_attn(unit)
+ int unit;
+{
+ outb(PORT + IEATT_ATTN, 0);
+}
+
+void sl_read_ether(unit, addr)
+ int unit;
+ unsigned char addr[6];
+{
+ int i;
+
+ for(i = 0; i < 6; i++)
+ addr[i] = inb(PORT + i);
+}
+
+
+static void
+iereset(unit, dummy)
+ int unit, dummy;
+{
+ int s = splimp();
+
+ if(unit >= NIE) {
+ splx(s);
+ return;
+ }
+
+ printf("ie%d: reset\n", unit);
+ ie_softc[unit].arpcom.ac_if.if_flags &= ~IFF_UP;
+ ieioctl(&ie_softc[unit].arpcom.ac_if, SIOCSIFFLAGS, 0);
+
+ /*
+ * Stop i82586 dead in its tracks.
+ */
+ if(command_and_wait(unit, IE_RU_ABORT | IE_CU_ABORT, 0, 0))
+ printf("ie%d: abort commands timed out\n", unit);
+
+ if(command_and_wait(unit, IE_RU_DISABLE | IE_CU_STOP, 0, 0))
+ printf("ie%d: disable commands timed out\n", unit);
+
+#ifdef notdef
+ if(!check_ie_present(unit, ie_softc[unit].iomembot, ie_softc[unit].iosize))
+ panic("ie disappeared!\n");
+#endif
+
+ ie_softc[unit].arpcom.ac_if.if_flags |= IFF_UP;
+ ieioctl(&ie_softc[unit].arpcom.ac_if, SIOCSIFFLAGS, 0);
+
+ splx(s);
+ return;
+}
+
+/*
+ * This is called if we time out.
+ */
+static void
+chan_attn_timeout(rock, arg2)
+ caddr_t rock;
+ int arg2;
+{
+ *(int *)rock = 1;
+}
+
+/*
+ * Send a command to the controller and wait for it to either
+ * complete or be accepted, depending on the command. If the
+ * command pointer is null, then pretend that the command is
+ * not an action command. If the command pointer is not null,
+ * and the command is an action command, wait for
+ * ((volatile struct ie_cmd_common *)pcmd)->ie_cmd_status & MASK
+ * to become true.
+ */
+static int command_and_wait(unit, cmd, pcmd, mask)
+ int unit;
+ int cmd;
+ volatile void *pcmd;
+ int mask;
+{
+ volatile struct ie_cmd_common *cc = pcmd;
+ volatile int timedout = 0;
+ extern int hz;
+
+ ie_softc[unit].scb->ie_command = (u_short)cmd;
+
+ if(IE_ACTION_COMMAND(cmd) && pcmd) {
+ (*ie_softc[unit].ie_chan_attn)(unit);
+
+ /*
+ * According to the packet driver, the minimum timeout should be
+ * .369 seconds, which we round up to .37.
+ */
+ timeout(chan_attn_timeout, (caddr_t)&timedout, 37 * hz / 100);
+ /* ignore cast-qual */
+
+ /*
+ * Now spin-lock waiting for status. This is not a very nice
+ * thing to do, but I haven't figured out how, or indeed if, we
+ * can put the process waiting for action to sleep. (We may
+ * be getting called through some other timeout running in the
+ * kernel.)
+ */
+ while(1) {
+ if((cc->ie_cmd_status & mask) || timedout)
+ break;
+ }
+
+ untimeout(chan_attn_timeout, (caddr_t)&timedout);
+ /* ignore cast-qual */
+
+ return timedout;
+ } else {
+
+ /*
+ * Otherwise, just wait for the command to be accepted.
+ */
+ (*ie_softc[unit].ie_chan_attn)(unit);
+
+ while(ie_softc[unit].scb->ie_command)
+ ; /* spin lock */
+
+ return 0;
+ }
+}
+
+/*
+ * Run the time-domain reflectometer...
+ */
+static void run_tdr(unit, cmd)
+ int unit;
+ struct ie_tdr_cmd *cmd;
+{
+ int result;
+
+ cmd->com.ie_cmd_status = 0;
+ cmd->com.ie_cmd_cmd = IE_CMD_TDR | IE_CMD_LAST;
+ cmd->com.ie_cmd_link = 0xffff;
+ cmd->ie_tdr_time = 0;
+
+ ie_softc[unit].scb->ie_command_list = MK_16(MEM, cmd);
+ cmd->ie_tdr_time = 0;
+
+ if(command_and_wait(unit, IE_CU_START, cmd, IE_STAT_COMPL))
+ result = 0x2000;
+ else
+ result = cmd->ie_tdr_time;
+
+ ie_ack(ie_softc[unit].scb, IE_ST_WHENCE, unit,
+ ie_softc[unit].ie_chan_attn);
+
+ if(result & IE_TDR_SUCCESS)
+ return;
+
+ if(result & IE_TDR_XCVR) {
+ printf("ie%d: transceiver problem\n", unit);
+ } else if(result & IE_TDR_OPEN) {
+ printf("ie%d: TDR detected an open %d clocks away\n", unit,
+ result & IE_TDR_TIME);
+ } else if(result & IE_TDR_SHORT) {
+ printf("ie%d: TDR detected a short %d clocks away\n", unit,
+ result & IE_TDR_TIME);
+ } else {
+ printf("ie%d: TDR returned unknown status %x\n", result);
+ }
+}
+
+static void start_receiver(unit)
+ int unit;
+{
+ int s = splimp();
+
+ ie_softc[unit].scb->ie_recv_list = MK_16(MEM, ie_softc[unit].rframes[0]);
+ command_and_wait(unit, IE_RU_START, 0, 0);
+
+ ie_ack(ie_softc[unit].scb, IE_ST_WHENCE, unit, ie_softc[unit].ie_chan_attn);
+
+ splx(s);
+}
+
+/*
+ * Here is a helper routine for iernr() and ieinit(). This sets up
+ * the RFA.
+ */
+static caddr_t setup_rfa(caddr_t ptr, struct ie_softc *ie) {
+ volatile struct ie_recv_frame_desc *rfd = (void *)ptr;
+ volatile struct ie_recv_buf_desc *rbd;
+ int i;
+ int unit = ie - &ie_softc[0];
+
+ /* First lay them out */
+ for(i = 0; i < NFRAMES; i++) {
+ ie->rframes[i] = rfd;
+ bzero((char *)rfd, sizeof *rfd); /* ignore cast-qual */
+ rfd++;
+ }
+
+ ptr = (caddr_t)Align((caddr_t)rfd); /* ignore cast-qual */
+
+ /* Now link them together */
+ for(i = 0; i < NFRAMES; i++) {
+ ie->rframes[i]->ie_fd_next =
+ MK_16(MEM, ie->rframes[(i + 1) % NFRAMES]);
+ }
+
+ /* Finally, set the EOL bit on the last one. */
+ ie->rframes[NFRAMES - 1]->ie_fd_last |= IE_FD_LAST;
+
+ /*
+ * Now lay out some buffers for the incoming frames. Note that
+ * we set aside a bit of slop in each buffer, to make sure that
+ * we have enough space to hold a single frame in every buffer.
+ */
+ rbd = (void *)ptr;
+
+ for(i = 0; i < NBUFFS; i++) {
+ ie->rbuffs[i] = rbd;
+ bzero((char *)rbd, sizeof *rbd); /* ignore cast-qual */
+ ptr = (caddr_t)Align(ptr + sizeof *rbd);
+ rbd->ie_rbd_length = IE_RBUF_SIZE;
+ rbd->ie_rbd_buffer = MK_24(MEM, ptr);
+ ie->cbuffs[i] = (void *)ptr;
+ ptr += IE_RBUF_SIZE;
+ rbd = (void *)ptr;
+ }
+
+ /* Now link them together */
+ for(i = 0; i < NBUFFS; i++) {
+ ie->rbuffs[i]->ie_rbd_next = MK_16(MEM, ie->rbuffs[(i + 1) % NBUFFS]);
+ }
+
+ /* Tag EOF on the last one */
+ ie->rbuffs[NBUFFS - 1]->ie_rbd_length |= IE_RBD_LAST;
+
+ /* We use the head and tail pointers on receive to keep track of
+ * the order in which RFDs and RBDs are used. */
+ ie->rfhead = 0;
+ ie->rftail = NFRAMES - 1;
+ ie->rbhead = 0;
+ ie->rbtail = NBUFFS - 1;
+
+ ie->scb->ie_recv_list = MK_16(MEM, ie->rframes[0]);
+ ie->rframes[0]->ie_fd_buf_desc = MK_16(MEM, ie->rbuffs[0]);
+
+ ptr = Align(ptr);
+ return ptr;
+}
+
+/*
+ * Run the multicast setup command.
+ * Call at splimp().
+ */
+static int mc_setup(int unit, caddr_t ptr,
+ volatile struct ie_sys_ctl_block *scb) {
+ struct ie_softc *ie = &ie_softc[unit];
+ volatile struct ie_mcast_cmd *cmd = (void *)ptr;
+
+ cmd->com.ie_cmd_status = 0;
+ cmd->com.ie_cmd_cmd = IE_CMD_MCAST | IE_CMD_LAST;
+ cmd->com.ie_cmd_link = 0xffff;
+
+ /* ignore cast-qual */
+ bcopy((caddr_t)ie->mcast_addrs, (caddr_t)cmd->ie_mcast_addrs,
+ ie->mcast_count * sizeof *ie->mcast_addrs);
+
+ cmd->ie_mcast_bytes = ie->mcast_count * 6; /* grrr... */
+
+ scb->ie_command_list = MK_16(MEM, cmd);
+ if(command_and_wait(unit, IE_CU_START, cmd, IE_STAT_COMPL)
+ || !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
+ printf("ie%d: multicast address setup command failed\n", unit);
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * This routine takes the environment generated by check_ie_present()
+ * and adds to it all the other structures we need to operate the adapter.
+ * This includes executing the CONFIGURE, IA-SETUP, and MC-SETUP commands,
+ * starting the receiver unit, and clearing interrupts.
+ *
+ * THIS ROUTINE MUST BE CALLED AT splimp() OR HIGHER.
+ */
+static void
+ieinit(unit)
+ int unit;
+{
+ struct ie_softc *ie = &ie_softc[unit];
+ volatile struct ie_sys_ctl_block *scb = ie->scb;
+ caddr_t ptr;
+
+ ptr = (caddr_t)Align((caddr_t)scb + sizeof *scb); /* ignore cast-qual */
+
+ /*
+ * Send the configure command first.
+ */
+ {
+ volatile struct ie_config_cmd *cmd = (void *)ptr;
+
+ ie_setup_config(cmd, ie->promisc, ie->hard_type == IE_STARLAN10);
+ cmd->com.ie_cmd_status = 0;
+ cmd->com.ie_cmd_cmd = IE_CMD_CONFIG | IE_CMD_LAST;
+ cmd->com.ie_cmd_link = 0xffff;
+
+ scb->ie_command_list = MK_16(MEM, cmd);
+
+ if(command_and_wait(unit, IE_CU_START, cmd, IE_STAT_COMPL)
+ || !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
+ printf("ie%d: configure command failed\n", unit);
+ return;
+ }
+ }
+ /*
+ * Now send the Individual Address Setup command.
+ */
+ {
+ volatile struct ie_iasetup_cmd *cmd = (void *)ptr;
+
+ cmd->com.ie_cmd_status = 0;
+ cmd->com.ie_cmd_cmd = IE_CMD_IASETUP | IE_CMD_LAST;
+ cmd->com.ie_cmd_link = 0xffff;
+
+ bcopy((char *)ie_softc[unit].arpcom.ac_enaddr, (char *)&cmd->ie_address,
+ sizeof cmd->ie_address); /* ignore cast-qual */
+
+ scb->ie_command_list = MK_16(MEM, cmd);
+ if(command_and_wait(unit, IE_CU_START, cmd, IE_STAT_COMPL)
+ || !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
+ printf("ie%d: individual address setup command failed\n", unit);
+ return;
+ }
+ }
+
+ /*
+ * Now run the time-domain reflectometer.
+ */
+ run_tdr(unit, (void *)ptr);
+
+ /*
+ * Acknowledge any interrupts we have generated thus far.
+ */
+ ie_ack(ie->scb, IE_ST_WHENCE, unit, ie->ie_chan_attn);
+
+ /*
+ * Set up the RFA.
+ */
+ ptr = setup_rfa(ptr, ie);
+
+ /*
+ * Finally, the transmit command and buffer are the last little bit of work.
+ */
+ ie->xmit_cmds[0] = (void *)ptr;
+ ptr += sizeof *ie->xmit_cmds[0];
+ ptr = Align(ptr);
+ ie->xmit_buffs[0] = (void *)ptr;
+ ptr += sizeof *ie->xmit_buffs[0];
+ ptr = Align(ptr);
+
+ /* Second transmit command */
+ ie->xmit_cmds[1] = (void *)ptr;
+ ptr += sizeof *ie->xmit_cmds[1];
+ ptr = Align(ptr);
+ ie->xmit_buffs[1] = (void *)ptr;
+ ptr += sizeof *ie->xmit_buffs[1];
+ ptr = Align(ptr);
+
+ /* Both transmit buffers */
+ ie->xmit_cbuffs[0] = (void *)ptr;
+ ptr += IE_BUF_LEN;
+ ptr = Align(ptr);
+ ie->xmit_cbuffs[1] = (void *)ptr;
+
+ bzero((caddr_t)ie->xmit_cmds[0], sizeof *ie->xmit_cmds[0]); /* ignore */
+ bzero((caddr_t)ie->xmit_buffs[0], sizeof *ie->xmit_buffs[0]); /* cast-qual */
+ bzero((caddr_t)ie->xmit_cmds[1], sizeof *ie->xmit_cmds[0]); /* warnings */
+ bzero((caddr_t)ie->xmit_buffs[1], sizeof *ie->xmit_buffs[0]); /* here */
+
+ /*
+ * This must be coordinated with iestart() and ietint().
+ */
+ ie->xmit_cmds[0]->ie_xmit_status = IE_STAT_COMPL;
+
+ ie->arpcom.ac_if.if_flags |= IFF_RUNNING; /* tell higher levels that we are here */
+ start_receiver(unit);
+ return;
+}
+
+static void ie_stop(unit)
+ int unit;
+{
+ command_and_wait(unit, IE_RU_DISABLE, 0, 0);
+}
+
+static int
+ieioctl(ifp, command, data)
+ struct ifnet *ifp;
+ int command;
+ caddr_t data;
+{
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ struct ie_softc *ie = &ie_softc[ifp->if_unit];
+ int s, error = 0;
+
+ s = splimp();
+
+ switch(command) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+
+ switch(ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ ieinit(ifp->if_unit);
+ ((struct arpcom *)ifp)->ac_ipaddr =
+ IA_SIN(ifa)->sin_addr;
+ arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
+ break;
+#endif /* INET */
+
+#ifdef NS
+ /* This magic copied from if_is.c; I don't use XNS, so I have no
+ * way of telling if this actually works or not.
+ */
+ case AF_NS:
+ {
+ struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+
+ if(ns_nullhost(*ina)) {
+ ina->x_host = *(union ns_host *)(ie->arpcom.ac_enaddr);
+ } else {
+ ifp->if_flags &= ~IFF_RUNNING;
+ bcopy((caddr_t)ina->x_host.c_host,
+ (caddr_t)ie->arpcom.ac_enaddr,
+ sizeof ie->arpcom.ac_enaddr);
+ }
+
+ ieinit(ifp->if_unit);
+ }
+ break;
+#endif /* NS */
+
+ default:
+ ieinit(ifp->if_unit);
+ break;
+ }
+ break;
+
+ case SIOCSIFFLAGS:
+ /*
+ * Note that this device doesn't have an "all multicast" mode, so we
+ * must turn on promiscuous mode and do the filtering manually.
+ */
+ if((ifp->if_flags & IFF_UP) == 0 &&
+ (ifp->if_flags & IFF_RUNNING)) {
+ ifp->if_flags &= ~IFF_RUNNING;
+ ie_stop(ifp->if_unit);
+ } else if((ifp->if_flags & IFF_UP) &&
+ (ifp->if_flags & IFF_RUNNING) == 0) {
+ ie_softc[ifp->if_unit].promisc =
+ ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI);
+ ieinit(ifp->if_unit);
+ } else if(ie_softc[ifp->if_unit].promisc ^
+ (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI))) {
+ ie_softc[ifp->if_unit].promisc =
+ ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI);
+ ieinit(ifp->if_unit);
+ }
+ break;
+
+#ifdef MULTICAST
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ /*
+ * Update multicast listeners
+ */
+ error = ((command == SIOCADDMULTI)
+ ? ether_addmulti((struct ifreq *)data, &ie->arpcom)
+ : ether_delmulti((struct ifreq *)data, &ie->arpcom));
+
+ if(error == ENETRESET) {
+ /* reset multicast filtering */
+ ie_mc_reset(ifp->if_unit);
+ error = 0;
+ }
+ break;
+#endif /* MULTICAST */
+
+ default:
+ error = EINVAL;
+ }
+
+ splx(s);
+ return error;
+}
+
+#ifdef MULTICAST
+static void ie_mc_reset(int unit) {
+ struct ie_softc *ie = &ie_softc[unit];
+ struct ether_multi *enm;
+ struct ether_multistep step;
+
+ /*
+ * Step through the list of addresses.
+ */
+ ie->mcast_count = 0;
+ ETHER_FIRST_MULTI(step, &ie->arpcom, enm);
+ while(enm) {
+ if(ie->mcast_count >= MAXMCAST
+ || bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
+ ie->arpcom.ac_if.if_flags |= IFF_ALLMULTI;
+ ieioctl(&ie->arpcom.ac_if, SIOCSIFFLAGS, (void *)0);
+ goto setflag;
+ }
+
+ bcopy(enm->enm_addrlo, &(ie->mcast_addrs[ie->mcast_count]), 6);
+ ie->mcast_count++;
+ ETHER_NEXT_MULTI(step, enm);
+ }
+
+setflag:
+ ie->want_mcsetup = 1;
+}
+
+#endif
+
+#ifdef DEBUG
+void print_rbd(volatile struct ie_recv_buf_desc *rbd) {
+ printf("RBD at %08lx:\n"
+ "actual %04x, next %04x, buffer %08x\n"
+ "length %04x, mbz %04x\n",
+ (unsigned long)rbd,
+ rbd->ie_rbd_actual, rbd->ie_rbd_next, rbd->ie_rbd_buffer,
+ rbd->ie_rbd_length, rbd->mbz);
+}
+#endif /* DEBUG */
+#endif /* NIE > 0 */
+
diff --git a/sys/dev/ie/if_iereg.h b/sys/dev/ie/if_iereg.h
new file mode 100644
index 0000000..3588b84
--- /dev/null
+++ b/sys/dev/ie/if_iereg.h
@@ -0,0 +1,24 @@
+/*
+ * $Id$
+ * definitions for AT&T StarLAN 10 etc...
+ */
+
+#define IEATT_RESET 0 /* any write here resets the 586 */
+#define IEATT_ATTN 1 /* any write here sends a Chan attn */
+#define IEATT_REVISION 6 /* read here to figure out this board */
+#define IEATT_ATTRIB 7 /* more information about this board */
+
+#define SL_BOARD(x) ((x) & 0x0f)
+#define SL_REV(x) ((x) >> 4)
+
+#define SL1_BOARD 0
+#define SL10_BOARD 1
+#define EN100_BOARD 2
+#define SLFIBER_BOARD 3
+
+#define SL_ATTR_WIDTH 0x04 /* bus width: clear -> 8-bit */
+#define SL_ATTR_SPEED 0x08 /* medium speed: clear -> 10 Mbps */
+#define SL_ATTR_CODING 0x10 /* encoding: clear -> Manchester */
+#define SL_ATTR_HBW 0x20 /* host bus width: clear -> 16-bit */
+#define SL_ATTR_TYPE 0x40 /* medium type: clear -> Ethernet */
+#define SL_ATTR_BOOTROM 0x80 /* set -> boot ROM present */
diff --git a/sys/dev/kbd/kbdtables.h b/sys/dev/kbd/kbdtables.h
new file mode 100644
index 0000000..a923c45
--- /dev/null
+++ b/sys/dev/kbd/kbdtables.h
@@ -0,0 +1,859 @@
+/*
+ * Copyright (C) 1992, 1993, 1994 Søren Schmidt
+ *
+ * This program is free software; you may redistribute it and/or
+ * modify it, provided that it retain the above copyright notice
+ * and the following disclaimer.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Søren Schmidt Email: sos@login.dkuug.dk
+ * Tritonvej 36 UUCP: ...uunet!dkuug!login!sos
+ * DK9210 Aalborg SO Phone: +45 9814 8076
+ *
+ * @(#)kbdtables.h 1.3 940123
+ * $Id: kbdtables.h,v 1.11 1994/02/01 09:27:43 ache Exp $
+ */
+
+#define SET8 0x80 /* eight bit for emacs SET8-key */
+
+#ifdef DKKEYMAP
+keymap_t key_map = { 0x69, /* DK iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, '1', '!', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '"', 0x00, 0x00, '@', '"', 0x00, 0x00, 0x00, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, 0x9E, '#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', 0xA4, NOP, NOP, '$', 0xA4, NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, '5', '%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '&', NOP, NOP, '6', '&', NOP, NOP, 0x33, 0x00,
+/* sc=08 */ '7', '/', NOP, NOP, '{', '/', NOP, NOP, 0x33, 0x00,
+/* sc=09 */ '8', '(', 0x1B, 0x1B, '[', '(', 0x1B, 0x1B, 0x00, 0x00,
+/* sc=0a */ '9', ')', 0x1D, 0x1D, ']', ')', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=0b */ '0', '=', NOP, NOP, '}', '=', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '+', '?', NOP, NOP, '+', '?', NOP, NOP, 0x33, 0x00,
+/* sc=0d */ '\'', '`', NOP, NOP, '|', '`', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x33, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ 0xE5, 0xC5, NOP, NOP, 0x86, 0x8F, NOP, NOP, 0x33, 0x01,
+/* sc=1b */ '"', '^', 0x1E, 0x1E, '~', '^', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ 0xE6, 0xC6, NOP, NOP, 0x91, 0x92, NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xF8, 0xD8, NOP, NOP, 0x9B, 0x9D, NOP, NOP, 0x33, 0x01,
+/* sc=29 */ 0xBD, 0xA7, NOP, NOP, 0xBD, 0xA7, NOP, NOP, 0x33, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\'', '*', NOP, NOP, '\'', '*', NOP, NOP, 0x33, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', ';', NOP, NOP, ',', ';', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', ':', NOP, NOP, '.', ':', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '-', '_', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, 0x00, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', '*', '*', '*', '*', '*', '*', 0x00, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, 0xFF, 0x00,
+/* sc=46 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', '-', '-', '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ NOP, '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', '6', '6', '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ '<', '>', 0x1C, 0x1C, '\\', '>', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x00, 0x02,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x00,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+#endif
+
+#ifdef UKKEYMAP
+keymap_t key_map = { 0x69, /* uk iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, '`', '`', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '"', 0x00, 0x00, '@', '@', 0x00, 0x00, 0x00, 0x00,
+/* sc=04 */ '3', 0xA3, NOP, NOP, '#', '#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, '4', '$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, '5', '%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '^', 0x1E, 0x1E, '^', '^', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=08 */ '7', '&', NOP, NOP, '[', '[', 0x1B, 0x1B, 0x30, 0x00,
+/* sc=09 */ '8', '*', NOP, NOP, '8', '*', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '9', '(', NOP, NOP, ']', ']', 0x1D, 0x1D, 0x30, 0x00,
+/* sc=0b */ '0', ')', NOP, NOP, '{', '{', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '-', '_', 0x1F, 0x1F, '|', '|', 0x1F, 0x1F, 0x00, 0x00,
+/* sc=0d */ '=', '+', NOP, NOP, '}', '}', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ '[', '{', 0x1B, 0x1B, '[', '{', 0x1B, 0x1B, 0x00, 0x00,
+/* sc=1b */ ']', '}', 0x1D, 0x1D, ']', '}', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ ';', ':', NOP, NOP, ';', ':', NOP, NOP, 0x33, 0x00,
+/* sc=28 */ '\'', '@', 0x00, 0x00, '\'', '@', 0x00, 0x00, 0x00, 0x00,
+/* sc=29 */ '\\', '|', 0x1C, 0x1C, '\\', '\\', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '#', '~', NOP, NOP, '~', '~', NOP, NOP, 0x33, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', '<', NOP, NOP, ',', '<', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', '>', NOP, NOP, '.', '>', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '/', '?', NOP, NOP, '/', '?', NOP, NOP, 0x33, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, 0x13, 0x13, NLK, NLK, 0x13, 0x13, 0xCC, 0x00,
+/* sc=46 */ SLK, SLK, 0x7F, 0x7F, SLK, SLK, 0x7F, 0x7F, 0xCC, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', 0x1F, 0x1F, '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ F(54), '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', 0x1E, 0x1E, '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ '\\', '|', 0x1C, 0x1C, '\\', '|', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0xFF, 0x02,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x02,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+#endif
+
+#ifdef GRKEYMAP
+keymap_t key_map = { 0x69, /* german iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, '`', '`', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '"', 0x00, 0x00, '@', '@', 0x00, 0x00, 0x00, 0x00,
+/* sc=04 */ '3', 0xA7, NOP, NOP, '#', '#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, '4', '$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, '5', '%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '&', 0x1E, 0x1E, '^', '^', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=08 */ '7', '/', 0x1B, 0x1B, '[', '[', 0x1B, 0x1B, 0x00, 0x00,
+/* sc=09 */ '8', '(', NOP, NOP, '8', '(', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '9', ')', 0x1D, 0x1D, ']', ']', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=0b */ '0', '=', NOP, NOP, '{', '{', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ 0xDF, '?', NOP, NOP, '|', '|', NOP, NOP, 0x33, 0x00,
+/* sc=0d */ 0x92, 0x93, NOP, NOP, '\'', '`', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ 0xFC, 0xDC, 0x1B, 0x1B, '[', '{', 0x1B, 0x1B, 0x00, 0x01,
+/* sc=1b */ '+', '*', 0x1D, 0x1D, ']', '}', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ 0xF6, 0xD6, NOP, NOP, 0xF6, 0xD6, NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xE4, 0xC4, NOP, NOP, 0xE4, 0xC4, NOP, NOP, 0x33, 0x01,
+/* sc=29 */ '<', '>', 0x1C, 0x1C, '\\', '|', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '#', '^', 0x1E, 0x1E, '`', '~', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=2c */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', ';', NOP, NOP, ',', ';', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', ':', NOP, NOP, '.', ':', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '-', '_', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, 0x00, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, 0x13, 0x13, NLK, NLK, 0x13, 0x13, 0xCC, 0x00,
+/* sc=46 */ SLK, SLK, 0x7F, 0x7F, SLK, SLK, 0x7F, 0x7F, 0xCC, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', 0x1F, 0x1F, '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ F(54), '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', 0x1E, 0x1E, '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0xFF, 0x02,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x02,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+#endif
+
+#ifdef SWKEYMAP
+keymap_t key_map = { 0x69, /* swedish iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=03 */ '2', '"', NOP, NOP, '@', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, 0xA3, NOP, NOP, NOP, 0x37, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, 0xA4, NOP, NOP, NOP, 0x37, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=07 */ '6', '&', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=08 */ '7', '/', NOP, NOP, '{', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=09 */ '8', '(', NOP, NOP, '[', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0a */ '9', ')', NOP, NOP, ']', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0b */ '0', '=', NOP, NOP, '}', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0c */ '+', '?', NOP, NOP, '\\', NOP, 0x1C, NOP, 0x35, 0x00,
+/* sc=0d */ 0x180, '`', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ 0xE5, 0xC5, NOP, NOP, '}', ']', NOP, NOP, 0x33, 0x01,
+/* sc=1b */ 0xA8, '^', NOP, NOP, '~', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ 0xF6, 0xD6, NOP, NOP, '|', '\\', NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xE4, 0xC4, NOP, NOP, '{', '[', NOP, NOP, 0x33, 0x01,
+/* sc=29 */ 0xA7, 0xBD, NOP, NOP, '\\', '|', NOP, NOP, 0x33, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\'', '*', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', ';', NOP, NOP, NOP, '<', NOP, NOP, 0x3B, 0x00,
+/* sc=34 */ '.', ':', NOP, NOP, NOP, '>', NOP, NOP, 0x3B, 0x00,
+/* sc=35 */ '-', '_', 0x1F, NOP, '/', '?', NOP, NOP, 0x13, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, 0x13, 0x13, NLK, NLK, 0x13, 0x13, 0xCC, 0x00,
+/* sc=46 */ SLK, SLK, 0x7F, 0x7F, SLK, SLK, 0x7F, 0x7F, 0xCC, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', 0x1F, 0x1F, '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ F(54), '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', 0x1E, 0x1E, '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ '<', '>', NOP, NOP, '|', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0xFF, 0x02,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x02,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+#endif
+
+#ifdef RUKEYMAP
+keymap_t key_map = { 0xe9, /* keys number */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * -------------------------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, NOP, NOP, SET8|0x1B, SET8|0x1B, DBG, NOP, 0x33, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, SET8|'1', SET8|'!', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '@', 0x00, 0x00, SET8|'2', SET8|'@', SET8|0x00, SET8|0x00, 0x00, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, SET8|'3', SET8|'#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, SET8|'4', SET8|'$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, SET8|'5', SET8|'%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '^', 0x1E, 0x1E, SET8|'6', SET8|'^', SET8|0x1E, SET8|0x1E, 0x00, 0x00,
+/* sc=08 */ '7', '&', NOP, NOP, SET8|'7', SET8|'&', NOP, NOP, 0x33, 0x00,
+/* sc=09 */ '8', '*', NOP, NOP, SET8|'8', SET8|'*', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '9', '(', NOP, NOP, SET8|'9', SET8|'(', NOP, NOP, 0x33, 0x00,
+/* sc=0b */ '0', ')', NOP, NOP, SET8|'0', SET8|')', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '-', '_', 0x1F, 0x1F, SET8|'-', SET8|'_', SET8|0x1F, SET8|0x1F, 0x00, 0x00,
+/* sc=0d */ '=', '+', NOP, NOP, SET8|'=', SET8|'+', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, SET8|0x08, SET8|0x08, SET8|0x7F, SET8|0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, F(16), NOP, NOP, SET8|0x09, F(16), NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, SET8|'q', SET8|'Q', SET8|0x11, SET8|0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, SET8|'w', SET8|'W', SET8|0x17, SET8|0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, SET8|'e', SET8|'E', SET8|0x05, SET8|0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, SET8|'r', SET8|'R', SET8|0x12, SET8|0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, SET8|'t', SET8|'T', SET8|0x14, SET8|0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, SET8|'y', SET8|'Y', SET8|0x19, SET8|0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, SET8|'u', SET8|'U', SET8|0x15, SET8|0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, SET8|'i', SET8|'I', SET8|0x09, SET8|0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, SET8|'o', SET8|'O', SET8|0x0F, SET8|0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, SET8|'p', SET8|'P', SET8|0x10, SET8|0x10, 0x00, 0x01,
+/* sc=1a */ '[', '{', 0x1B, 0x1B, SET8|'[', SET8|'{', SET8|0x1B, SET8|0x1B, 0x00, 0x00,
+/* sc=1b */ ']', '}', 0x1D, 0x1D, SET8|']', SET8|'}', SET8|0x1D, SET8|0x1D, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, SET8|0x0D, SET8|0x0D, SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, SET8|'a', SET8|'A', SET8|0x01, SET8|0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, SET8|'s', SET8|'S', SET8|0x13, SET8|0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, SET8|'d', SET8|'D', SET8|0x04, SET8|0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, SET8|'f', SET8|'F', SET8|0x06, SET8|0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, SET8|'g', SET8|'G', SET8|0x07, SET8|0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, SET8|'h', SET8|'H', SET8|0x08, SET8|0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, SET8|'j', SET8|'J', SET8|0x0A, SET8|0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, SET8|'k', SET8|'K', SET8|0x0B, SET8|0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, SET8|'l', SET8|'L', SET8|0x0C, SET8|0x0C, 0x00, 0x01,
+/* sc=27 */ ';', ':', NOP, NOP, SET8|';', SET8|':', NOP, NOP, 0x33, 0x00,
+/* sc=28 */ '\'', '"', NOP, NOP, SET8|'\'', SET8|'"', NOP, NOP, 0x33, 0x00,
+/* sc=29 */ '`', '~', NOP, NOP, SET8|'`', SET8|'~', NOP, NOP, 0x33, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\\', '|', 0x1C, 0x1C, SET8|'\\', SET8|'|', SET8|0x1C, SET8|0x1C, 0x00, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, SET8|'z', SET8|'Z', SET8|0x1A, SET8|0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, SET8|'x', SET8|'X', SET8|0x18, SET8|0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, SET8|'c', SET8|'C', SET8|0x03, SET8|0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, SET8|'v', SET8|'V', SET8|0x16, SET8|0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, SET8|'b', SET8|'B', SET8|0x02, SET8|0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, SET8|'n', SET8|'N', SET8|0x0E, SET8|0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, SET8|'m', SET8|'M', SET8|0x0D, SET8|0x0D, 0x00, 0x01,
+/* sc=33 */ ',', '<', NOP, NOP, SET8|',', SET8|'<', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', '>', NOP, NOP, SET8|'.', SET8|'>', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '/', '?', NOP, NOP, SET8|'/', SET8|'?', NOP, NOP, 0x33, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, SET8|'*', SET8|'*', SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', SET8|' ', SET8|' ', SET8|' ', SET8|' ', 0x00, 0x00,
+/* sc=3a */ ALK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, 0xFF, 0x00,
+/* sc=46 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', SET8|'7', SET8|'7', SET8|'7', SET8|'7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', SET8|'8', SET8|'8', SET8|'8', SET8|'8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', SET8|'9', SET8|'9', SET8|'9', SET8|'9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', '-', '-', SET8|'-', SET8|'-', SET8|'-', SET8|'-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', SET8|'4', SET8|'4', SET8|'4', SET8|'4', 0x80, 0x02,
+/* sc=4c */ F(48), '5', '5', '5', SET8|'5', SET8|'5', SET8|'5', SET8|'5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', '6', '6', SET8|'6', SET8|'6', SET8|'6', SET8|'6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', SET8|'+', SET8|'+', SET8|'+', SET8|'+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', SET8|'1', SET8|'1', SET8|'1', SET8|'1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', SET8|'2', SET8|'2', SET8|'2', SET8|'2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', SET8|'3', SET8|'3', SET8|'3', SET8|'3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', SET8|'0', SET8|'0', SET8|'0', SET8|'0', 0x80, 0x02,
+/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0x82, 0x02,
+/* sc=54 */ ALK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0A, 0x0A, SET8|0x0D, SET8|0x0D, SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', NOP, NOP, SET8|'/', SET8|'/', NOP, NOP, 0x33, 0x00,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0xC2, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=69 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6a */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6b */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6c */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6d */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6e */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6f */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=70 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=71 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=72 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=73 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=74 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=75 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=76 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=77 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=78 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=79 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7a */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7b */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7c */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7d */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7e */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7f */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* extended (ALTGR LOCK keys) */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, NOP, NOP, SET8|0x1B, SET8|0x1B, DBG, NOP, 0x33, 0x00,
+/* sc=02 */ '!', '1', NOP, NOP, SET8|'1', SET8|'!', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '"', '2', 0x00, 0x00, SET8|'2', SET8|'@', SET8|0x00, SET8|0x00, 0x00, 0x00,
+/* sc=04 */ '\'', '3', NOP, NOP, SET8|'3', SET8|'#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ ';', '4', NOP, NOP, SET8|'4', SET8|'$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ ':', '5', NOP, NOP, SET8|'5', SET8|'%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ ',', '6', 0x1E, 0x1E, SET8|'6', SET8|'^', SET8|0x1E, SET8|0x1E, 0x00, 0x00,
+/* sc=08 */ '.', '7', NOP, NOP, SET8|'7', SET8|'&', NOP, NOP, 0x33, 0x00,
+/* sc=09 */ '*', '8', NOP, NOP, SET8|'8', SET8|'*', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '(', '9', NOP, NOP, SET8|'9', SET8|'(', NOP, NOP, 0x33, 0x00,
+/* sc=0b */ ')', '0', NOP, NOP, SET8|'0', SET8|')', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '-', '_', 0x1F, 0x1F, SET8|'-', SET8|'_', SET8|0x1F, SET8|0x1F, 0x00, 0x00,
+/* sc=0d */ '=', '+', NOP, NOP, SET8|'=', SET8|'+', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, SET8|0x08, SET8|0x08, SET8|0x7F, SET8|0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, F(16), NOP, NOP, SET8|0x09, F(16), NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 0xca, 0xea, 0x11, 0x11, SET8|'q', SET8|'Q', SET8|0x11, SET8|0x11, 0x00, 0x01,
+/* sc=11 */ 0xc3, 0xe3, 0x17, 0x17, SET8|'w', SET8|'W', SET8|0x17, SET8|0x17, 0x00, 0x01,
+/* sc=12 */ 0xd5, 0xf5, 0x05, 0x05, SET8|'e', SET8|'E', SET8|0x05, SET8|0x05, 0x00, 0x01,
+/* sc=13 */ 0xcb, 0xeb, 0x12, 0x12, SET8|'r', SET8|'R', SET8|0x12, SET8|0x12, 0x00, 0x01,
+/* sc=14 */ 0xc5, 0xe5, 0x14, 0x14, SET8|'t', SET8|'T', SET8|0x14, SET8|0x14, 0x00, 0x01,
+/* sc=15 */ 0xce, 0xee, 0x19, 0x19, SET8|'y', SET8|'Y', SET8|0x19, SET8|0x19, 0x00, 0x01,
+/* sc=16 */ 0xc7, 0xe7, 0x15, 0x15, SET8|'u', SET8|'U', SET8|0x15, SET8|0x15, 0x00, 0x01,
+/* sc=17 */ 0xdb, 0xfb, 0x09, 0x09, SET8|'i', SET8|'I', SET8|0x09, SET8|0x09, 0x00, 0x01,
+/* sc=18 */ 0xdd, 0xfd, 0x0F, 0x0F, SET8|'o', SET8|'O', SET8|0x0F, SET8|0x0F, 0x00, 0x01,
+/* sc=19 */ 0xda, 0xfa, 0x10, 0x10, SET8|'p', SET8|'P', SET8|0x10, SET8|0x10, 0x00, 0x01,
+/* sc=1a */ 0xc8, 0xe8, 0x1B, 0x1B, SET8|'[', SET8|'{', SET8|0x1B, SET8|0x1B, 0x00, 0x01,
+/* sc=1b */ 0xdf, 0xff, 0x1D, 0x1D, SET8|']', SET8|'}', SET8|0x1D, SET8|0x1D, 0x00, 0x01,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, SET8|0x0D, SET8|0x0D, SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 0xc6, 0xe6, 0x01, 0x01, SET8|'a', SET8|'A', SET8|0x01, SET8|0x01, 0x00, 0x01,
+/* sc=1f */ 0xd9, 0xf9, 0x13, 0x13, SET8|'s', SET8|'S', SET8|0x13, SET8|0x13, 0x00, 0x01,
+/* sc=20 */ 0xd7, 0xf7, 0x04, 0x04, SET8|'d', SET8|'D', SET8|0x04, SET8|0x04, 0x00, 0x01,
+/* sc=21 */ 0xc1, 0xe1, 0x06, 0x06, SET8|'f', SET8|'F', SET8|0x06, SET8|0x06, 0x00, 0x01,
+/* sc=22 */ 0xd0, 0xf0, 0x07, 0x07, SET8|'g', SET8|'G', SET8|0x07, SET8|0x07, 0x00, 0x01,
+/* sc=23 */ 0xd2, 0xf2, 0x08, 0x08, SET8|'h', SET8|'H', SET8|0x08, SET8|0x08, 0x00, 0x01,
+/* sc=24 */ 0xcf, 0xef, 0x0A, 0x0A, SET8|'j', SET8|'J', SET8|0x0A, SET8|0x0A, 0x00, 0x01,
+/* sc=25 */ 0xcc, 0xec, 0x0B, 0x0B, SET8|'k', SET8|'K', SET8|0x0B, SET8|0x0B, 0x00, 0x01,
+/* sc=26 */ 0xc4, 0xe4, 0x0C, 0x0C, SET8|'l', SET8|'L', SET8|0x0C, SET8|0x0C, 0x00, 0x01,
+/* sc=27 */ 0xd6, 0xf6, NOP, NOP, SET8|';', SET8|':', NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xdc, 0xfc, NOP, NOP, SET8|'\'', SET8|'"', NOP, NOP, 0x33, 0x01,
+/* sc=29 */ 0xa3, 0xb3, NOP, NOP, SET8|'`', SET8|'~', NOP, NOP, 0x33, 0x01,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\\', '|', 0x1C, 0x1C, SET8|'\\', SET8|'|', SET8|0x1C, SET8|0x1C, 0x00, 0x00,
+/* sc=2c */ 0xd1, 0xf1, 0x1A, 0x1A, SET8|'z', SET8|'Z', SET8|0x1A, SET8|0x1A, 0x00, 0x01,
+/* sc=2d */ 0xde, 0xfe, 0x18, 0x18, SET8|'x', SET8|'X', SET8|0x18, SET8|0x18, 0x00, 0x01,
+/* sc=2e */ 0xd3, 0xf3, 0x03, 0x03, SET8|'c', SET8|'C', SET8|0x03, SET8|0x03, 0x00, 0x01,
+/* sc=2f */ 0xcd, 0xed, 0x16, 0x16, SET8|'v', SET8|'V', SET8|0x16, SET8|0x16, 0x00, 0x01,
+/* sc=30 */ 0xc9, 0xe9, 0x02, 0x02, SET8|'b', SET8|'B', SET8|0x02, SET8|0x02, 0x00, 0x01,
+/* sc=31 */ 0xd4, 0xf4, 0x0E, 0x0E, SET8|'n', SET8|'N', SET8|0x0E, SET8|0x0E, 0x00, 0x01,
+/* sc=32 */ 0xd8, 0xf8, 0x0D, 0x0D, SET8|'m', SET8|'M', SET8|0x0D, SET8|0x0D, 0x00, 0x01,
+/* sc=33 */ 0xc2, 0xe2, NOP, NOP, SET8|',', SET8|'<', NOP, NOP, 0x33, 0x01,
+/* sc=34 */ 0xc0, 0xe0, NOP, NOP, SET8|'.', SET8|'>', NOP, NOP, 0x33, 0x01,
+/* sc=35 */ '/', '?', NOP, NOP, SET8|'/', SET8|'?', NOP, NOP, 0x33, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, SET8|'*', SET8|'*', SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', SET8|' ', SET8|' ', SET8|' ', SET8|' ', 0x00, 0x00,
+/* sc=3a */ ALK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, 0xFF, 0x00,
+/* sc=46 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', SET8|'7', SET8|'7', SET8|'7', SET8|'7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', SET8|'8', SET8|'8', SET8|'8', SET8|'8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', SET8|'9', SET8|'9', SET8|'9', SET8|'9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', '-', '-', SET8|'-', SET8|'-', SET8|'-', SET8|'-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', SET8|'4', SET8|'4', SET8|'4', SET8|'4', 0x80, 0x02,
+/* sc=4c */ F(48), '5', '5', '5', SET8|'5', SET8|'5', SET8|'5', SET8|'5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', '6', '6', SET8|'6', SET8|'6', SET8|'6', SET8|'6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', SET8|'+', SET8|'+', SET8|'+', SET8|'+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', SET8|'1', SET8|'1', SET8|'1', SET8|'1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', SET8|'2', SET8|'2', SET8|'2', SET8|'2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', SET8|'3', SET8|'3', SET8|'3', SET8|'3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', SET8|'0', SET8|'0', SET8|'0', SET8|'0', 0x80, 0x02,
+/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0x82, 0x02,
+/* sc=54 */ ALK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0A, 0x0A, SET8|0x0D, SET8|0x0D, SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', NOP, NOP, SET8|'/', SET8|'/', NOP, NOP, 0x33, 0x00,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0xC2, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+
+#endif
+
+#if !defined(DKKEYMAP) && !defined(UKKEYMAP) && !defined(GRKEYMAP) && !defined(SWKEYMAP) && !defined(RUKEYMAP)
+keymap_t key_map = { 0x69, /* US iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, '1', '!', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '@', 0x00, 0x00, '2', '@', 0x00, 0x00, 0x00, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, '3', '#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, '4', '$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, '5', '%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '^', 0x1E, 0x1E, '6', '^', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=08 */ '7', '&', NOP, NOP, '7', '&', NOP, NOP, 0x33, 0x00,
+/* sc=09 */ '8', '*', NOP, NOP, '8', '*', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '9', '(', NOP, NOP, '9', '(', NOP, NOP, 0x33, 0x00,
+/* sc=0b */ '0', ')', NOP, NOP, '0', ')', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '-', '_', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, 0x00, 0x00,
+/* sc=0d */ '=', '+', NOP, NOP, '=', '+', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x33, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ '[', '{', 0x1B, 0x1B, '[', '{', 0x1B, 0x1B, 0x00, 0x00,
+/* sc=1b */ ']', '}', 0x1D, 0x1D, ']', '}', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ ';', ':', NOP, NOP, ';', ':', NOP, NOP, 0x33, 0x00,
+/* sc=28 */ '\'', '"', NOP, NOP, '\'', '"', NOP, NOP, 0x33, 0x00,
+/* sc=29 */ '`', '~', NOP, NOP, '`', '~', NOP, NOP, 0x33, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\\', '|', 0x1C, 0x1C, '\\', '|', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', '<', NOP, NOP, ',', '<', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', '>', NOP, NOP, '.', '>', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '/', '?', NOP, NOP, '/', '?', NOP, NOP, 0x33, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, 0xFF, 0x00,
+/* sc=46 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', '-', '-', '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ NOP, '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', '6', '6', '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x00, 0x00,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x00,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+
+#endif
+
+fkeytab_t fkey_tab[60] = {
+/* 00-03 */ {"\033[M", 3}, {"\033[N", 3}, {"\033[O", 3}, {"\033[P", 3},
+/* 04-07 */ {"\033[Q", 3}, {"\033[R", 3}, {"\033[S", 3}, {"\033[T", 3},
+/* 08-0B */ {"\033[U", 3}, {"\033[V", 3}, {"\033[W", 3}, {"\033[X", 3},
+/* 0C-0F */ {"\033[W", 3}, {"\033[X", 3}, {"\033[Y", 3}, {"\033[Z", 3},
+/* 10-13 */ {"\033[a", 3}, {"\033[b", 3}, {"\033[c", 3}, {"\033[d", 3},
+/* 14-17 */ {"\033[e", 3}, {"\033[f", 3}, {"\033[g", 3}, {"\033[h", 3},
+/* 18-1B */ {"\033[g", 3}, {"\033[h", 3}, {"\033[i", 3}, {"\033[j", 3},
+/* 1C-1F */ {"\033[k", 3}, {"\033[l", 3}, {"\033[m", 3}, {"\033[n", 3},
+/* 20-23 */ {"\033[o", 3}, {"\033[p", 3}, {"\033[q", 3}, {"\033[r", 3},
+/* 24-27 */ {"\033[g", 3}, {"\033[h", 3}, {"\033[i", 3}, {"\033[j", 3},
+/* 28-2B */ {"\033[k", 3}, {"\033[l", 3}, {"\033[m", 3}, {"\033[n", 3},
+/* 2C-2F */ {"\033[o", 3}, {"\033[p", 3}, {"\033[q", 3}, {"\033[r", 3},
+/* 30-33 */ {"\033[H", 3}, {"\033[A", 3}, {"\033[I", 3}, {"-" , 1},
+/* 34-37 */ {"\033[D", 3}, {"\177" , 1}, {"\033[C", 3}, {"+" , 1},
+/* 38-3B */ {"\033[F", 3}, {"\033[B", 3}, {"\033[G", 3}, {"\033[L", 3}
+};
diff --git a/sys/dev/mcd/mcd.c b/sys/dev/mcd/mcd.c
new file mode 100644
index 0000000..7309f42
--- /dev/null
+++ b/sys/dev/mcd/mcd.c
@@ -0,0 +1,1335 @@
+/*
+ * Copyright 1993 by Holger Veit (data part)
+ * Copyright 1993 by Brian Moore (audio part)
+ * Changes Copyright 1993 by Gary Clark II
+ *
+ * Rewrote probe routine to work on newer Mitsumi drives.
+ * Additional changes (C) 1994 by Jordan K. Hubbard
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This software was developed by Holger Veit and Brian Moore
+ * for use with "386BSD" and similar operating systems.
+ * "Similar operating systems" includes mainly non-profit oriented
+ * systems for research and education, including but not restricted to
+ * "NetBSD", "FreeBSD", "Mach" (by CMU).
+ * 4. Neither the name of the developer(s) nor the name "386BSD"
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: mcd.c,v 1.15 1994/04/20 07:06:41 davidg Exp $
+ */
+static char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore";
+
+#include "mcd.h"
+#if NMCD > 0
+#include "types.h"
+#include "param.h"
+#include "systm.h"
+#include "conf.h"
+#include "file.h"
+#include "buf.h"
+#include "stat.h"
+#include "uio.h"
+#include "ioctl.h"
+#include "cdio.h"
+#include "errno.h"
+#include "dkbad.h"
+#include "disklabel.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "mcdreg.h"
+
+/* user definable options */
+/*#define MCD_TO_WARNING_ON*/ /* define to get timeout messages */
+/*#define MCDMINI*/ /* define for a mini configuration for boot kernel */
+
+
+#ifdef MCDMINI
+#define MCD_TRACE(fmt,a,b,c,d)
+#ifdef MCD_TO_WARNING_ON
+#undef MCD_TO_WARNING_ON
+#endif
+#else
+#define MCD_TRACE(fmt,a,b,c,d) {if (mcd_data[unit].debug) {printf("mcd%d st=%02x: ",unit,mcd_data[unit].status); printf(fmt,a,b,c,d);}}
+#endif
+
+#define mcd_part(dev) ((minor(dev)) & 7)
+#define mcd_unit(dev) (((minor(dev)) & 0x38) >> 3)
+#define mcd_phys(dev) (((minor(dev)) & 0x40) >> 6)
+#define RAW_PART 0
+
+/* flags */
+#define MCDOPEN 0x0001 /* device opened */
+#define MCDVALID 0x0002 /* parameters loaded */
+#define MCDINIT 0x0004 /* device is init'd */
+#define MCDWAIT 0x0008 /* waiting for something */
+#define MCDLABEL 0x0010 /* label is read */
+#define MCDPROBING 0x0020 /* probing */
+#define MCDREADRAW 0x0040 /* read raw mode (2352 bytes) */
+#define MCDVOLINFO 0x0080 /* already read volinfo */
+#define MCDTOC 0x0100 /* already read toc */
+#define MCDMBXBSY 0x0200 /* local mbx is busy */
+
+/* status */
+#define MCDAUDIOBSY MCD_ST_AUDIOBSY /* playing audio */
+#define MCDDSKCHNG MCD_ST_DSKCHNG /* sensed change of disk */
+#define MCDDSKIN MCD_ST_DSKIN /* sensed disk in drive */
+#define MCDDOOROPEN MCD_ST_DOOROPEN /* sensed door open */
+
+/* These are apparently the different states a mitsumi can get up to */
+#define MCDCDABSENT 0x0030
+#define MCDCDPRESENT 0x0020
+#define MCDSCLOSED 0x0080
+#define MCDSOPEN 0x00a0
+
+/* toc */
+#define MCD_MAXTOCS 104 /* from the Linux driver */
+#define MCD_LASTPLUS1 170 /* special toc entry */
+
+struct mcd_mbx {
+ short unit;
+ short port;
+ short retry;
+ short nblk;
+ int sz;
+ u_long skip;
+ struct buf *bp;
+ int p_offset;
+ short count;
+};
+
+struct mcd_data {
+ short config;
+ short flags;
+ short status;
+ int blksize;
+ u_long disksize;
+ int iobase;
+ struct disklabel dlabel;
+ int partflags[MAXPARTITIONS];
+ int openflags;
+ struct mcd_volinfo volinfo;
+#ifndef MCDMINI
+ struct mcd_qchninfo toc[MCD_MAXTOCS];
+ short audio_status;
+ struct mcd_read2 lastpb;
+#endif
+ short debug;
+ struct buf head; /* head of buf queue */
+ struct mcd_mbx mbx;
+} mcd_data[NMCD];
+
+/* reader state machine */
+#define MCD_S_BEGIN 0
+#define MCD_S_BEGIN1 1
+#define MCD_S_WAITSTAT 2
+#define MCD_S_WAITMODE 3
+#define MCD_S_WAITREAD 4
+
+/* prototypes */
+int mcdopen(dev_t dev);
+int mcdclose(dev_t dev);
+void mcdstrategy(struct buf *bp);
+int mcdioctl(dev_t dev, int cmd, caddr_t addr, int flags);
+int mcdsize(dev_t dev);
+static void mcd_done(struct mcd_mbx *mbx);
+static void mcd_start(int unit);
+static int mcd_getdisklabel(int unit);
+static void mcd_configure(struct mcd_data *cd);
+static int mcd_get(int unit, char *buf, int nmax);
+static void mcd_setflags(int unit,struct mcd_data *cd);
+static int mcd_getstat(int unit,int sflg);
+static int mcd_send(int unit, int cmd,int nretrys);
+static int bcd2bin(bcd_t b);
+static bcd_t bin2bcd(int b);
+static void hsg2msf(int hsg, bcd_t *msf);
+static int msf2hsg(bcd_t *msf);
+static int mcd_volinfo(int unit);
+static int mcd_waitrdy(int port,int dly);
+static void mcd_doread(int state, struct mcd_mbx *mbxin);
+#ifndef MCDMINI
+static int mcd_setmode(int unit, int mode);
+static int mcd_getqchan(int unit, struct mcd_qchninfo *q);
+static int mcd_subchan(int unit, struct ioc_read_subchannel *sc);
+static int mcd_toc_header(int unit, struct ioc_toc_header *th);
+static int mcd_read_toc(int unit);
+static int mcd_toc_entry(int unit, struct ioc_read_toc_entry *te);
+static int mcd_stop(int unit);
+static int mcd_playtracks(int unit, struct ioc_play_track *pt);
+static int mcd_play(int unit, struct mcd_read2 *pb);
+static int mcd_pause(int unit);
+static int mcd_resume(int unit);
+#endif
+
+extern int hz;
+extern int mcd_probe(struct isa_device *dev);
+extern int mcd_attach(struct isa_device *dev);
+struct isa_driver mcddriver = { mcd_probe, mcd_attach, "mcd" };
+
+#define mcd_put(port,byte) outb(port,byte)
+
+#define MCD_RETRYS 5
+#define MCD_RDRETRYS 8
+
+#define MCDBLK 2048 /* for cooked mode */
+#define MCDRBLK 2352 /* for raw mode */
+
+/* several delays */
+#define RDELAY_WAITSTAT 300
+#define RDELAY_WAITMODE 300
+#define RDELAY_WAITREAD 800
+
+#define DELAY_STATUS 10000l /* 10000 * 1us */
+#define DELAY_GETREPLY 200000l /* 200000 * 2us */
+#define DELAY_SEEKREAD 20000l /* 20000 * 1us */
+#define mcd_delay DELAY
+
+int mcd_attach(struct isa_device *dev)
+{
+ struct mcd_data *cd = mcd_data + dev->id_unit;
+ int i;
+
+ cd->iobase = dev->id_iobase;
+ cd->flags |= MCDINIT;
+ cd->openflags = 0;
+ for (i=0; i<MAXPARTITIONS; i++) cd->partflags[i] = 0;
+
+#ifdef NOTYET
+ /* wire controller for interrupts and dma */
+ mcd_configure(cd);
+#endif
+
+ return 1;
+}
+
+int mcdopen(dev_t dev)
+{
+ int unit,part,phys;
+ struct mcd_data *cd;
+
+ unit = mcd_unit(dev);
+ if (unit >= NMCD)
+ return ENXIO;
+
+ cd = mcd_data + unit;
+ part = mcd_part(dev);
+ phys = mcd_phys(dev);
+
+ /* not initialized*/
+ if (!(cd->flags & MCDINIT))
+ return ENXIO;
+
+ /* invalidated in the meantime? mark all open part's invalid */
+ if (!(cd->flags & MCDVALID) && cd->openflags)
+ return ENXIO;
+
+ if (mcd_getstat(unit,1) < 0)
+ return ENXIO;
+
+ /* XXX get a default disklabel */
+ mcd_getdisklabel(unit);
+
+ if (mcdsize(dev) < 0) {
+ printf("mcd%d: failed to get disk size\n",unit);
+ return ENXIO;
+ } else
+ cd->flags |= MCDVALID;
+
+MCD_TRACE("open: partition=%d, disksize = %d, blksize=%d\n",
+ part,cd->disksize,cd->blksize,0);
+
+ if (part == RAW_PART ||
+ (part < cd->dlabel.d_npartitions &&
+ cd->dlabel.d_partitions[part].p_fstype != FS_UNUSED)) {
+ cd->partflags[part] |= MCDOPEN;
+ cd->openflags |= (1<<part);
+ if (part == RAW_PART && phys != 0)
+ cd->partflags[part] |= MCDREADRAW;
+ return 0;
+ }
+
+ return ENXIO;
+}
+
+int mcdclose(dev_t dev)
+{
+ int unit,part,phys;
+ struct mcd_data *cd;
+
+ unit = mcd_unit(dev);
+ if (unit >= NMCD)
+ return ENXIO;
+
+ cd = mcd_data + unit;
+ part = mcd_part(dev);
+ phys = mcd_phys(dev);
+
+ if (!(cd->flags & MCDINIT))
+ return ENXIO;
+
+ mcd_getstat(unit,1); /* get status */
+
+ /* close channel */
+ cd->partflags[part] &= ~(MCDOPEN|MCDREADRAW);
+ cd->openflags &= ~(1<<part);
+ MCD_TRACE("close: partition=%d\n",part,0,0,0);
+
+ return 0;
+}
+
+void
+mcdstrategy(struct buf *bp)
+{
+ struct mcd_data *cd;
+ struct buf *qp;
+ int s;
+
+ int unit = mcd_unit(bp->b_dev);
+
+ cd = mcd_data + unit;
+
+ /* test validity */
+/*MCD_TRACE("strategy: buf=0x%lx, unit=%ld, block#=%ld bcount=%ld\n",
+ bp,unit,bp->b_blkno,bp->b_bcount);*/
+ if (unit >= NMCD || bp->b_blkno < 0) {
+ printf("mcdstrategy: unit = %d, blkno = %d, bcount = %d\n",
+ unit, bp->b_blkno, bp->b_bcount);
+ pg("mcd: mcdstratregy failure");
+ bp->b_error = EINVAL;
+ bp->b_flags |= B_ERROR;
+ goto bad;
+ }
+
+ /* if device invalidated (e.g. media change, door open), error */
+ if (!(cd->flags & MCDVALID)) {
+MCD_TRACE("strategy: drive not valid\n",0,0,0,0);
+ bp->b_error = EIO;
+ goto bad;
+ }
+
+ /* read only */
+ if (!(bp->b_flags & B_READ)) {
+ bp->b_error = EROFS;
+ goto bad;
+ }
+
+ /* no data to read */
+ if (bp->b_bcount == 0)
+ goto done;
+
+ /* for non raw access, check partition limits */
+ if (mcd_part(bp->b_dev) != RAW_PART) {
+ if (!(cd->flags & MCDLABEL)) {
+ bp->b_error = EIO;
+ goto bad;
+ }
+ /* adjust transfer if necessary */
+ if (bounds_check_with_label(bp,&cd->dlabel,1) <= 0) {
+ goto done;
+ }
+ } else {
+ bp->b_pblkno = bp->b_blkno;
+ bp->b_resid = 0;
+ }
+
+ /* queue it */
+ qp = &cd->head;
+ s = splbio();
+ disksort(qp,bp);
+ splx(s);
+
+ /* now check whether we can perform processing */
+ mcd_start(unit);
+ return;
+
+bad:
+ bp->b_flags |= B_ERROR;
+done:
+ bp->b_resid = bp->b_bcount;
+ biodone(bp);
+ return;
+}
+
+static void mcd_start(int unit)
+{
+ struct mcd_data *cd = mcd_data + unit;
+ struct buf *bp, *qp = &cd->head;
+ struct partition *p;
+ int part;
+ register s = splbio();
+
+ if (cd->flags & MCDMBXBSY)
+ return;
+
+ if ((bp = qp->b_actf) != 0) {
+ /* block found to process, dequeue */
+ /*MCD_TRACE("mcd_start: found block bp=0x%x\n",bp,0,0,0);*/
+ qp->b_actf = bp->av_forw;
+ splx(s);
+ } else {
+ /* nothing to do */
+ splx(s);
+ return;
+ }
+
+ /* changed media? */
+ if (!(cd->flags & MCDVALID)) {
+ MCD_TRACE("mcd_start: drive not valid\n",0,0,0,0);
+ return;
+ }
+
+ p = cd->dlabel.d_partitions + mcd_part(bp->b_dev);
+
+ cd->flags |= MCDMBXBSY;
+ cd->mbx.unit = unit;
+ cd->mbx.port = cd->iobase;
+ cd->mbx.retry = MCD_RETRYS;
+ cd->mbx.bp = bp;
+ cd->mbx.p_offset = p->p_offset;
+
+ /* calling the read routine */
+ mcd_doread(MCD_S_BEGIN,&(cd->mbx));
+ /* triggers mcd_start, when successful finished */
+ return;
+}
+
+int mcdioctl(dev_t dev, int cmd, caddr_t addr, int flags)
+{
+ struct mcd_data *cd;
+ int unit,part;
+
+ unit = mcd_unit(dev);
+ part = mcd_part(dev);
+ cd = mcd_data + unit;
+
+#ifdef MCDMINI
+ return ENOTTY;
+#else
+ if (!(cd->flags & MCDVALID))
+ return EIO;
+MCD_TRACE("ioctl called 0x%x\n",cmd,0,0,0);
+
+ switch (cmd) {
+ case DIOCSBAD:
+ return EINVAL;
+ case DIOCGDINFO:
+ case DIOCGPART:
+ case DIOCWDINFO:
+ case DIOCSDINFO:
+ case DIOCWLABEL:
+ return ENOTTY;
+ case CDIOCPLAYTRACKS:
+ return mcd_playtracks(unit, (struct ioc_play_track *) addr);
+ case CDIOCPLAYBLOCKS:
+ return mcd_play(unit, (struct mcd_read2 *) addr);
+ case CDIOCREADSUBCHANNEL:
+ return mcd_subchan(unit, (struct ioc_read_subchannel *) addr);
+ case CDIOREADTOCHEADER:
+ return mcd_toc_header(unit, (struct ioc_toc_header *) addr);
+ case CDIOREADTOCENTRYS:
+ return mcd_toc_entry(unit, (struct ioc_read_toc_entry *) addr);
+ case CDIOCSETPATCH:
+ case CDIOCGETVOL:
+ case CDIOCSETVOL:
+ case CDIOCSETMONO:
+ case CDIOCSETSTERIO:
+ case CDIOCSETMUTE:
+ case CDIOCSETLEFT:
+ case CDIOCSETRIGHT:
+ return EINVAL;
+ case CDIOCRESUME:
+ return mcd_resume(unit);
+ case CDIOCPAUSE:
+ return mcd_pause(unit);
+ case CDIOCSTART:
+ return EINVAL;
+ case CDIOCSTOP:
+ return mcd_stop(unit);
+ case CDIOCEJECT:
+ return EINVAL;
+ case CDIOCSETDEBUG:
+ cd->debug = 1;
+ return 0;
+ case CDIOCCLRDEBUG:
+ cd->debug = 0;
+ return 0;
+ case CDIOCRESET:
+ return EINVAL;
+ default:
+ return ENOTTY;
+ }
+ /*NOTREACHED*/
+#endif /*!MCDMINI*/
+}
+
+/* this could have been taken from scsi/cd.c, but it is not clear
+ * whether the scsi cd driver is linked in
+ */
+static int mcd_getdisklabel(int unit)
+{
+ struct mcd_data *cd = mcd_data + unit;
+
+ if (cd->flags & MCDLABEL)
+ return -1;
+
+ bzero(&cd->dlabel,sizeof(struct disklabel));
+ strncpy(cd->dlabel.d_typename,"Mitsumi CD ROM ",16);
+ strncpy(cd->dlabel.d_packname,"unknown ",16);
+ cd->dlabel.d_secsize = cd->blksize;
+ cd->dlabel.d_nsectors = 100;
+ cd->dlabel.d_ntracks = 1;
+ cd->dlabel.d_ncylinders = (cd->disksize/100)+1;
+ cd->dlabel.d_secpercyl = 100;
+ cd->dlabel.d_secperunit = cd->disksize;
+ cd->dlabel.d_rpm = 300;
+ cd->dlabel.d_interleave = 1;
+ cd->dlabel.d_flags = D_REMOVABLE;
+ cd->dlabel.d_npartitions= 1;
+ cd->dlabel.d_partitions[0].p_offset = 0;
+ cd->dlabel.d_partitions[0].p_size = cd->disksize;
+ cd->dlabel.d_partitions[0].p_fstype = 9;
+ cd->dlabel.d_magic = DISKMAGIC;
+ cd->dlabel.d_magic2 = DISKMAGIC;
+ cd->dlabel.d_checksum = dkcksum(&cd->dlabel);
+
+ cd->flags |= MCDLABEL;
+ return 0;
+}
+
+int mcdsize(dev_t dev)
+{
+ int size;
+ int unit = mcd_unit(dev);
+ struct mcd_data *cd = mcd_data + unit;
+
+ if (mcd_volinfo(unit) >= 0) {
+ cd->blksize = MCDBLK;
+ size = msf2hsg(cd->volinfo.vol_msf);
+ cd->disksize = size * (MCDBLK/DEV_BSIZE);
+ return 0;
+ }
+ return -1;
+}
+
+/***************************************************************
+ * lower level of driver starts here
+ **************************************************************/
+
+#ifdef NOTDEF
+static char
+irqs[] = {
+ 0x00,0x00,0x10,0x20,0x00,0x30,0x00,0x00,
+ 0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00
+};
+
+static char
+drqs[] = {
+ 0x00,0x01,0x00,0x03,0x00,0x05,0x06,0x07,
+};
+#endif
+
+static void
+mcd_configure(struct mcd_data *cd)
+{
+ outb(cd->iobase+mcd_config,cd->config);
+}
+
+/* Wait for non-busy - return 0 on timeout */
+static int
+twiddle_thumbs(int port, int unit, int count, char *whine)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (!(inb(port+MCD_FLAGS) & MCD_ST_BUSY)) {
+ return 1;
+ }
+ }
+#ifdef MCD_TO_WARNING_ON
+ printf("mcd%d: timeout %s\n", unit, whine);
+#endif
+ return 0;
+}
+
+/* check to see if a Mitsumi CD-ROM is attached to the ISA bus */
+
+int
+mcd_probe(struct isa_device *dev)
+{
+ int port = dev->id_iobase;
+ int unit = dev->id_unit;
+ int i, j;
+ int status;
+ unsigned char stbytes[3];
+
+ mcd_data[unit].flags = MCDPROBING;
+
+#ifdef NOTDEF
+ /* get irq/drq configuration word */
+ mcd_data[unit].config = irqs[dev->id_irq]; /* | drqs[dev->id_drq];*/
+#else
+ mcd_data[unit].config = 0;
+#endif
+
+ /* send a reset */
+ outb(port+MCD_FLAGS, M_RESET);
+
+ /*
+ * delay awhile by getting any pending garbage (old data) and
+ * throwing it away.
+ */
+ for (i = 1000000; i != 0; i--) {
+ inb(port+MCD_FLAGS);
+ }
+
+ /* Get status */
+ outb(port+MCD_DATA, MCD_CMDGETSTAT);
+ if (!twiddle_thumbs(port, unit, 1000000, "getting status")) {
+ return 0; /* Timeout */
+ }
+ status = inb(port+MCD_DATA);
+ if (status != MCDCDABSENT && status != MCDCDPRESENT &&
+ status != MCDSOPEN && status != MCDSCLOSED)
+ return 0; /* Not actually a Mitsumi drive here */
+ /* Get version information */
+ outb(port+MCD_DATA, MCD_CMDCONTINFO);
+ for (j = 0; j < 3; j++) {
+ if (!twiddle_thumbs(port, unit, 3000, "getting version info")) {
+ return 0;
+ }
+ stbytes[j] = (inb(port+MCD_DATA) & 0xFF);
+ }
+ printf("mcd%d: version information is %x %c %x\n", unit,
+ stbytes[0], stbytes[1], stbytes[2]);
+ if (stbytes[1] >= 4) {
+ outb(port+MCD_CTRL, M_PICKLE);
+ printf("mcd%d: Adjusted for newer drive model\n", unit);
+ }
+ return 4;
+}
+
+
+static int
+mcd_waitrdy(int port,int dly)
+{
+ int i;
+
+ /* wait until xfer port senses data ready */
+ for (i=0; i<dly; i++) {
+ if ((inb(port+mcd_xfer) & MCD_ST_BUSY)==0)
+ return 0;
+ mcd_delay(1);
+ }
+ return -1;
+}
+
+static int
+mcd_getreply(int unit,int dly)
+{
+ int i;
+ struct mcd_data *cd = mcd_data + unit;
+ int port = cd->iobase;
+
+ /* wait data to become ready */
+ if (mcd_waitrdy(port,dly)<0) {
+#ifdef MCD_TO_WARNING_ON
+ printf("mcd%d: timeout getreply\n",unit);
+#endif
+ return -1;
+ }
+
+ /* get the data */
+ return inb(port+mcd_status) & 0xFF;
+}
+
+static int
+mcd_getstat(int unit,int sflg)
+{
+ int i;
+ struct mcd_data *cd = mcd_data + unit;
+ int port = cd->iobase;
+
+ /* get the status */
+ if (sflg)
+ outb(port+mcd_command, MCD_CMDGETSTAT);
+ i = mcd_getreply(unit,DELAY_GETREPLY);
+ if (i<0) return -1;
+
+ cd->status = i;
+
+ mcd_setflags(unit,cd);
+ return cd->status;
+}
+
+static void
+mcd_setflags(int unit, struct mcd_data *cd)
+{
+ /* check flags */
+ if (cd->status & (MCDDSKCHNG|MCDDOOROPEN)) {
+ MCD_TRACE("getstat: sensed DSKCHNG or DOOROPEN\n",0,0,0,0);
+ cd->flags &= ~MCDVALID;
+ }
+
+#ifndef MCDMINI
+ if (cd->status & MCDAUDIOBSY)
+ cd->audio_status = CD_AS_PLAY_IN_PROGRESS;
+ else if (cd->audio_status == CD_AS_PLAY_IN_PROGRESS)
+ cd->audio_status = CD_AS_PLAY_COMPLETED;
+#endif
+}
+
+static int
+mcd_get(int unit, char *buf, int nmax)
+{
+ int port = mcd_data[unit].iobase;
+ int i,k;
+
+ for (i=0; i<nmax; i++) {
+ /* wait for data */
+ if ((k = mcd_getreply(unit,DELAY_GETREPLY)) < 0) {
+#ifdef MCD_TO_WARNING_ON
+ printf("mcd%d: timeout mcd_get\n",unit);
+#endif
+ return -1;
+ }
+ buf[i] = k;
+ }
+ return i;
+}
+
+static int
+mcd_send(int unit, int cmd,int nretrys)
+{
+ int i,k;
+ int port = mcd_data[unit].iobase;
+
+/*MCD_TRACE("mcd_send: command = 0x%x\n",cmd,0,0,0);*/
+ for (i=0; i<nretrys; i++) {
+ outb(port+mcd_command, cmd);
+ if ((k=mcd_getstat(unit,0)) != -1) {
+ break;
+ }
+ }
+ if (i == nretrys) {
+ printf("mcd%d: mcd_send retry cnt exceeded\n",unit);
+ return -1;
+ }
+/*MCD_TRACE("mcd_send: status = 0x%x\n",k,0,0,0);*/
+ return 0;
+}
+
+static int
+bcd2bin(bcd_t b)
+{
+ return (b >> 4) * 10 + (b & 15);
+}
+
+static bcd_t
+bin2bcd(int b)
+{
+ return ((b / 10) << 4) | (b % 10);
+}
+
+static void
+hsg2msf(int hsg, bcd_t *msf)
+{
+ hsg += 150;
+ M_msf(msf) = bin2bcd(hsg / 4500);
+ hsg %= 4500;
+ S_msf(msf) = bin2bcd(hsg / 75);
+ F_msf(msf) = bin2bcd(hsg % 75);
+}
+
+static int
+msf2hsg(bcd_t *msf)
+{
+ return (bcd2bin(M_msf(msf)) * 60 +
+ bcd2bin(S_msf(msf))) * 75 +
+ bcd2bin(F_msf(msf)) - 150;
+}
+
+static int
+mcd_volinfo(int unit)
+{
+ struct mcd_data *cd = mcd_data + unit;
+ int i;
+
+/*MCD_TRACE("mcd_volinfo: enter\n",0,0,0,0);*/
+
+ /* Get the status, in case the disc has been changed */
+ if (mcd_getstat(unit, 1) < 0) return EIO;
+
+ /* Just return if we already have it */
+ if (cd->flags & MCDVOLINFO) return 0;
+
+ /* send volume info command */
+ if (mcd_send(unit,MCD_CMDGETVOLINFO,MCD_RETRYS) < 0)
+ return -1;
+
+ /* get data */
+ if (mcd_get(unit,(char*) &cd->volinfo,sizeof(struct mcd_volinfo)) < 0) {
+ printf("mcd%d: mcd_volinfo: error read data\n",unit);
+ return -1;
+ }
+
+ if (cd->volinfo.trk_low != 0 || cd->volinfo.trk_high != 0) {
+ cd->flags |= MCDVOLINFO; /* volinfo is OK */
+ return 0;
+ }
+
+ return -1;
+}
+
+void
+mcdintr(unit)
+ int unit;
+{
+ int port = mcd_data[unit].iobase;
+ u_int i;
+
+ MCD_TRACE("stray interrupt xfer=0x%x\n",inb(port+mcd_xfer),0,0,0);
+
+ /* just read out status and ignore the rest */
+ if ((inb(port+mcd_xfer)&0xFF) != 0xFF) {
+ i = inb(port+mcd_status);
+ }
+}
+
+/* state machine to process read requests
+ * initialize with MCD_S_BEGIN: calculate sizes, and read status
+ * MCD_S_WAITSTAT: wait for status reply, set mode
+ * MCD_S_WAITMODE: waits for status reply from set mode, set read command
+ * MCD_S_WAITREAD: wait for read ready, read data
+ */
+static struct mcd_mbx *mbxsave;
+
+static void
+mcd_doread(int state, struct mcd_mbx *mbxin)
+{
+ struct mcd_mbx *mbx = (state!=MCD_S_BEGIN) ? mbxsave : mbxin;
+ int unit = mbx->unit;
+ int port = mbx->port;
+ struct buf *bp = mbx->bp;
+ struct mcd_data *cd = mcd_data + unit;
+
+ int rm,i,k;
+ struct mcd_read2 rbuf;
+ int blknum;
+ caddr_t addr;
+
+loop:
+ switch (state) {
+ case MCD_S_BEGIN:
+ mbx = mbxsave = mbxin;
+
+ case MCD_S_BEGIN1:
+ /* get status */
+ outb(port+mcd_command, MCD_CMDGETSTAT);
+ mbx->count = RDELAY_WAITSTAT;
+ timeout((timeout_func_t)mcd_doread,
+ (caddr_t)MCD_S_WAITSTAT,hz/100); /* XXX */
+ return;
+ case MCD_S_WAITSTAT:
+ untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITSTAT);
+ if (mbx->count-- >= 0) {
+ if (inb(port+mcd_xfer) & MCD_ST_BUSY) {
+ timeout((timeout_func_t)mcd_doread,
+ (caddr_t)MCD_S_WAITSTAT,hz/100); /* XXX */
+ return;
+ }
+ mcd_setflags(unit,cd);
+ MCD_TRACE("got WAITSTAT delay=%d\n",
+ RDELAY_WAITSTAT-mbx->count,0,0,0);
+ /* reject, if audio active */
+ if (cd->status & MCDAUDIOBSY) {
+ printf("mcd%d: audio is active\n",unit);
+ goto readerr;
+ }
+
+ /* to check for raw/cooked mode */
+ if (cd->flags & MCDREADRAW) {
+ rm = MCD_MD_RAW;
+ mbx->sz = MCDRBLK;
+ } else {
+ rm = MCD_MD_COOKED;
+ mbx->sz = cd->blksize;
+ }
+
+ mbx->count = RDELAY_WAITMODE;
+
+ mcd_put(port+mcd_command, MCD_CMDSETMODE);
+ mcd_put(port+mcd_command, rm);
+ timeout((timeout_func_t)mcd_doread,
+ (caddr_t)MCD_S_WAITMODE,hz/100); /* XXX */
+ return;
+ } else {
+#ifdef MCD_TO_WARNING_ON
+ printf("mcd%d: timeout getstatus\n",unit);
+#endif
+ goto readerr;
+ }
+
+ case MCD_S_WAITMODE:
+ untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITMODE);
+ if (mbx->count-- < 0) {
+#ifdef MCD_TO_WARNING_ON
+ printf("mcd%d: timeout set mode\n",unit);
+#endif
+ goto readerr;
+ }
+ if (inb(port+mcd_xfer) & MCD_ST_BUSY) {
+ timeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITMODE,hz/100);
+ return;
+ }
+ mcd_setflags(unit,cd);
+ MCD_TRACE("got WAITMODE delay=%d\n",
+ RDELAY_WAITMODE-mbx->count,0,0,0);
+ /* for first block */
+ mbx->nblk = (bp->b_bcount + (mbx->sz-1)) / mbx->sz;
+ mbx->skip = 0;
+
+nextblock:
+ blknum = (bp->b_blkno / (mbx->sz/DEV_BSIZE))
+ + mbx->p_offset + mbx->skip/mbx->sz;
+
+ MCD_TRACE("mcd_doread: read blknum=%d for bp=0x%x\n",
+ blknum,bp,0,0);
+
+ /* build parameter block */
+ hsg2msf(blknum,rbuf.start_msf);
+
+ /* send the read command */
+ mcd_put(port+mcd_command,MCD_CMDREAD2);
+ mcd_put(port+mcd_command,rbuf.start_msf[0]);
+ mcd_put(port+mcd_command,rbuf.start_msf[1]);
+ mcd_put(port+mcd_command,rbuf.start_msf[2]);
+ mcd_put(port+mcd_command,0);
+ mcd_put(port+mcd_command,0);
+ mcd_put(port+mcd_command,1);
+ mbx->count = RDELAY_WAITREAD;
+ timeout((timeout_func_t)mcd_doread,
+ (caddr_t)MCD_S_WAITREAD,hz/100); /* XXX */
+ return;
+ case MCD_S_WAITREAD:
+ untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITREAD);
+ if (mbx->count-- > 0) {
+ k = inb(port+mcd_xfer);
+ if ((k & 2)==0) {
+ MCD_TRACE("got data delay=%d\n",
+ RDELAY_WAITREAD-mbx->count,0,0,0);
+ /* data is ready */
+ addr = bp->b_un.b_addr + mbx->skip;
+ outb(port+mcd_ctl2,0x04); /* XXX */
+ for (i=0; i<mbx->sz; i++)
+ *addr++ = inb(port+mcd_rdata);
+ outb(port+mcd_ctl2,0x0c); /* XXX */
+
+ if (--mbx->nblk > 0) {
+ mbx->skip += mbx->sz;
+ goto nextblock;
+ }
+
+ /* return buffer */
+ bp->b_resid = 0;
+ biodone(bp);
+
+ cd->flags &= ~MCDMBXBSY;
+ mcd_start(mbx->unit);
+ return;
+ }
+ if ((k & 4)==0)
+ mcd_getstat(unit,0);
+ timeout((timeout_func_t)mcd_doread,
+ (caddr_t)MCD_S_WAITREAD,hz/100); /* XXX */
+ return;
+ } else {
+#ifdef MCD_TO_WARNING_ON
+ printf("mcd%d: timeout read data\n",unit);
+#endif
+ goto readerr;
+ }
+ }
+
+readerr:
+ if (mbx->retry-- > 0) {
+#ifdef MCD_TO_WARNING_ON
+ printf("mcd%d: retrying\n",unit);
+#endif
+ state = MCD_S_BEGIN1;
+ goto loop;
+ }
+
+ /* invalidate the buffer */
+ bp->b_flags |= B_ERROR;
+ bp->b_resid = bp->b_bcount;
+ biodone(bp);
+ mcd_start(mbx->unit);
+ return;
+
+#ifdef NOTDEF
+ printf("mcd%d: unit timeout, resetting\n",mbx->unit);
+ outb(mbx->port+mcd_reset,MCD_CMDRESET);
+ DELAY(300000);
+ (void)mcd_getstat(mbx->unit,1);
+ (void)mcd_getstat(mbx->unit,1);
+ /*cd->status &= ~MCDDSKCHNG; */
+ cd->debug = 1; /* preventive set debug mode */
+
+#endif
+
+}
+
+#ifndef MCDMINI
+static int
+mcd_setmode(int unit, int mode)
+{
+ struct mcd_data *cd = mcd_data + unit;
+ int port = cd->iobase;
+ int retry;
+
+ printf("mcd%d: setting mode to %d\n", unit, mode);
+ for(retry=0; retry<MCD_RETRYS; retry++)
+ {
+ outb(port+mcd_command, MCD_CMDSETMODE);
+ outb(port+mcd_command, mode);
+ if (mcd_getstat(unit, 0) != -1) return 0;
+ }
+
+ return -1;
+}
+
+static int
+mcd_toc_header(int unit, struct ioc_toc_header *th)
+{
+ struct mcd_data *cd = mcd_data + unit;
+
+ if (mcd_volinfo(unit) < 0) {
+ return ENXIO;
+ }
+
+ th->len = msf2hsg(cd->volinfo.vol_msf);
+ th->starting_track = bcd2bin(cd->volinfo.trk_low);
+ th->ending_track = bcd2bin(cd->volinfo.trk_high);
+
+ return 0;
+}
+
+static int
+mcd_read_toc(int unit)
+{
+ struct mcd_data *cd = mcd_data + unit;
+ struct ioc_toc_header th;
+ struct mcd_qchninfo q;
+ int rc, trk, idx, retry;
+
+ /* Only read TOC if needed */
+ if (cd->flags & MCDTOC) {
+ return 0;
+ }
+
+ printf("mcd%d: reading toc header\n", unit);
+ if (mcd_toc_header(unit, &th) != 0) {
+ return ENXIO;
+ }
+
+ printf("mcd%d: stopping play\n", unit);
+ if ((rc=mcd_stop(unit)) != 0) {
+ return rc;
+ }
+
+ /* try setting the mode twice */
+ if (mcd_setmode(unit, MCD_MD_TOC) != 0) {
+ return EIO;
+ }
+ if (mcd_setmode(unit, MCD_MD_TOC) != 0) {
+ return EIO;
+ }
+
+ printf("mcd%d: get_toc reading qchannel info\n",unit);
+ for(trk=th.starting_track; trk<=th.ending_track; trk++)
+ cd->toc[trk].idx_no = 0;
+ trk = th.ending_track - th.starting_track + 1;
+ for(retry=0; retry<300 && trk>0; retry++)
+ {
+ if (mcd_getqchan(unit, &q) < 0) break;
+ idx = bcd2bin(q.idx_no);
+ if (idx>0 && idx < MCD_MAXTOCS && q.trk_no==0) {
+ if (cd->toc[idx].idx_no == 0) {
+ cd->toc[idx] = q;
+ trk--;
+ }
+ }
+ }
+
+ if (mcd_setmode(unit, MCD_MD_COOKED) != 0) {
+ return EIO;
+ }
+
+ if (trk != 0) {
+ return ENXIO;
+ }
+
+ /* add a fake last+1 */
+ idx = th.ending_track + 1;
+ cd->toc[idx].ctrl_adr = cd->toc[idx-1].ctrl_adr;
+ cd->toc[idx].trk_no = 0;
+ cd->toc[idx].idx_no = 0xAA;
+ cd->toc[idx].hd_pos_msf[0] = cd->volinfo.vol_msf[0];
+ cd->toc[idx].hd_pos_msf[1] = cd->volinfo.vol_msf[1];
+ cd->toc[idx].hd_pos_msf[2] = cd->volinfo.vol_msf[2];
+
+ cd->flags |= MCDTOC;
+
+ return 0;
+}
+
+static int
+mcd_toc_entry(int unit, struct ioc_read_toc_entry *te)
+{
+ struct mcd_data *cd = mcd_data + unit;
+ struct ret_toc {
+ struct ioc_toc_header th;
+ struct cd_toc_entry rt;
+ } ret_toc;
+ struct ioc_toc_header th;
+ int rc, i;
+
+ /* Make sure we have a valid toc */
+ if ((rc=mcd_read_toc(unit)) != 0) {
+ return rc;
+ }
+
+ /* find the toc to copy*/
+ i = te->starting_track;
+ if (i == MCD_LASTPLUS1) {
+ i = bcd2bin(cd->volinfo.trk_high) + 1;
+ }
+
+ /* verify starting track */
+ if (i < bcd2bin(cd->volinfo.trk_low) ||
+ i > bcd2bin(cd->volinfo.trk_high)+1) {
+ return EINVAL;
+ }
+
+ /* do we have room */
+ if (te->data_len < sizeof(struct ioc_toc_header) +
+ sizeof(struct cd_toc_entry)) {
+ return EINVAL;
+ }
+
+ /* Copy the toc header */
+ if (mcd_toc_header(unit, &th) < 0) {
+ return EIO;
+ }
+ ret_toc.th = th;
+
+ /* copy the toc data */
+ ret_toc.rt.control = cd->toc[i].ctrl_adr;
+ ret_toc.rt.addr_type = te->address_format;
+ ret_toc.rt.track = i;
+ if (te->address_format == CD_MSF_FORMAT) {
+ ret_toc.rt.addr.addr[1] = cd->toc[i].hd_pos_msf[0];
+ ret_toc.rt.addr.addr[2] = cd->toc[i].hd_pos_msf[1];
+ ret_toc.rt.addr.addr[3] = cd->toc[i].hd_pos_msf[2];
+ }
+
+ /* copy the data back */
+ copyout(&ret_toc, te->data, sizeof(struct cd_toc_entry)
+ + sizeof(struct ioc_toc_header));
+
+ return 0;
+}
+
+static int
+mcd_stop(int unit)
+{
+ struct mcd_data *cd = mcd_data + unit;
+
+ if (mcd_send(unit, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0) {
+ return ENXIO;
+ }
+ cd->audio_status = CD_AS_PLAY_COMPLETED;
+ return 0;
+}
+
+static int
+mcd_getqchan(int unit, struct mcd_qchninfo *q)
+{
+ struct mcd_data *cd = mcd_data + unit;
+
+ if (mcd_send(unit, MCD_CMDGETQCHN, MCD_RETRYS) < 0) {
+ return -1;
+ }
+ if (mcd_get(unit, (char *) q, sizeof(struct mcd_qchninfo)) < 0) {
+ return -1;
+ }
+ if (cd->debug) {
+ printf("mcd%d: qchannel ctl=%d, t=%d, i=%d, ttm=%d:%d.%d dtm=%d:%d.%d\n",
+ unit,
+ q->ctrl_adr, q->trk_no, q->idx_no,
+ q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2],
+ q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2]);
+ }
+ return 0;
+}
+
+static int
+mcd_subchan(int unit, struct ioc_read_subchannel *sc)
+{
+ struct mcd_data *cd = mcd_data + unit;
+ struct mcd_qchninfo q;
+ struct cd_sub_channel_info data;
+
+ printf("mcd%d: subchan af=%d, df=%d\n", unit,
+ sc->address_format,
+ sc->data_format);
+ if (sc->address_format != CD_MSF_FORMAT) {
+ return EIO;
+ }
+ if (sc->data_format != CD_CURRENT_POSITION) {
+ return EIO;
+ }
+ if (mcd_getqchan(unit, &q) < 0) {
+ return EIO;
+ }
+
+ data.header.audio_status = cd->audio_status;
+ data.what.position.data_format = CD_MSF_FORMAT;
+ data.what.position.track_number = bcd2bin(q.trk_no);
+
+ if (copyout(&data, sc->data, sizeof(struct cd_sub_channel_info))!=0) {
+ return EFAULT;
+ }
+ return 0;
+}
+
+static int
+mcd_playtracks(int unit, struct ioc_play_track *pt)
+{
+ struct mcd_data *cd = mcd_data + unit;
+ struct mcd_read2 pb;
+ int a = pt->start_track;
+ int z = pt->end_track;
+ int rc;
+
+ if ((rc = mcd_read_toc(unit)) != 0) {
+ return rc;
+ }
+ printf("mcd%d: playtracks from %d:%d to %d:%d\n", unit,
+ a, pt->start_index, z, pt->end_index);
+
+ if (a < cd->volinfo.trk_low || a > cd->volinfo.trk_high || a > z ||
+ z < cd->volinfo.trk_low || z > cd->volinfo.trk_high) {
+ return EINVAL;
+ }
+
+ pb.start_msf[0] = cd->toc[a].hd_pos_msf[0];
+ pb.start_msf[1] = cd->toc[a].hd_pos_msf[1];
+ pb.start_msf[2] = cd->toc[a].hd_pos_msf[2];
+ pb.end_msf[0] = cd->toc[z+1].hd_pos_msf[0];
+ pb.end_msf[1] = cd->toc[z+1].hd_pos_msf[1];
+ pb.end_msf[2] = cd->toc[z+1].hd_pos_msf[2];
+
+ return mcd_play(unit, &pb);
+}
+
+static int
+mcd_play(int unit, struct mcd_read2 *pb)
+{
+ struct mcd_data *cd = mcd_data + unit;
+ int port = cd->iobase;
+ int retry, st;
+
+ cd->lastpb = *pb;
+ for(retry=0; retry<MCD_RETRYS; retry++) {
+ outb(port+mcd_command, MCD_CMDREAD2);
+ outb(port+mcd_command, pb->start_msf[0]);
+ outb(port+mcd_command, pb->start_msf[1]);
+ outb(port+mcd_command, pb->start_msf[2]);
+ outb(port+mcd_command, pb->end_msf[0]);
+ outb(port+mcd_command, pb->end_msf[1]);
+ outb(port+mcd_command, pb->end_msf[2]);
+ if ((st=mcd_getstat(unit, 0)) != -1) {
+ break;
+ }
+ }
+
+ if (cd->debug) {
+ printf("mcd%d: mcd_play retry=%d, status=%d\n", unit, retry, st);
+ }
+ if (st == -1) {
+ return ENXIO;
+ }
+ cd->audio_status = CD_AS_PLAY_IN_PROGRESS;
+ return 0;
+}
+
+static int
+mcd_pause(int unit)
+{
+ struct mcd_data *cd = mcd_data + unit;
+ struct mcd_qchninfo q;
+ int rc;
+
+ /* Verify current status */
+ if (cd->audio_status != CD_AS_PLAY_IN_PROGRESS) {
+ printf("mcd%d: pause attempted when not playing\n", unit);
+ return EINVAL;
+ }
+
+ /* Get the current position */
+ if (mcd_getqchan(unit, &q) < 0) {
+ return EIO;
+ }
+
+ /* Copy it into lastpb */
+ cd->lastpb.start_msf[0] = q.hd_pos_msf[0];
+ cd->lastpb.start_msf[1] = q.hd_pos_msf[1];
+ cd->lastpb.start_msf[2] = q.hd_pos_msf[2];
+
+ /* Stop playing */
+ if ((rc=mcd_stop(unit)) != 0) {
+ return rc;
+ }
+
+ /* Set the proper status and exit */
+ cd->audio_status = CD_AS_PLAY_PAUSED;
+ return 0;
+}
+
+static int
+mcd_resume(int unit)
+{
+ struct mcd_data *cd = mcd_data + unit;
+
+ if (cd->audio_status != CD_AS_PLAY_PAUSED) {
+ return EINVAL;
+ }
+ return mcd_play(unit, &cd->lastpb);
+}
+#endif /*!MCDMINI*/
+
+#endif /* NMCD > 0 */
diff --git a/sys/dev/mcd/mcdreg.h b/sys/dev/mcd/mcdreg.h
new file mode 100644
index 0000000..0ce5de7
--- /dev/null
+++ b/sys/dev/mcd/mcdreg.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright 1993 by Holger Veit (data part)
+ * Copyright 1993 by Brian Moore (audio part)
+ * Changes Copyright 1993 by Gary Clark II
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This software was developed by Holger Veit and Brian Moore
+ * for use with "386BSD" and similar operating systems.
+ * "Similar operating systems" includes mainly non-profit oriented
+ * systems for research and education, including but not restricted to
+ * "NetBSD", "FreeBSD", "Mach" (by CMU).
+ * 4. Neither the name of the developer(s) nor the name "386BSD"
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file contains definitions for some cdrom control commands
+ * and status codes. This info was "inherited" from the DOS MTMCDE.SYS
+ * driver, and is thus not complete (and may even be wrong). Some day
+ * the manufacturer or anyone else might provide better documentation,
+ * so this file (and the driver) will then have a better quality.
+ *
+ * $Id: mcdreg.h,v 1.2 1994/01/16 23:34:17 jkh Exp $
+ */
+
+#ifndef MCD_H
+#define MCD_H
+
+#ifdef __GNUC__
+#if __GNUC__ >= 2
+#pragma pack(1)
+#endif
+#endif
+
+typedef unsigned char bcd_t;
+#define M_msf(msf) msf[0]
+#define S_msf(msf) msf[1]
+#define F_msf(msf) msf[2]
+
+/* io lines used */
+#define MCD_IO_BASE 0x300
+
+#define mcd_command 0
+#define mcd_status 0
+#define mcd_rdata 0
+
+#define mcd_reset 1
+#define mcd_xfer 1
+#define mcd_ctl2 2 /* XXX Is this right? */
+#define mcd_config 3
+
+#define MCD_MASK_DMA 0x07 /* bits 2-0 = DMA channel */
+#define MCD_MASK_IRQ 0x70 /* bits 6-4 = INT number */
+ /* 001 = int 2,9 */
+ /* 010 = int 3 */
+ /* 011 = int 5 */
+ /* 100 = int 10 */
+ /* 101 = int 11 */
+/* flags */
+#define STATUS_AVAIL 0xB
+#define DATA_AVAIL 0xF
+
+/* New Flags */
+#define M_STATUS_AVAIL 0xFB
+#define M_DATA_AVAIL 0xFD
+
+/* New Commands */
+#define M_RESET 0x00
+#define M_PICKLE 0x04
+
+/* ports */
+#define MCD_DATA 0
+#define MCD_FLAGS 1
+#define MCD_CTRL 2
+#define CHANNEL 3 /* XXX ??? */
+
+/* Status bits */
+#define MCD_ST_DOOROPEN 0x80
+#define MCD_ST_DSKIN 0x40
+#define MCD_ST_DSKCHNG 0x20
+#define MCD_ST_BUSY 0x04
+#define MCD_ST_AUDIOBSY 0x02
+
+/* commands known by the controller */
+#define MCD_CMDRESET 0x00
+#define MCD_CMDGETVOLINFO 0x10 /* gets mcd_volinfo */
+#define MCD_CMDGETQCHN 0x20 /* gets mcd_qchninfo */
+#define MCD_CMDGETSTAT 0x40 /* gets a byte of status */
+#define MCD_CMDSETMODE 0x50 /* set transmission mode, needs byte */
+#define MCD_MD_RAW 0x60
+#define MCD_MD_COOKED 0x01
+#define MCD_MD_TOC 0x05
+#define MCD_CMDSTOPAUDIO 0x70
+#define MCD_CMDGETVOLUME 0x8E /* gets mcd_volume */
+#define MCD_CMDSETVOLUME 0xAE /* sets mcd_volume */
+#define MCD_CMDREAD1 0xB0 /* read n sectors */
+#define MCD_CMDREAD2 0xC0 /* read from-to */
+#define MCD_CMDCONTINFO 0xDC /* Get controller info */
+#define MCD_CMDEJECTDISK 0xF6
+#define MCD_CMDCLOSETRAY 0xF8
+#define MCD_CMDLOCKDRV 0xFE /* needs byte */
+#define MCD_LK_UNLOCK 0x00
+#define MCD_LK_LOCK 0x01
+#define MCD_LK_TEST 0x02
+
+struct mcd_volinfo {
+ bcd_t trk_low;
+ bcd_t trk_high;
+ bcd_t vol_msf[3];
+ bcd_t trk1_msf[3];
+};
+
+struct mcd_qchninfo {
+ u_char ctrl_adr;
+ u_char trk_no;
+ u_char idx_no;
+ bcd_t trk_size_msf[3];
+ u_char :8;
+ bcd_t hd_pos_msf[3];
+};
+
+struct mcd_volume {
+ u_char v0l;
+ u_char v0rs;
+ u_char v0r;
+ u_char v0ls;
+};
+
+struct mcd_read1 {
+ bcd_t start_msf[3];
+ u_char nsec[3];
+};
+
+struct mcd_read2 {
+ bcd_t start_msf[3];
+ bcd_t end_msf[3];
+};
+#endif /* MCD_H */
diff --git a/sys/dev/mse/mse.c b/sys/dev/mse/mse.c
new file mode 100644
index 0000000..eebe163
--- /dev/null
+++ b/sys/dev/mse/mse.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright 1992 by the University of Guelph
+ *
+ * Permission to use, copy and modify this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation.
+ * University of Guelph makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+/*
+ * Driver for the Logitech and ATI Inport Bus mice for use with 386bsd and
+ * the X386 port, courtesy of
+ * Rick Macklem, rick@snowhite.cis.uoguelph.ca
+ * Caveats: The driver currently uses spltty(), but doesn't use any
+ * generic tty code. It could use splmse() (that only masks off the
+ * bus mouse interrupt, but that would require hacking in i386/isa/icu.s.
+ * (This may be worth the effort, since the Logitech generates 30/60
+ * interrupts/sec continuously while it is open.)
+ * NB: The ATI has NOT been tested yet!
+ */
+
+/*
+ * Modification history:
+ *
+ * Oct 19, 1992 -- E. Stark (stark@cs.sunysb.edu)
+ * fixes to make it work with Microsoft InPort busmouse
+ *
+ * Jan, 1993 -- E. Stark (stark@cs.sunysb.edu)
+ * added patches for new "select" interface
+ *
+ * May 4, 1993 -- E. Stark (stark@cs.sunysb.edu)
+ * changed position of some spl()'s in mseread
+ *
+ * October 8, 1993 -- E. Stark (stark@cs.sunysb.edu)
+ * limit maximum negative x/y value to -127 to work around XFree problem
+ * that causes spurious button pushes.
+ */
+
+#include "mse.h"
+#if NMSE > 0
+#include "param.h"
+#include "proc.h"
+#include "user.h"
+#include "buf.h"
+#include "systm.h"
+#include "kernel.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "uio.h"
+
+#include "i386/isa/isa_device.h"
+#include "i386/isa/icu.h"
+
+static int mseprobe(struct isa_device *);
+static int mseattach(struct isa_device *);
+void mseintr(int);
+
+struct isa_driver msedriver = {
+ mseprobe, mseattach, "mse"
+};
+
+/*
+ * Software control structure for mouse. The sc_enablemouse(),
+ * sc_disablemouse() and sc_getmouse() routines must be called spl'd().
+ */
+#define PROTOBYTES 5
+struct mse_softc {
+ int sc_flags;
+ int sc_mousetype;
+ pid_t sc_selp;
+ u_int sc_port;
+ void (*sc_enablemouse)();
+ void (*sc_disablemouse)();
+ void (*sc_getmouse)();
+ int sc_deltax;
+ int sc_deltay;
+ int sc_obuttons;
+ int sc_buttons;
+ int sc_bytesread;
+ u_char sc_bytes[PROTOBYTES];
+} mse_sc[NMSE];
+
+/* Flags */
+#define MSESC_OPEN 0x1
+#define MSESC_WANT 0x2
+
+/* and Mouse Types */
+#define MSE_LOGITECH 0x1
+#define MSE_ATIINPORT 0x2
+
+#define MSE_PORTA 0
+#define MSE_PORTB 1
+#define MSE_PORTC 2
+#define MSE_PORTD 3
+
+#define MSE_UNIT(dev) (minor(dev) >> 1)
+#define MSE_NBLOCKIO(dev) (minor(dev) & 0x1)
+
+/*
+ * Logitech bus mouse definitions
+ */
+#define MSE_SETUP 0x91 /* What does this mean? */
+#define MSE_HOLD 0x80
+#define MSE_RXLOW 0x00
+#define MSE_RXHIGH 0x20
+#define MSE_RYLOW 0x40
+#define MSE_RYHIGH 0x60
+#define MSE_DISINTR 0x10
+#define MSE_INTREN 0x00
+
+static int mse_probelogi();
+static void mse_enablelogi(), mse_disablelogi(), mse_getlogi();
+
+/*
+ * ATI Inport mouse definitions
+ */
+#define MSE_INPORT_RESET 0x80
+#define MSE_INPORT_STATUS 0x00
+#define MSE_INPORT_DX 0x01
+#define MSE_INPORT_DY 0x02
+#define MSE_INPORT_MODE 0x07
+#define MSE_INPORT_HOLD 0x20
+#define MSE_INPORT_INTREN 0x09
+
+static int mse_probeati();
+static void mse_enableati(), mse_disableati(), mse_getati();
+
+#define MSEPRI (PZERO + 3)
+
+/*
+ * Table of mouse types.
+ * Keep the Logitech last, since I haven't figured out how to probe it
+ * properly yet. (Someday I'll have the documentation.)
+ */
+struct mse_types {
+ int m_type; /* Type of bus mouse */
+ int (*m_probe)(); /* Probe routine to test for it */
+ void (*m_enable)(); /* Start routine */
+ void (*m_disable)(); /* Disable interrupts routine */
+ void (*m_get)(); /* and get mouse status */
+} mse_types[] = {
+ { MSE_ATIINPORT, mse_probeati, mse_enableati, mse_disableati, mse_getati },
+ { MSE_LOGITECH, mse_probelogi, mse_enablelogi, mse_disablelogi, mse_getlogi },
+ { 0, },
+};
+
+int
+mseprobe(idp)
+ register struct isa_device *idp;
+{
+ register struct mse_softc *sc = &mse_sc[idp->id_unit];
+ register int i;
+
+ /*
+ * Check for each mouse type in the table.
+ */
+ i = 0;
+ while (mse_types[i].m_type) {
+ if ((*mse_types[i].m_probe)(idp)) {
+ sc->sc_mousetype = mse_types[i].m_type;
+ sc->sc_enablemouse = mse_types[i].m_enable;
+ sc->sc_disablemouse = mse_types[i].m_disable;
+ sc->sc_getmouse = mse_types[i].m_get;
+ return (1);
+ }
+ i++;
+ }
+ return (0);
+}
+
+int
+mseattach(idp)
+ struct isa_device *idp;
+{
+ struct mse_softc *sc = &mse_sc[idp->id_unit];
+
+ sc->sc_port = idp->id_iobase;
+ return (1);
+}
+
+/*
+ * Exclusive open the mouse, initialize it and enable interrupts.
+ */
+int
+mseopen(dev, flag)
+ dev_t dev;
+ int flag;
+{
+ register struct mse_softc *sc;
+ int s;
+
+ if (MSE_UNIT(dev) >= NMSE)
+ return (ENXIO);
+ sc = &mse_sc[MSE_UNIT(dev)];
+ if (sc->sc_flags & MSESC_OPEN)
+ return (EBUSY);
+ sc->sc_flags |= MSESC_OPEN;
+ sc->sc_obuttons = sc->sc_buttons = 0x7;
+ sc->sc_deltax = sc->sc_deltay = 0;
+ sc->sc_bytesread = PROTOBYTES;
+
+ /*
+ * Initialize mouse interface and enable interrupts.
+ */
+ s = spltty();
+ (*sc->sc_enablemouse)(sc->sc_port);
+ splx(s);
+ return (0);
+}
+
+/*
+ * mseclose: just turn off mouse innterrupts.
+ */
+int
+mseclose(dev, flag)
+ dev_t dev;
+ int flag;
+{
+ struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
+ int s;
+
+ s = spltty();
+ (*sc->sc_disablemouse)(sc->sc_port);
+ sc->sc_flags &= ~MSESC_OPEN;
+ splx(s);
+ return(0);
+}
+
+/*
+ * mseread: return mouse info using the MSC serial protocol, but without
+ * using bytes 4 and 5.
+ * (Yes this is cheesy, but it makes the X386 server happy, so...)
+ */
+int
+mseread(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+ register struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
+ int xfer, s, error;
+
+ /*
+ * If there are no protocol bytes to be read, set up a new protocol
+ * packet.
+ */
+ s = spltty(); /* XXX Should be its own spl, but where is imlXX() */
+ if (sc->sc_bytesread >= PROTOBYTES) {
+ while (sc->sc_deltax == 0 && sc->sc_deltay == 0 &&
+ (sc->sc_obuttons ^ sc->sc_buttons) == 0) {
+ if (MSE_NBLOCKIO(dev)) {
+ splx(s);
+ return (0);
+ }
+ sc->sc_flags |= MSESC_WANT;
+ if (error = tsleep((caddr_t)sc, MSEPRI | PCATCH,
+ "mseread", 0)) {
+ splx(s);
+ return (error);
+ }
+ }
+
+ /*
+ * Generate protocol bytes.
+ * For some reason X386 expects 5 bytes but never uses
+ * the fourth or fifth?
+ */
+ sc->sc_bytes[0] = 0x80 | (sc->sc_buttons & ~0xf8);
+ if (sc->sc_deltax > 127)
+ sc->sc_deltax = 127;
+ if (sc->sc_deltax < -127)
+ sc->sc_deltax = -127;
+ sc->sc_deltay = -sc->sc_deltay; /* Otherwise mousey goes wrong way */
+ if (sc->sc_deltay > 127)
+ sc->sc_deltay = 127;
+ if (sc->sc_deltay < -127)
+ sc->sc_deltay = -127;
+ sc->sc_bytes[1] = sc->sc_deltax;
+ sc->sc_bytes[2] = sc->sc_deltay;
+ sc->sc_bytes[3] = sc->sc_bytes[4] = 0;
+ sc->sc_obuttons = sc->sc_buttons;
+ sc->sc_deltax = sc->sc_deltay = 0;
+ sc->sc_bytesread = 0;
+ }
+ splx(s);
+ xfer = MIN(uio->uio_resid, PROTOBYTES - sc->sc_bytesread);
+ if (error = uiomove(&sc->sc_bytes[sc->sc_bytesread], xfer, uio))
+ return (error);
+ sc->sc_bytesread += xfer;
+ return(0);
+}
+
+/*
+ * mseselect: check for mouse input to be processed.
+ */
+int
+mseselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ register struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
+ int s;
+
+ s = spltty();
+ if (sc->sc_bytesread != PROTOBYTES || sc->sc_deltax != 0 ||
+ sc->sc_deltay != 0 || (sc->sc_obuttons ^ sc->sc_buttons) != 0) {
+ splx(s);
+ return (1);
+ }
+
+ /*
+ * Since this is an exclusive open device, any previous proc.
+ * pointer is trash now, so we can just assign it.
+ */
+ sc->sc_selp = p->p_pid;
+ splx(s);
+ return (0);
+}
+
+/*
+ * mseintr: update mouse status. sc_deltax and sc_deltay are accumulative.
+ */
+void
+mseintr(unit)
+ int unit;
+{
+ register struct mse_softc *sc = &mse_sc[unit];
+ pid_t p;
+
+#ifdef DEBUG
+ static int mse_intrcnt = 0;
+ if((mse_intrcnt++ % 10000) == 0)
+ printf("mseintr\n");
+#endif /* DEBUG */
+ if ((sc->sc_flags & MSESC_OPEN) == 0)
+ return;
+
+ (*sc->sc_getmouse)(sc->sc_port, &sc->sc_deltax, &sc->sc_deltay, &sc->sc_buttons);
+
+ /*
+ * If mouse state has changed, wake up anyone wanting to know.
+ */
+ if (sc->sc_deltax != 0 || sc->sc_deltay != 0 ||
+ (sc->sc_obuttons ^ sc->sc_buttons) != 0) {
+ if (sc->sc_flags & MSESC_WANT) {
+ sc->sc_flags &= ~MSESC_WANT;
+ wakeup((caddr_t)sc);
+ }
+ if (sc->sc_selp) {
+ p = sc->sc_selp;
+ sc->sc_selp = (pid_t)0;
+ selwakeup(p, 0);
+ }
+ }
+}
+
+/*
+ * Routines for the Logitech mouse.
+ */
+/*
+ * Test for a Logitech bus mouse and return 1 if it is.
+ * (until I know how to use the signature port properly, just disable
+ * interrupts and return 1)
+ */
+static int
+mse_probelogi(idp)
+ register struct isa_device *idp;
+{
+
+ outb(idp->id_iobase + MSE_PORTB, 0x55);
+ if (inb(idp->id_iobase + MSE_PORTB) == 0x55) {
+ outb(idp->id_iobase + MSE_PORTB, 0xaa);
+ if (inb(idp->id_iobase + MSE_PORTB) == 0xaa)
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Initialize Logitech mouse and enable interrupts.
+ */
+static void
+mse_enablelogi(port)
+ register u_int port;
+{
+ int dx, dy, but;
+
+ outb(port + MSE_PORTD, MSE_SETUP);
+ mse_getlogi(port, &dx, &dy, &but);
+}
+
+/*
+ * Disable interrupts for Logitech mouse.
+ */
+static void
+mse_disablelogi(port)
+ register u_int port;
+{
+
+ outb(port + MSE_PORTC, MSE_DISINTR);
+}
+
+/*
+ * Get the current dx, dy and button up/down state.
+ */
+static void
+mse_getlogi(port, dx, dy, but)
+ register u_int port;
+ int *dx;
+ int *dy;
+ int *but;
+{
+ register char x, y;
+
+ outb(port + MSE_PORTC, MSE_HOLD | MSE_RXLOW);
+ x = inb(port + MSE_PORTA);
+ *but = (x >> 5) & 0x7;
+ x &= 0xf;
+ outb(port + MSE_PORTC, MSE_HOLD | MSE_RXHIGH);
+ x |= (inb(port + MSE_PORTA) << 4);
+ outb(port + MSE_PORTC, MSE_HOLD | MSE_RYLOW);
+ y = (inb(port + MSE_PORTA) & 0xf);
+ outb(port + MSE_PORTC, MSE_HOLD | MSE_RYHIGH);
+ y |= (inb(port + MSE_PORTA) << 4);
+ *dx += x;
+ *dy += y;
+ outb(port + MSE_PORTC, MSE_INTREN);
+}
+
+/*
+ * Routines for the ATI Inport bus mouse.
+ */
+/*
+ * Test for a ATI Inport bus mouse and return 1 if it is.
+ * (do not enable interrupts)
+ */
+static int
+mse_probeati(idp)
+ register struct isa_device *idp;
+{
+ int i;
+
+ for (i = 0; i < 2; i++)
+ if (inb(idp->id_iobase + MSE_PORTC) == 0xde)
+ return (1);
+ return (0);
+}
+
+/*
+ * Initialize ATI Inport mouse and enable interrupts.
+ */
+static void
+mse_enableati(port)
+ register u_int port;
+{
+
+ outb(port + MSE_PORTA, MSE_INPORT_RESET);
+ outb(port + MSE_PORTA, MSE_INPORT_MODE);
+ outb(port + MSE_PORTB, MSE_INPORT_INTREN);
+}
+
+/*
+ * Disable interrupts for ATI Inport mouse.
+ */
+static void
+mse_disableati(port)
+ register u_int port;
+{
+
+ outb(port + MSE_PORTA, MSE_INPORT_MODE);
+ outb(port + MSE_PORTB, 0);
+}
+
+/*
+ * Get current dx, dy and up/down button state.
+ */
+static void
+mse_getati(port, dx, dy, but)
+ register u_int port;
+ int *dx;
+ int *dy;
+ int *but;
+{
+ register char byte;
+
+ outb(port + MSE_PORTA, MSE_INPORT_MODE);
+ outb(port + MSE_PORTB, MSE_INPORT_HOLD);
+ outb(port + MSE_PORTA, MSE_INPORT_STATUS);
+ *but = ~(inb(port + MSE_PORTB) & 0x7);
+ outb(port + MSE_PORTA, MSE_INPORT_DX);
+ byte = inb(port + MSE_PORTB);
+ *dx += byte;
+ outb(port + MSE_PORTA, MSE_INPORT_DY);
+ byte = inb(port + MSE_PORTB);
+ *dy += byte;
+ outb(port + MSE_PORTA, MSE_INPORT_MODE);
+ outb(port + MSE_PORTB, MSE_INPORT_INTREN);
+}
+#endif /* NMSE */
diff --git a/sys/dev/ppbus/lptio.h b/sys/dev/ppbus/lptio.h
new file mode 100644
index 0000000..87af5bc
--- /dev/null
+++ b/sys/dev/ppbus/lptio.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 1994 Geoffrey M. Rehmet
+ *
+ * This program is free software; you may redistribute it and/or
+ * modify it, provided that it retain the above copyright notice
+ * and the following disclaimer.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Geoff Rehmet, Rhodes University, South Africa <csgr@cs.ru.ac.za>
+ *
+ */
+
+#ifndef _LPT_PRINTER_H_
+#define _LPT_PRINTER_H_
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#define LPT_IRQ _IOW('p', 1, long) /* set interrupt status */
+
+#endif
diff --git a/sys/dev/sio/sio.c b/sys/dev/sio/sio.c
new file mode 100644
index 0000000..ad09f7a3
--- /dev/null
+++ b/sys/dev/sio/sio.c
@@ -0,0 +1,1919 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)com.c 7.5 (Berkeley) 5/16/91
+ * $Id: sio.c,v 1.44 1994/04/03 12:25:57 ache Exp $
+ */
+
+#include "sio.h"
+#if NSIO > 0
+/*
+ * Serial driver, based on 386BSD-0.1 com driver.
+ * Mostly rewritten to use pseudo-DMA.
+ * Works for National Semiconductor NS8250-NS16550AF UARTs.
+ * COM driver, based on HP dca driver.
+ */
+#include "param.h"
+#include "systm.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "proc.h"
+#include "user.h"
+#include "conf.h"
+#include "file.h"
+#include "uio.h"
+#include "kernel.h"
+#include "syslog.h"
+
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/comreg.h"
+#include "i386/isa/ic/ns16550.h"
+
+#define FAKE_DCD(unit) ((unit) == comconsole)
+#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
+#define RB_I_HIGH_WATER (RBSZ - 2 * RS_IBUFSIZE)
+#define RB_I_LOW_WATER ((RBSZ - 2 * RS_IBUFSIZE) * 7 / 8)
+#define RS_IBUFSIZE 256
+#define TTY_BI TTY_FE /* XXX */
+#define TTY_OE TTY_PE /* XXX */
+
+#ifdef COM_BIDIR
+#define CALLOUT(x) (minor(x) & COM_CALLOUT_MASK)
+#define COM_CALLOUT_MASK 0x80
+#define COM_MINOR_MAGIC_MASK 0x80
+#else /* COM_BIDIR */
+#define COM_MINOR_MAGIC_MASK 0
+#endif /* COM_BIDIR */
+
+#define UNIT(x) (minor(x) & ~COM_MINOR_MAGIC_MASK)
+
+#ifdef COM_MULTIPORT
+/* checks in flags for multiport and which is multiport "master chip"
+ * for a given card
+ */
+#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
+#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
+#define COM_NOMASTER(dev) ((dev)->id_flags & 0x04)
+#endif /* COM_MULTIPORT */
+
+#define COM_NOFIFO(dev) ((dev)->id_flags & 0x02)
+
+#ifndef FIFO_TRIGGER
+/*
+ * This driver is fast enough to work with any value and for high values
+ * to be only slightly more efficient. Low values may be better because
+ * they give lower latency.
+ * TODO: always use low values for low speeds. Mouse movements are jerky
+ * if more than one packet arrives at once. The low speeds used for
+ * serial mice help avoid this, but not if (large) fifos are enabled.
+ */
+#define FIFO_TRIGGER FIFO_TRIGGER_14
+#endif
+
+#define com_scr 7 /* scratch register for 16450-16550 (R/W) */
+
+#ifndef setsofttty
+#define OLD_INTERRUPT_HANDLING /* XXX FreeBSD-1.1 and earlier */
+#define setsofttty() (ipending |= 1 << 4) /* XXX requires owning IRQ4 */
+extern u_int ipending; /* XXX */
+void softsio1 __P((void));
+#endif
+
+/*
+ * Input buffer watermarks.
+ * The external device is asked to stop sending when the buffer exactly reaches
+ * high water, or when the high level requests it.
+ * The high level is notified immediately (rather than at a later clock tick)
+ * when this watermark is reached.
+ * The buffer size is chosen so the watermark should almost never be reached.
+ * The low watermark is invisibly 0 since the buffer is always emptied all at
+ * once.
+ */
+#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
+
+/*
+ * com state bits.
+ * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
+ * than the other bits so that they can be tested as a group without masking
+ * off the low bits.
+ *
+ * The following com and tty flags correspond closely:
+ * TS_BUSY = CS_BUSY (maintained by comstart() and comflush())
+ * CS_TTGO = ~TS_TTSTOP (maintained by comstart() and siostop())
+ * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam())
+ * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam())
+ * TS_FLUSH is not used.
+ * Bug: I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
+ */
+#define CS_BUSY 0x80 /* output in progress */
+#define CS_TTGO 0x40 /* output not stopped by XOFF */
+#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */
+#define CS_CHECKMSR 1 /* check of MSR scheduled */
+#define CS_CTS_OFLOW 2 /* use CTS output flow control */
+#define CS_ODONE 4 /* output completed */
+#define CS_RTS_IFLOW 8 /* use RTS input flow control */
+
+static char *error_desc[] = {
+#define CE_OVERRUN 0
+ "silo overflow",
+#define CE_INTERRUPT_BUF_OVERFLOW 1
+ "interrupt-level buffer overflow",
+#define CE_TTY_BUF_OVERFLOW 2
+ "tty-level buffer overflow",
+};
+
+#define CE_NTYPES 3
+#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum])
+
+/* types. XXX - should be elsewhere */
+typedef u_int Port_t; /* hardware port */
+typedef u_char bool_t; /* boolean */
+
+/* com device structure */
+struct com_s {
+ u_char state; /* miscellaneous flag bits */
+ u_char cfcr_image; /* copy of value written to CFCR */
+ bool_t hasfifo; /* nonzero for 16550 UARTs */
+ u_char mcr_image; /* copy of value written to MCR */
+#ifdef COM_BIDIR
+ bool_t bidir; /* is this unit bidirectional? */
+ bool_t active; /* is the port active _at all_? */
+ bool_t active_in; /* is the incoming port in use? */
+ bool_t active_out; /* is the outgoing port in use? */
+#endif /* COM_BIDIR */
+#ifdef COM_MULTIPORT
+ bool_t multiport; /* is this unit part of a multiport device? */
+#endif /* COM_MULTIPORT */
+ int dtr_wait; /* time to hold DTR down on close (* 1/HZ) */
+ u_int tx_fifo_size;
+
+ /*
+ * The high level of the driver never reads status registers directly
+ * because there would be too many side effects to handle conveniently.
+ * Instead, it reads copies of the registers stored here by the
+ * interrupt handler.
+ */
+ u_char last_modem_status; /* last MSR read by intr handler */
+ u_char prev_modem_status; /* last MSR handled by high level */
+
+ u_char *ibuf; /* start of input buffer */
+ u_char *ibufend; /* end of input buffer */
+ u_char *ihighwater; /* threshold in input buffer */
+ u_char *iptr; /* next free spot in input buffer */
+
+ u_char *obufend; /* end of output buffer */
+ int ocount; /* original count for current output */
+ u_char *optr; /* next char to output */
+
+ Port_t data_port; /* i/o ports */
+ Port_t int_id_port;
+ Port_t iobase;
+ Port_t modem_ctl_port;
+ Port_t line_status_port;
+ Port_t modem_status_port;
+
+ struct tty *tp; /* cross reference */
+
+#ifdef TIOCTIMESTAMP
+ bool_t do_timestamp;
+ struct timeval timestamp;
+#endif
+
+ u_long bytes_in; /* statistics */
+ u_long bytes_out;
+ u_int delta_error_counts[CE_NTYPES];
+ u_int error_counts[CE_NTYPES];
+
+ /*
+ * Ping-pong input buffers. The extra factor of 2 in the sizes is
+ * to allow for an error byte for each input byte.
+ */
+#define CE_INPUT_OFFSET RS_IBUFSIZE
+ u_char ibuf1[2 * RS_IBUFSIZE];
+ u_char ibuf2[2 * RS_IBUFSIZE];
+};
+
+/*
+ * The public functions in the com module ought to be declared in a com-driver
+ * system header.
+ */
+#define Dev_t int /* promoted dev_t */
+
+/* Interrupt handling entry points. */
+void siointr __P((int unit));
+void siopoll __P((void));
+
+/* Device switch entry points. */
+int sioopen __P((Dev_t dev, int oflags, int devtype,
+ struct proc *p));
+int sioclose __P((Dev_t dev, int fflag, int devtype,
+ struct proc *p));
+int sioread __P((Dev_t dev, struct uio *uio, int ioflag));
+int siowrite __P((Dev_t dev, struct uio *uio, int ioflag));
+int sioioctl __P((Dev_t dev, int cmd, caddr_t data,
+ int fflag, struct proc *p));
+void siostop __P((struct tty *tp, int rw));
+#define sioreset noreset
+int sioselect __P((Dev_t dev, int rw, struct proc *p));
+#define siommap nommap
+#define siostrategy nostrategy
+
+/* Console device entry points. */
+int siocngetc __P((Dev_t dev));
+struct consdev;
+void siocninit __P((struct consdev *cp));
+void siocnprobe __P((struct consdev *cp));
+void siocnputc __P((Dev_t dev, int c));
+
+static int sioattach __P((struct isa_device *dev));
+static void comflush __P((struct com_s *com));
+static void comhardclose __P((struct com_s *com));
+static void siointr1 __P((struct com_s *com));
+static void commctl __P((struct com_s *com, int bits, int how));
+static int comparam __P((struct tty *tp, struct termios *t));
+static int sioprobe __P((struct isa_device *dev));
+static void comstart __P((struct tty *tp));
+static void comwakeup __P((caddr_t chan, int ticks));
+static int tiocm_xxx2mcr __P((int tiocm_xxx));
+
+/* table and macro for fast conversion from a unit number to its com struct */
+static struct com_s *p_com_addr[NSIO];
+#define com_addr(unit) (p_com_addr[unit])
+
+static struct com_s com_structs[NSIO];
+
+#ifdef TIOCTIMESTAMP
+static struct timeval intr_timestamp;
+#endif
+
+struct isa_driver siodriver = {
+ sioprobe, sioattach, "sio"
+};
+
+#ifdef COMCONSOLE
+static int comconsole = COMCONSOLE;
+#else
+static int comconsole = -1;
+#endif
+static speed_t comdefaultrate = TTYDEF_SPEED;
+static u_int com_events; /* input chars + weighted output completions */
+static int commajor;
+#ifdef DONT_MALLOC_TTYS
+#define TB_OUT(tp) (&(tp)->t_out)
+#define TB_RAW(tp) (&(tp)->t_raw)
+struct tty sio_tty[NSIO];
+#else
+#define TB_OUT(tp) ((tp)->t_out)
+#define TB_RAW(tp) ((tp)->t_raw)
+struct tty *sio_tty[NSIO];
+#endif
+extern struct tty *constty;
+extern int tk_nin; /* XXX */
+extern int tk_rawcc; /* XXX */
+
+#ifdef KGDB
+#include "machine/remote-sl.h"
+
+extern int kgdb_dev;
+extern int kgdb_rate;
+extern int kgdb_debug_init;
+#endif
+
+static struct speedtab comspeedtab[] = {
+ 0, 0,
+ 50, COMBRD(50),
+ 75, COMBRD(75),
+ 110, COMBRD(110),
+ 134, COMBRD(134),
+ 150, COMBRD(150),
+ 200, COMBRD(200),
+ 300, COMBRD(300),
+ 600, COMBRD(600),
+ 1200, COMBRD(1200),
+ 1800, COMBRD(1800),
+ 2400, COMBRD(2400),
+ 4800, COMBRD(4800),
+ 9600, COMBRD(9600),
+ 19200, COMBRD(19200),
+ 38400, COMBRD(38400),
+ 57600, COMBRD(57600),
+ 115200, COMBRD(115200),
+ -1, -1
+};
+
+/* XXX - configure this list */
+static Port_t likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, };
+
+static int
+sioprobe(dev)
+ struct isa_device *dev;
+{
+ static bool_t already_init;
+ Port_t *com_ptr;
+ Port_t iobase;
+ int result;
+
+ if (!already_init) {
+ /*
+ * Turn off MCR_IENABLE for all likely serial ports. An unused
+ * port with its MCR_IENABLE gate open will inhibit interrupts
+ * from any used port that shares the interrupt vector.
+ */
+ for (com_ptr = likely_com_ports;
+ com_ptr < &likely_com_ports[sizeof likely_com_ports
+ / sizeof likely_com_ports[0]];
+ ++com_ptr)
+ outb(*com_ptr + com_mcr, 0);
+ already_init = TRUE;
+ }
+ iobase = dev->id_iobase;
+ result = IO_COMSIZE;
+
+ /*
+ * We don't want to get actual interrupts, just masked ones.
+ * Interrupts from this line should already be masked in the ICU,
+ * but mask them in the processor as well in case there are some
+ * (misconfigured) shared interrupts.
+ */
+ disable_intr();
+
+ /*
+ * Initialize the speed so that any junk in the THR or output fifo will
+ * be transmitted in a known time. (There may be lots of junk after a
+ * soft reboot, and output interrupts don't work right after a master
+ * reset, at least for 16550s. (The speed is undefined after MR, but
+ * MR empties the THR and the TSR so it's not clear why this matters)).
+ * Enable output interrupts (only) and check the following:
+ * o the CFCR, IER and MCR in UART hold the values written to them
+ * (the values happen to be all distinct - this is good for
+ * avoiding false positive tests from bus echoes).
+ * o an output interrupt is generated and its vector is correct.
+ * o the interrupt goes away when the IIR in the UART is read.
+ */
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ outb(iobase + com_dlbl, COMBRD(9600) & 0xff);
+ outb(iobase + com_dlbh, (u_int) COMBRD(9600) >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS); /* ensure IER is addressed */
+ outb(iobase + com_mcr, MCR_IENABLE); /* open gate early */
+ outb(iobase + com_ier, 0); /* ensure edge on next intr */
+ outb(iobase + com_ier, IER_ETXRDY); /* generate interrupt */
+ DELAY((16 + 1) * 9600 / 10); /* enough to drain 16 bytes */
+ if ( inb(iobase + com_cfcr) != CFCR_8BITS
+ || inb(iobase + com_ier) != IER_ETXRDY
+ || inb(iobase + com_mcr) != MCR_IENABLE
+#ifndef COM_MULTIPORT /* XXX - need to do more to enable interrupts */
+ || !isa_irq_pending(dev)
+#endif
+ || (inb(iobase + com_iir) & IIR_IMASK) != IIR_TXRDY
+ || isa_irq_pending(dev)
+ || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
+ result = 0;
+
+ /*
+ * Turn off all device interrupts and check that they go off properly.
+ * Leave MCR_IENABLE set. It gates the OUT2 output of the UART to
+ * the ICU input. Closing the gate would give a floating ICU input
+ * (unless there is another device driving at) and spurious interrupts.
+ * (On the system that this was first tested on, the input floats high
+ * and gives a (masked) interrupt as soon as the gate is closed.)
+ */
+ outb(iobase + com_ier, 0);
+ outb(iobase + com_mcr, MCR_IENABLE); /* dummy to avoid bus echo */
+ if ( inb(iobase + com_ier) != 0
+ || isa_irq_pending(dev)
+ || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
+ result = 0;
+ if (result == 0)
+ outb(iobase + com_mcr, 0);
+
+ enable_intr();
+ return (result);
+}
+
+static int
+sioattach(isdp)
+ struct isa_device *isdp;
+{
+ struct com_s *com;
+ static bool_t comwakeup_started = FALSE;
+ Port_t iobase;
+ int s;
+ int unit;
+
+ iobase = isdp->id_iobase;
+ unit = isdp->id_unit;
+ s = spltty();
+
+ /*
+ * sioprobe() has initialized the device registers as follows:
+ * o cfcr = CFCR_8BITS.
+ * It is most important that CFCR_DLAB is off, so that the
+ * data port is not hidden when we enable interrupts.
+ * o ier = 0.
+ * Interrupts are only enabled when the line is open.
+ * o mcr = MCR_IENABLE.
+ * Keeping MCR_DTR and MCR_RTS off might stop the external
+ * device from sending before we are ready.
+ */
+
+ com = &com_structs[unit]; /* XXX malloc it */
+ com->cfcr_image = CFCR_8BITS;
+ com->mcr_image = MCR_IENABLE;
+ com->dtr_wait = 3 * hz;
+ com->tx_fifo_size = 1;
+ com->iptr = com->ibuf = com->ibuf1;
+ com->ibufend = com->ibuf1 + RS_IBUFSIZE;
+ com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
+ com->iobase = iobase;
+ com->data_port = iobase + com_data;
+ com->int_id_port = iobase + com_iir;
+ com->modem_ctl_port = iobase + com_mcr;
+ com->line_status_port = iobase + com_lsr;
+ com->modem_status_port = iobase + com_msr;
+#ifdef DONT_MALLOC_TTYS
+ com->tp = &sio_tty[unit];
+#endif
+
+ /* attempt to determine UART type */
+ printf("sio%d: type", unit);
+#ifdef COM_MULTIPORT
+ if (!COM_ISMULTIPORT(isdp))
+#endif
+ {
+ u_char scr;
+ u_char scr1;
+ u_char scr2;
+
+ scr = inb(iobase + com_scr);
+ outb(iobase + com_scr, 0xa5);
+ scr1 = inb(iobase + com_scr);
+ outb(iobase + com_scr, 0x5a);
+ scr2 = inb(iobase + com_scr);
+ outb(iobase + com_scr, scr);
+ if (scr1 != 0xa5 || scr2 != 0x5a) {
+ printf(" 8250");
+ goto determined_type;
+ }
+ }
+ outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14);
+ DELAY(100);
+ switch (inb(com->int_id_port) & IIR_FIFO_MASK) {
+ case FIFO_TRIGGER_1:
+ printf(" 16450");
+ break;
+ case FIFO_TRIGGER_4:
+ printf(" 16450?");
+ break;
+ case FIFO_TRIGGER_8:
+ printf(" 16550?");
+ break;
+ case FIFO_TRIGGER_14:
+ printf(" 16550A");
+ if (COM_NOFIFO(isdp))
+ printf(" fifo disabled");
+ else {
+ com->hasfifo = TRUE;
+ com->tx_fifo_size = 16;
+ }
+ break;
+ }
+ outb(iobase + com_fifo, 0);
+determined_type: ;
+
+#ifdef COM_MULTIPORT
+ if (COM_ISMULTIPORT(isdp)) {
+ com->multiport = TRUE;
+ printf(" (multiport)");
+
+ /* Note: some cards have no master port (e.g., BocaBoards) */
+ if (!COM_NOMASTER(isdp)) {
+ struct isa_device *masterdev;
+
+ /* set the master's common-interrupt-enable reg.,
+ * as appropriate. YYY See your manual
+ */
+ /* enable only common interrupt for port */
+ outb(com->modem_ctl_port, com->mcr_image = 0);
+
+ masterdev = find_isadev(isa_devtab_tty, &siodriver,
+ COM_MPMASTER(isdp));
+ outb(masterdev->id_iobase + com_scr, 0x80);
+ }
+
+ } else
+ com->multiport = FALSE;
+#endif /* COM_MULTIPORT */
+ printf("\n");
+
+#ifdef KGDB
+ if (kgdb_dev == makedev(commajor, unit)) {
+ if (comconsole == unit)
+ kgdb_dev = -1; /* can't debug over console port */
+ else {
+ int divisor;
+
+ /*
+ * XXX now unfinished and broken. Need to do
+ * something more like a full open(). There's no
+ * suitable interrupt handler so don't enable device
+ * interrupts. Watch out for null tp's.
+ */
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ divisor = ttspeedtab(kgdb_rate, comspeedtab);
+ outb(iobase + com_dlbl, divisor & 0xFF);
+ outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS);
+ outb(com->modem_status_port,
+ com->mcr_image |= MCR_DTR | MCR_RTS);
+
+ if (kgdb_debug_init) {
+ /*
+ * Print prefix of device name,
+ * let kgdb_connect print the rest.
+ */
+ printf("sio%d: ", unit);
+ kgdb_connect(1);
+ } else
+ printf("sio%d: kgdb enabled\n", unit);
+ }
+ }
+#endif
+
+ com_addr(unit) = com;
+ splx(s);
+ if (!comwakeup_started) {
+ comwakeup((caddr_t) NULL, 0);
+ comwakeup_started = TRUE;
+ }
+ return (1);
+}
+
+/* ARGSUSED */
+int
+sioopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+#ifdef COM_BIDIR
+ bool_t callout;
+#endif /* COM_BIDIR */
+ struct com_s *com;
+ int error = 0;
+ bool_t got_status = FALSE;
+ Port_t iobase;
+ int s;
+ struct tty *tp;
+ int unit;
+
+ unit = UNIT(dev);
+ if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL)
+ return (ENXIO);
+#ifdef COM_BIDIR
+ /* if it's a callout device, and bidir not possible on that dev, die */
+ callout = CALLOUT(dev);
+ if (callout && !(com->bidir))
+ return (ENXIO);
+#endif /* COM_BIDIR */
+
+#ifdef DONT_MALLOC_TTYS
+ tp = com->tp;
+#else
+ sio_tty[unit] = ttymalloc(sio_tty[unit]);
+ tp = com->tp = sio_tty[unit];
+#endif
+ s = spltty();
+
+#ifdef COM_BIDIR
+
+bidir_open_top:
+ got_status = FALSE;
+ /* if it's bidirectional, we've gotta deal with it... */
+ if (com->bidir) {
+ if (callout) {
+ if (com->active_in) {
+ /* it's busy. die */
+ splx(s);
+ return (EBUSY);
+ } else {
+ /* it's ours. lock it down, and set it up */
+ com->active_out = TRUE;
+ }
+ } else {
+ if (com->active_out) {
+ /* it's busy, outgoing. wait, if possible */
+ if (flag & O_NONBLOCK) {
+ /* can't wait; bail */
+ splx(s);
+ return (EBUSY);
+ } else {
+ /* wait for it... */
+ error = tsleep((caddr_t)&com->active_out,
+ TTIPRI|PCATCH,
+ "siooth",
+ 0);
+ /* if there was an error, take off. */
+ if (error != 0) {
+ splx(s);
+ return (error);
+ }
+ /* else take it from the top */
+ goto bidir_open_top;
+ }
+ }
+ disable_intr();
+ com->prev_modem_status =
+ com->last_modem_status = inb(com->modem_status_port);
+ enable_intr();
+ got_status = TRUE;
+ if (com->prev_modem_status & MSR_DCD
+ || FAKE_DCD(unit)) {
+ /* there's a carrier on the line; we win */
+ com->active_in = TRUE;
+ } else {
+ /* there is no carrier on the line */
+ if (flag & O_NONBLOCK) {
+ /* can't wait; let it open */
+ com->active_in = TRUE;
+ } else {
+ /* put DTR & RTS up */
+ /* XXX - bring up RTS earlier? */
+ commctl(com, MCR_DTR | MCR_RTS, DMSET);
+ outb(com->iobase + com_ier, IER_EMSC);
+
+ /* wait for it... */
+ error = tsleep((caddr_t)&com->active_in,
+ TTIPRI|PCATCH,
+ "siodcd",
+ 0);
+
+ /* if not active, turn intrs and DTR off */
+ if (!com->active) {
+ outb(com->iobase + com_ier, 0);
+ commctl(com, MCR_DTR, DMBIC);
+ }
+
+ /* if there was an error, take off. */
+ if (error != 0) {
+ splx(s);
+ return (error);
+ }
+ /* else take it from the top */
+ goto bidir_open_top;
+ }
+ }
+ }
+ }
+
+ com->active = TRUE;
+#endif /* COM_BIDIR */
+
+ tp->t_oproc = comstart;
+ tp->t_param = comparam;
+ tp->t_dev = dev;
+ if (!(tp->t_state & TS_ISOPEN)) {
+ tp->t_state |= TS_WOPEN;
+ ttychars(tp);
+ if (tp->t_ispeed == 0) {
+ /*
+ * We don't use all the flags from <sys/ttydefaults.h>
+ * since those are only relevant for logins. It's
+ * important to have echo off initially so that the
+ * line doesn't start blathering before the echo flag
+ * can be turned off.
+ */
+ tp->t_iflag = 0;
+ tp->t_oflag = 0;
+ tp->t_cflag = CREAD | CS8;
+#ifdef COM_BIDIR
+ if (com->bidir && !callout)
+ tp->t_cflag |= HUPCL;
+#endif
+ tp->t_lflag = 0;
+ tp->t_ispeed = tp->t_ospeed = comdefaultrate;
+ if (unit == comconsole) {
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ }
+ }
+
+ /*
+ * XXX the full state after a first open() needs to be
+ * programmable and separate for callin and callout.
+ */
+#ifdef COM_BIDIR
+ if (com->bidir) {
+ if (callout)
+ tp->t_cflag |= CLOCAL;
+ else
+ tp->t_cflag &= ~CLOCAL;
+ }
+#endif
+
+ commctl(com, MCR_DTR | MCR_RTS, DMSET);
+ error = comparam(tp, &tp->t_termios);
+ if (error != 0)
+ goto out;
+ ttsetwater(tp);
+ iobase = com->iobase;
+ if (com->hasfifo) {
+ /* (re)enable and drain FIFO */
+ outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER
+ | FIFO_RCV_RST | FIFO_XMT_RST);
+ DELAY(100);
+ }
+ disable_intr();
+ (void) inb(com->line_status_port);
+ (void) inb(com->data_port);
+ if (!got_status)
+ com->prev_modem_status =
+ com->last_modem_status = inb(com->modem_status_port);
+ outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
+ | IER_EMSC);
+ enable_intr();
+ if (com->prev_modem_status & MSR_DCD || FAKE_DCD(unit))
+ tp->t_state |= TS_CARR_ON;
+ } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
+ splx(s);
+ return (EBUSY);
+ }
+ while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL)
+#ifdef COM_BIDIR
+ /* We went through a lot of trouble to open it,
+ * but it's certain we have a carrier now, so
+ * don't spend any time on it now.
+ */
+ && !(com->bidir)
+#endif /* COM_BIDIR */
+ && !(tp->t_state & TS_CARR_ON)) {
+ tp->t_state |= TS_WOPEN;
+ error = ttysleep(tp, (caddr_t)TB_RAW(tp), TTIPRI | PCATCH,
+ ttopen, 0);
+ if (error != 0)
+ break;
+ }
+out:
+ if (error == 0)
+ error = (*linesw[tp->t_line].l_open)(dev, tp, 0);
+ splx(s);
+
+#ifdef COM_BIDIR
+ /* wakeup sleepers */
+ wakeup((caddr_t) &com->active_in);
+#endif /* COM_BIDIR */
+
+ /*
+ * XXX - the next step was once not done, so interrupts, DTR and RTS
+ * remained hot if the process was killed while it was sleeping
+ * waiting for carrier. Now there is the opposite problem. If several
+ * processes are sleeping waiting for carrier on the same line and one
+ * is killed, interrupts are turned off so the other processes will
+ * never see the carrier rise.
+ */
+ if (error != 0 && !(tp->t_state & TS_ISOPEN))
+ comhardclose(com);
+ tp->t_state &= ~TS_WOPEN;
+
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+sioclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct com_s *com;
+ int s;
+ struct tty *tp;
+
+ com = com_addr(UNIT(dev));
+ tp = com->tp;
+ s = spltty();
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ siostop(tp, FREAD | FWRITE);
+ comhardclose(com);
+ ttyclose(tp);
+ splx(s);
+ return (0);
+}
+
+static void
+comhardclose(com)
+ struct com_s *com;
+{
+ Port_t iobase;
+ int s;
+ struct tty *tp;
+ int unit;
+
+ unit = com - &com_structs[0];
+ iobase = com->iobase;
+ s = spltty();
+#ifdef TIOCTIMESTAMP
+ com->do_timestamp = 0;
+#endif
+ outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
+#ifdef KGDB
+ /* do not disable interrupts or hang up if debugging */
+ if (kgdb_dev != makedev(commajor, unit))
+#endif
+ {
+ outb(iobase + com_ier, 0);
+ tp = com->tp;
+ if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN
+#ifdef COM_BIDIR
+ /*
+ * XXX we will miss any carrier drop between here and the
+ * next open. Perhaps we should watch DCD even when the
+ * port is closed; it is not sufficient to check it at
+ * the next open because it might go up and down while
+ * we're not watching. And we shouldn't look at DCD if
+ * CLOCAL is set (here or for the dialin device ...).
+ * When the termios state is reinitialized for initial
+ * opens, the correct CLOCAL bit will be
+ * ((the bit now) & (the initial bit)).
+ */
+ || com->active_in
+ && !(com->prev_modem_status & MSR_DCD) && !FAKE_DCD(unit)
+#endif
+ || !(tp->t_state & TS_ISOPEN)) {
+ commctl(com, MCR_RTS, DMSET);
+ if (com->dtr_wait != 0)
+ /*
+ * Uninterruptible sleep since we want to
+ * wait a fixed time.
+ * XXX - delay in open() (if necessary),
+ * not here (always).
+ */
+ tsleep((caddr_t)&com->dtr_wait, TTIPRI,
+ "sioclose", com->dtr_wait);
+ }
+ }
+
+#ifdef COM_BIDIR
+ com->active = com->active_in = com->active_out = FALSE;
+
+ /* wakeup sleepers who are waiting for out to finish */
+ wakeup((caddr_t) &com->active_out);
+#endif /* COM_BIDIR */
+
+ splx(s);
+}
+
+int
+sioread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct tty *tp = com_addr(UNIT(dev))->tp;
+
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+int
+siowrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int unit = UNIT(dev);
+ struct tty *tp = com_addr(unit)->tp;
+
+ /*
+ * (XXX) We disallow virtual consoles if the physical console is
+ * a serial port. This is in case there is a display attached that
+ * is not the console. In that situation we don't need/want the X
+ * server taking over the console.
+ */
+ if (constty && unit == comconsole)
+ constty = NULL;
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+#ifdef TIOCTIMESTAMP
+/* Interrupt routine for timekeeping purposes */
+void
+siointrts(unit)
+ int unit;
+{
+ microtime(&intr_timestamp);
+ siointr(unit);
+}
+#endif
+
+void
+siointr(unit)
+ int unit;
+{
+#ifndef COM_MULTIPORT
+ siointr1(com_addr(unit));
+#else /* COM_MULTIPORT */
+ bool_t possibly_more_intrs;
+ struct com_s *com;
+
+ /*
+ * Loop until there is no activity on any port. This is necessary
+ * to get an interrupt edge more than to avoid another interrupt.
+ * If the IRQ signal is just an OR of the IRQ signals from several
+ * devices, then the edge from one may be lost because another is
+ * on.
+ */
+ do {
+ possibly_more_intrs = FALSE;
+ for (unit = 0; unit < NSIO; ++unit) {
+ com = com_addr(unit);
+ if (com != NULL
+ && (inb(com->int_id_port) & IIR_IMASK)
+ != IIR_NOPEND) {
+ siointr1(com);
+ possibly_more_intrs = TRUE;
+ }
+ }
+ } while (possibly_more_intrs);
+#endif /* COM_MULTIPORT */
+}
+
+static void
+siointr1(com)
+ struct com_s *com;
+{
+ u_char line_status;
+ u_char modem_status;
+ u_char *ioptr;
+ u_char recv_data;
+
+#ifdef TIOCTIMESTAMP
+ if (com->do_timestamp)
+ /* XXX a little bloat here... */
+ com->timestamp = intr_timestamp;
+#endif
+ while (TRUE) {
+ line_status = inb(com->line_status_port);
+
+ /* input event? (check first to help avoid overruns) */
+ while (line_status & LSR_RCV_MASK) {
+ /* break/unnattached error bits or real input? */
+ if (!(line_status & LSR_RXRDY))
+ recv_data = 0;
+ else
+ recv_data = inb(com->data_port);
+ ++com->bytes_in;
+ /* XXX reduce SLIP input latency */
+#define FRAME_END 0xc0
+ if (recv_data == FRAME_END)
+ setsofttty();
+#ifdef KGDB
+ /* trap into kgdb? (XXX - needs testing and optim) */
+ if (recv_data == FRAME_END
+ && !(com->tp->t_state & TS_ISOPEN)
+ && kgdb_dev == makedev(commajor, unit)) {
+ kgdb_connect(0);
+ continue;
+ }
+#endif /* KGDB */
+ ioptr = com->iptr;
+ if (ioptr >= com->ibufend)
+ CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
+ else {
+ ++com_events;
+#if 0 /* for testing input latency vs efficiency */
+if (com->iptr - com->ibuf == 8)
+ setsofttty();
+#endif
+ ioptr[0] = recv_data;
+ ioptr[CE_INPUT_OFFSET] = line_status;
+ com->iptr = ++ioptr;
+ if (ioptr == com->ihighwater
+ && com->state & CS_RTS_IFLOW)
+ outb(com->modem_ctl_port,
+ com->mcr_image &= ~MCR_RTS);
+ /* XXX - move this out of isr */
+ if (line_status & LSR_OE)
+ CE_RECORD(com, CE_OVERRUN);
+ }
+
+ /*
+ * "& 0x7F" is to avoid the gcc-1.40 generating a slow
+ * jump from the top of the loop to here
+ */
+ line_status = inb(com->line_status_port) & 0x7F;
+ }
+
+ /* modem status change? (always check before doing output) */
+ modem_status = inb(com->modem_status_port);
+ if (modem_status != com->last_modem_status) {
+ /*
+ * Schedule high level to handle DCD changes. Note
+ * that we don't use the delta bits anywhere. Some
+ * UARTs mess them up, and it's easy to remember the
+ * previous bits and calculate the delta.
+ */
+ com->last_modem_status = modem_status;
+ if (!(com->state & CS_CHECKMSR)) {
+ com_events += LOTS_OF_EVENTS;
+ com->state |= CS_CHECKMSR;
+ setsofttty();
+ }
+
+ /* handle CTS change immediately for crisp flow ctl */
+ if (com->state & CS_CTS_OFLOW) {
+ if (modem_status & MSR_CTS)
+ com->state |= CS_ODEVREADY;
+ else
+ com->state &= ~CS_ODEVREADY;
+ }
+ }
+
+ /* output queued and everything ready? */
+ if (line_status & LSR_TXRDY
+ && com->state >= (CS_ODEVREADY | CS_BUSY | CS_TTGO)) {
+ ioptr = com->optr;
+ if (com->tx_fifo_size > 1) {
+ u_int ocount;
+
+ ocount = com->obufend - ioptr;
+ if (ocount > com->tx_fifo_size)
+ ocount = com->tx_fifo_size;
+ com->bytes_out += ocount;
+ do
+ outb(com->data_port, *ioptr++);
+ while (--ocount != 0);
+ } else {
+ outb(com->data_port, *ioptr++);
+ ++com->bytes_out;
+ }
+ com->optr = ioptr;
+ if (ioptr >= com->obufend) {
+ /* output just completed */
+ com_events += LOTS_OF_EVENTS;
+ com->state ^= (CS_ODONE | CS_BUSY);
+ setsofttty(); /* handle at high level ASAP */
+ }
+ }
+
+ /* finished? */
+#ifndef COM_MULTIPORT
+ if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
+#endif /* COM_MULTIPORT */
+ return;
+ }
+}
+
+static int
+tiocm_xxx2mcr(tiocm_xxx)
+ int tiocm_xxx;
+{
+ int mcr;
+
+ mcr = 0;
+ if (tiocm_xxx & TIOCM_DTR)
+ mcr |= MCR_DTR;
+ if (tiocm_xxx & TIOCM_RTS)
+ mcr |= MCR_RTS;
+ return (mcr);
+}
+
+int
+sioioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct com_s *com;
+ int error;
+ Port_t iobase;
+ int mcr;
+ int msr;
+ int s;
+ int tiocm_xxx;
+ struct tty *tp;
+
+ com = com_addr(UNIT(dev));
+ tp = com->tp;
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
+ if (error >= 0)
+ return (error);
+ error = ttioctl(tp, cmd, data, flag);
+
+#ifdef COM_BIDIR
+ /* XXX: plug security hole while sticky bits not yet implemented */
+ if (com->bidir && com->active_in && p->p_ucred->cr_uid != 0)
+ tp->t_cflag &= ~CLOCAL;
+#endif
+
+ if (error >= 0)
+ return (error);
+
+ iobase = com->iobase;
+ s = spltty();
+ switch (cmd) {
+ case TIOCSBRK:
+ outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
+ break;
+ case TIOCCBRK:
+ outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
+ break;
+ case TIOCSDTR:
+ commctl(com, MCR_DTR, DMBIS);
+ break;
+ case TIOCCDTR:
+ commctl(com, MCR_DTR, DMBIC);
+ break;
+ case TIOCMSET:
+ commctl(com, tiocm_xxx2mcr(*(int *)data), DMSET);
+ break;
+ case TIOCMBIS:
+ commctl(com, tiocm_xxx2mcr(*(int *)data), DMBIS);
+ break;
+ case TIOCMBIC:
+ commctl(com, tiocm_xxx2mcr(*(int *)data), DMBIC);
+ break;
+ case TIOCMGET:
+ tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
+ mcr = com->mcr_image;
+ if (mcr & MCR_DTR)
+ tiocm_xxx |= TIOCM_DTR;
+ if (mcr & MCR_RTS)
+ tiocm_xxx |= TIOCM_RTS;
+ msr = com->prev_modem_status;
+ if (msr & MSR_CTS)
+ tiocm_xxx |= TIOCM_CTS;
+ if (msr & MSR_DCD)
+ tiocm_xxx |= TIOCM_CD;
+ if (msr & MSR_DSR)
+ tiocm_xxx |= TIOCM_DSR;
+ /*
+ * XXX - MSR_RI is naturally volatile, and we make MSR_TERI
+ * more volatile by reading the modem status a lot. Perhaps
+ * we should latch both bits until the status is read here.
+ */
+ if (msr & (MSR_RI | MSR_TERI))
+ tiocm_xxx |= TIOCM_RI;
+ *(int *)data = tiocm_xxx;
+ break;
+#ifdef COM_BIDIR
+ case TIOCMSBIDIR:
+ /* must be root to set bidir. capability */
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0) {
+ splx(s);
+ return(EPERM);
+ }
+
+ /* if it's the console, can't do it (XXX why?) */
+ if (UNIT(dev) == comconsole) {
+ splx(s);
+ return(ENOTTY);
+ }
+
+#if 0
+ /* XXX - can't do the next, for obvious reasons...
+ * but there are problems to be looked at...
+ */
+ /* if the port is active, don't do it */
+ if (com->active) {
+ splx(s);
+ return(EBUSY);
+ }
+#endif
+
+ com->bidir = *(int *)data;
+ break;
+ case TIOCMGBIDIR:
+ *(int *)data = com->bidir;
+ break;
+#endif /* COM_BIDIR */
+ case TIOCMSDTRWAIT:
+ /* must be root since the wait applies to following logins */
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0) {
+ splx(s);
+ return(EPERM);
+ }
+
+ /* if it's the console, can't do it (XXX why?) */
+ if (UNIT(dev) == comconsole) {
+ splx(s);
+ return(ENOTTY);
+ }
+ com->dtr_wait = *(int *)data;
+ break;
+ case TIOCMGDTRWAIT:
+ *(int *)data = com->dtr_wait;
+ break;
+#ifdef TIOCTIMESTAMP
+ case TIOCTIMESTAMP:
+ com->do_timestamp = TRUE;
+ *(struct timeval *)data = com->timestamp;
+ break;
+#endif
+ default:
+ splx(s);
+ return (ENOTTY);
+ }
+ splx(s);
+ return (0);
+}
+
+/* cancel pending output */
+static void
+comflush(com)
+ struct com_s *com;
+{
+ struct ringb *rbp;
+
+ disable_intr();
+ if (com->state & CS_ODONE)
+ com_events -= LOTS_OF_EVENTS;
+ com->state &= ~(CS_ODONE | CS_BUSY);
+ enable_intr();
+ rbp = TB_OUT(com->tp);
+ rbp->rb_hd += com->ocount;
+ rbp->rb_hd = RB_ROLLOVER(rbp, rbp->rb_hd);
+ com->ocount = 0;
+ com->tp->t_state &= ~TS_BUSY;
+}
+
+void
+siopoll()
+{
+#ifdef OLD_INTERRUPT_HANDLING
+ static bool_t awake = FALSE;
+ int s;
+#endif
+ int unit;
+
+ if (com_events == 0)
+ return;
+
+#ifdef OLD_INTERRUPT_HANDLING
+ disable_intr();
+ if (awake) {
+ enable_intr();
+ return;
+ }
+ awake = TRUE;
+ enable_intr();
+ s = spltty();
+#endif
+
+repeat:
+ for (unit = 0; unit < NSIO; ++unit) {
+ u_char *buf;
+ struct com_s *com;
+ u_char *ibuf;
+ int incc;
+ struct tty *tp;
+
+ com = com_addr(unit);
+ if (com == NULL)
+ continue;
+ tp = com->tp;
+#ifdef DONT_MALLOC_TTYS
+ if (tp == NULL)
+ continue;
+#endif
+
+ /* switch the role of the low-level input buffers */
+ if (com->iptr == (ibuf = com->ibuf)) {
+ buf = NULL; /* not used, but compiler can't tell */
+ incc = 0;
+ } else {
+ buf = ibuf;
+ disable_intr();
+ incc = com->iptr - buf;
+ com_events -= incc;
+ if (ibuf == com->ibuf1)
+ ibuf = com->ibuf2;
+ else
+ ibuf = com->ibuf1;
+ com->ibufend = ibuf + RS_IBUFSIZE;
+ com->ihighwater = ibuf + RS_IHIGHWATER;
+ com->iptr = ibuf;
+
+ /*
+ * There is now room for another low-level buffer full
+ * of input, so enable RTS if it is now disabled and
+ * there is room in the high-level buffer.
+ */
+ /*
+ * XXX this used not to look at CS_RTS_IFLOW. The
+ * change is to allow full control of MCR_RTS via
+ * ioctls after turning CS_RTS_IFLOW off. Check
+ * for races. We shouldn't allow the ioctls while
+ * CS_RTS_IFLOW is on.
+ */
+ if ((com->state & CS_RTS_IFLOW)
+ && !(com->mcr_image & MCR_RTS)
+ && !(tp->t_state & TS_RTS_IFLOW))
+ outb(com->modem_ctl_port,
+ com->mcr_image |= MCR_RTS);
+ enable_intr();
+ com->ibuf = ibuf;
+ }
+
+ if (com->state & CS_CHECKMSR) {
+ u_char delta_modem_status;
+
+ disable_intr();
+ delta_modem_status = com->last_modem_status
+ ^ com->prev_modem_status;
+ com->prev_modem_status = com->last_modem_status;
+ com_events -= LOTS_OF_EVENTS;
+ com->state &= ~CS_CHECKMSR;
+ enable_intr();
+ if (delta_modem_status & MSR_DCD && !FAKE_DCD(unit)) {
+ if (com->prev_modem_status & MSR_DCD) {
+ (*linesw[tp->t_line].l_modem)(tp, 1);
+#ifdef COM_BIDIR
+ wakeup((caddr_t) &com->active_in);
+#endif /* COM_BIDIR */
+ } else
+ (*linesw[tp->t_line].l_modem)(tp, 0);
+ }
+ }
+
+ /* XXX */
+ if (TRUE) {
+ u_int delta;
+ int errnum;
+ u_long total;
+
+ for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
+ disable_intr();
+ delta = com->delta_error_counts[errnum];
+ com->delta_error_counts[errnum] = 0;
+ enable_intr();
+ if (delta != 0) {
+ total =
+ com->error_counts[errnum] += delta;
+ log(LOG_WARNING,
+ "sio%d: %u more %s%s (total %lu)\n",
+ unit, delta, error_desc[errnum],
+ delta == 1 ? "" : "s", total);
+ }
+ }
+ }
+ if (com->state & CS_ODONE) {
+ comflush(com);
+ /* XXX - why isn't the table used for t_line == 0? */
+ if (tp->t_line != 0)
+ (*linesw[tp->t_line].l_start)(tp);
+ else
+ comstart(tp);
+ }
+ if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
+ continue;
+ if (com->state & CS_RTS_IFLOW
+ && RB_LEN(TB_RAW(tp)) + incc >= RB_I_HIGH_WATER
+ && !(tp->t_state & TS_RTS_IFLOW)
+ /*
+ * XXX - need RTS flow control for all line disciplines.
+ * Only have it in standard one now.
+ */
+ && linesw[tp->t_line].l_rint == ttyinput) {
+ tp->t_state |= TS_RTS_IFLOW;
+ ttstart(tp);
+ }
+ /*
+ * Avoid the grotesquely inefficient lineswitch routine
+ * (ttyinput) in "raw" mode. It usually takes about 450
+ * instructions (that's without canonical processing or echo!).
+ * slinput is reasonably fast (usually 40 instructions plus
+ * call overhead).
+ */
+ if (!(tp->t_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP
+ | IXOFF | IXON))
+ && !(tp->t_lflag & (ECHO | ECHONL | ICANON | IEXTEN | ISIG
+ | PENDIN))
+ && !(tp->t_state & (TS_CNTTB | TS_LNCH))
+ && linesw[tp->t_line].l_rint == ttyinput) {
+ tk_nin += incc;
+ tk_rawcc += incc;
+ tp->t_rawcc += incc;
+ com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
+ += incc - rb_write(TB_RAW(tp), (char *) buf,
+ incc);
+ ttwakeup(tp);
+ if (tp->t_state & TS_TTSTOP
+ && (tp->t_iflag & IXANY
+ || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
+ tp->t_state &= ~TS_TTSTOP;
+ tp->t_lflag &= ~FLUSHO;
+ ttstart(tp);
+ }
+ } else {
+ do {
+ u_char line_status;
+ int recv_data;
+
+ line_status = (u_char) buf[CE_INPUT_OFFSET];
+ recv_data = (u_char) *buf++;
+ if (line_status
+ & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
+ if (line_status & LSR_BI)
+ recv_data |= TTY_BI;
+ if (line_status & LSR_FE)
+ recv_data |= TTY_FE;
+ if (line_status & LSR_OE)
+ recv_data |= TTY_OE;
+ if (line_status & LSR_PE)
+ recv_data |= TTY_PE;
+ }
+ (*linesw[tp->t_line].l_rint)(recv_data, tp);
+ } while (--incc > 0);
+ }
+ if (com_events == 0)
+ break;
+ }
+ if (com_events >= LOTS_OF_EVENTS)
+ goto repeat;
+
+#ifdef OLD_INTERRUPT_HANDLING
+ splx(s);
+ awake = FALSE;
+#endif
+}
+
+static int
+comparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ u_int cfcr;
+ int cflag;
+ struct com_s *com;
+ int divisor;
+ int error;
+ Port_t iobase;
+ int s;
+ int unit;
+
+ /* check requested parameters */
+ divisor = ttspeedtab(t->c_ospeed, comspeedtab);
+ if (t->c_ispeed == 0)
+ t->c_ispeed = t->c_ospeed;
+ if (divisor < 0 || t->c_ispeed != t->c_ospeed)
+ return (EINVAL);
+
+ /* parameters are OK, convert them to the com struct and the device */
+ unit = UNIT(tp->t_dev);
+ com = com_addr(unit);
+ iobase = com->iobase;
+ s = spltty();
+ if (divisor == 0)
+ commctl(com, MCR_DTR, DMBIC); /* hang up line */
+ else
+ commctl(com, MCR_DTR, DMBIS);
+ cflag = t->c_cflag;
+ switch (cflag & CSIZE) {
+ case CS5:
+ cfcr = CFCR_5BITS;
+ break;
+ case CS6:
+ cfcr = CFCR_6BITS;
+ break;
+ case CS7:
+ cfcr = CFCR_7BITS;
+ break;
+ default:
+ cfcr = CFCR_8BITS;
+ break;
+ }
+ if (cflag & PARENB) {
+ cfcr |= CFCR_PENAB;
+ if (!(cflag & PARODD))
+ cfcr |= CFCR_PEVEN;
+ }
+ if (cflag & CSTOPB)
+ cfcr |= CFCR_STOPB;
+
+ /*
+ * Some UARTs lock up if the divisor latch registers are selected
+ * while the UART is doing output (they refuse to transmit anything
+ * more until given a hard reset). Fix this by stopping filling
+ * the device buffers and waiting for them to drain. Reading the
+ * line status port outside of siointr1() might lose some receiver
+ * error bits, but that is acceptable here.
+ */
+ disable_intr();
+retry:
+ com->state &= ~CS_TTGO;
+ enable_intr();
+ while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
+ != (LSR_TSRE | LSR_TXRDY)) {
+ error = ttysleep(tp, (caddr_t)TB_RAW(tp), TTIPRI | PCATCH,
+ "sioparam", 1);
+ if (error != 0 && error != EAGAIN) {
+ if (!(tp->t_state & TS_TTSTOP)) {
+ disable_intr();
+ com->state |= CS_TTGO;
+ enable_intr();
+ }
+ splx(s);
+ return (error);
+ }
+ }
+
+ disable_intr(); /* very important while com_data is hidden */
+
+ /*
+ * XXX - clearing CS_TTGO is not sufficient to stop further output,
+ * because siopoll() calls comstart() which usually sets it again
+ * because TS_TTSTOP is clear. Setting TS_TTSTOP would not be
+ * sufficient, for similar reasons.
+ */
+ if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
+ != (LSR_TSRE | LSR_TXRDY))
+ goto retry;
+
+ if (divisor != 0) {
+ outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
+ outb(iobase + com_dlbl, divisor & 0xFF);
+ outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ }
+ outb(iobase + com_cfcr, com->cfcr_image = cfcr);
+ if (!(tp->t_state & TS_TTSTOP))
+ com->state |= CS_TTGO;
+ if (cflag & CRTS_IFLOW)
+ com->state |= CS_RTS_IFLOW; /* XXX - secondary changes? */
+ else
+ com->state &= ~CS_RTS_IFLOW;
+
+ /*
+ * Set up state to handle output flow control.
+ * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
+ * Now has 16+ msec latency, while CTS flow has 50- usec latency.
+ */
+ com->state &= ~CS_CTS_OFLOW;
+ com->state |= CS_ODEVREADY;
+ if (cflag & CCTS_OFLOW) {
+ com->state |= CS_CTS_OFLOW;
+ if (!(com->last_modem_status & MSR_CTS))
+ com->state &= ~CS_ODEVREADY;
+ }
+
+ /*
+ * Recover from fiddling with CS_TTGO. We used to call siointr1()
+ * unconditionally, but that defeated the careful discarding of
+ * stale input in sioopen().
+ *
+ * XXX sioopen() is not careful waiting for carrier for the callout
+ * case.
+ */
+ if (com->state >= (CS_BUSY | CS_TTGO))
+ siointr1(com);
+
+ enable_intr();
+ splx(s);
+ return (0);
+}
+
+static void
+comstart(tp)
+ struct tty *tp;
+{
+ struct com_s *com;
+ int s;
+ int unit;
+
+ unit = UNIT(tp->t_dev);
+ com = com_addr(unit);
+ s = spltty();
+ disable_intr();
+ if (tp->t_state & TS_TTSTOP)
+ com->state &= ~CS_TTGO;
+ else
+ com->state |= CS_TTGO;
+ if (tp->t_state & TS_RTS_IFLOW) {
+ if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
+ outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
+ } else {
+ /*
+ * XXX don't raise MCR_RTS if CTS_RTS_IFLOW is off. Set it
+ * appropriately in comparam() if RTS-flow is being changed.
+ * Check for races.
+ */
+ if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater)
+ outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
+ }
+ enable_intr();
+ if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
+ goto out;
+ if (RB_LEN(TB_OUT(tp)) <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)TB_OUT(tp));
+ }
+ if (tp->t_wsel) {
+ selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
+ tp->t_wsel = 0;
+ tp->t_state &= ~TS_WCOLL;
+ }
+ }
+ if (com->ocount != 0) {
+ disable_intr();
+ siointr1(com);
+ enable_intr();
+ } else if (RB_LEN(TB_OUT(tp)) != 0) {
+ tp->t_state |= TS_BUSY;
+ com->ocount = RB_CONTIGGET(TB_OUT(tp));
+ disable_intr();
+ com->obufend = (com->optr = (u_char *)TB_OUT(tp)->rb_hd)
+ + com->ocount;
+ com->state |= CS_BUSY;
+ siointr1(com); /* fake interrupt to start output */
+ enable_intr();
+ }
+out:
+ splx(s);
+}
+
+void
+siostop(tp, rw)
+ struct tty *tp;
+ int rw;
+{
+ struct com_s *com;
+
+ com = com_addr(UNIT(tp->t_dev));
+ if (rw & FWRITE)
+ comflush(com);
+ disable_intr();
+ if (rw & FREAD) {
+ com_events -= (com->iptr - com->ibuf);
+ com->iptr = com->ibuf;
+ }
+ if (tp->t_state & TS_TTSTOP)
+ com->state &= ~CS_TTGO;
+ else
+ com->state |= CS_TTGO;
+ enable_intr();
+}
+
+int
+sioselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ return (ttselect(dev & ~COM_MINOR_MAGIC_MASK, rw, p));
+}
+
+static void
+commctl(com, bits, how)
+ struct com_s *com;
+ int bits;
+ int how;
+{
+ disable_intr();
+ switch (how) {
+ case DMSET:
+ outb(com->modem_ctl_port,
+ com->mcr_image = bits | (com->mcr_image & MCR_IENABLE));
+ break;
+ case DMBIS:
+ outb(com->modem_ctl_port, com->mcr_image |= bits);
+ break;
+ case DMBIC:
+ outb(com->modem_ctl_port, com->mcr_image &= ~bits);
+ break;
+ }
+ enable_intr();
+}
+
+static void
+comwakeup(chan, ticks)
+ caddr_t chan;
+ int ticks;
+{
+ int unit;
+
+ timeout(comwakeup, (caddr_t) NULL, hz / 100);
+
+ if (com_events != 0) {
+#ifndef OLD_INTERRUPT_HANDLING
+ int s = splsofttty();
+#endif
+ siopoll();
+#ifndef OLD_INTERRUPT_HANDLING
+ splx(s);
+#endif
+ }
+
+ /* recover from lost output interrupts */
+ for (unit = 0; unit < NSIO; ++unit) {
+ struct com_s *com;
+
+ com = com_addr(unit);
+ if (com != NULL && com->state >= (CS_BUSY | CS_TTGO)) {
+ disable_intr();
+ siointr1(com);
+ enable_intr();
+ }
+ }
+}
+
+#ifdef OLD_INTERRUPT_HANDLING
+void
+softsio1()
+{
+ siopoll();
+}
+#endif
+
+/*
+ * Following are all routines needed for SIO to act as console
+ */
+#include "i386/i386/cons.h"
+
+struct siocnstate {
+ u_char dlbl;
+ u_char dlbh;
+ u_char ier;
+ u_char cfcr;
+ u_char mcr;
+};
+
+static Port_t siocniobase;
+
+static void
+siocntxwait()
+{
+ int timo;
+
+ /*
+ * Wait for any pending transmission to finish. Required to avoid
+ * the UART lockup bug when the speed is changed, and for normal
+ * transmits.
+ */
+ timo = 100000;
+ while ((inb(siocniobase + com_lsr) & (LSR_TSRE | LSR_TXRDY))
+ != (LSR_TSRE | LSR_TXRDY) && --timo != 0)
+ ;
+}
+
+static void
+siocnopen(sp)
+ struct siocnstate *sp;
+{
+ int divisor;
+ Port_t iobase;
+
+ /*
+ * Save all the device control registers except the fifo register
+ * and set our default ones (cs8 -parenb speed=comdefaultrate).
+ * We can't save the fifo register since it is read-only.
+ */
+ iobase = siocniobase;
+ sp->ier = inb(iobase + com_ier);
+ outb(iobase + com_ier, 0); /* spltty() doesn't stop siointr() */
+ siocntxwait();
+ sp->cfcr = inb(iobase + com_cfcr);
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ sp->dlbl = inb(iobase + com_dlbl);
+ sp->dlbh = inb(iobase + com_dlbh);
+ divisor = ttspeedtab(comdefaultrate, comspeedtab);
+ outb(iobase + com_dlbl, divisor & 0xFF);
+ outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS);
+ sp->mcr = inb(iobase + com_mcr);
+ outb(iobase + com_mcr, MCR_DTR | MCR_RTS);
+}
+
+static void
+siocnclose(sp)
+ struct siocnstate *sp;
+{
+ Port_t iobase;
+
+ /*
+ * Restore the device control registers.
+ */
+ siocntxwait();
+ iobase = siocniobase;
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ outb(iobase + com_dlbl, sp->dlbl);
+ outb(iobase + com_dlbh, sp->dlbh);
+ outb(iobase + com_cfcr, sp->cfcr);
+ /*
+ * XXX damp osicllations of MCR_DTR or MCR_RTS by not restoring them.
+ */
+ outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS);
+ outb(iobase + com_ier, sp->ier);
+}
+
+void
+siocnprobe(cp)
+ struct consdev *cp;
+{
+ int unit;
+
+ /* locate the major number */
+ /* XXX - should be elsewhere since KGDB uses it */
+ for (commajor = 0; commajor < nchrdev; commajor++)
+ if (cdevsw[commajor].d_open == sioopen)
+ break;
+
+ /* XXX: ick */
+ unit = UNIT(CONUNIT);
+ siocniobase = CONADDR;
+
+ /* make sure hardware exists? XXX */
+
+ /* initialize required fields */
+ cp->cn_dev = makedev(commajor, unit);
+#ifdef COMCONSOLE
+ cp->cn_pri = CN_REMOTE; /* Force a serial port console */
+#else
+ cp->cn_pri = CN_NORMAL;
+#endif
+}
+
+void
+siocninit(cp)
+ struct consdev *cp;
+{
+ /*
+ * XXX can delete more comconsole stuff now that i/o routines are
+ * fairly reentrant.
+ */
+ comconsole = UNIT(cp->cn_dev);
+}
+
+int
+siocngetc(dev)
+ dev_t dev;
+{
+ int c;
+ Port_t iobase;
+ int s;
+ struct siocnstate sp;
+
+ iobase = siocniobase;
+ s = spltty();
+ siocnopen(&sp);
+ while (!(inb(iobase + com_lsr) & LSR_RXRDY))
+ ;
+ c = inb(iobase + com_data);
+ siocnclose(&sp);
+ splx(s);
+ return (c);
+}
+
+void
+siocnputc(dev, c)
+ dev_t dev;
+ int c;
+{
+ int s;
+ struct siocnstate sp;
+
+ s = spltty();
+ siocnopen(&sp);
+ siocntxwait();
+ outb(siocniobase + com_data, c);
+ siocnclose(&sp);
+ splx(s);
+}
+
+#endif /* NSIO > 0 */
diff --git a/sys/dev/sio/sioreg.h b/sys/dev/sio/sioreg.h
new file mode 100644
index 0000000..4b0f1b6
--- /dev/null
+++ b/sys/dev/sio/sioreg.h
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)comreg.h 7.2 (Berkeley) 5/9/91
+ * $Id$
+ */
+
+
+/* 16 bit baud rate divisor (lower byte in dca_data, upper in dca_ier) */
+#define COMBRD(x) (1843200 / (16*(x)))
+
+/* interrupt enable register */
+#define IER_ERXRDY 0x1
+#define IER_ETXRDY 0x2
+#define IER_ERLS 0x4
+#define IER_EMSC 0x8
+
+/* interrupt identification register */
+#define IIR_IMASK 0xf
+#define IIR_RXTOUT 0xc
+#define IIR_RLS 0x6
+#define IIR_RXRDY 0x4
+#define IIR_TXRDY 0x2
+#define IIR_NOPEND 0x1
+#define IIR_MLSC 0x0
+#define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */
+
+/* fifo control register */
+#define FIFO_ENABLE 0x01
+#define FIFO_RCV_RST 0x02
+#define FIFO_XMT_RST 0x04
+#define FIFO_DMA_MODE 0x08
+#define FIFO_TRIGGER_1 0x00
+#define FIFO_TRIGGER_4 0x40
+#define FIFO_TRIGGER_8 0x80
+#define FIFO_TRIGGER_14 0xc0
+
+/* character format control register */
+#define CFCR_DLAB 0x80
+#define CFCR_SBREAK 0x40
+#define CFCR_PZERO 0x30
+#define CFCR_PONE 0x20
+#define CFCR_PEVEN 0x10
+#define CFCR_PODD 0x00
+#define CFCR_PENAB 0x08
+#define CFCR_STOPB 0x04
+#define CFCR_8BITS 0x03
+#define CFCR_7BITS 0x02
+#define CFCR_6BITS 0x01
+#define CFCR_5BITS 0x00
+
+/* modem control register */
+#define MCR_LOOPBACK 0x10
+#define MCR_IENABLE 0x08
+#define MCR_DRS 0x04
+#define MCR_RTS 0x02
+#define MCR_DTR 0x01
+
+/* line status register */
+#define LSR_RCV_FIFO 0x80
+#define LSR_TSRE 0x40
+#define LSR_TXRDY 0x20
+#define LSR_BI 0x10
+#define LSR_FE 0x08
+#define LSR_PE 0x04
+#define LSR_OE 0x02
+#define LSR_RXRDY 0x01
+#define LSR_RCV_MASK 0x1f
+
+/* modem status register */
+#define MSR_DCD 0x80
+#define MSR_RI 0x40
+#define MSR_DSR 0x20
+#define MSR_CTS 0x10
+#define MSR_DDCD 0x08
+#define MSR_TERI 0x04
+#define MSR_DDSR 0x02
+#define MSR_DCTS 0x01
+
+/*
+ * WARNING: Serial console is assumed to be at COM1 address
+ * and CONUNIT must be 0.
+ */
+#define CONADDR (0x3f8)
+#define CONUNIT (0)
diff --git a/sys/dev/speaker/speaker.h b/sys/dev/speaker/speaker.h
new file mode 100644
index 0000000..af80a28
--- /dev/null
+++ b/sys/dev/speaker/speaker.h
@@ -0,0 +1,30 @@
+/*
+ * speaker.h -- interface definitions for speaker ioctl()
+ *
+ * v1.4 by Eric S. Raymond (esr@snark.thyrsus.com) Aug 1993
+ * modified for FreeBSD by Andrew A. Chernov <ache@astral.msk.su>
+ */
+
+#ifndef _SPEAKER_H_
+#define _SPEAKER_H_
+
+#include <sys/ioctl.h>
+
+#define SPKRTONE _IOW('S', 1, tone_t) /* emit tone */
+#define SPKRTUNE _IO('S', 2) /* emit tone sequence*/
+
+typedef struct
+{
+ int frequency; /* in hertz */
+ int duration; /* in 1/100ths of a second */
+}
+tone_t;
+
+/*
+ * Strings written to the speaker device are interpreted as tunes and played;
+ * see the spkr(4) man page for details.
+ */
+
+#endif /* _SPEAKER_H_ */
+
+/* speaker.h ends here */
diff --git a/sys/dev/speaker/spkr.c b/sys/dev/speaker/spkr.c
new file mode 100644
index 0000000..d273f31
--- /dev/null
+++ b/sys/dev/speaker/spkr.c
@@ -0,0 +1,541 @@
+/*
+ * spkr.c -- device driver for console speaker
+ *
+ * v1.4 by Eric S. Raymond (esr@snark.thyrsus.com) Aug 1993
+ * modified for FreeBSD by Andrew A. Chernov <ache@astral.msk.su>
+ *
+ * $Id: spkr.c,v 1.7 1994/01/25 23:04:27 ache Exp $
+ */
+
+#include "speaker.h"
+
+#if NSPEAKER > 0
+
+#include "param.h"
+#include "systm.h"
+#include "kernel.h"
+#include "errno.h"
+#include "buf.h"
+#include "uio.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/timerreg.h"
+#include "machine/speaker.h"
+
+/**************** MACHINE DEPENDENT PART STARTS HERE *************************
+ *
+ * This section defines a function tone() which causes a tone of given
+ * frequency and duration from the 80x86's console speaker.
+ * Another function endtone() is defined to force sound off, and there is
+ * also a rest() entry point to do pauses.
+ *
+ * Audible sound is generated using the Programmable Interval Timer (PIT) and
+ * Programmable Peripheral Interface (PPI) attached to the 80x86's speaker. The
+ * PPI controls whether sound is passed through at all; the PIT's channel 2 is
+ * used to generate clicks (a square wave) of whatever frequency is desired.
+ */
+
+/*
+ * PIT and PPI port addresses and control values
+ *
+ * Most of the magic is hidden in the TIMER_PREP value, which selects PIT
+ * channel 2, frequency LSB first, square-wave mode and binary encoding.
+ * The encoding is as follows:
+ *
+ * +----------+----------+---------------+-----+
+ * | 1 0 | 1 1 | 0 1 1 | 0 |
+ * | SC1 SC0 | RW1 RW0 | M2 M1 M0 | BCD |
+ * +----------+----------+---------------+-----+
+ * Counter Write Mode 3 Binary
+ * Channel 2 LSB first, (Square Wave) Encoding
+ * MSB second
+ */
+#define PPI_SPKR 0x03 /* turn these PPI bits on to pass sound */
+#define PIT_MODE 0xB6 /* set timer mode for sound generation */
+
+/*
+ * Magic numbers for timer control.
+ */
+#define TIMER_CLK 1193180L /* corresponds to 18.2 MHz tick rate */
+
+#define SPKRPRI PSOCK
+static char endtone, endrest;
+
+static void tone(thz, ticks)
+/* emit tone of frequency thz for given number of ticks */
+unsigned int thz, ticks;
+{
+ unsigned int divisor = TIMER_CLK / thz;
+ int sps;
+
+#ifdef DEBUG
+ (void) printf("tone: thz=%d ticks=%d\n", thz, ticks);
+#endif /* DEBUG */
+
+ /* set timer to generate clicks at given frequency in Hertz */
+ sps = spltty();
+
+ if (acquire_timer2(PIT_MODE)) {
+ /* enter list of waiting procs ??? */
+ return;
+ }
+ outb(TIMER_CNTR2, (divisor & 0xff)); /* send lo byte */
+ outb(TIMER_CNTR2, (divisor >> 8)); /* send hi byte */
+ splx(sps);
+
+ /* turn the speaker on */
+ outb(IO_PPI, inb(IO_PPI) | PPI_SPKR);
+
+ /*
+ * Set timeout to endtone function, then give up the timeslice.
+ * This is so other processes can execute while the tone is being
+ * emitted.
+ */
+ (void) tsleep((caddr_t)&endtone, SPKRPRI | PCATCH, "spkrtn", ticks);
+ outb(IO_PPI, inb(IO_PPI) & ~PPI_SPKR);
+ release_timer2();
+}
+
+static void rest(ticks)
+/* rest for given number of ticks */
+int ticks;
+{
+ /*
+ * Set timeout to endrest function, then give up the timeslice.
+ * This is so other processes can execute while the rest is being
+ * waited out.
+ */
+#ifdef DEBUG
+ (void) printf("rest: %d\n", ticks);
+#endif /* DEBUG */
+ (void) tsleep((caddr_t)&endrest, SPKRPRI | PCATCH, "spkrrs", ticks);
+}
+
+/**************** PLAY STRING INTERPRETER BEGINS HERE **********************
+ *
+ * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement;
+ * M[LNS] are missing; the ~ synonym and the _ slur mark and the octave-
+ * tracking facility are added.
+ * Requires tone(), rest(), and endtone(). String play is not interruptible
+ * except possibly at physical block boundaries.
+ */
+
+typedef int bool;
+#define TRUE 1
+#define FALSE 0
+
+#define toupper(c) ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z')))
+#define isdigit(c) (((c) >= '0') && ((c) <= '9'))
+#define dtoi(c) ((c) - '0')
+
+static int octave; /* currently selected octave */
+static int whole; /* whole-note time at current tempo, in ticks */
+static int value; /* whole divisor for note time, quarter note = 1 */
+static int fill; /* controls spacing of notes */
+static bool octtrack; /* octave-tracking on? */
+static bool octprefix; /* override current octave-tracking state? */
+
+/*
+ * Magic number avoidance...
+ */
+#define SECS_PER_MIN 60 /* seconds per minute */
+#define WHOLE_NOTE 4 /* quarter notes per whole note */
+#define MIN_VALUE 64 /* the most we can divide a note by */
+#define DFLT_VALUE 4 /* default value (quarter-note) */
+#define FILLTIME 8 /* for articulation, break note in parts */
+#define STACCATO 6 /* 6/8 = 3/4 of note is filled */
+#define NORMAL 7 /* 7/8ths of note interval is filled */
+#define LEGATO 8 /* all of note interval is filled */
+#define DFLT_OCTAVE 4 /* default octave */
+#define MIN_TEMPO 32 /* minimum tempo */
+#define DFLT_TEMPO 120 /* default tempo */
+#define MAX_TEMPO 255 /* max tempo */
+#define NUM_MULT 3 /* numerator of dot multiplier */
+#define DENOM_MULT 2 /* denominator of dot multiplier */
+
+/* letter to half-tone: A B C D E F G */
+static int notetab[8] = {9, 11, 0, 2, 4, 5, 7};
+
+/*
+ * This is the American Standard A440 Equal-Tempered scale with frequencies
+ * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook...
+ * our octave 0 is standard octave 2.
+ */
+#define OCTAVE_NOTES 12 /* semitones per octave */
+static int pitchtab[] =
+{
+/* C C# D D# E F F# G G# A A# B*/
+/* 0 */ 65, 69, 73, 78, 82, 87, 93, 98, 103, 110, 117, 123,
+/* 1 */ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247,
+/* 2 */ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494,
+/* 3 */ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988,
+/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975,
+/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951,
+/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902,
+};
+
+static void playinit()
+{
+ octave = DFLT_OCTAVE;
+ whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO;
+ fill = NORMAL;
+ value = DFLT_VALUE;
+ octtrack = FALSE;
+ octprefix = TRUE; /* act as though there was an initial O(n) */
+}
+
+static void playtone(pitch, value, sustain)
+/* play tone of proper duration for current rhythm signature */
+int pitch, value, sustain;
+{
+ register int sound, silence, snum = 1, sdenom = 1;
+
+ /* this weirdness avoids floating-point arithmetic */
+ for (; sustain; sustain--)
+ {
+ /* See the BUGS section in the man page for discussion */
+ snum *= NUM_MULT;
+ sdenom *= DENOM_MULT;
+ }
+
+ if (pitch == -1)
+ rest(whole * snum / (value * sdenom));
+ else
+ {
+ sound = (whole * snum) / (value * sdenom)
+ - (whole * (FILLTIME - fill)) / (value * FILLTIME);
+ silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom);
+
+#ifdef DEBUG
+ (void) printf("playtone: pitch %d for %d ticks, rest for %d ticks\n",
+ pitch, sound, silence);
+#endif /* DEBUG */
+
+ tone(pitchtab[pitch], sound);
+ if (fill != LEGATO)
+ rest(silence);
+ }
+}
+
+static int abs(n)
+int n;
+{
+ if (n < 0)
+ return(-n);
+ else
+ return(n);
+}
+
+static void playstring(cp, slen)
+/* interpret and play an item from a notation string */
+char *cp;
+size_t slen;
+{
+ int pitch, oldfill, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE;
+
+#define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \
+ {v = v * 10 + (*++cp - '0'); slen--;}
+ for (; slen--; cp++)
+ {
+ int sustain, timeval, tempo;
+ register char c = toupper(*cp);
+
+#ifdef DEBUG
+ (void) printf("playstring: %c (%x)\n", c, c);
+#endif /* DEBUG */
+
+ switch (c)
+ {
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+
+ /* compute pitch */
+ pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES;
+
+ /* this may be followed by an accidental sign */
+ if (cp[1] == '#' || cp[1] == '+')
+ {
+ ++pitch;
+ ++cp;
+ slen--;
+ }
+ else if (cp[1] == '-')
+ {
+ --pitch;
+ ++cp;
+ slen--;
+ }
+
+ /*
+ * If octave-tracking mode is on, and there has been no octave-
+ * setting prefix, find the version of the current letter note
+ * closest to the last regardless of octave.
+ */
+ if (octtrack && !octprefix)
+ {
+ if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch))
+ {
+ ++octave;
+ pitch += OCTAVE_NOTES;
+ }
+
+ if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch))
+ {
+ --octave;
+ pitch -= OCTAVE_NOTES;
+ }
+ }
+ octprefix = FALSE;
+ lastpitch = pitch;
+
+ /* ...which may in turn be followed by an override time value */
+ GETNUM(cp, timeval);
+ if (timeval <= 0 || timeval > MIN_VALUE)
+ timeval = value;
+
+ /* ...and/or sustain dots */
+ for (sustain = 0; cp[1] == '.'; cp++)
+ {
+ slen--;
+ sustain++;
+ }
+
+ /* ...and/or a slur mark */
+ oldfill = fill;
+ if (cp[1] == '_')
+ {
+ fill = LEGATO;
+ ++cp;
+ slen--;
+ }
+
+ /* time to emit the actual tone */
+ playtone(pitch, timeval, sustain);
+
+ fill = oldfill;
+ break;
+
+ case 'O':
+ if (cp[1] == 'N' || cp[1] == 'n')
+ {
+ octprefix = octtrack = FALSE;
+ ++cp;
+ slen--;
+ }
+ else if (cp[1] == 'L' || cp[1] == 'l')
+ {
+ octtrack = TRUE;
+ ++cp;
+ slen--;
+ }
+ else
+ {
+ GETNUM(cp, octave);
+ if (octave >= sizeof(pitchtab) / OCTAVE_NOTES)
+ octave = DFLT_OCTAVE;
+ octprefix = TRUE;
+ }
+ break;
+
+ case '>':
+ if (octave < sizeof(pitchtab) / OCTAVE_NOTES - 1)
+ octave++;
+ octprefix = TRUE;
+ break;
+
+ case '<':
+ if (octave > 0)
+ octave--;
+ octprefix = TRUE;
+ break;
+
+ case 'N':
+ GETNUM(cp, pitch);
+ for (sustain = 0; cp[1] == '.'; cp++)
+ {
+ slen--;
+ sustain++;
+ }
+ oldfill = fill;
+ if (cp[1] == '_')
+ {
+ fill = LEGATO;
+ ++cp;
+ slen--;
+ }
+ playtone(pitch - 1, value, sustain);
+ fill = oldfill;
+ break;
+
+ case 'L':
+ GETNUM(cp, value);
+ if (value <= 0 || value > MIN_VALUE)
+ value = DFLT_VALUE;
+ break;
+
+ case 'P':
+ case '~':
+ /* this may be followed by an override time value */
+ GETNUM(cp, timeval);
+ if (timeval <= 0 || timeval > MIN_VALUE)
+ timeval = value;
+ for (sustain = 0; cp[1] == '.'; cp++)
+ {
+ slen--;
+ sustain++;
+ }
+ playtone(-1, timeval, sustain);
+ break;
+
+ case 'T':
+ GETNUM(cp, tempo);
+ if (tempo < MIN_TEMPO || tempo > MAX_TEMPO)
+ tempo = DFLT_TEMPO;
+ whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo;
+ break;
+
+ case 'M':
+ if (cp[1] == 'N' || cp[1] == 'n')
+ {
+ fill = NORMAL;
+ ++cp;
+ slen--;
+ }
+ else if (cp[1] == 'L' || cp[1] == 'l')
+ {
+ fill = LEGATO;
+ ++cp;
+ slen--;
+ }
+ else if (cp[1] == 'S' || cp[1] == 's')
+ {
+ fill = STACCATO;
+ ++cp;
+ slen--;
+ }
+ break;
+ }
+ }
+}
+
+/******************* UNIX DRIVER HOOKS BEGIN HERE **************************
+ *
+ * This section implements driver hooks to run playstring() and the tone(),
+ * endtone(), and rest() functions defined above.
+ */
+
+static int spkr_active = FALSE; /* exclusion flag */
+static struct buf *spkr_inbuf; /* incoming buf */
+
+int spkropen(dev)
+dev_t dev;
+{
+#ifdef DEBUG
+ (void) printf("spkropen: entering with dev = %x\n", dev);
+#endif /* DEBUG */
+
+ if (minor(dev) != 0)
+ return(ENXIO);
+ else if (spkr_active)
+ return(EBUSY);
+ else
+ {
+#ifdef DEBUG
+ (void) printf("spkropen: about to perform play initialization\n");
+#endif /* DEBUG */
+ playinit();
+ spkr_inbuf = geteblk(DEV_BSIZE);
+ spkr_active = TRUE;
+ return(0);
+ }
+}
+
+int spkrwrite(dev, uio)
+dev_t dev;
+struct uio *uio;
+{
+#ifdef DEBUG
+ printf("spkrwrite: entering with dev = %x, count = %d\n",
+ dev, uio->uio_resid);
+#endif /* DEBUG */
+
+ if (minor(dev) != 0)
+ return(ENXIO);
+ else if (uio->uio_resid > DEV_BSIZE) /* prevent system crashes */
+ return(E2BIG);
+ else
+ {
+ unsigned n;
+ char *cp;
+ int error;
+
+ n = uio->uio_resid;
+ cp = spkr_inbuf->b_un.b_addr;
+ if (!(error = uiomove(cp, n, uio)))
+ playstring(cp, n);
+ return(error);
+ }
+}
+
+int spkrclose(dev)
+dev_t dev;
+{
+#ifdef DEBUG
+ (void) printf("spkrclose: entering with dev = %x\n", dev);
+#endif /* DEBUG */
+
+ if (minor(dev) != 0)
+ return(ENXIO);
+ else
+ {
+ wakeup((caddr_t)&endtone);
+ wakeup((caddr_t)&endrest);
+ brelse(spkr_inbuf);
+ spkr_active = FALSE;
+ return(0);
+ }
+}
+
+int spkrioctl(dev, cmd, cmdarg)
+dev_t dev;
+int cmd;
+caddr_t cmdarg;
+{
+#ifdef DEBUG
+ (void) printf("spkrioctl: entering with dev = %x, cmd = %x\n");
+#endif /* DEBUG */
+
+ if (minor(dev) != 0)
+ return(ENXIO);
+ else if (cmd == SPKRTONE)
+ {
+ tone_t *tp = (tone_t *)cmdarg;
+
+ if (tp->frequency == 0)
+ rest(tp->duration);
+ else
+ tone(tp->frequency, tp->duration);
+ return 0;
+ }
+ else if (cmd == SPKRTUNE)
+ {
+ tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg);
+ tone_t ttp;
+ int error;
+
+ for (; ; tp++) {
+ error = copyin(tp, &ttp, sizeof(tone_t));
+ if (error)
+ return(error);
+ if (ttp.duration == 0)
+ break;
+ if (ttp.frequency == 0)
+ rest(ttp.duration);
+ else
+ tone(ttp.frequency, ttp.duration);
+ }
+ return(0);
+ }
+ return(EINVAL);
+}
+
+#endif /* NSPEAKER > 0 */
+/* spkr.c ends here */
diff --git a/sys/dev/syscons/syscons.c b/sys/dev/syscons/syscons.c
new file mode 100644
index 0000000..8757295
--- /dev/null
+++ b/sys/dev/syscons/syscons.c
@@ -0,0 +1,2659 @@
+/*-
+ * Copyright (c) 1992-1994 Søren Schmidt
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz and Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from:@(#)syscons.c 1.3 940129
+ * $Id: syscons.c,v 1.44 1994/04/21 14:22:26 sos Exp $
+ *
+ */
+
+#if !defined(__FreeBSD__)
+#define FAT_CURSOR
+#endif
+
+#include "param.h"
+#include "conf.h"
+#include "ioctl.h"
+#include "proc.h"
+#include "user.h"
+#include "tty.h"
+#include "uio.h"
+#include "callout.h"
+#include "systm.h"
+#include "kernel.h"
+#include "syslog.h"
+#include "errno.h"
+#include "malloc.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/timerreg.h"
+#include "i386/i386/cons.h"
+#include "machine/console.h"
+#include "machine/psl.h"
+#include "machine/frame.h"
+#include "machine/pc/display.h"
+#include "iso8859.font"
+#include "kbdtables.h"
+#include "sc.h"
+
+#if NSC > 0
+
+#if !defined(NCONS)
+#define NCONS 12
+#endif
+
+/* status flags */
+#define LOCK_KEY_MASK 0x0000F
+#define LED_MASK 0x00007
+#define UNKNOWN_MODE 0x00010
+#define KBD_RAW_MODE 0x00020
+#define SWITCH_WAIT_REL 0x00040
+#define SWITCH_WAIT_ACQ 0x00080
+
+/* video hardware memory addresses */
+#define VIDEOMEM 0x000A0000
+
+/* misc defines */
+#define MAX_ESC_PAR 3
+#define TEXT80x25 1
+#define TEXT80x50 2
+#define COL 80
+#define ROW 25
+#define BELL_DURATION 5
+#define BELL_PITCH 800
+#define TIMER_FREQ 1193182 /* should be in isa.h */
+#define PCBURST 128
+
+/* defines related to hardware addresses */
+#define MONO_BASE 0x3B4 /* crt controller base mono */
+#define COLOR_BASE 0x3D4 /* crt controller base color */
+#define ATC IO_VGA+0x00 /* attribute controller */
+#define TSIDX IO_VGA+0x04 /* timing sequencer idx */
+#define TSREG IO_VGA+0x05 /* timing sequencer data */
+#define PIXMASK IO_VGA+0x06 /* pixel write mask */
+#define PALRADR IO_VGA+0x07 /* palette read address */
+#define PALWADR IO_VGA+0x08 /* palette write address */
+#define PALDATA IO_VGA+0x09 /* palette data register */
+#define GDCIDX IO_VGA+0x0E /* graph data controller idx */
+#define GDCREG IO_VGA+0x0F /* graph data controller data */
+
+/* special characters */
+#define cntlc 0x03
+#define cntld 0x04
+#define bs 0x08
+#define lf 0x0a
+#define cr 0x0d
+#define del 0x7f
+
+typedef struct term_stat {
+ int esc; /* processing escape sequence */
+ int num_param; /* # of parameters to ESC */
+ int last_param; /* last parameter # */
+ int param[MAX_ESC_PAR]; /* contains ESC parameters */
+ int cur_attr; /* current attributes */
+ int std_attr; /* normal attributes */
+ int rev_attr; /* reverse attributes */
+} term_stat;
+
+typedef struct scr_stat {
+ u_short *crt_base; /* address of screen memory */
+ u_short *scr_buf; /* buffer when off screen */
+ u_short *crtat; /* cursor address */
+ int xpos; /* current X position */
+ int ypos; /* current Y position */
+ int xsize; /* X size */
+ int ysize; /* Y size */
+ term_stat term; /* terminal emulation stuff */
+ char cursor_start; /* cursor start line # */
+ char cursor_end; /* cursor end line # */
+ u_char border; /* border color */
+ u_short bell_duration;
+ u_short bell_pitch;
+ u_short status; /* status (bitfield) */
+ u_short mode; /* mode */
+ pid_t pid; /* pid of controlling proc */
+ struct proc *proc; /* proc* of controlling proc */
+ struct vt_mode smode; /* switch mode */
+} scr_stat;
+
+typedef struct default_attr {
+ int std_attr; /* normal attributes */
+ int rev_attr; /* reverse attributes */
+} default_attr;
+
+static default_attr user_default = {
+ (FG_LIGHTGREY | BG_BLACK) << 8,
+ (FG_BLACK | BG_LIGHTGREY) << 8
+};
+
+static default_attr kernel_default = {
+ (FG_WHITE | BG_BLACK) << 8,
+ (FG_BLACK | BG_LIGHTGREY) << 8
+};
+
+#define CONSOLE_BUFFER_SIZE 1024
+int console_buffer_count;
+char console_buffer[CONSOLE_BUFFER_SIZE];
+
+static scr_stat console[NCONS];
+static scr_stat *cur_console = &console[0];
+static scr_stat *new_scp, *old_scp;
+static term_stat kernel_console;
+static default_attr *current_default;
+static int switch_in_progress = 0;
+static u_short *crtat = 0;
+static u_int crtc_addr = MONO_BASE;
+static char crtc_vga = 0;
+static u_char shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0;
+static u_char nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0;
+static char palette[3*256];
+static const u_int n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab);
+static int cur_cursor_pos = -1;
+static char in_putc = 0;
+static char polling = 0;
+static int delayed_next_scr;
+static char saved_console = -1; /* saved console number */
+static long scrn_blank_time = 0; /* screen saver timout value */
+static int scrn_blanked = 0; /* screen saver active flag */
+static int scrn_saver = 0; /* screen saver routine */
+static long scrn_time_stamp;
+static u_char scr_map[256];
+extern int hz;
+extern struct timeval time;
+
+/* function prototypes */
+int pcprobe(struct isa_device *dev);
+int pcattach(struct isa_device *dev);
+int pcopen(dev_t dev, int flag, int mode, struct proc *p);
+int pcclose(dev_t dev, int flag, int mode, struct proc *p);
+int pcread(dev_t dev, struct uio *uio, int flag);
+int pcwrite(dev_t dev, struct uio *uio, int flag);
+int pcparam(struct tty *tp, struct termios *t);
+int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p);
+void pcxint(dev_t dev);
+void pcstart(struct tty *tp);
+void pccnprobe(struct consdev *cp);
+void pccninit(struct consdev *cp);
+void pccnputc(dev_t dev, char c);
+int pccngetc(dev_t dev);
+void scintr(int unit);
+int pcmmap(dev_t dev, int offset, int nprot);
+u_int sgetc(int noblock);
+int getchar(void);
+static void scinit(void);
+static void scput(u_char c);
+static u_int scgetc(int noblock);
+static struct tty *get_tty_ptr(dev_t dev);
+static scr_stat *get_scr_stat(dev_t dev);
+static int get_scr_num();
+static void cursor_shape(int start, int end);
+static void get_cursor_shape(int *start, int *end);
+static void cursor_pos(int force);
+static void clear_screen(scr_stat *scp);
+static int switch_scr(u_int next_scr);
+static void exchange_scr(void);
+static void move_crsr(scr_stat *scp, int x, int y);
+static void move_up(u_short *s, u_short *d, u_int len);
+static void move_down(u_short *s, u_short *d, u_int len);
+static void scan_esc(scr_stat *scp, u_char c);
+static void ansi_put(scr_stat *scp, u_char c);
+static u_char *get_fstr(u_int c, u_int *len);
+static void update_leds(int which);
+static void kbd_wait(void);
+static void kbd_cmd(u_char command);
+static void kbd_cmd2(u_char command, u_char arg);
+static int kbd_reply(void);
+static void set_mode(scr_stat *scp);
+static void set_border(int color);
+static void load_font(int segment, int size, char* font);
+static void save_palette(void);
+static void load_palette(void);
+static void change_winsize(struct tty *tp, int x, int y);
+
+
+/* available screen savers */
+
+static void none_saver(int test);
+static void blank_saver(int test);
+static void fade_saver(int test);
+static void star_saver(int test);
+static void snake_saver(int test);
+
+static const struct {
+ char *name;
+ void (*routine)();
+} screen_savers[] = {
+ { "none", none_saver }, /* 0 */
+ { "blank", blank_saver }, /* 1 */
+ { "fade", fade_saver }, /* 2 */
+ { "star", star_saver }, /* 3 */
+ { "snake", snake_saver }, /* 4 */
+};
+#define SCRN_SAVER(arg) (*screen_savers[scrn_saver].routine)(arg)
+#define NUM_SCRN_SAVERS (sizeof(screen_savers) / sizeof(screen_savers[0]))
+
+/* OS specific stuff */
+
+#if defined(NetBSD)
+#define VIRTUAL_TTY(x) pc_tty[x] ? (pc_tty[x]) : (pc_tty[x] = ttymalloc())
+#define CONSOLE_TTY pc_tty[NCONS] ? (pc_tty[NCONS]) : (pc_tty[NCONS] = ttymalloc())
+#define frametype struct trapframe
+#define eflags tf_eflags
+extern u_short *Crtat;
+struct tty *pc_tty[NCONS+1];
+int ttrstrt();
+#endif
+
+#if defined(__FreeBSD__)
+#define VIRTUAL_TTY(x) (pccons[x] = ttymalloc(pccons[x]))
+#define CONSOLE_TTY (pccons[NCONS] = ttymalloc(pccons[NCONS]))
+#define frametype struct trapframe
+#define eflags tf_eflags
+#define timeout_t timeout_func_t
+#define MONO_BUF (KERNBASE+0xB0000)
+#define CGA_BUF (KERNBASE+0xB8000)
+struct tty *pccons[NCONS+1];
+#endif
+
+#if defined(__386BSD__) && !defined(__FreeBSD__)
+#define VIRTUAL_TTY(x) &pccons[x]
+#define CONSOLE_TTY &pccons[NCONS]
+#define frametype struct syscframe
+#define eflags sf_eflags
+#define timeout_t caddr_t
+#define MONO_BUF (0xFE0B0000)
+#define CGA_BUF (0xFE0B8000)
+struct tty pccons[NCONS+1];
+#endif
+
+#if defined(__386BSD__) || defined(__FreeBSD__)
+u_short *Crtat = (u_short *)MONO_BUF;
+void consinit(void) {scinit();}
+#include "ddb.h"
+#if NDDB > 0
+#define DDB 1
+#endif
+#endif
+
+struct isa_driver scdriver = {
+ pcprobe, pcattach, "sc",
+};
+
+
+int pcprobe(struct isa_device *dev)
+{
+ /* Enable interrupts and keyboard controller */
+ kbd_wait();
+ outb(KB_STAT, KB_WRITE);
+ kbd_cmd(0x4D);
+
+ /* Start keyboard stuff RESET */
+ for (;;) {
+ kbd_cmd(KB_RESET);
+ if (kbd_reply() == KB_ACK && /* command accepted */
+ kbd_reply() == 0xaa) /* self test passed */
+ break;
+ printf("Keyboard reset failed\n");
+ }
+ return (IO_KBDSIZE);
+}
+
+
+int pcattach(struct isa_device *dev)
+{
+ scr_stat *scp;
+ int start = -1, end = -1, i;
+
+ printf("sc%d: ", dev->id_unit);
+ if (crtc_vga)
+ if (crtc_addr == MONO_BASE)
+ printf("VGA mono");
+ else
+ printf("VGA color");
+ else
+ if (crtc_addr == MONO_BASE)
+ printf("MDA/hercules");
+ else
+ printf("CGA/EGA");
+
+ if (NCONS > 1)
+ printf(" <%d virtual consoles>\n", NCONS);
+ else
+ printf("\n");
+#if defined(FAT_CURSOR)
+ start = 0;
+ end = 18;
+ if (crtc_vga) {
+#else
+ if (crtc_vga) {
+ get_cursor_shape(&start, &end);
+#endif
+ save_palette();
+ load_font(0, 16, font_8x16);
+ load_font(1, 8, font_8x8);
+ load_font(2, 14, font_8x14);
+ }
+ current_default = &user_default;
+ for (i = 0; i < NCONS; i++) {
+ scp = &console[i];
+ scp->scr_buf = (u_short *)malloc(COL * ROW * 2, M_DEVBUF, M_NOWAIT);
+ scp->mode = TEXT80x25;
+ scp->term.esc = 0;
+ scp->term.std_attr = current_default->std_attr;
+ scp->term.rev_attr = current_default->rev_attr;
+ scp->term.cur_attr = scp->term.std_attr;
+ scp->border = BG_BLACK;
+ scp->cursor_start = start;
+ scp->cursor_end = end;
+ scp->xsize = COL;
+ scp->ysize = ROW;
+ scp->bell_pitch = BELL_PITCH;
+ scp->bell_duration = BELL_DURATION;
+ scp->status = 0;
+ scp->pid = 0;
+ scp->proc = NULL;
+ scp->smode.mode = VT_AUTO;
+ if (i > 0) {
+ scp->crt_base = scp->crtat = scp->scr_buf;
+ fillw(scp->term.cur_attr|scr_map[0x20], scp->scr_buf, COL*ROW);
+ }
+ }
+ /* get cursor going */
+#if defined(FAT_CURSOR)
+ cursor_shape(console[0].cursor_start,
+ console[0].cursor_end);
+#endif
+ cursor_pos(1);
+ return 0;
+}
+
+
+static struct tty *get_tty_ptr(dev_t dev)
+{
+ int unit = minor(dev);
+
+ if (unit > NCONS)
+ return(NULL);
+ if (unit == NCONS)
+ return(CONSOLE_TTY);
+ return(VIRTUAL_TTY(unit));
+}
+
+
+static scr_stat *get_scr_stat(dev_t dev)
+{
+ int unit = minor(dev);
+
+ if (unit > NCONS)
+ return(NULL);
+ if (unit == NCONS)
+ return(&console[0]);
+ return(&console[unit]);
+}
+
+
+static int get_scr_num()
+{
+ int i = 0;
+
+ while ((i < NCONS) && (cur_console != &console[i])) i++;
+ return i < NCONS ? i : 0;
+}
+
+int pcopen(dev_t dev, int flag, int mode, struct proc *p)
+{
+ struct tty *tp = get_tty_ptr(dev);
+
+ if (!tp)
+ return(ENXIO);
+
+ tp->t_oproc = pcstart;
+ tp->t_param = pcparam;
+ tp->t_dev = dev;
+ if (!(tp->t_state & TS_ISOPEN)) {
+ tp->t_state |= TS_WOPEN;
+ ttychars(tp);
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
+ pcparam(tp, &tp->t_termios);
+ ttsetwater(tp);
+ } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
+ return(EBUSY);
+ tp->t_state |= TS_CARR_ON;
+ tp->t_cflag |= CLOCAL;
+#if defined(__FreeBSD__)
+ return((*linesw[tp->t_line].l_open)(dev, tp, 0));
+#else
+ return((*linesw[tp->t_line].l_open)(dev, tp));
+#endif
+}
+
+
+int pcclose(dev_t dev, int flag, int mode, struct proc *p)
+{
+ struct tty *tp = get_tty_ptr(dev);
+ struct scr_stat *scp;
+
+ if (!tp)
+ return(ENXIO);
+ if (minor(dev) < NCONS) {
+ scp = get_scr_stat(tp->t_dev);
+ if (scp->status & SWITCH_WAIT_ACQ)
+ wakeup((caddr_t)&scp->smode);
+ scp->pid = 0;
+ scp->proc = NULL;
+ scp->smode.mode = VT_AUTO;
+ }
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ ttyclose(tp);
+ return(0);
+}
+
+
+int pcread(dev_t dev, struct uio *uio, int flag)
+{
+ struct tty *tp = get_tty_ptr(dev);
+
+ if (!tp)
+ return(ENXIO);
+ return((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+
+int pcwrite(dev_t dev, struct uio *uio, int flag)
+{
+ struct tty *tp = get_tty_ptr(dev);
+
+ if (!tp)
+ return(ENXIO);
+ return((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+
+/*
+ * Got a console interrupt, keyboard action !
+ * Catch the character, and see who it goes to.
+ */
+void scintr(int unit)
+{
+ static struct tty *cur_tty;
+ int c, len;
+ u_char *cp;
+
+ /* make screensaver happy */
+ scrn_time_stamp = time.tv_sec;
+ if (scrn_blanked)
+ SCRN_SAVER(0);
+
+ c = scgetc(1);
+
+ cur_tty = VIRTUAL_TTY(get_scr_num());
+ if (!(cur_tty->t_state & TS_ISOPEN))
+ cur_tty = CONSOLE_TTY;
+
+ if (!(cur_tty->t_state & TS_ISOPEN) || polling)
+ return;
+
+ switch (c & 0xff00) {
+ case 0x0000: /* normal key */
+ (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
+ break;
+ case NOKEY: /* nothing there */
+ break;
+ case FKEY: /* function key, return string */
+ if (cp = get_fstr((u_int)c, (u_int *)&len)) {
+ while (len-- > 0)
+ (*linesw[cur_tty->t_line].l_rint)
+ (*cp++ & 0xFF, cur_tty);
+ }
+ break;
+ case MKEY: /* meta is active, prepend ESC */
+ (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
+ (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
+ break;
+ }
+}
+
+
+/*
+ * Set line parameters
+ */
+int pcparam(struct tty *tp, struct termios *t)
+{
+ int cflag = t->c_cflag;
+
+ /* and copy to tty */
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
+ tp->t_cflag = cflag;
+ return 0;
+}
+
+
+int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
+{
+ int i, error;
+ struct tty *tp;
+ frametype *fp;
+ scr_stat *scp;
+
+ tp = get_tty_ptr(dev);
+ if (!tp)
+ return ENXIO;
+ scp = get_scr_stat(tp->t_dev);
+
+ switch (cmd) { /* process console hardware related ioctl's */
+
+ case CONS_BLANKTIME: /* set screen saver timeout (0 = no saver) */
+ scrn_blank_time = *(int*)data;
+ return 0;
+ case CONS_SSAVER: /* set screen saver */
+ {
+ register ssaver_t *sav = (ssaver_t *)data;
+ if (sav->num < 0 || sav->num >= NUM_SCRN_SAVERS)
+ return EIO;
+ SCRN_SAVER(0);
+ scrn_saver = sav->num;
+ scrn_blank_time = sav->time;
+ return 0;
+ }
+ case CONS_GSAVER: /* get screen saver info */
+ {
+ register ssaver_t *sav = (ssaver_t *)data;
+ if (sav->num < 0)
+ sav->num = scrn_saver;
+ else if (sav->num >= NUM_SCRN_SAVERS)
+ return EIO;
+ sav->time = scrn_blank_time;
+ strcpy(sav->name, screen_savers[sav->num].name);
+ return 0;
+ }
+ case CONS_80x25TEXT: /* set 80x25 text mode */
+ if (!crtc_vga)
+ return ENXIO;
+ scp->mode = TEXT80x25;
+ scp->ysize = 25;
+ free(scp->scr_buf, M_DEVBUF);
+ scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*2,
+ M_DEVBUF, M_NOWAIT);
+ if (scp != cur_console)
+ scp->crt_base = scp->scr_buf;
+ set_mode(scp);
+ clear_screen(scp);
+ change_winsize(tp, scp->xsize, scp->ysize);
+ return 0;
+
+ case CONS_80x50TEXT: /* set 80x50 text mode */
+ if (!crtc_vga)
+ return ENXIO;
+ scp->mode = TEXT80x50;
+ scp->ysize = 50;
+ free(scp->scr_buf, M_DEVBUF);
+ scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*2,
+ M_DEVBUF, M_NOWAIT);
+ if (scp != cur_console)
+ scp->crt_base = scp->scr_buf;
+ set_mode(scp);
+ clear_screen(scp);
+ change_winsize(tp, scp->xsize, scp->ysize);
+ return 0;
+
+ case CONS_GETVERS: /* get version number */
+ *(int*)data = 0x103; /* version 1.3 */
+ return 0;
+
+ case CONS_GETINFO: /* get current (virtual) console info */
+ {
+ vid_info_t *ptr = (vid_info_t*)data;
+ if (ptr->size == sizeof(struct vid_info)) {
+ ptr->m_num = get_scr_num();
+ ptr->mv_col = scp->xpos;
+ ptr->mv_row = scp->ypos;
+ ptr->mv_csz = scp->xsize;
+ ptr->mv_rsz = scp->ysize;
+ ptr->mv_norm.fore = (scp->term.std_attr & 0x0f00)>>8;
+ ptr->mv_norm.back = (scp->term.std_attr & 0xf000)>>12;
+ ptr->mv_rev.fore = (scp->term.rev_attr & 0x0f00)>>8;
+ ptr->mv_rev.back = (scp->term.rev_attr & 0xf000)>>12;
+ ptr->mv_grfc.fore = 0; /* not supported */
+ ptr->mv_grfc.back = 0; /* not supported */
+ ptr->mv_ovscan = scp->border;
+ ptr->mk_keylock = scp->status & LOCK_KEY_MASK;
+ return 0;
+ }
+ return EINVAL;
+ }
+
+ case VT_SETMODE: /* set screen switcher mode */
+ bcopy(data, &scp->smode, sizeof(struct vt_mode));
+ if (scp->smode.mode == VT_PROCESS) {
+ scp->proc = p;
+ scp->pid = scp->proc->p_pid;
+ }
+ return 0;
+
+ case VT_GETMODE: /* get screen switcher mode */
+ bcopy(&scp->smode, data, sizeof(struct vt_mode));
+ return 0;
+
+ case VT_RELDISP: /* screen switcher ioctl */
+ switch(*data) {
+ case VT_FALSE: /* user refuses to release screen, abort */
+ if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
+ old_scp->status &= ~SWITCH_WAIT_REL;
+ switch_in_progress = 0;
+ return 0;
+ }
+ return EINVAL;
+
+ case VT_TRUE: /* user has released screen, go on */
+ if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
+ scp->status &= ~SWITCH_WAIT_REL;
+ exchange_scr();
+ if (new_scp->smode.mode == VT_PROCESS) {
+ new_scp->status |= SWITCH_WAIT_ACQ;
+ psignal(new_scp->proc,
+ new_scp->smode.acqsig);
+ }
+ else
+ switch_in_progress = 0;
+ return 0;
+ }
+ return EINVAL;
+
+ case VT_ACKACQ: /* acquire acknowledged, switch completed */
+ if (scp == new_scp && (scp->status & SWITCH_WAIT_ACQ)) {
+ scp->status &= ~SWITCH_WAIT_ACQ;
+ switch_in_progress = 0;
+ return 0;
+ }
+ return EINVAL;
+
+ default:
+ return EINVAL;
+ }
+ /* NOT REACHED */
+
+ case VT_OPENQRY: /* return free virtual console */
+ for (i = 0; i < NCONS; i++) {
+ tp = VIRTUAL_TTY(i);
+ if (!(tp->t_state & TS_ISOPEN)) {
+ *data = i + 1;
+ return 0;
+ }
+ }
+ return EINVAL;
+
+ case VT_ACTIVATE: /* switch to screen *data */
+ return switch_scr((*data) - 1);
+
+ case VT_WAITACTIVE: /* wait for switch to occur */
+ if (*data > NCONS)
+ return EINVAL;
+ if (minor(dev) == (*data) - 1)
+ return 0;
+ if (*data == 0) {
+ if (scp == cur_console)
+ return 0;
+ while ((error=tsleep((caddr_t)&scp->smode,
+ PZERO|PCATCH, "waitvt", 0)) == ERESTART) ;
+ }
+ else
+ while ((error=tsleep(
+ (caddr_t)&console[*(data-1)].smode,
+ PZERO|PCATCH, "waitvt", 0)) == ERESTART) ;
+ return error;
+
+ case VT_GETACTIVE:
+ *data = get_scr_num()+1;
+ return 0;
+
+ case KDENABIO: /* allow io operations */
+ fp = (frametype *)p->p_regs;
+ fp->eflags |= PSL_IOPL;
+ return 0;
+
+ case KDDISABIO: /* disallow io operations (default) */
+ fp = (frametype *)p->p_regs;
+ fp->eflags &= ~PSL_IOPL;
+ return 0;
+
+ case KDSETMODE: /* set current mode of this (virtual) console */
+ switch (*data) {
+ case KD_TEXT: /* switch to TEXT (known) mode */
+ /* restore fonts & palette ! */
+ if (crtc_vga) {
+ load_font(0, 16, font_8x16);
+ load_font(1, 8, font_8x8);
+ load_font(2, 14, font_8x14);
+ load_palette();
+ }
+ /* FALL THROUGH */
+
+ case KD_TEXT1: /* switch to TEXT (known) mode */
+ /* no restore fonts & palette */
+ scp->status &= ~UNKNOWN_MODE;
+ set_mode(scp);
+ clear_screen(scp);
+ return 0;
+
+ case KD_GRAPHICS:/* switch to GRAPHICS (unknown) mode */
+ scp->status |= UNKNOWN_MODE;
+ return 0;
+ default:
+ return EINVAL;
+ }
+ /* NOT REACHED */
+
+ case KDGETMODE: /* get current mode of this (virtual) console */
+ *data = (scp->status & UNKNOWN_MODE) ? KD_GRAPHICS : KD_TEXT;
+ return 0;
+
+ case KDSBORDER: /* set border color of this (virtual) console */
+ if (!crtc_vga)
+ return ENXIO;
+ scp->border = *data;
+ if (scp == cur_console)
+ set_border(scp->border);
+ return 0;
+
+ case KDSKBSTATE: /* set keyboard state (locks) */
+ if (*data >= 0 && *data <= LOCK_KEY_MASK) {
+ scp->status &= ~LOCK_KEY_MASK;
+ scp->status |= *data;
+ if (scp == cur_console)
+ update_leds(scp->status);
+ return 0;
+ }
+ return EINVAL;
+
+ case KDGKBSTATE: /* get keyboard state (locks) */
+ *data = scp->status & LOCK_KEY_MASK;
+ return 0;
+
+ case KDSETRAD: /* set keyboard repeat & delay rates */
+ if (*data & 0x80)
+ return EINVAL;
+ kbd_cmd2(KB_SETRAD, *data);
+ return 0;
+
+ case KDSKBMODE: /* set keyboard mode */
+ switch (*data) {
+ case K_RAW: /* switch to RAW scancode mode */
+ scp->status |= KBD_RAW_MODE;
+ return 0;
+
+ case K_XLATE: /* switch to XLT ascii mode */
+ if (scp == cur_console && scp->status == KBD_RAW_MODE)
+ shfts = ctls = alts = agrs = metas = 0;
+ scp->status &= ~KBD_RAW_MODE;
+ return 0;
+ default:
+ return EINVAL;
+ }
+ /* NOT REACHED */
+
+ case KDGKBMODE: /* get keyboard mode */
+ *data = (scp->status & KBD_RAW_MODE) ? K_RAW : K_XLATE;
+ return 0;
+
+ case KDMKTONE: /* sound the bell */
+ if (scp == cur_console)
+ sysbeep(scp->bell_pitch, scp->bell_duration);
+ return 0;
+
+ case KIOCSOUND: /* make tone (*data) hz */
+ if (scp == cur_console) {
+ if (*(int*)data) {
+ int pitch = TIMER_FREQ/(*(int*)data);
+ /* set command for counter 2, 2 byte write */
+ if (acquire_timer2(TIMER_16BIT|TIMER_SQWAVE)) {
+ return EBUSY;
+ }
+ /* set pitch */
+ outb(TIMER_CNTR2, pitch);
+ outb(TIMER_CNTR2, (pitch>>8));
+ /* enable counter 2 output to speaker */
+ outb(IO_PPI, inb(IO_PPI) | 3);
+ }
+ else {
+ /* disable counter 2 output to speaker */
+ outb(IO_PPI, inb(IO_PPI) & 0xFC);
+ release_timer2();
+ }
+ }
+ return 0;
+
+ case KDGKBTYPE: /* get keyboard type */
+ *data = 0; /* type not known (yet) */
+ return 0;
+
+ case KDSETLED: /* set keyboard LED status */
+ if (*data >= 0 && *data <= LED_MASK) {
+ scp->status &= ~LED_MASK;
+ scp->status |= *data;
+ if (scp == cur_console)
+ update_leds(scp->status);
+ return 0;
+ }
+ return EINVAL;
+
+ case KDGETLED: /* get keyboard LED status */
+ *data = scp->status & LED_MASK;
+ return 0;
+
+ case GETFKEY: /* get functionkey string */
+ if (*(u_short*)data < n_fkey_tab) {
+ fkeyarg_t *ptr = (fkeyarg_t*)data;
+ bcopy(&fkey_tab[ptr->keynum].str,
+ ptr->keydef,
+ fkey_tab[ptr->keynum].len);
+ ptr->flen = fkey_tab[ptr->keynum].len;
+ return 0;
+ }
+ else
+ return EINVAL;
+
+ case SETFKEY: /* set functionkey string */
+ if (*(u_short*)data < n_fkey_tab) {
+ fkeyarg_t *ptr = (fkeyarg_t*)data;
+ bcopy(ptr->keydef,
+ &fkey_tab[ptr->keynum].str,
+ min(ptr->flen, MAXFK));
+ fkey_tab[ptr->keynum].len = min(ptr->flen, MAXFK);
+ return 0;
+ }
+ else
+ return EINVAL;
+
+ case GIO_SCRNMAP: /* get output translation table */
+ bcopy(&scr_map, data, sizeof(scr_map));
+ return 0;
+
+ case PIO_SCRNMAP: /* set output translation table */
+ bcopy(data, &scr_map, sizeof(scr_map));
+ return 0;
+
+ case GIO_KEYMAP: /* get keyboard translation table */
+ bcopy(&key_map, data, sizeof(key_map));
+ return 0;
+
+ case PIO_KEYMAP: /* set keyboard translation table */
+ bcopy(data, &key_map, sizeof(key_map));
+ return 0;
+
+ case PIO_FONT8x8: /* set 8x8 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(data, &font_8x8, sizeof(font_8x8));
+ load_font(1, 8, font_8x8);
+ return 0;
+
+ case GIO_FONT8x8: /* get 8x8 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(&font_8x8, data, sizeof(font_8x8));
+ return 0;
+
+ case PIO_FONT8x14: /* set 8x14 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(data, &font_8x14, sizeof(font_8x14));
+ load_font(2, 14, font_8x14);
+ return 0;
+
+ case GIO_FONT8x14: /* get 8x14 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(&font_8x14, data, sizeof(font_8x14));
+ return 0;
+
+ case PIO_FONT8x16: /* set 8x16 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(data, &font_8x16, sizeof(font_8x16));
+ load_font(0, 16, font_8x16);
+ return 0;
+
+ case GIO_FONT8x16: /* get 8x16 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(&font_8x16, data, sizeof(font_8x16));
+ return 0;
+
+ case CONSOLE_X_MODE_ON: /* just to be compatible */
+ if (saved_console < 0) {
+ saved_console = get_scr_num();
+ switch_scr(minor(dev));
+ fp = (frametype *)p->p_regs;
+ fp->eflags |= PSL_IOPL;
+ scp->status |= UNKNOWN_MODE;
+ scp->status |= KBD_RAW_MODE;
+ return 0;
+ }
+ return EAGAIN;
+
+ case CONSOLE_X_MODE_OFF:/* just to be compatible */
+ fp = (frametype *)p->p_regs;
+ fp->eflags &= ~PSL_IOPL;
+ if (crtc_vga) {
+ load_font(0, 16, font_8x16);
+ load_font(1, 8, font_8x8);
+ load_font(2, 14, font_8x14);
+ load_palette();
+ }
+ scp->status &= ~UNKNOWN_MODE;
+ set_mode(scp);
+ clear_screen(scp);
+ scp->status &= ~KBD_RAW_MODE;
+ switch_scr(saved_console);
+ saved_console = -1;
+ return 0;
+
+ case CONSOLE_X_BELL: /* more compatibility */
+ /*
+ * if set, data is a pointer to a length 2 array of
+ * integers. data[0] is the pitch in Hz and data[1]
+ * is the duration in msec.
+ */
+ if (data)
+ sysbeep(TIMER_FREQ/((int*)data)[0],
+ ((int*)data)[1]*hz/3000);
+ else
+ sysbeep(scp->bell_pitch, scp->bell_duration);
+ return 0;
+
+ default:
+ break;
+ }
+
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
+ if (error >= 0)
+ return(error);
+ error = ttioctl(tp, cmd, data, flag);
+ if (error >= 0)
+ return(error);
+ return(ENOTTY);
+}
+
+
+void pcxint(dev_t dev)
+{
+ struct tty *tp = get_tty_ptr(dev);
+
+ if (!tp)
+ return;
+ tp->t_state &= ~TS_BUSY;
+ if (tp->t_line)
+ (*linesw[tp->t_line].l_start)(tp);
+ else
+ pcstart(tp);
+}
+
+
+void pcstart(struct tty *tp)
+{
+#if defined(NetBSD)
+ struct clist *rbp;
+ int i, s, len;
+ u_char buf[PCBURST];
+ scr_stat *scp = get_scr_stat(tp->t_dev);
+
+ if (scp->status & SLKED)
+ return;
+ s = spltty();
+ if (!(tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))) {
+ tp->t_state |= TS_BUSY;
+ splx(s);
+ rbp = &tp->t_outq;
+ len = q_to_b(rbp, buf, PCBURST);
+ for (i=0; i<len; i++)
+ if (buf[i]) ansi_put(scp, buf[i]);
+ s = spltty();
+ tp->t_state &= ~TS_BUSY;
+ if (rbp->c_cc) {
+ tp->t_state |= TS_TIMEOUT;
+ timeout((timeout_t)ttrstrt, (caddr_t)tp, 1);
+ }
+ if (rbp->c_cc <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)rbp);
+ }
+ selwakeup(&tp->t_wsel);
+ }
+ }
+ splx(s);
+
+#else /* __FreeBSD__ & __386BSD__ */
+
+ int c, s, len, i;
+ scr_stat *scp = get_scr_stat(tp->t_dev);
+ u_char buf[PCBURST];
+
+ if (scp->status & SLKED)
+ return;
+ s = spltty();
+ if (!(tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))) {
+ for (;;) {
+ if (RB_LEN(tp->t_out) <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)tp->t_out);
+ }
+ if (tp->t_wsel) {
+ selwakeup(tp->t_wsel,
+ tp->t_state & TS_WCOLL);
+ tp->t_wsel = 0;
+ tp->t_state &= ~TS_WCOLL;
+ }
+ }
+ if (RB_LEN(tp->t_out) == 0)
+ break;
+ if (scp->status & SLKED)
+ break;
+ len = 0;
+ while( len < PCBURST) {
+ buf[len++] = getc(tp->t_out);
+ if( RB_LEN(tp->t_out) == 0)
+ break;
+ }
+ tp->t_state |= TS_BUSY;
+ splx(s);
+ for(i=0;i<len;i++)
+ ansi_put(scp, buf[i]);
+ s = spltty();
+ tp->t_state &= ~TS_BUSY;
+ }
+ tp->t_state |= TS_BUSY;
+ if( in_putc == 0) {
+ int i;
+ for(i=0;i<console_buffer_count;i++) {
+ scput(console_buffer[i]);
+ }
+ console_buffer_count = 0;
+ }
+ tp->t_state &= ~TS_BUSY;
+ }
+ splx(s);
+#endif
+}
+
+
+void pccnprobe(struct consdev *cp)
+{
+ int maj;
+
+ /* locate the major number */
+ for (maj = 0; maj < nchrdev; maj++)
+ if ((void*)cdevsw[maj].d_open == (void*)pcopen)
+ break;
+
+ /* initialize required fields */
+ cp->cn_dev = makedev(maj, NCONS);
+ cp->cn_pri = CN_INTERNAL;
+#if defined(__386BSD__) && !defined(__FreeBSD__)
+ cp->cn_tp = CONSOLE_TTY;
+#endif
+}
+
+
+void pccninit(struct consdev *cp)
+{
+ scinit();
+}
+
+
+void pccnputc(dev_t dev, char c)
+{
+ if (c == '\n')
+ scput('\r');
+ scput(c);
+ if (cur_console == &console[0]) {
+ int pos = cur_console->crtat - cur_console->crt_base;
+ if (pos != cur_cursor_pos) {
+ cur_cursor_pos = pos;
+ outb(crtc_addr,14);
+ outb(crtc_addr+1,pos >> 8);
+ outb(crtc_addr,15);
+ outb(crtc_addr+1,pos&0xff);
+ }
+ }
+}
+
+
+int pccngetc(dev_t dev)
+{
+ int s = spltty(); /* block scintr while we poll */
+ int c = scgetc(0);
+ splx(s);
+ if (c == '\r') c = '\n';
+ return(c);
+}
+
+static void none_saver(int test)
+{
+}
+
+static void fade_saver(int test)
+{
+ static int count = 0;
+ int i;
+
+ if (test) {
+ scrn_blanked = 1;
+ if (count < 64) {
+ outb(PIXMASK, 0xFF); /* no pixelmask */
+ outb(PALWADR, 0x00);
+ outb(PALDATA, 0);
+ outb(PALDATA, 0);
+ outb(PALDATA, 0);
+ for (i = 3; i < 768; i++) {
+ if (palette[i] - count > 15)
+ outb(PALDATA, palette[i]-count);
+ else
+ outb(PALDATA, 15);
+ }
+ inb(crtc_addr+6); /* reset flip/flop */
+ outb(ATC, 0x20); /* enable palette */
+ count++;
+ }
+ }
+ else {
+ count = scrn_blanked = 0;
+ load_palette();
+ }
+}
+
+static void blank_saver(int test)
+{
+ u_char val;
+ if (test) {
+ scrn_blanked = 1;
+ outb(TSIDX, 0x01); val = inb(TSREG);
+ outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
+ }
+ else {
+ scrn_blanked = 0;
+ outb(TSIDX, 0x01); val = inb(TSREG);
+ outb(TSIDX, 0x01); outb(TSREG, val & 0xDF);
+ }
+}
+
+static u_long rand_next = 1;
+
+static int rand()
+{
+ return ((rand_next = rand_next * 1103515245 + 12345) & 0x7FFFFFFF);
+}
+
+/*
+ * Alternate saver that got its inspiration from a well known utility
+ * package for an unfamous OS.
+ */
+
+#define NUM_STARS 50
+
+static void star_saver(int test)
+{
+ scr_stat *scp = cur_console;
+ int cell, i;
+ char pattern[] = {"...........++++*** "};
+ char colors[] = {FG_DARKGREY, FG_LIGHTGREY,
+ FG_WHITE, FG_LIGHTCYAN};
+ static u_short stars[NUM_STARS][2];
+
+ if (test) {
+ if (!scrn_blanked) {
+ bcopy(Crtat, scp->scr_buf,
+ scp->xsize * scp->ysize * 2);
+ fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20], Crtat,
+ scp->xsize * scp->ysize);
+ set_border(0);
+ i = scp->ysize * scp->xsize + 5;
+ outb(crtc_addr, 14);
+ outb(crtc_addr+1, i >> 8);
+ outb(crtc_addr, 15);
+ outb(crtc_addr+1, i & 0xff);
+ scrn_blanked = 1;
+ for(i=0; i<NUM_STARS; i++) {
+ stars[i][0] =
+ rand() % (scp->xsize*scp->ysize);
+ stars[i][1] = 0;
+ }
+ }
+ cell = rand() % NUM_STARS;
+ *((u_short*)(Crtat + stars[cell][0])) =
+ scr_map[pattern[stars[cell][1]]] |
+ colors[rand()%sizeof(colors)] << 8;
+ if ((stars[cell][1]+=(rand()%4)) >= sizeof(pattern)-1) {
+ stars[cell][0] = rand() % (scp->xsize*scp->ysize);
+ stars[cell][1] = 0;
+ }
+ }
+ else {
+ if (scrn_blanked) {
+ bcopy(scp->scr_buf, Crtat, scp->xsize*scp->ysize*2);
+ cur_cursor_pos = -1;
+ set_border(scp->border);
+ scrn_blanked = 0;
+ }
+ }
+}
+
+
+static void snake_saver(int test)
+{
+ const char saves[] = {"FreeBSD"};
+ static u_char *savs[sizeof(saves)-1];
+ static int dirx, diry;
+ int f;
+ scr_stat *scp = cur_console;
+
+ if (test) {
+ if (!scrn_blanked) {
+ bcopy(Crtat, scp->scr_buf,
+ scp->xsize * scp->ysize * 2);
+ fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20],
+ Crtat, scp->xsize * scp->ysize);
+ set_border(0);
+ dirx = (scp->xpos ? 1 : -1);
+ diry = (scp->ypos ?
+ scp->xsize : -scp->xsize);
+ for (f=0; f< sizeof(saves)-1; f++)
+ savs[f] = (u_char *)Crtat + 2 *
+ (scp->xpos+scp->ypos*scp->xsize);
+ *(savs[0]) = scr_map[*saves];
+ f = scp->ysize * scp->xsize + 5;
+ outb(crtc_addr, 14);
+ outb(crtc_addr+1, f >> 8);
+ outb(crtc_addr, 15);
+ outb(crtc_addr+1, f & 0xff);
+ scrn_blanked = 1;
+ }
+ if (scrn_blanked++ < 4)
+ return;
+ scrn_blanked = 1;
+ *(savs[sizeof(saves)-2]) = scr_map[0x20];
+ for (f=sizeof(saves)-2; f > 0; f--)
+ savs[f] = savs[f-1];
+ f = (savs[0] - (u_char *)Crtat) / 2;
+ if ((f % scp->xsize) == 0 ||
+ (f % scp->xsize) == scp->xsize - 1 ||
+ (rand() % 50) == 0)
+ dirx = -dirx;
+ if ((f / scp->xsize) == 0 ||
+ (f / scp->xsize) == scp->ysize - 1 ||
+ (rand() % 20) == 0)
+ diry = -diry;
+ savs[0] += 2*dirx + 2*diry;
+ for (f=sizeof(saves)-2; f>=0; f--)
+ *(savs[f]) = scr_map[saves[f]];
+ }
+ else {
+ if (scrn_blanked) {
+ bcopy(scp->scr_buf, Crtat,
+ scp->xsize * scp->ysize * 2);
+ cur_cursor_pos = -1;
+ set_border(scp->border);
+ scrn_blanked = 0;
+ }
+ }
+}
+
+static void cursor_shape(int start, int end)
+{
+ outb(crtc_addr, 10);
+ outb(crtc_addr+1, start & 0xFF);
+ outb(crtc_addr, 11);
+ outb(crtc_addr+1, end & 0xFF);
+}
+
+
+#if !defined(FAT_CURSOR)
+static void get_cursor_shape(int *start, int *end)
+{
+ outb(crtc_addr, 10);
+ *start = inb(crtc_addr+1) & 0x1F;
+ outb(crtc_addr, 11);
+ *end = inb(crtc_addr+1) & 0x1F;
+}
+#endif
+
+
+static void cursor_pos(int force)
+{
+ int pos;
+
+ if (cur_console->status & UNKNOWN_MODE)
+ return;
+ if (scrn_blank_time && (time.tv_sec > scrn_time_stamp+scrn_blank_time))
+ SCRN_SAVER(1);
+ pos = cur_console->crtat - cur_console->crt_base;
+ if (force || (!scrn_blanked && pos != cur_cursor_pos)) {
+ cur_cursor_pos = pos;
+ outb(crtc_addr, 14);
+ outb(crtc_addr+1, pos>>8);
+ outb(crtc_addr, 15);
+ outb(crtc_addr+1, pos&0xff);
+ }
+ timeout((timeout_t)cursor_pos, 0, hz/20);
+}
+
+
+static void clear_screen(scr_stat *scp)
+{
+ move_crsr(scp, 0, 0);
+ fillw(scp->term.cur_attr | scr_map[0x20], scp->crt_base,
+ scp->xsize * scp->ysize);
+}
+
+
+static int switch_scr(u_int next_scr)
+{
+ if (in_putc) { /* delay switch if in putc */
+ delayed_next_scr = next_scr+1;
+ return 0;
+ }
+ if (switch_in_progress &&
+ (cur_console->proc != pfind(cur_console->pid)))
+ switch_in_progress = 0;
+
+ if (next_scr >= NCONS || switch_in_progress) {
+ sysbeep(BELL_PITCH, BELL_DURATION);
+ return EINVAL;
+ }
+
+ /* is the wanted virtual console open ? */
+ if (next_scr) {
+ struct tty *tp = VIRTUAL_TTY(next_scr);
+ if (!(tp->t_state & TS_ISOPEN)) {
+ sysbeep(BELL_PITCH, BELL_DURATION);
+ return EINVAL;
+ }
+ }
+
+ switch_in_progress = 1;
+ old_scp = cur_console;
+ new_scp = &console[next_scr];
+ wakeup((caddr_t)&new_scp->smode);
+ if (new_scp == old_scp) {
+ switch_in_progress = 0;
+ return 0;
+ }
+
+ /* has controlling process died? */
+ if (old_scp->proc && (old_scp->proc != pfind(old_scp->pid)))
+ old_scp->smode.mode = VT_AUTO;
+ if (new_scp->proc && (new_scp->proc != pfind(new_scp->pid)))
+ new_scp->smode.mode = VT_AUTO;
+
+ /* check the modes and switch approbiatly */
+ if (old_scp->smode.mode == VT_PROCESS) {
+ old_scp->status |= SWITCH_WAIT_REL;
+ psignal(old_scp->proc, old_scp->smode.relsig);
+ }
+ else {
+ exchange_scr();
+ if (new_scp->smode.mode == VT_PROCESS) {
+ new_scp->status |= SWITCH_WAIT_ACQ;
+ psignal(new_scp->proc, new_scp->smode.acqsig);
+ }
+ else
+ switch_in_progress = 0;
+ }
+ return 0;
+}
+
+
+static void exchange_scr(void)
+{
+ struct tty *tp;
+
+ bcopy(Crtat, old_scp->scr_buf, old_scp->xsize * old_scp->ysize * 2);
+ old_scp->crt_base = old_scp->scr_buf;
+ move_crsr(old_scp, old_scp->xpos, old_scp->ypos);
+ cur_console = new_scp;
+ set_mode(new_scp);
+ new_scp->crt_base = Crtat;
+ move_crsr(new_scp, new_scp->xpos, new_scp->ypos);
+ bcopy(new_scp->scr_buf, Crtat, new_scp->xsize * new_scp->ysize * 2);
+ update_leds(new_scp->status);
+ if ((old_scp->status & UNKNOWN_MODE) && crtc_vga) {
+ load_font(0, 16, font_8x16);
+ load_font(1, 8, font_8x8);
+ load_font(2, 14, font_8x14);
+ load_palette();
+ }
+ if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE)
+ shfts = ctls = alts = agrs = metas = 0;
+ delayed_next_scr = 0;
+}
+
+
+static void move_crsr(scr_stat *scp, int x, int y)
+{
+ if (x < 0 || y < 0 || x >= scp->xsize || y >= scp->ysize)
+ return;
+ scp->xpos = x;
+ scp->ypos = y;
+ scp->crtat = scp->crt_base + scp->ypos * scp->xsize + scp->xpos;
+}
+
+static void move_up(u_short *s, u_short *d, u_int len)
+{
+ s += len;
+ d += len;
+ while (len-- > 0)
+ *--d = *--s;
+}
+
+static void move_down(u_short *s, u_short *d, u_int len)
+{
+ while (len-- > 0)
+ *d++ = *s++;
+}
+
+static void scan_esc(scr_stat *scp, u_char c)
+{
+ static u_char ansi_col[16] =
+ {0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15};
+ int i, n;
+ u_short *src, *dst, count;
+
+ if (scp->term.esc == 1) {
+ switch (c) {
+
+ case '[': /* Start ESC [ sequence */
+ scp->term.esc = 2;
+ scp->term.last_param = -1;
+ for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
+ scp->term.param[i] = 1;
+ scp->term.num_param = 0;
+ return;
+
+ case 'M': /* Move cursor up 1 line, scroll if at top */
+ if (scp->ypos > 0)
+ move_crsr(scp, scp->xpos, scp->ypos - 1);
+ else {
+ move_up(scp->crt_base,
+ scp->crt_base + scp->xsize,
+ (scp->ysize - 1) * scp->xsize);
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base, scp->xsize);
+ }
+ break;
+#if notyet
+ case 'Q':
+ scp->term.esc = 4;
+ break;
+#endif
+ case 'c': /* Clear screen & home */
+ clear_screen(scp);
+ break;
+ }
+ }
+ else if (scp->term.esc == 2) {
+ if (c >= '0' && c <= '9') {
+ if (scp->term.num_param < MAX_ESC_PAR) {
+ if (scp->term.last_param != scp->term.num_param) {
+ scp->term.last_param = scp->term.num_param;
+ scp->term.param[scp->term.num_param] = 0;
+ }
+ else
+ scp->term.param[scp->term.num_param] *= 10;
+ scp->term.param[scp->term.num_param] += c - '0';
+ return;
+ }
+ }
+ scp->term.num_param = scp->term.last_param + 1;
+ switch (c) {
+
+ case ';':
+ if (scp->term.num_param < MAX_ESC_PAR)
+ return;
+ break;
+
+ case '=':
+ scp->term.esc = 3;
+ scp->term.last_param = -1;
+ for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
+ scp->term.param[i] = 1;
+ scp->term.num_param = 0;
+ return;
+
+ case 'A': /* up n rows */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos, scp->ypos - n);
+ break;
+
+ case 'B': /* down n rows */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos, scp->ypos + n);
+ break;
+
+ case 'C': /* right n columns */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos + n, scp->ypos);
+ break;
+
+ case 'D': /* left n columns */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos - n, scp->ypos);
+ break;
+
+ case 'E': /* cursor to start of line n lines down */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, 0, scp->ypos + n);
+ break;
+
+ case 'F': /* cursor to start of line n lines up */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, 0, scp->ypos - n);
+ break;
+
+ case 'f': /* System V consoles .. */
+ case 'H': /* Cursor move */
+ if (scp->term.num_param == 0)
+ move_crsr(scp, 0, 0);
+ else if (scp->term.num_param == 2)
+ move_crsr(scp, scp->term.param[1] - 1,
+ scp->term.param[0] - 1);
+ break;
+
+ case 'J': /* Clear all or part of display */
+ if (scp->term.num_param == 0)
+ n = 0;
+ else
+ n = scp->term.param[0];
+ switch (n) {
+ case 0: /* clear form cursor to end of display */
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crtat, scp->crt_base +
+ scp->xsize * scp->ysize -
+ scp->crtat);
+ break;
+ case 1: /* clear from beginning of display to cursor */
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base,
+ scp->crtat - scp->crt_base);
+ break;
+ case 2: /* clear entire display */
+ clear_screen(scp);
+ break;
+ }
+ break;
+
+ case 'K': /* Clear all or part of line */
+ if (scp->term.num_param == 0)
+ n = 0;
+ else
+ n = scp->term.param[0];
+ switch (n) {
+ case 0: /* clear form cursor to end of line */
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crtat, scp->xsize - scp->xpos);
+ break;
+ case 1: /* clear from beginning of line to cursor */
+ fillw(scp->term.cur_attr|scr_map[0x20],
+ scp->crtat - (scp->xsize - scp->xpos),
+ (scp->xsize - scp->xpos) + 1);
+ break;
+ case 2: /* clear entire line */
+ fillw(scp->term.cur_attr|scr_map[0x20],
+ scp->crtat - (scp->xsize - scp->xpos),
+ scp->xsize);
+ break;
+ }
+ break;
+
+ case 'L': /* Insert n lines */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->ysize - scp->ypos)
+ n = scp->ysize - scp->ypos;
+ src = scp->crt_base + scp->ypos * scp->xsize;
+ dst = src + n * scp->xsize;
+ count = scp->ysize - (scp->ypos + n);
+ move_up(src, dst, count * scp->xsize);
+ fillw(scp->term.cur_attr | scr_map[0x20], src,
+ n * scp->xsize);
+ break;
+
+ case 'M': /* Delete n lines */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->ysize - scp->ypos)
+ n = scp->ysize - scp->ypos;
+ dst = scp->crt_base + scp->ypos * scp->xsize;
+ src = dst + n * scp->xsize;
+ count = scp->ysize - (scp->ypos + n);
+ move_down(src, dst, count * scp->xsize);
+ src = dst + count * scp->xsize;
+ fillw(scp->term.cur_attr | scr_map[0x20], src,
+ n * scp->xsize);
+ break;
+
+ case 'P': /* Delete n chars */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->xsize - scp->xpos)
+ n = scp->xsize - scp->xpos;
+ dst = scp->crtat;
+ src = dst + n;
+ count = scp->xsize - (scp->xpos + n);
+ move_down(src, dst, count);
+ src = dst + count;
+ fillw(scp->term.cur_attr | scr_map[0x20], src, n);
+ break;
+
+ case '@': /* Insert n chars */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->xsize - scp->xpos)
+ n = scp->xsize - scp->xpos;
+ src = scp->crtat;
+ dst = src + n;
+ count = scp->xsize - (scp->xpos + n);
+ move_up(src, dst, count);
+ fillw(scp->term.cur_attr | scr_map[0x20], src, n);
+ break;
+
+ case 'S': /* scroll up n lines */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->ypos)
+ n = scp->ypos;
+ bcopy(scp->crt_base + (scp->xsize * n),
+ scp->crt_base,
+ scp->xsize * (scp->ysize - n) *
+ sizeof(u_short));
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base + scp->xsize *
+ (scp->ysize - 1),
+ scp->xsize);
+ break;
+
+ case 'T': /* scroll down n lines */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->ysize - scp->ypos)
+ n = scp->ysize - scp->ypos;
+ bcopy(scp->crt_base,
+ scp->crt_base + (scp->xsize * n),
+ scp->xsize * (scp->ysize - n) *
+ sizeof(u_short));
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base, scp->xsize);
+ break;
+
+ case 'X': /* delete n characters in line */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->xsize - scp->xpos)
+ n = scp->xsize - scp->xpos;
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base + scp->xpos +
+ ((scp->xsize*scp->ypos) * sizeof(u_short)), n);
+ break;
+
+ case 'Z': /* move n tabs backwards */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if ((i = scp->xpos & 0xf8) == scp->xpos)
+ i -= 8*n;
+ else
+ i -= 8*(n-1);
+ if (i < 0)
+ i = 0;
+ move_crsr(scp, i, scp->ypos);
+ break;
+
+ case '`': /* move cursor to column n */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, n, scp->ypos);
+ break;
+
+ case 'a': /* move cursor n columns to the right */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos + n, scp->ypos);
+ break;
+
+ case 'd': /* move cursor to row n */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos, n);
+ break;
+
+ case 'e': /* move cursor n rows down */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos, scp->ypos + n);
+ break;
+
+ case 'm': /* change attribute */
+ if (scp->term.num_param == 0)
+ n = 0;
+ else
+ n = scp->term.param[0];
+ switch (n) {
+ case 0: /* back to normal */
+ scp->term.cur_attr = scp->term.std_attr;
+ break;
+ case 1: /* highlight (bold) */
+ scp->term.cur_attr &= 0xFF00;
+ scp->term.cur_attr |= 0x0800;
+ break;
+ case 4: /* highlight (underline) */
+ scp->term.cur_attr &= 0x0F00;
+ scp->term.cur_attr |= 0x0800;
+ break;
+ case 5: /* blink */
+ scp->term.cur_attr &= 0xFF00;
+ scp->term.cur_attr |= 0x8000;
+ break;
+ case 7: /* reverse video */
+ scp->term.cur_attr = scp->term.rev_attr;
+ break;
+ case 30: case 31: case 32: case 33: /* set fg color */
+ case 34: case 35: case 36: case 37:
+ scp->term.cur_attr = (scp->term.cur_attr & 0xF0FF)
+ | (ansi_col[(n - 30) & 7] << 8);
+ break;
+ case 40: case 41: case 42: case 43: /* set bg color */
+ case 44: case 45: case 46: case 47:
+ scp->term.cur_attr = (scp->term.cur_attr & 0x0FFF)
+ | (ansi_col[(n - 40) & 7] << 12);
+ break;
+ }
+ break;
+
+ case 'x':
+ if (scp->term.num_param == 0)
+ n = 0;
+ else
+ n = scp->term.param[0];
+ switch (n) {
+ case 0: /* reset attributes */
+ scp->term.cur_attr = scp->term.std_attr =
+ current_default->std_attr;
+ scp->term.rev_attr = current_default->rev_attr;
+ break;
+ case 1: /* set ansi background */
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.std_attr & 0x0F00) |
+ (ansi_col[(scp->term.param[1])&0x0F]<<12);
+ break;
+ case 2: /* set ansi foreground */
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.std_attr & 0xF000) |
+ (ansi_col[(scp->term.param[1])&0x0F]<<8);
+ break;
+ case 3: /* set ansi attribute directly */
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.param[1]&0xFF)<<8;
+ break;
+ case 5: /* set ansi reverse video background */
+ scp->term.rev_attr =
+ (scp->term.rev_attr & 0x0F00) |
+ (ansi_col[(scp->term.param[1])&0x0F]<<12);
+ break;
+ case 6: /* set ansi reverse video foreground */
+ scp->term.rev_attr =
+ (scp->term.rev_attr & 0xF000) |
+ (ansi_col[(scp->term.param[1])&0x0F]<<8);
+ break;
+ case 7: /* set ansi reverse video directly */
+ scp->term.rev_attr = (scp->term.param[1]&0xFF)<<8;
+ break;
+ }
+ break;
+
+ case 'z': /* switch to (virtual) console n */
+ if (scp->term.num_param == 1)
+ switch_scr(scp->term.param[0]);
+ break;
+ }
+ }
+ else if (scp->term.esc == 3) {
+ if (c >= '0' && c <= '9') {
+ if (scp->term.num_param < MAX_ESC_PAR) {
+ if (scp->term.last_param != scp->term.num_param) {
+ scp->term.last_param = scp->term.num_param;
+ scp->term.param[scp->term.num_param] = 0;
+ }
+ else
+ scp->term.param[scp->term.num_param] *= 10;
+ scp->term.param[scp->term.num_param] += c - '0';
+ return;
+ }
+ }
+ scp->term.num_param = scp->term.last_param + 1;
+ switch (c) {
+
+ case ';':
+ if (scp->term.num_param < MAX_ESC_PAR)
+ return;
+ break;
+
+ case 'A': /* set display border color */
+ if (scp->term.num_param == 1)
+ scp->border=scp->term.param[0] & 0xff;
+ if (scp == cur_console)
+ set_border(scp->border);
+ break;
+
+ case 'B': /* set bell pitch and duration */
+ if (scp->term.num_param == 2) {
+ scp->bell_pitch = scp->term.param[0];
+ scp->bell_duration = scp->term.param[1]*10;
+ }
+ break;
+
+ case 'C': /* set cursor shape (start & end line) */
+ if (scp->term.num_param == 2) {
+ scp->cursor_start = scp->term.param[0] & 0x1F;
+ scp->cursor_end = scp->term.param[1] & 0x1F;
+ if (scp == cur_console)
+ cursor_shape(scp->cursor_start,
+ scp->cursor_end);
+ }
+ break;
+
+ case 'F': /* set ansi foreground */
+ if (scp->term.num_param == 1)
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.std_attr & 0xF000)
+ | ((scp->term.param[0] & 0x0F) << 8);
+ break;
+
+ case 'G': /* set ansi background */
+ if (scp->term.num_param == 1)
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.std_attr & 0x0F00)
+ | ((scp->term.param[0] & 0x0F) << 12);
+ break;
+
+ case 'H': /* set ansi reverse video foreground */
+ if (scp->term.num_param == 1)
+ scp->term.rev_attr =
+ (scp->term.rev_attr & 0xF000)
+ | ((scp->term.param[0] & 0x0F) << 8);
+ break;
+
+ case 'I': /* set ansi reverse video background */
+ if (scp->term.num_param == 1)
+ scp->term.rev_attr =
+ (scp->term.rev_attr & 0x0F00)
+ | ((scp->term.param[0] & 0x0F) << 12);
+ break;
+ }
+ }
+ scp->term.esc = 0;
+}
+
+
+static void ansi_put(scr_stat *scp, u_char c)
+{
+ if (scp->status & UNKNOWN_MODE)
+ return;
+
+ /* make screensaver happy */
+ if (scp == cur_console) {
+ scrn_time_stamp = time.tv_sec;
+ if (scrn_blanked)
+ SCRN_SAVER(0);
+ }
+ in_putc++;
+ if (scp->term.esc)
+ scan_esc(scp, c);
+ else switch(c) {
+ case 0x1B: /* start escape sequence */
+ scp->term.esc = 1;
+ scp->term.num_param = 0;
+ break;
+ case 0x07:
+ if (scp == cur_console)
+ sysbeep(scp->bell_pitch, scp->bell_duration);
+ break;
+ case '\t': /* non-destructive tab */
+ scp->crtat += (8 - scp->xpos % 8);
+ scp->xpos += (8 - scp->xpos % 8);
+ break;
+ case '\b': /* non-destructive backspace */
+ if (scp->crtat > scp->crt_base) {
+ scp->crtat--;
+ if (scp->xpos > 0)
+ scp->xpos--;
+ else {
+ scp->xpos += scp->xsize - 1;
+ scp->ypos--;
+ }
+ }
+ break;
+ case '\r': /* return to pos 0 */
+ move_crsr(scp, 0, scp->ypos);
+ break;
+ case '\n': /* newline, same pos */
+ scp->crtat += scp->xsize;
+ scp->ypos++;
+ break;
+ case '\f': /* form feed, clears screen */
+ clear_screen(scp);
+ break;
+ default:
+ /* Print only printables */
+ *scp->crtat = (scp->term.cur_attr | scr_map[c]);
+ scp->crtat++;
+ if (++scp->xpos >= scp->xsize) {
+ scp->xpos = 0;
+ scp->ypos++;
+ }
+ break;
+ }
+ if (scp->crtat >= scp->crt_base + scp->ysize * scp->xsize) {
+ bcopy(scp->crt_base + scp->xsize, scp->crt_base,
+ scp->xsize * (scp->ysize - 1) * sizeof(u_short));
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base + scp->xsize * (scp->ysize - 1),
+ scp->xsize);
+ scp->crtat -= scp->xsize;
+ scp->ypos--;
+ }
+ in_putc--;
+ if (delayed_next_scr)
+ switch_scr(delayed_next_scr - 1);
+}
+
+static void scinit(void)
+{
+ u_short volatile *cp = Crtat + (CGA_BUF-MONO_BUF)/sizeof(u_short), was;
+ unsigned cursorat;
+ int i;
+
+ /*
+ * catch that once in a blue moon occurence when scinit is called
+ * TWICE, adding the CGA_BUF offset again -> poooff
+ */
+ if (crtat != 0)
+ return;
+ /*
+ * Crtat initialized to point to MONO buffer, if not present change
+ * to CGA_BUF offset. ONLY ADD the difference since locore.s adds
+ * in the remapped offset at the "right" time
+ */
+ was = *cp;
+ *cp = (u_short) 0xA55A;
+ if (*cp != 0xA55A) {
+ crtc_addr = MONO_BASE;
+ } else {
+ *cp = was;
+ crtc_addr = COLOR_BASE;
+ Crtat = Crtat + (CGA_BUF-MONO_BUF)/sizeof(u_short);
+ }
+
+ /* Extract cursor location */
+ outb(crtc_addr,14);
+ cursorat = inb(crtc_addr+1)<<8 ;
+ outb(crtc_addr,15);
+ cursorat |= inb(crtc_addr+1);
+ crtat = Crtat + cursorat;
+
+ /* is this a VGA or higher ? */
+ outb(crtc_addr, 7);
+ if (inb(crtc_addr) == 7)
+ crtc_vga = 1;
+
+ current_default = &user_default;
+ console[0].crtat = crtat;
+ console[0].crt_base = Crtat;
+ console[0].term.esc = 0;
+ console[0].term.std_attr = current_default->std_attr;
+ console[0].term.rev_attr = current_default->rev_attr;
+ console[0].term.cur_attr = current_default->std_attr;
+ console[0].xpos = cursorat % COL;
+ console[0].ypos = cursorat / COL;
+ console[0].border = BG_BLACK;;
+ console[0].xsize = COL;
+ console[0].ysize = ROW;
+ console[0].status = 0;
+ console[0].pid = 0;
+ console[0].proc = NULL;
+ console[0].smode.mode = VT_AUTO;
+ console[0].bell_pitch = BELL_PITCH;
+ console[0].bell_duration = BELL_DURATION;
+ kernel_console.esc = 0;
+ kernel_console.std_attr = kernel_default.std_attr;
+ kernel_console.rev_attr = kernel_default.rev_attr;
+ kernel_console.cur_attr = kernel_default.std_attr;
+ /* initialize mapscrn array to a one to one map */
+ for (i=0; i<sizeof(scr_map); i++)
+ scr_map[i] = i;
+ clear_screen(&console[0]);
+}
+
+
+static void scput(u_char c)
+{
+ scr_stat *scp = &console[0];
+ term_stat save;
+
+ if (crtat == 0)
+ scinit();
+ if( in_putc == 0) {
+ ++in_putc;
+ save = scp->term;
+ scp->term = kernel_console;
+ current_default = &kernel_default;
+ ansi_put(scp, c);
+ kernel_console = scp->term;
+ current_default = &user_default;
+ scp->term = save;
+ --in_putc;
+ } else {
+ if( console_buffer_count < CONSOLE_BUFFER_SIZE)
+ console_buffer[console_buffer_count++] = c;
+ }
+}
+
+
+static u_char *get_fstr(u_int c, u_int *len)
+{
+ u_int i;
+
+ if (!(c & FKEY))
+ return(NULL);
+ i = (c & 0xFF) - F_FN;
+ if (i > n_fkey_tab)
+ return(NULL);
+ *len = fkey_tab[i].len;
+ return(fkey_tab[i].str);
+}
+
+
+static void update_leds(int which)
+{
+ static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+
+ /* replace CAPS led with ALTGR led for ALTGR keyboards */
+ if (key_map.n_keys > ALTGR_OFFSET) {
+ if (which & ALKED)
+ which |= CLKED;
+ else
+ which &= ~CLKED;
+ }
+ kbd_cmd2(KB_SETLEDS, xlate_leds[which & LED_MASK]);
+}
+
+
+/*
+ * scgetc(noblock) : get a character from the keyboard.
+ * If noblock = 0 wait until a key is gotten. Otherwise return NOKEY.
+ */
+u_int scgetc(int noblock)
+{
+ u_char val, code, release;
+ u_int state, action;
+ struct key_t *key;
+ static u_char esc_flag = 0, compose = 0;
+ static u_int chr = 0;
+
+next_code:
+ kbd_wait();
+ /* First see if there is something in the keyboard port */
+ if (inb(KB_STAT) & KB_BUF_FULL)
+ val = inb(KB_DATA);
+ else if (noblock)
+ return(NOKEY);
+ else
+ goto next_code;
+
+ if (cur_console->status & KBD_RAW_MODE)
+ return val;
+
+ code = val & 0x7F;
+ release = val & 0x80;
+
+ switch (esc_flag) {
+ case 0x00: /* normal scancode */
+ switch(code) {
+ case 0x38: /* left alt (compose key) */
+ if (release && compose) {
+ compose = 0;
+ if (chr > 255) {
+ sysbeep(BELL_PITCH, BELL_DURATION);
+ chr = 0;
+ }
+ }
+ else {
+ if (!compose) {
+ compose = 1;
+ chr = 0;
+ }
+ }
+ break;
+ case 0x60:
+ case 0x61:
+ esc_flag = code;
+ goto next_code;
+ }
+ break;
+ case 0x60: /* 0xE0 prefix */
+ esc_flag = 0;
+ switch (code) {
+ case 0x1c: /* right enter key */
+ code = 0x59;
+ break;
+ case 0x1d: /* right ctrl key */
+ code = 0x5a;
+ break;
+ case 0x35: /* keypad divide key */
+ code = 0x5b;
+ break;
+ case 0x37: /* print scrn key */
+ code = 0x5c;
+ break;
+ case 0x38: /* right alt key (alt gr) */
+ code = 0x5d;
+ break;
+ case 0x47: /* grey home key */
+ code = 0x5e;
+ break;
+ case 0x48: /* grey up arrow key */
+ code = 0x5f;
+ break;
+ case 0x49: /* grey page up key */
+ code = 0x60;
+ break;
+ case 0x4b: /* grey left arrow key */
+ code = 0x61;
+ break;
+ case 0x4d: /* grey right arrow key */
+ code = 0x62;
+ break;
+ case 0x4f: /* grey end key */
+ code = 0x63;
+ break;
+ case 0x50: /* grey down arrow key */
+ code = 0x64;
+ break;
+ case 0x51: /* grey page down key */
+ code = 0x65;
+ break;
+ case 0x52: /* grey insert key */
+ code = 0x66;
+ break;
+ case 0x53: /* grey delete key */
+ code = 0x67;
+ break;
+ default: /* ignore everything else */
+ goto next_code;
+ }
+ break;
+ case 0x61: /* 0xE1 prefix */
+ esc_flag = 0;
+ if (code == 0x1D)
+ esc_flag = 0x1D;
+ goto next_code;
+ /* NOT REACHED */
+ case 0x1D: /* pause / break */
+ esc_flag = 0;
+ if (code != 0x45)
+ goto next_code;
+ code = 0x68;
+ break;
+ }
+
+ if (compose) {
+ switch (code) {
+ case 0x47:
+ case 0x48: /* keypad 7,8,9 */
+ case 0x49:
+ if (!release)
+ chr = (code - 0x40) + chr*10;
+ goto next_code;
+ case 0x4b:
+ case 0x4c: /* keypad 4,5,6 */
+ case 0x4d:
+ if (!release)
+ chr = (code - 0x47) + chr*10;
+ goto next_code;
+ case 0x4f:
+ case 0x50: /* keypad 1,2,3 */
+ case 0x51:
+ if (!release)
+ chr = (code - 0x4e) + chr*10;
+ goto next_code;
+ case 0x52: /* keypad 0 */
+ if (!release)
+ chr *= 10;
+ goto next_code;
+ case 0x38: /* left alt key */
+ break;
+ default:
+ if (chr) {
+ compose = chr = 0;
+ sysbeep(BELL_PITCH, BELL_DURATION);
+ goto next_code;
+ }
+ break;
+ }
+ }
+
+ state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0));
+ if ((!agrs && (cur_console->status & ALKED))
+ || (agrs && !(cur_console->status & ALKED)))
+ code += ALTGR_OFFSET;
+ key = &key_map.key[code];
+ if ( ((key->flgs & FLAG_LOCK_C) && (cur_console->status & CLKED))
+ || ((key->flgs & FLAG_LOCK_N) && (cur_console->status & NLKED)) )
+ state ^= 1;
+
+ /* Check for make/break */
+ action = key->map[state];
+ if (release) { /* key released */
+ if (key->spcl & 0x80) {
+ switch (action) {
+ case LSH:
+ shfts &= ~1;
+ break;
+ case RSH:
+ shfts &= ~2;
+ break;
+ case LCTR:
+ ctls &= ~1;
+ break;
+ case RCTR:
+ ctls &= ~2;
+ break;
+ case LALT:
+ alts &= ~1;
+ break;
+ case RALT:
+ alts &= ~2;
+ break;
+ case NLK:
+ nlkcnt = 0;
+ break;
+ case CLK:
+ clkcnt = 0;
+ break;
+ case SLK:
+ slkcnt = 0;
+ break;
+ case ASH:
+ agrs = 0;
+ break;
+ case ALK:
+ alkcnt = 0;
+ break;
+ case META:
+ metas = 0;
+ break;
+ }
+ }
+ if (chr && !compose) {
+ action = chr;
+ chr = 0;
+ return(action);
+ }
+ } else {
+ /* key pressed */
+ if (key->spcl & (0x80>>state)) {
+ switch (action) {
+ /* LOCKING KEYS */
+ case NLK:
+ if (!nlkcnt) {
+ nlkcnt++;
+ if (cur_console->status & NLKED)
+ cur_console->status &= ~NLKED;
+ else
+ cur_console->status |= NLKED;
+ update_leds(cur_console->status);
+ }
+ break;
+ case CLK:
+ if (!clkcnt) {
+ clkcnt++;
+ if (cur_console->status & CLKED)
+ cur_console->status &= ~CLKED;
+ else
+ cur_console->status |= CLKED;
+ update_leds(cur_console->status);
+ }
+ break;
+ case SLK:
+ if (!slkcnt) {
+ slkcnt++;
+ if (cur_console->status & SLKED) {
+ cur_console->status &= ~SLKED;
+ pcstart(VIRTUAL_TTY(get_scr_num()));
+ }
+ else
+ cur_console->status |= SLKED;
+ update_leds(cur_console->status);
+ }
+ break;
+ case ALK:
+ if (!alkcnt) {
+ alkcnt++;
+ if (cur_console->status & ALKED)
+ cur_console->status &= ~ALKED;
+ else
+ cur_console->status |= ALKED;
+ update_leds(cur_console->status);
+ }
+ break;
+
+ /* NON-LOCKING KEYS */
+ case NOP:
+ break;
+ case RBT:
+#if defined(__FreeBSD__)
+ shutdown_nice();
+#else
+ cpu_reset();
+#endif
+ break;
+ case DBG:
+#if DDB > 0 /* try to switch to console 0 */
+ if (cur_console->smode.mode == VT_AUTO &&
+ console[0].smode.mode == VT_AUTO)
+ switch_scr(0);
+ Debugger("manual escape to debugger");
+ return(NOKEY);
+#else
+ printf("No debugger in kernel\n");
+#endif
+ break;
+ case LSH:
+ shfts |= 1;
+ break;
+ case RSH:
+ shfts |= 2;
+ break;
+ case LCTR:
+ ctls |= 1;
+ break;
+ case RCTR:
+ ctls |= 2;
+ break;
+ case LALT:
+ alts |= 1;
+ break;
+ case RALT:
+ alts |= 2;
+ break;
+ case ASH:
+ agrs = 1;
+ break;
+ case META:
+ metas = 1;
+ break;
+ case NEXT:
+ switch_scr((get_scr_num()+1)%NCONS);
+ break;
+ default:
+ if (action >= F_SCR && action <= L_SCR) {
+ switch_scr(action - F_SCR);
+ break;
+ }
+ if (action >= F_FN && action <= L_FN)
+ action |= FKEY;
+ return(action);
+ }
+ }
+ else {
+ if (metas)
+ action |= MKEY;
+ return(action);
+ }
+ }
+ goto next_code;
+}
+
+
+int getchar(void)
+{
+ u_char thechar;
+ int s;
+
+ polling = 1;
+ s = splhigh();
+ scput('>');
+ thechar = (u_char) scgetc(0);
+ polling = 0;
+ splx(s);
+ switch (thechar) {
+ default:
+ if (thechar >= scr_map[0x20])
+ scput(thechar);
+ return(thechar);
+ case cr:
+ case lf:
+ scput(cr); scput(lf);
+ return(lf);
+ case bs:
+ case del:
+ scput(bs); scput(scr_map[0x20]); scput(bs);
+ return(thechar);
+ case cntld:
+ scput('^'); scput('D'); scput('\r'); scput('\n');
+ return(0);
+ }
+}
+
+
+u_int sgetc(int noblock)
+{
+ return (scgetc(noblock) & 0xff);
+}
+
+int pcmmap(dev_t dev, int offset, int nprot)
+{
+ if (offset > 0x20000)
+ return EINVAL;
+ return i386_btop((VIDEOMEM + offset));
+}
+
+
+static void kbd_wait(void)
+{
+ int i;
+
+ for (i=0; i<1000; i++) { /* up to 10 msec */
+ if ((inb(KB_STAT) & KB_READY) == 0)
+ break;
+ DELAY (10);
+ }
+}
+
+
+static void kbd_cmd(u_char command)
+{
+ kbd_wait();
+ outb(KB_DATA, command);
+}
+
+
+static void kbd_cmd2(u_char command, u_char arg)
+{
+ int r, s = spltty();
+ do {
+ kbd_cmd(command);
+ r = kbd_reply();
+ if (r == KB_ACK) {
+ kbd_cmd(arg & 0x7f);
+ r = kbd_reply();
+ }
+ } while (r != KB_ACK);
+ splx(s);
+}
+
+
+static int kbd_reply()
+{
+ int i;
+
+ kbd_wait();
+ for (i=0; i<60000; i++) { /* at least 300 msec, 600 msec enough */
+ if (inb(KB_STAT) & KB_BUF_FULL)
+ return ((u_char) inb(KB_DATA));
+ DELAY (10);
+ }
+ return(-1);
+}
+
+
+static void set_mode(scr_stat *scp)
+{
+ u_char byte;
+ int s;
+
+ if (scp != cur_console)
+ return;
+
+ /* (re)activate cursor */
+ untimeout((timeout_t)cursor_pos, 0);
+ cursor_pos(1);
+
+ /* change cursor type if set */
+ if (scp->cursor_start != -1 && scp->cursor_end != -1)
+ cursor_shape(scp->cursor_start, scp->cursor_end);
+
+ /* mode change only on VGA's */
+ if (!crtc_vga)
+ return;
+
+ /* setup video hardware for the given mode */
+ s = splhigh();
+ switch(scp->mode) {
+ case TEXT80x25:
+ outb(crtc_addr, 9); byte = inb(crtc_addr+1);
+ outb(crtc_addr, 9); outb(crtc_addr+1, byte | 0x0F);
+ outb(TSIDX, 0x03); outb(TSREG, 0x00); /* select font 0 */
+ break;
+ case TEXT80x50:
+ outb(crtc_addr, 9); byte = inb(crtc_addr+1);
+ outb(crtc_addr, 9); outb(crtc_addr+1, (byte & 0xF0) | 0x07);
+ outb(TSIDX, 0x03); outb(TSREG, 0x05); /* select font 1 */
+ break;
+ default:
+ break;
+ }
+ splx(s);
+
+ /* set border color for this (virtual) console */
+ set_border(scp->border);
+ return;
+}
+
+
+static void set_border(int color)
+{
+ inb(crtc_addr+6); /* reset flip-flop */
+ outb(ATC, 0x11); outb(ATC, color);
+ inb(crtc_addr+6); /* reset flip-flop */
+ outb(ATC, 0x20); /* enable Palette */
+}
+
+static void load_font(int segment, int size, char* font)
+{
+ int ch, line, s;
+ u_char val;
+
+ outb(TSIDX, 0x01); val = inb(TSREG); /* blank screen */
+ outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
+
+ /* setup vga for loading fonts (graphics plane mode) */
+ s = splhigh();
+ inb(crtc_addr+6); /* reset flip/flop */
+ outb(ATC, 0x30); outb(ATC, 0x01);
+ outb(TSIDX, 0x02); outb(TSREG, 0x04);
+ outb(TSIDX, 0x04); outb(TSREG, 0x06);
+ outb(GDCIDX, 0x04); outb(GDCREG, 0x02);
+ outb(GDCIDX, 0x05); outb(GDCREG, 0x00);
+ outb(GDCIDX, 0x06); outb(GDCREG, 0x05); /* addr = a0000, 64kb */
+ splx(s);
+ for (ch=0; ch < 256; ch++)
+ for (line=0; line < size; line++)
+ *((char *)atdevbase+(segment*0x4000)+(ch*32)+line) =
+ font[(ch*size)+line];
+ /* setup vga for text mode again */
+ s = splhigh();
+ inb(crtc_addr+6); /* reset flip/flop */
+ outb(ATC, 0x30); outb(ATC, 0x0C);
+ outb(TSIDX, 0x02); outb(TSREG, 0x03);
+ outb(TSIDX, 0x04); outb(TSREG, 0x02);
+ outb(GDCIDX, 0x04); outb(GDCREG, 0x00);
+ outb(GDCIDX, 0x05); outb(GDCREG, 0x10);
+ if (crtc_addr == MONO_BASE) {
+ outb(GDCIDX, 0x06); outb(GDCREG, 0x0A); /* addr = b0000, 32kb */
+ }
+ else {
+ outb(GDCIDX, 0x06); outb(GDCREG, 0x0E); /* addr = b8000, 32kb */
+ }
+ splx(s);
+ outb(TSIDX, 0x01); val = inb(TSREG); /* unblank screen */
+ outb(TSIDX, 0x01); outb(TSREG, val & 0xDF);
+}
+
+
+static void load_palette(void)
+{
+ int i;
+
+ outb(PIXMASK, 0xFF); /* no pixelmask */
+ outb(PALWADR, 0x00);
+ for (i=0x00; i<0x300; i++)
+ outb(PALDATA, palette[i]);
+ inb(crtc_addr+6); /* reset flip/flop */
+ outb(ATC, 0x20); /* enable palette */
+}
+
+static void save_palette(void)
+{
+ int i;
+
+ outb(PALRADR, 0x00);
+ for (i=0x00; i<0x300; i++)
+ palette[i] = inb(PALDATA);
+ inb(crtc_addr+6); /* reset flip/flop */
+}
+
+
+static void change_winsize(struct tty *tp, int x, int y)
+{
+ if (tp->t_winsize.ws_col != x || tp->t_winsize.ws_row != y) {
+ tp->t_winsize.ws_col = x;
+ tp->t_winsize.ws_row = y;
+ pgsignal(tp->t_pgrp, SIGWINCH, 1);
+ }
+}
+
+#endif /* NSC */
diff --git a/sys/gnu/i386/fpemul/Changelog b/sys/gnu/i386/fpemul/Changelog
new file mode 100644
index 0000000..a2fbccd1
--- /dev/null
+++ b/sys/gnu/i386/fpemul/Changelog
@@ -0,0 +1,36 @@
+This file contains the changes made to W. Metzenthem's 387 FPU
+emulator to make it work under NetBSD.
+
+a, Changes to make it compile:
+
+ 1 - Changed the #include's to get the appropriate .h files.
+ 2 - Renamed .S to .s, to satisfy the kernel Makefile.
+ 3 - Changed the C++ style // comments to /* */
+ 4 - Changed the FPU_ORIG_EIP macro. A letter from bde included
+ in the package suggested using tf_isp for using instead
+ of the linux __orig_eip. This later turned out to interfere
+ with the user stack, so i created a separate variable, stored
+ in the i387_union.
+ 5 - Changed the get_fs_.. put_fs_.. fns to fubyte,fuword,subyte,
+ suword.
+ 6 - Removed the verify_area fns. I don't really know what they do,
+ i suppose they verify access to memory. The sufu routines
+ should do this.
+
+b, Changes to make it work:
+
+ 1 - Made math_emulate() to return 0 when successful, so trap() won't
+ try to generate a signal.
+ 2 - Changed the size of the save87 struct in /sys/arch/i387/include/
+ npx.h to accomodate the i387_union.
+
+d, Other changes:
+
+ 1 - Removed obsolate and/or linux specific stuff.
+ 2 - Changed the RE_ENTRANT_CHECK_[ON|OFF] macro to
+ REENTRANT_CHECK([ON|OFF]) so indent can grok it.
+ 3 - Re-indented to Berkeley style.
+ 4 - Limited max no of lookaheads. LOOKAHEAD_LIMIT in fpu_entry.c
+
+
+ Szabolcs Szigeti (pink@fsz.bme.hu)
diff --git a/sys/gnu/i386/fpemul/README b/sys/gnu/i386/fpemul/README
new file mode 100644
index 0000000..4982c35
--- /dev/null
+++ b/sys/gnu/i386/fpemul/README
@@ -0,0 +1,267 @@
+/*
+ * wm-FPU-emu an FPU emulator for 80386 and 80486SX microprocessors.
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+wm-FPU-emu is an FPU emulator for Linux. It is derived from wm-emu387
+which is my 80387 emulator for djgpp (gcc under msdos); wm-emu387 was
+in turn based upon emu387 which was written by DJ Delorie for djgpp.
+The interface to the Linux kernel is based upon the original Linux
+math emulator by Linus Torvalds.
+
+My target FPU for wm-FPU-emu is that described in the Intel486
+Programmer's Reference Manual (1992 edition). Numerous facets of the
+functioning of the FPU are not well covered in the Reference Manual;
+in the absence of clear details I have made guesses about the most
+reasonable behaviour. Recently, this situation has improved because
+I now have some access to the results produced by a real 80486 FPU.
+
+wm-FPU-emu does not implement all of the behaviour of the 80486 FPU.
+See "Limitations" later in this file for a partial list of some
+differences. I believe that the missing features are never used by
+normal C or FORTRAN programs.
+
+
+Please report bugs, etc to me at:
+ apm233m@vaxc.cc.monash.edu.au
+
+
+--Bill Metzenthen
+ May 1993
+
+
+----------------------- Internals of wm-FPU-emu -----------------------
+
+Numeric algorithms:
+(1) Add, subtract, and multiply. Nothing remarkable in these.
+(2) Divide has been tuned to get reasonable performance. The algorithm
+ is not the obvious one which most people seem to use, but is designed
+ to take advantage of the characteristics of the 80386. I expect that
+ it has been invented many times before I discovered it, but I have not
+ seen it. It is based upon one of those ideas which one carries around
+ for years without ever bothering to check it out.
+(3) The sqrt function has been tuned to get good performance. It is based
+ upon Newton's classic method. Performance was improved by capitalizing
+ upon the properties of Newton's method, and the code is once again
+ structured taking account of the 80386 characteristics.
+(4) The trig, log, and exp functions are based in each case upon quasi-
+ "optimal" polynomial approximations. My definition of "optimal" was
+ based upon getting good accuracy with reasonable speed.
+
+The code of the emulator is complicated slightly by the need to
+account for a limited form of re-entrancy. Normally, the emulator will
+emulate each FPU instruction to completion without interruption.
+However, it may happen that when the emulator is accessing the user
+memory space, swapping may be needed. In this case the emulator may be
+temporarily suspended while disk i/o takes place. During this time
+another process may use the emulator, thereby changing some static
+variables (eg FPU_st0_ptr, etc). The code which accesses user memory
+is confined to five files:
+ fpu_entry.c
+ reg_ld_str.c
+ load_store.c
+ get_address.c
+ errors.c
+
+----------------------- Limitations of wm-FPU-emu -----------------------
+
+There are a number of differences between the current wm-FPU-emu
+(version beta 1.4) and the 80486 FPU (apart from bugs). Some of the
+more important differences are listed below:
+
+All internal computations are performed at 64 bit or higher precision
+and rounded etc as required by the PC bits of the FPU control word.
+Under the crt0 version for Linux current at March 1993, the FPU PC
+bits specify 53 bits precision.
+
+The precision flag (PE of the FPU status word) and the Roundup flag
+(C1 of the status word) are now partially implemented. Does anyone
+write code which uses these features?
+
+The functions which load/store the FPU state are partially implemented,
+but the implementation should be sufficient for handling FPU errors etc
+in 32 bit protected mode.
+
+The implementation of the exception mechanism is flawed for unmasked
+interrupts.
+
+Detection of certain conditions, such as denormal operands, is not yet
+complete.
+
+----------------------- Performance of wm-FPU-emu -----------------------
+
+Speed.
+-----
+
+The speed of floating point computation with the emulator will depend
+upon instruction mix. Relative performance is best for the instructions
+which require most computation. The simple instructions are adversely
+affected by the fpu instruction trap overhead.
+
+
+Timing: Some simple timing tests have been made on the emulator functions.
+The times include load/store instructions. All times are in microseconds
+measured on a 33MHz 386 with 64k cache. The Turbo C tests were under
+ms-dos, the next two columns are for emulators running with the djgpp
+ms-dos extender. The final column is for wm-FPU-emu in Linux 0.97,
+using libm4.0 (hard).
+
+function Turbo C djgpp 1.06 WM-emu387 wm-FPU-emu
+
+ + 60.5 154.8 76.5 139.4
+ - 61.1-65.5 157.3-160.8 76.2-79.5 142.9-144.7
+ * 71.0 190.8 79.6 146.6
+ / 61.2-75.0 261.4-266.9 75.3-91.6 142.2-158.1
+
+ sin() 310.8 4692.0 319.0 398.5
+ cos() 284.4 4855.2 308.0 388.7
+ tan() 495.0 8807.1 394.9 504.7
+ atan() 328.9 4866.4 601.1 419.5-491.9
+
+ sqrt() 128.7 crashed 145.2 227.0
+ log() 413.1-419.1 5103.4-5354.21 254.7-282.2 409.4-437.1
+ exp() 479.1 6619.2 469.1 850.8
+
+
+The performance under Linux is improved by the use of look-ahead code.
+The following results show the improvement which is obtained under
+Linux due to the look-ahead code. Also given are the times for the
+original Linux emulator with the 4.1 'soft' lib.
+
+ [ Linus' note: I changed look-ahead to be the default under linux, as
+ there was no reason not to use it after I had edited it to be
+ disabled during tracing ]
+
+ wm-FPU-emu w original w
+ look-ahead 'soft' lib
+ + 106.4 190.2
+ - 108.6-111.6 192.4-216.2
+ * 113.4 193.1
+ / 108.8-124.4 700.1-706.2
+
+ sin() 390.5 2642.0
+ cos() 381.5 2767.4
+ tan() 496.5 3153.3
+ atan() 367.2-435.5 2439.4-3396.8
+
+ sqrt() 195.1 4732.5
+ log() 358.0-387.5 3359.2-3390.3
+ exp() 619.3 4046.4
+
+
+These figures are now somewhat out-of-date. The emulator has become
+progressively slower for most functions as more of the 80486 features
+have been implemented.
+
+
+----------------------- Accuracy of wm-FPU-emu -----------------------
+
+
+Accuracy: The following table gives the accuracy of the sqrt(), trig
+and log functions. Each function was tested at about 400 points. Ideal
+results would be 64 bits. The reduced accuracy of cos() and tan() for
+arguments greater than pi/4 can be thought of as being due to the
+precision of the argument x; e.g. an argument of pi/2-(1e-10) which is
+accurate to 64 bits can result in a relative accuracy in cos() of about
+64 + log2(cos(x)) = 31 bits. Results for the Turbo C emulator are given
+in the last column.
+
+
+Function Tested x range Worst result (bits) Turbo C
+
+sqrt(x) 1 .. 2 64.1 63.2
+atan(x) 1e-10 .. 200 62.6 62.8
+cos(x) 0 .. pi/2-(1e-10) 63.2 (x <= pi/4) 62.4
+ 35.2 (x = pi/2-(1e-10)) 31.9
+sin(x) 1e-10 .. pi/2 63.0 62.8
+tan(x) 1e-10 .. pi/2-(1e-10) 62.4 (x <= pi/4) 62.1
+ 35.2 (x = pi/2-(1e-10)) 31.9
+exp(x) 0 .. 1 63.1 62.9
+log(x) 1+1e-6 .. 2 62.4 62.1
+
+
+As of version 1.3 of the emulator, the accuracy of the basic
+arithmetic has been improved (by a small fraction of a bit). Care has
+been taken to ensure full accuracy of the rounding of the basic
+arithmetic functions (+,-,*,/,and fsqrt), and they all now produce
+results which are exact to the 64th bit (unless there are any bugs
+left). To ensure this, it was necessary to effectively get information
+of up to about 128 bits precision. The emulator now passes the
+"paranoia" tests (compiled with gcc 2.3.3) for 'float' variables (24
+bit precision numbers) when precision control is set to 24, 53 or 64
+bits, and for 'double' variables (53 bit precision numbers) when
+precision control is set to 53 bits (a properly performing FPU cannot
+pass the 'paranoia' tests for 'double' variables when precision
+control is set to 64 bits).
+
+------------------------- Contributors -------------------------------
+
+A number of people have contributed to the development of the
+emulator, often by just reporting bugs, sometimes with a suggested
+fix, and a few kind people have provided me with access in one way or
+another to an 80486 machine. Contributors include (to those people who
+I have forgotten, please excuse me):
+
+Linus Torvalds
+Tommy.Thorn@daimi.aau.dk
+Andrew.Tridgell@anu.edu.au
+Nick Holloway alfie@dcs.warwick.ac.uk
+Hermano Moura moura@dcs.gla.ac.uk
+Jon Jagger J.Jagger@scp.ac.uk
+Lennart Benschop
+Brian Gallew geek+@CMU.EDU
+Thomas Staniszewski ts3v+@andrew.cmu.edu
+Martin Howell mph@plasma.apana.org.au
+M Saggaf alsaggaf@athena.mit.edu
+Peter Barker PETER@socpsy.sci.fau.edu
+tom@vlsivie.tuwien.ac.at
+Dan Russel russed@rpi.edu
+Daniel Carosone danielce@ee.mu.oz.au
+cae@jpmorgan.com
+Hamish Coleman t933093@minyos.xx.rmit.oz.au
+
+...and numerous others who responded to my request for help with
+a real 80486.
+
diff --git a/sys/gnu/i386/fpemul/bde_trapinfo.mail b/sys/gnu/i386/fpemul/bde_trapinfo.mail
new file mode 100644
index 0000000..2749e04
--- /dev/null
+++ b/sys/gnu/i386/fpemul/bde_trapinfo.mail
@@ -0,0 +1,35 @@
+From bde@kralizec.zeta.org.au Sun Jun 27 01:18:32 1993
+Received: from ultima.socs.uts.EDU.AU by bsd.coe.montana.edu (5.67/KAOS-1)
+ id AA11952; Sun, 27 Jun 93 01:18:32 -0600
+Received: by ultima.socs.uts.EDU.AU (5.65+/SMI-3.3)
+ id AA03033; Sun, 27 Jun 93 17:10:22 +1000
+Received: by kralizec.zeta.org.au (4.0/SMI-4.0)
+ id AA15074; Sat, 26 Jun 93 02:32:58 EST
+Date: Sat, 26 Jun 93 02:32:58 EST
+From: bde@kralizec.zeta.org.au (Bruce Evans)
+Message-Id: <9306251632.AA15074@kralizec.zeta.org.au>
+To: nate@bsd.coe.montana.edu
+Subject: Re: Trapframe information
+Status: OR
+
+tf_isp original esp (probably spare - popal ignores it)
+tf_trapno s/w trap no (may be spare - trap.c has already looked at it)
+tf_err h/w error code (probably spare - gets discarded before iret)
+
+___fs not stored in 386BSD pcb. Constant anyway unless user has
+ screwed with it (?).
+___gs ditto
+___orig_eip in linux, this is on the stack just before the call to the
+ emulator. The reason that it's not a local variable is to
+ avoid passing around pointers to it - current->frame (or
+ whatever) points to everything in the stack frame. The
+ macros hide a lot of slow memory references
+ current->frame->var.
+
+>(And I need to see if I can map orig_eip to one of the three that I'm unsure of
+>in the BSD sources)
+
+tf_isp is the least evil.
+
+Bruce
+
diff --git a/sys/gnu/i386/fpemul/control_w.h b/sys/gnu/i386/fpemul/control_w.h
new file mode 100644
index 0000000..ac3e0f4
--- /dev/null
+++ b/sys/gnu/i386/fpemul/control_w.h
@@ -0,0 +1,85 @@
+/*
+ * control_w.h
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+#ifndef _CONTROLW_H_
+#define _CONTROLW_H_
+
+#ifdef LOCORE
+#define _Const_(x) $/**/x
+#else
+#define _Const_(x) x
+#endif
+
+#define CW_RC _Const_(0x0C00) /* rounding control */
+#define CW_PC _Const_(0x0300) /* precision control */
+
+#define CW_Precision Const_(0x0020) /* loss of precision mask */
+#define CW_Underflow Const_(0x0010) /* underflow mask */
+#define CW_Overflow Const_(0x0008) /* overflow mask */
+#define CW_ZeroDiv Const_(0x0004) /* divide by zero mask */
+#define CW_Denormal Const_(0x0002) /* denormalized operand mask */
+#define CW_Invalid Const_(0x0001) /* invalid operation mask */
+
+#define CW_Exceptions _Const_(0x003f) /* all masks */
+
+#define RC_RND _Const_(0x0000)
+#define RC_DOWN _Const_(0x0400)
+#define RC_UP _Const_(0x0800)
+#define RC_CHOP _Const_(0x0C00)
+
+/* p 15-5: Precision control bits affect only the following:
+ ADD, SUB(R), MUL, DIV(R), and SQRT */
+#define PR_24_BITS _Const_(0x000)
+#define PR_53_BITS _Const_(0x200)
+#define PR_64_BITS _Const_(0x300)
+/* FULL_PRECISION simulates all exceptions masked */
+#define FULL_PRECISION (PR_64_BITS | RC_RND | 0x3f)
+
+#endif /* _CONTROLW_H_ */
diff --git a/sys/gnu/i386/fpemul/div_small.s b/sys/gnu/i386/fpemul/div_small.s
new file mode 100644
index 0000000..0b3a7b9
--- /dev/null
+++ b/sys/gnu/i386/fpemul/div_small.s
@@ -0,0 +1,91 @@
+ .file "div_small.S"
+/*
+ * div_small.S
+ *
+ * Divide a 64 bit integer by a 32 bit integer & return remainder.
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | unsigned long div_small(unsigned long long *x, unsigned long y) |
+ +---------------------------------------------------------------------------*/
+
+#include "fpu_asm.h"
+
+.text
+ .align 2,144
+
+.globl _div_small
+
+_div_small:
+ pushl %ebp
+ movl %esp,%ebp
+
+ pushl %esi
+
+ movl PARAM1,%esi /* pointer to num */
+ movl PARAM2,%ecx /* The denominator */
+
+ movl 4(%esi),%eax /* Get the current num msw */
+ xorl %edx,%edx
+ divl %ecx
+
+ movl %eax,4(%esi)
+
+ movl (%esi),%eax /* Get the num lsw */
+ divl %ecx
+
+ movl %eax,(%esi)
+
+ movl %edx,%eax /* Return the remainder in eax */
+
+ popl %esi
+
+ leave
+ ret
+
diff --git a/sys/gnu/i386/fpemul/errors.c b/sys/gnu/i386/fpemul/errors.c
new file mode 100644
index 0000000..69782af
--- /dev/null
+++ b/sys/gnu/i386/fpemul/errors.c
@@ -0,0 +1,602 @@
+/*
+ * errors.c
+ *
+ * The error handling functions for wm-FPU-emu
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | Note: |
+ | The file contains code which accesses user memory. |
+ | Emulator static data may change when user memory is accessed, due to |
+ | other processes using the emulator while swapping is in progress. |
+ +---------------------------------------------------------------------------*/
+
+
+
+
+
+#include "param.h"
+#include "proc.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+#include "status_w.h"
+#include "control_w.h"
+#include "reg_constant.h"
+#include "version.h"
+
+/* */
+#undef PRINT_MESSAGES
+/* */
+
+
+void
+Un_impl(void)
+{
+ unsigned char byte1, FPU_modrm;
+
+ REENTRANT_CHECK(OFF);
+ byte1 = fubyte((unsigned char *) FPU_ORIG_EIP);
+ FPU_modrm = fubyte(1 + (unsigned char *) FPU_ORIG_EIP);
+
+ printf("Unimplemented FPU Opcode at eip=%p : %02x ",
+ FPU_ORIG_EIP, byte1);
+
+ if (FPU_modrm >= 0300)
+ printf("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
+ else
+ printf("/%d\n", (FPU_modrm >> 3) & 7);
+ REENTRANT_CHECK(ON);
+
+ EXCEPTION(EX_Invalid);
+
+}
+
+
+
+
+void
+emu_printall()
+{
+ int i;
+ static char *tag_desc[] = {"Valid", "Zero", "ERROR", "ERROR",
+ "DeNorm", "Inf", "NaN", "Empty"};
+ unsigned char byte1, FPU_modrm;
+
+ REENTRANT_CHECK(OFF);
+ byte1 = fubyte((unsigned char *) FPU_ORIG_EIP);
+ FPU_modrm = fubyte(1 + (unsigned char *) FPU_ORIG_EIP);
+
+#ifdef DEBUGGING
+ if (status_word & SW_Backward)
+ printf("SW: backward compatibility\n");
+ if (status_word & SW_C3)
+ printf("SW: condition bit 3\n");
+ if (status_word & SW_C2)
+ printf("SW: condition bit 2\n");
+ if (status_word & SW_C1)
+ printf("SW: condition bit 1\n");
+ if (status_word & SW_C0)
+ printf("SW: condition bit 0\n");
+ if (status_word & SW_Summary)
+ printf("SW: exception summary\n");
+ if (status_word & SW_Stack_Fault)
+ printf("SW: stack fault\n");
+ if (status_word & SW_Precision)
+ printf("SW: loss of precision\n");
+ if (status_word & SW_Underflow)
+ printf("SW: underflow\n");
+ if (status_word & SW_Overflow)
+ printf("SW: overflow\n");
+ if (status_word & SW_Zero_Div)
+ printf("SW: divide by zero\n");
+ if (status_word & SW_Denorm_Op)
+ printf("SW: denormalized operand\n");
+ if (status_word & SW_Invalid)
+ printf("SW: invalid operation\n");
+#endif /* DEBUGGING */
+
+ status_word = status_word & ~SW_Top;
+ status_word |= (top & 7) << SW_Top_Shift;
+
+ printf("At %p: %02x ", FPU_ORIG_EIP, byte1);
+ if (FPU_modrm >= 0300)
+ printf("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
+ else
+ printf("/%d, mod=%d rm=%d\n",
+ (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7);
+
+ printf(" SW: b=%d st=%d es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n",
+ status_word & 0x8000 ? 1 : 0, /* busy */
+ (status_word & 0x3800) >> 11, /* stack top pointer */
+ status_word & 0x80 ? 1 : 0, /* Error summary status */
+ status_word & 0x40 ? 1 : 0, /* Stack flag */
+ status_word & SW_C3 ? 1 : 0, status_word & SW_C2 ? 1 : 0, /* cc */
+ status_word & SW_C1 ? 1 : 0, status_word & SW_C0 ? 1 : 0, /* cc */
+ status_word & SW_Precision ? 1 : 0, status_word & SW_Underflow ? 1 : 0,
+ status_word & SW_Overflow ? 1 : 0, status_word & SW_Zero_Div ? 1 : 0,
+ status_word & SW_Denorm_Op ? 1 : 0, status_word & SW_Invalid ? 1 : 0);
+
+ printf(" CW: ic=%d rc=%d%d pc=%d%d iem=%d ef=%d%d%d%d%d%d\n",
+ control_word & 0x1000 ? 1 : 0,
+ (control_word & 0x800) >> 11, (control_word & 0x400) >> 10,
+ (control_word & 0x200) >> 9, (control_word & 0x100) >> 8,
+ control_word & 0x80 ? 1 : 0,
+ control_word & SW_Precision ? 1 : 0, control_word & SW_Underflow ? 1 : 0,
+ control_word & SW_Overflow ? 1 : 0, control_word & SW_Zero_Div ? 1 : 0,
+ control_word & SW_Denorm_Op ? 1 : 0, control_word & SW_Invalid ? 1 : 0);
+
+ for (i = 0; i < 8; i++) {
+ FPU_REG *r = &st(i);
+ switch (r->tag) {
+ case TW_Empty:
+ continue;
+ break;
+ case TW_Zero:
+ printf("st(%d) %c .0000 0000 0000 0000 ",
+ i, r->sign ? '-' : '+');
+ break;
+ case TW_Valid:
+ case TW_NaN:
+ case TW_Denormal:
+ case TW_Infinity:
+ printf("st(%d) %c .%04x %04x %04x %04x e%+-6d ", i,
+ r->sign ? '-' : '+',
+ (long) (r->sigh >> 16),
+ (long) (r->sigh & 0xFFFF),
+ (long) (r->sigl >> 16),
+ (long) (r->sigl & 0xFFFF),
+ r->exp - EXP_BIAS + 1);
+ break;
+ default:
+ printf("Whoops! Error in errors.c ");
+ break;
+ }
+ printf("%s\n", tag_desc[(int) (unsigned) r->tag]);
+ }
+
+ printf("[data] %c .%04x %04x %04x %04x e%+-6d ",
+ FPU_loaded_data.sign ? '-' : '+',
+ (long) (FPU_loaded_data.sigh >> 16),
+ (long) (FPU_loaded_data.sigh & 0xFFFF),
+ (long) (FPU_loaded_data.sigl >> 16),
+ (long) (FPU_loaded_data.sigl & 0xFFFF),
+ FPU_loaded_data.exp - EXP_BIAS + 1);
+ printf("%s\n", tag_desc[(int) (unsigned) FPU_loaded_data.tag]);
+ REENTRANT_CHECK(ON);
+
+}
+
+static struct {
+ int type;
+ char *name;
+} exception_names[] = {
+ {
+ EX_StackOver, "stack overflow"
+ },
+ {
+ EX_StackUnder, "stack underflow"
+ },
+ {
+ EX_Precision, "loss of precision"
+ },
+ {
+ EX_Underflow, "underflow"
+ },
+ {
+ EX_Overflow, "overflow"
+ },
+ {
+ EX_ZeroDiv, "divide by zero"
+ },
+ {
+ EX_Denormal, "denormalized operand"
+ },
+ {
+ EX_Invalid, "invalid operation"
+ },
+ {
+ EX_INTERNAL, "INTERNAL BUG in " FPU_VERSION
+ },
+ {
+ 0, NULL
+ }
+};
+/*
+ EX_INTERNAL is always given with a code which indicates where the
+ error was detected.
+
+ Internal error types:
+ 0x14 in e14.c
+ 0x1nn in a *.c file:
+ 0x101 in reg_add_sub.c
+ 0x102 in reg_mul.c
+ 0x103 in poly_sin.c
+ 0x104 in poly_tan.c
+ 0x105 in reg_mul.c
+ 0x106 in reg_mov.c
+ 0x107 in fpu_trig.c
+ 0x108 in reg_compare.c
+ 0x109 in reg_compare.c
+ 0x110 in reg_add_sub.c
+ 0x111 in interface.c
+ 0x112 in fpu_trig.c
+ 0x113 in reg_add_sub.c
+ 0x114 in reg_ld_str.c
+ 0x115 in fpu_trig.c
+ 0x116 in fpu_trig.c
+ 0x117 in fpu_trig.c
+ 0x118 in fpu_trig.c
+ 0x119 in fpu_trig.c
+ 0x120 in poly_atan.c
+ 0x121 in reg_compare.c
+ 0x122 in reg_compare.c
+ 0x123 in reg_compare.c
+ 0x2nn in an *.s file:
+ 0x201 in reg_u_add.S
+ 0x202 in reg_u_div.S
+ 0x203 in reg_u_div.S
+ 0x204 in reg_u_div.S
+ 0x205 in reg_u_mul.S
+ 0x206 in reg_u_sub.S
+ 0x207 in wm_sqrt.S
+ 0x208 in reg_div.S
+ 0x209 in reg_u_sub.S
+ 0x210 in reg_u_sub.S
+ 0x211 in reg_u_sub.S
+ 0x212 in reg_u_sub.S
+ 0x213 in wm_sqrt.S
+ 0x214 in wm_sqrt.S
+ 0x215 in wm_sqrt.S
+ 0x216 in reg_round.S
+ 0x217 in reg_round.S
+ 0x218 in reg_round.S
+ */
+
+void
+exception(int n)
+{
+ int i, int_type;
+
+ int_type = 0; /* Needed only to stop compiler warnings */
+ if (n & EX_INTERNAL) {
+ int_type = n - EX_INTERNAL;
+ n = EX_INTERNAL;
+ /* Set lots of exception bits! */
+ status_word |= (SW_Exc_Mask | SW_Summary | FPU_BUSY);
+ } else {
+ /* Extract only the bits which we use to set the status word */
+ n &= (SW_Exc_Mask);
+ /* Set the corresponding exception bit */
+ status_word |= n;
+ if (status_word & ~control_word & CW_Exceptions)
+ status_word |= SW_Summary;
+ if (n & (SW_Stack_Fault | EX_Precision)) {
+ if (!(n & SW_C1))
+ /* This bit distinguishes over- from underflow
+ * for a stack fault, and roundup from
+ * round-down for precision loss. */
+ status_word &= ~SW_C1;
+ }
+ }
+
+ REENTRANT_CHECK(OFF);
+ if ((~control_word & n & CW_Exceptions) || (n == EX_INTERNAL)) {
+#ifdef PRINT_MESSAGES
+ /* My message from the sponsor */
+ printf(FPU_VERSION " " __DATE__ " (C) W. Metzenthen.\n");
+#endif /* PRINT_MESSAGES */
+
+ /* Get a name string for error reporting */
+ for (i = 0; exception_names[i].type; i++)
+ if ((exception_names[i].type & n) == exception_names[i].type)
+ break;
+
+ if (exception_names[i].type) {
+#ifdef PRINT_MESSAGES
+ printf("FP Exception: %s!\n", exception_names[i].name);
+#endif /* PRINT_MESSAGES */
+ } else
+ printf("FP emulator: Unknown Exception: 0x%04x!\n", n);
+
+ if (n == EX_INTERNAL) {
+ printf("FP emulator: Internal error type 0x%04x\n", int_type);
+ emu_printall();
+ }
+#ifdef PRINT_MESSAGES
+ else
+ emu_printall();
+#endif /* PRINT_MESSAGES */
+
+ /* The 80486 generates an interrupt on the next non-control
+ * FPU instruction. So we need some means of flagging it. We
+ * use the ES (Error Summary) bit for this, assuming that this
+ * is the way a real FPU does it (until I can check it out),
+ * if not, then some method such as the following kludge might
+ * be needed. */
+/* regs[0].tag |= TW_FPU_Interrupt; */
+ }
+ REENTRANT_CHECK(ON);
+
+#ifdef __DEBUG__
+ math_abort(SIGFPE);
+#endif /* __DEBUG__ */
+
+}
+
+
+/* Real operation attempted on two operands, one a NaN */
+void
+real_2op_NaN(FPU_REG * a, FPU_REG * b, FPU_REG * dest)
+{
+ FPU_REG *x;
+ int signalling;
+
+ x = a;
+ if (a->tag == TW_NaN) {
+ if (b->tag == TW_NaN) {
+ signalling = !(a->sigh & b->sigh & 0x40000000);
+ /* find the "larger" */
+ if (*(long long *) &(a->sigl) < *(long long *) &(b->sigl))
+ x = b;
+ } else {
+ /* return the quiet version of the NaN in a */
+ signalling = !(a->sigh & 0x40000000);
+ }
+ } else
+#ifdef PARANOID
+ if (b->tag == TW_NaN)
+#endif /* PARANOID */
+ {
+ signalling = !(b->sigh & 0x40000000);
+ x = b;
+ }
+#ifdef PARANOID
+ else {
+ signalling = 0;
+ EXCEPTION(EX_INTERNAL | 0x113);
+ x = &CONST_QNaN;
+ }
+#endif /* PARANOID */
+
+ if (!signalling) {
+ if (!(x->sigh & 0x80000000)) /* pseudo-NaN ? */
+ x = &CONST_QNaN;
+ reg_move(x, dest);
+ return;
+ }
+ if (control_word & CW_Invalid) {
+ /* The masked response */
+ if (!(x->sigh & 0x80000000)) /* pseudo-NaN ? */
+ x = &CONST_QNaN;
+ reg_move(x, dest);
+ /* ensure a Quiet NaN */
+ dest->sigh |= 0x40000000;
+ }
+ EXCEPTION(EX_Invalid);
+
+ return;
+}
+/* Invalid arith operation on Valid registers */
+void
+arith_invalid(FPU_REG * dest)
+{
+
+ if (control_word & CW_Invalid) {
+ /* The masked response */
+ reg_move(&CONST_QNaN, dest);
+ }
+ EXCEPTION(EX_Invalid);
+
+ return;
+
+}
+
+
+/* Divide a finite number by zero */
+void
+divide_by_zero(int sign, FPU_REG * dest)
+{
+
+ if (control_word & CW_ZeroDiv) {
+ /* The masked response */
+ reg_move(&CONST_INF, dest);
+ dest->sign = (unsigned char) sign;
+ }
+ EXCEPTION(EX_ZeroDiv);
+
+ return;
+
+}
+
+
+/* This may be called often, so keep it lean */
+void
+set_precision_flag_up(void)
+{
+ if (control_word & CW_Precision)
+ status_word |= (SW_Precision | SW_C1); /* The masked response */
+ else
+ exception(EX_Precision | SW_C1);
+
+}
+
+
+/* This may be called often, so keep it lean */
+void
+set_precision_flag_down(void)
+{
+ if (control_word & CW_Precision) { /* The masked response */
+ status_word &= ~SW_C1;
+ status_word |= SW_Precision;
+ } else
+ exception(EX_Precision);
+}
+
+
+int
+denormal_operand(void)
+{
+ if (control_word & CW_Denormal) { /* The masked response */
+ status_word |= SW_Denorm_Op;
+ return 0;
+ } else {
+ exception(EX_Denormal);
+ return 1;
+ }
+}
+
+
+void
+arith_overflow(FPU_REG * dest)
+{
+
+ if (control_word & CW_Overflow) {
+ char sign;
+ /* The masked response */
+/* **** The response here depends upon the rounding mode */
+ sign = dest->sign;
+ reg_move(&CONST_INF, dest);
+ dest->sign = sign;
+ } else {
+ /* Subtract the magic number from the exponent */
+ dest->exp -= (3 * (1 << 13));
+ }
+
+ /* By definition, precision is lost. It appears that the roundup bit
+ * (C1) is also set by convention. */
+ EXCEPTION(EX_Overflow | EX_Precision | SW_C1);
+
+ return;
+
+}
+
+
+void
+arith_underflow(FPU_REG * dest)
+{
+
+ if (control_word & CW_Underflow) {
+ /* The masked response */
+ if (dest->exp <= EXP_UNDER - 63)
+ reg_move(&CONST_Z, dest);
+ } else {
+ /* Add the magic number to the exponent */
+ dest->exp += (3 * (1 << 13));
+ }
+
+ EXCEPTION(EX_Underflow);
+
+ return;
+}
+
+
+void
+stack_overflow(void)
+{
+
+ if (control_word & CW_Invalid) {
+ /* The masked response */
+ top--;
+ reg_move(&CONST_QNaN, FPU_st0_ptr = &st(0));
+ }
+ EXCEPTION(EX_StackOver);
+
+ return;
+
+}
+
+
+void
+stack_underflow(void)
+{
+
+ if (control_word & CW_Invalid) {
+ /* The masked response */
+ reg_move(&CONST_QNaN, FPU_st0_ptr);
+ }
+ EXCEPTION(EX_StackUnder);
+
+ return;
+
+}
+
+
+void
+stack_underflow_i(int i)
+{
+
+ if (control_word & CW_Invalid) {
+ /* The masked response */
+ reg_move(&CONST_QNaN, &(st(i)));
+ }
+ EXCEPTION(EX_StackUnder);
+
+ return;
+
+}
+
+
+void
+stack_underflow_pop(int i)
+{
+
+ if (control_word & CW_Invalid) {
+ /* The masked response */
+ reg_move(&CONST_QNaN, &(st(i)));
+ pop();
+ }
+ EXCEPTION(EX_StackUnder);
+
+ return;
+
+}
diff --git a/sys/gnu/i386/fpemul/exception.h b/sys/gnu/i386/fpemul/exception.h
new file mode 100644
index 0000000..a48769d
--- /dev/null
+++ b/sys/gnu/i386/fpemul/exception.h
@@ -0,0 +1,92 @@
+/*
+ * exception.h
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ *
+ */
+
+#ifndef _EXCEPTION_H_
+#define _EXCEPTION_H_
+
+
+#ifdef LOCORE
+#define Const_(x) $/**/x
+#else
+#define Const_(x) x
+#endif
+
+#ifndef SW_C1
+#include "fpu_emu.h"
+#endif /* SW_C1 */
+
+#define FPU_BUSY Const_(0x8000) /* FPU busy bit (8087 compatibility) */
+#define EX_ErrorSummary Const_(0x0080) /* Error summary status */
+/* Special exceptions: */
+#define EX_INTERNAL Const_(0x8000) /* Internal error in wm-FPU-emu */
+#define EX_StackOver Const_(0x0041|SW_C1) /* stack overflow */
+#define EX_StackUnder Const_(0x0041) /* stack underflow */
+/* Exception flags: */
+#define EX_Precision Const_(0x0020) /* loss of precision */
+#define EX_Underflow Const_(0x0010) /* underflow */
+#define EX_Overflow Const_(0x0008) /* overflow */
+#define EX_ZeroDiv Const_(0x0004) /* divide by zero */
+#define EX_Denormal Const_(0x0002) /* denormalized operand */
+#define EX_Invalid Const_(0x0001) /* invalid operation */
+
+
+#ifndef LOCORE
+
+#ifdef DEBUG
+#define EXCEPTION(x) { printf("exception in %s at line %d\n", \
+ __FILE__, __LINE__); exception(x); }
+#else
+#define EXCEPTION(x) exception(x)
+#endif
+
+#endif /* LOCORE */
+
+#endif /* _EXCEPTION_H_ */
diff --git a/sys/gnu/i386/fpemul/fpu_arith.c b/sys/gnu/i386/fpemul/fpu_arith.c
new file mode 100644
index 0000000..4ed9e1d
--- /dev/null
+++ b/sys/gnu/i386/fpemul/fpu_arith.c
@@ -0,0 +1,225 @@
+/*
+ * fpu_arith.c
+ *
+ * Code to implement the FPU register/register arithmetic instructions
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+
+
+
+#include "param.h"
+#include "proc.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "control_w.h"
+
+
+void
+fadd__()
+{
+ /* fadd st,st(i) */
+ reg_add(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
+}
+
+
+void
+fmul__()
+{
+ /* fmul st,st(i) */
+ reg_mul(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
+}
+
+
+
+void
+fsub__()
+{
+ /* fsub st,st(i) */
+ reg_sub(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
+}
+
+
+void
+fsubr_()
+{
+ /* fsubr st,st(i) */
+ reg_sub(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word);
+}
+
+
+void
+fdiv__()
+{
+ /* fdiv st,st(i) */
+ reg_div(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
+}
+
+
+void
+fdivr_()
+{
+ /* fdivr st,st(i) */
+ reg_div(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word);
+}
+
+
+
+void
+fadd_i()
+{
+ /* fadd st(i),st */
+ reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+}
+
+
+void
+fmul_i()
+{
+ /* fmul st(i),st */
+ reg_mul(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+}
+
+
+void
+fsubri()
+{
+ /* fsubr st(i),st */
+ /* This is the sense of the 80486 manual reg_sub(&st(FPU_rm),
+ * FPU_st0_ptr, &st(FPU_rm), control_word); */
+ reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+}
+
+
+void
+fsub_i()
+{
+ /* fsub st(i),st */
+ /* This is the sense of the 80486 manual reg_sub(FPU_st0_ptr,
+ * &st(FPU_rm), &st(FPU_rm), control_word); */
+ reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+}
+
+
+void
+fdivri()
+{
+ /* fdivr st(i),st */
+ reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+}
+
+
+void
+fdiv_i()
+{
+ /* fdiv st(i),st */
+ reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+}
+
+
+
+void
+faddp_()
+{
+ /* faddp st(i),st */
+ reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+ pop();
+}
+
+
+void
+fmulp_()
+{
+ /* fmulp st(i),st */
+ reg_mul(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+ pop();
+}
+
+
+
+void
+fsubrp()
+{
+ /* fsubrp st(i),st */
+ /* This is the sense of the 80486 manual reg_sub(&st(FPU_rm),
+ * FPU_st0_ptr, &st(FPU_rm), control_word); */
+ reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+ pop();
+}
+
+
+void
+fsubp_()
+{
+ /* fsubp st(i),st */
+ /* This is the sense of the 80486 manual reg_sub(FPU_st0_ptr,
+ * &st(FPU_rm), &st(FPU_rm), control_word); */
+ reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+ pop();
+}
+
+
+void
+fdivrp()
+{
+ /* fdivrp st(i),st */
+ reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+ pop();
+}
+
+
+void
+fdivp_()
+{
+ /* fdivp st(i),st */
+ reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+ pop();
+}
diff --git a/sys/gnu/i386/fpemul/fpu_asm.h b/sys/gnu/i386/fpemul/fpu_asm.h
new file mode 100644
index 0000000..a13035f
--- /dev/null
+++ b/sys/gnu/i386/fpemul/fpu_asm.h
@@ -0,0 +1,72 @@
+/*
+ * fpu_asm.h
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+#ifndef _FPU_ASM_H_
+#define _FPU_ASM_H_
+
+#include "fpu_emu.h"
+
+#define EXCEPTION _exception
+
+
+#define PARAM1 8(%ebp)
+#define PARAM2 12(%ebp)
+#define PARAM3 16(%ebp)
+#define PARAM4 20(%ebp)
+
+#define SIGL_OFFSET 8
+#define SIGN(x) (x)
+#define TAG(x) 1(x)
+#define EXP(x) 4(x)
+#define SIG(x) SIGL_OFFSET/**/(x)
+#define SIGL(x) SIGL_OFFSET/**/(x)
+#define SIGH(x) 12(x)
+
+#endif /* _FPU_ASM_H_ */
diff --git a/sys/gnu/i386/fpemul/fpu_aux.c b/sys/gnu/i386/fpemul/fpu_aux.c
new file mode 100644
index 0000000..93f288b
--- /dev/null
+++ b/sys/gnu/i386/fpemul/fpu_aux.c
@@ -0,0 +1,223 @@
+/*
+ * fpu_aux.c
+ *
+ * Code to implement some of the FPU auxiliary instructions.
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+
+#include "param.h"
+#include "proc.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+#include "status_w.h"
+
+
+
+void
+fclex(void)
+{
+ status_word &= ~(SW_Backward | SW_Summary | SW_Stack_Fault | SW_Precision |
+ SW_Underflow | SW_Overflow | SW_Zero_Div | SW_Denorm_Op |
+ SW_Invalid);
+ FPU_entry_eip = ip_offset; /* We want no net effect */
+}
+/* Needs to be externally visible */
+void
+finit()
+{
+ int r;
+ control_word = 0x037f;
+ status_word = 0;
+ top = 0; /* We don't keep top in the status word
+ * internally. */
+ for (r = 0; r < 8; r++) {
+ regs[r].tag = TW_Empty;
+ }
+ FPU_entry_eip = ip_offset = 0;
+}
+
+static FUNC finit_table[] = {
+ Un_impl, Un_impl, fclex, finit, Un_impl, Un_impl, Un_impl, Un_impl
+};
+
+void
+finit_()
+{
+ (finit_table[FPU_rm]) ();
+}
+
+
+static void
+fstsw_ax(void)
+{
+
+ status_word &= ~SW_Top;
+ status_word |= (top & 7) << SW_Top_Shift;
+
+ *(short *) &FPU_EAX = status_word;
+
+}
+
+static FUNC fstsw_table[] = {
+ fstsw_ax, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl
+};
+
+void
+fstsw_()
+{
+ (fstsw_table[FPU_rm]) ();
+}
+
+
+
+static void
+fnop(void)
+{
+}
+
+FUNC fp_nop_table[] = {
+ fnop, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl
+};
+
+void
+fp_nop()
+{
+ (fp_nop_table[FPU_rm]) ();
+}
+
+
+void
+fld_i_()
+{
+ FPU_REG *st_new_ptr;
+
+ if (STACK_OVERFLOW) {
+ stack_overflow();
+ return;
+ }
+ /* fld st(i) */
+ if (NOT_EMPTY(FPU_rm)) {
+ reg_move(&st(FPU_rm), st_new_ptr);
+ push();
+ } else {
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ push();
+ stack_underflow();
+ } else
+ EXCEPTION(EX_StackUnder);
+ }
+
+}
+
+
+void
+fxch_i()
+{
+ /* fxch st(i) */
+ FPU_REG t;
+ register FPU_REG *sti_ptr = &st(FPU_rm);
+
+ if (FPU_st0_tag == TW_Empty) {
+ if (sti_ptr->tag == TW_Empty) {
+ stack_underflow();
+ stack_underflow_i(FPU_rm);
+ return;
+ }
+ reg_move(sti_ptr, FPU_st0_ptr);
+ stack_underflow_i(FPU_rm);
+ return;
+ }
+ if (sti_ptr->tag == TW_Empty) {
+ reg_move(FPU_st0_ptr, sti_ptr);
+ stack_underflow();
+ return;
+ }
+ reg_move(FPU_st0_ptr, &t);
+ reg_move(sti_ptr, FPU_st0_ptr);
+ reg_move(&t, sti_ptr);
+}
+
+
+void
+ffree_()
+{
+ /* ffree st(i) */
+ st(FPU_rm).tag = TW_Empty;
+}
+
+
+void
+ffreep()
+{
+ /* ffree st(i) + pop - unofficial code */
+ st(FPU_rm).tag = TW_Empty;
+ pop();
+}
+
+
+void
+fst_i_()
+{
+ /* fst st(i) */
+ reg_move(FPU_st0_ptr, &st(FPU_rm));
+}
+
+
+void
+fstp_i()
+{
+ /* fstp st(i) */
+ reg_move(FPU_st0_ptr, &st(FPU_rm));
+ pop();
+}
diff --git a/sys/gnu/i386/fpemul/fpu_emu.h b/sys/gnu/i386/fpemul/fpu_emu.h
new file mode 100644
index 0000000..7e20611
--- /dev/null
+++ b/sys/gnu/i386/fpemul/fpu_emu.h
@@ -0,0 +1,178 @@
+/*
+ * fpu_emu.h
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+
+#ifndef _FPU_EMU_H_
+#define _FPU_EMU_H_
+
+/*
+ * Define DENORM_OPERAND to make the emulator detect denormals
+ * and use the denormal flag of the status word. Note: this only
+ * affects the flag and corresponding interrupt, the emulator
+ * will always generate denormals and operate upon them as required.
+ */
+#define DENORM_OPERAND
+
+/*
+ * Define PECULIAR_486 to get a closer approximation to 80486 behaviour,
+ * rather than behaviour which appears to be cleaner.
+ * This is a matter of opinion: for all I know, the 80486 may simply
+ * be complying with the IEEE spec. Maybe one day I'll get to see the
+ * spec...
+ */
+#define PECULIAR_486
+
+#ifdef LOCORE
+#include "fpu_asm.h"
+#define Const(x) $/**/x
+#else
+#define Const(x) x
+#endif
+
+#define EXP_BIAS Const(0)
+#define EXP_OVER Const(0x4000) /* smallest invalid large exponent */
+#define EXP_UNDER Const(-0x3fff) /* largest invalid small exponent */
+
+#define SIGN_POS Const(0)
+#define SIGN_NEG Const(1)
+
+/* Keep the order TW_Valid, TW_Zero, TW_Denormal */
+#define TW_Valid Const(0)/* valid */
+#define TW_Zero Const(1)/* zero */
+/* The following fold to 2 (Special) in the Tag Word */
+#define TW_Denormal Const(4)/* De-normal */
+#define TW_Infinity Const(5)/* + or - infinity */
+#define TW_NaN Const(6)/* Not a Number */
+
+#define TW_Empty Const(7)/* empty */
+
+ /* #define TW_FPU_Interrupt Const(0x80) *//* Signals an interrupt */
+
+
+#ifndef LOCORE
+
+#include "types.h"
+#include "math_emu.h"
+
+#ifdef PARANOID
+extern char emulating;
+#define REENTRANT_CHECK(state) emulating = (state)
+#define ON 1
+#define OFF 0
+#else
+#define REENTRANT_CHECK(state)
+#endif /* PARANOID */
+
+typedef void (*FUNC) (void);
+typedef struct fpu_reg FPU_REG;
+
+#define st(x) ( regs[((top+x) &7 )] )
+
+#define STACK_OVERFLOW (st_new_ptr = &st(-1), st_new_ptr->tag != TW_Empty)
+#define NOT_EMPTY(i) (st(i).tag != TW_Empty)
+#define NOT_EMPTY_0 (FPU_st0_tag ^ TW_Empty)
+
+extern unsigned char FPU_rm;
+
+extern char FPU_st0_tag;
+extern FPU_REG *FPU_st0_ptr;
+
+extern void *FPU_data_address;
+
+extern FPU_REG FPU_loaded_data;
+
+#define pop() { FPU_st0_ptr->tag = TW_Empty; top++; }
+
+/* push() does not affect the tags */
+#define push() { top--; FPU_st0_ptr = st_new_ptr; }
+
+
+#define reg_move(x, y) { \
+ *(short *)&((y)->sign) = *(short *)&((x)->sign); \
+ *(long *)&((y)->exp) = *(long *)&((x)->exp); \
+ *(long long *)&((y)->sigl) = *(long long *)&((x)->sigl); }
+
+
+/*----- Prototypes for functions written in assembler -----*/
+/* extern void reg_move(FPU_REG *a, FPU_REG *b); */
+
+extern void mul64(long long *a, long long *b, long long *result);
+extern void poly_div2(long long *x);
+extern void poly_div4(long long *x);
+extern void poly_div16(long long *x);
+extern void
+polynomial(unsigned accum[], unsigned x[],
+ unsigned short terms[][4], int n);
+ extern void normalize(FPU_REG * x);
+ extern void normalize_nuo(FPU_REG * x);
+ extern void reg_div(FPU_REG * arg1, FPU_REG * arg2, FPU_REG * answ,
+ unsigned int control_w);
+ extern void reg_u_sub(FPU_REG * arg1, FPU_REG * arg2, FPU_REG * answ,
+ unsigned int control_w);
+ extern void reg_u_mul(FPU_REG * arg1, FPU_REG * arg2, FPU_REG * answ,
+ unsigned int control_w);
+ extern void reg_u_div(FPU_REG * arg1, FPU_REG * arg2, FPU_REG * answ,
+ unsigned int control_w);
+ extern void reg_u_add(FPU_REG * arg1, FPU_REG * arg2, FPU_REG * answ,
+ unsigned int control_w);
+ extern void wm_sqrt(FPU_REG * n, unsigned int control_w);
+ extern unsigned shrx(void *l, unsigned x);
+ extern unsigned shrxs(void *v, unsigned x);
+ extern unsigned long div_small(unsigned long long *x, unsigned long y);
+ extern void round_reg(FPU_REG * arg, unsigned int extent,
+ unsigned int control_w);
+
+#ifndef MAKING_PROTO
+#include "fpu_proto.h"
+#endif
+
+#endif /* LOCORE */
+
+#endif /* _FPU_EMU_H_ */
diff --git a/sys/gnu/i386/fpemul/fpu_entry.c b/sys/gnu/i386/fpemul/fpu_entry.c
new file mode 100644
index 0000000..31dfcdf
--- /dev/null
+++ b/sys/gnu/i386/fpemul/fpu_entry.c
@@ -0,0 +1,503 @@
+/*
+ * fpu_entry.c
+ *
+ * The entry function for wm-FPU-emu
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of the copyright is to ensure that the covered software
+ * remains freely available to everyone. It is felt to be necessary to
+ * try and prevent the software being taken by unscrupulous people and
+ * (perhaps after modification) being copyrighted or otherwise
+ * restricted and being made no longer freely available. There are a
+ * number of examples of corporations hijacking ideas and trying to
+ * sue the pants of lesser financed entities who try to subsequently
+ * use the ideas.
+ *
+ * If the software were placed in the public domain then there would
+ * be no protection at all. By claiming a copyright it puts at least a
+ * strong moral pressure on the greedy to restrain themselves and
+ * behave ethically. And let's not be naive, we are all subject to the
+ * emotion of greed to some extent...
+ *
+ * Up until now, the software has been covered by the GNU copyleft.
+ * That copyright mechanism has problems for operating systems which
+ * are not themselves covered by the GNU copyleft. Hence I have
+ * decided to allow the covered software to be used with 386BSD under
+ * restrictions which are meant to be broadly similar, but not
+ * identical, to those which already cover the 386BSD operating
+ * system.
+ *
+ * The software, in its form for the Linux operating system, remains
+ * available under the terms of the GNU copyleft.
+ *
+ * W. Metzenthen June 1993.
+ *
+ * $Id:$
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | Note: |
+ | The file contains code which accesses user memory. |
+ | Emulator static data may change when user memory is accessed, due to |
+ | other processes using the emulator while swapping is in progress. |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | math_emulate() is the sole entry point for wm-FPU-emu |
+ +---------------------------------------------------------------------------*/
+
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+#include "control_w.h"
+#include "status_w.h"
+
+
+#define __BAD__ Un_impl /* Not implemented */
+
+#define FPU_LOOKAHEAD 1 /* For performance boost */
+
+#if FPU_LOOKAHEAD != 0 /* I think thet we have to limit the */
+#define LOOKAHEAD_LIMIT 7 /* Max number of lookahead instructions*/
+#endif /* Or else a prog consisting of a million */
+ /* fnops will spend all its time in kernel*/
+
+#ifndef NO_UNDOC_CODE /* Un-documented FPU op-codes supported by
+ * default. */
+
+/* WARNING: These codes are not documented by Intel in their 80486 manual
+ and may not work on FPU clones or later Intel FPUs. */
+
+/* Changes to support the un-doc codes provided by Linus Torvalds. */
+
+#define _d9_d8_ fstp_i /* unofficial code (19) */
+#define _dc_d0_ fcom_st /* unofficial code (14) */
+#define _dc_d8_ fcompst /* unofficial code (1c) */
+#define _dd_c8_ fxch_i /* unofficial code (0d) */
+#define _de_d0_ fcompst /* unofficial code (16) */
+#define _df_c0_ ffreep /* unofficial code (07) ffree + pop */
+#define _df_c8_ fxch_i /* unofficial code (0f) */
+#define _df_d0_ fstp_i /* unofficial code (17) */
+#define _df_d8_ fstp_i /* unofficial code (1f) */
+
+static FUNC st_instr_table[64] = {
+ fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, _df_c0_,
+ fmul__, fxch_i, __BAD__, __BAD__, fmul_i, _dd_c8_, fmulp_, _df_c8_,
+ fcom_st, fp_nop, __BAD__, __BAD__, _dc_d0_, fst_i_, _de_d0_, _df_d0_,
+ fcompst, _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i, fcompp, _df_d8_,
+ fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
+ fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
+ fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
+ fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
+};
+#else /* Support only documented FPU op-codes */
+
+static FUNC st_instr_table[64] = {
+ fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__,
+ fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__,
+ fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__,
+ fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__,
+ fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
+ fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
+ fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
+ fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
+};
+#endif /* NO_UNDOC_CODE */
+
+
+#define _NONE_ 0 /* Take no special action */
+#define _REG0_ 1 /* Need to check for not empty st(0) */
+#define _REGI_ 2 /* Need to check for not empty st(0) and
+ * st(rm) */
+#define _REGi_ 0 /* Uses st(rm) */
+#define _PUSH_ 3 /* Need to check for space to push onto stack */
+#define _null_ 4 /* Function illegal or not implemented */
+#define _REGIi 5 /* Uses st(0) and st(rm), result to st(rm) */
+#define _REGIp 6 /* Uses st(0) and st(rm), result to st(rm)
+ * then pop */
+#define _REGIc 0 /* Compare st(0) and st(rm) */
+#define _REGIn 0 /* Uses st(0) and st(rm), but handle checks
+ * later */
+
+#ifndef NO_UNDOC_CODE
+
+/* Un-documented FPU op-codes supported by default. (see above) */
+
+static unsigned char type_table[64] = {
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_,
+ _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_,
+ _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
+ _REGIc, _REG0_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
+ _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
+ _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
+};
+#else /* Support only documented FPU op-codes */
+
+static unsigned char type_table[64] = {
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_,
+ _REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
+ _REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
+ _REGIc, _null_, _null_, _null_, _null_, _REG0_, _REGIc, _null_,
+ _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
+ _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
+};
+#endif /* NO_UNDOC_CODE */
+
+/* Be careful when using any of these global variables...
+ they might change if swapping is triggered */
+unsigned char FPU_rm;
+char FPU_st0_tag;
+FPU_REG *FPU_st0_ptr;
+
+#ifdef PARANOID
+char emulating = 0;
+#endif /* PARANOID */
+
+#define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x))
+#define math_abort(signo) \
+ FPU_EIP = FPU_ORIG_EIP;REENTRANT_CHECK(OFF);return(signo);
+
+int
+math_emulate(struct trapframe * tframe)
+{
+
+ unsigned char FPU_modrm;
+ unsigned short code;
+#ifdef LOOKAHEAD_LIMIT
+ int lookahead_limit = LOOKAHEAD_LIMIT;
+#endif
+#ifdef PARANOID
+ if (emulating) {
+ printf("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
+ }
+ REENTRANT_CHECK(ON);
+#endif /* PARANOID */
+
+ if ((((struct pcb *) curproc->p_addr)->pcb_flags & FP_SOFTFP) == 0) {
+ finit();
+ ((struct pcb *) curproc->p_addr)->pcb_flags |= FP_SOFTFP;
+ }
+ FPU_info = tframe;
+ FPU_ORIG_EIP = FPU_EIP; /* --pink-- */
+
+ if (FPU_CS != 0x001f) {
+ printf("math_emulate: %x : %x\n", FPU_CS, FPU_EIP);
+ panic("FPU emulation in kernel");
+ }
+#ifdef notyet
+ /* We cannot handle emulation in v86-mode */
+ if (FPU_EFLAGS & 0x00020000) {
+ FPU_ORIG_EIP = FPU_EIP;
+ math_abort(FPU_info, SIGILL);
+ }
+#endif
+
+ FPU_lookahead = FPU_LOOKAHEAD;
+#if notnow /* I dont know that much of traceing. Is it right? --pink-- */
+ if (curproc->p_flag & STRC)
+ FPU_lookahead = 0;
+#endif
+
+do_another_FPU_instruction:
+
+ REENTRANT_CHECK(OFF);
+ code = fuword((u_int *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ if ((code & 0xff) == 0x9b) { /* fwait */
+ if (status_word & SW_Summary)
+ goto do_the_FPU_interrupt;
+ else {
+ FPU_EIP++;
+ goto FPU_instruction_done;
+ }
+ }
+ if (status_word & SW_Summary) {
+ /* Ignore the error for now if the current instruction is a
+ * no-wait control instruction */
+ /* The 80486 manual contradicts itself on this topic, so I use
+ * the following list of such instructions until I can check
+ * on a real 80486: fninit, fnstenv, fnsave, fnstsw, fnstenv,
+ * fnclex. */
+ if (!((((code & 0xf803) == 0xe003) || /* fnclex, fninit,
+ * fnstsw */
+ (((code & 0x3003) == 0x3001) && /* fnsave, fnstcw,
+ * fnstenv, fnstsw */
+ ((code & 0xc000) != 0xc000))))) {
+ /* This is a guess about what a real FPU might do to
+ * this bit: */
+/* status_word &= ~SW_Summary; ****/
+
+ /* We need to simulate the action of the kernel to FPU
+ * interrupts here. Currently, the "real FPU" part of
+ * the kernel (0.99.10) clears the exception flags,
+ * sets the registers to empty, and passes information
+ * back to the interrupted process via the cs selector
+ * and operand selector, so we do the same. */
+ do_the_FPU_interrupt:
+ cs_selector &= 0xffff0000;
+ cs_selector |= (status_word & ~SW_Top) | ((top & 7) << SW_Top_Shift);
+ operand_selector = tag_word();
+ status_word = 0;
+ top = 0;
+ {
+ int r;
+ for (r = 0; r < 8; r++) {
+ regs[r].tag = TW_Empty;
+ }
+ }
+ REENTRANT_CHECK(OFF);
+ math_abort(SIGFPE);
+ }
+ }
+ FPU_entry_eip = FPU_ORIG_EIP = FPU_EIP;
+
+ if ((code & 0xff) == 0x66) { /* size prefix */
+ FPU_EIP++;
+ REENTRANT_CHECK(OFF);
+ code = fuword((u_int *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ }
+ FPU_EIP += 2;
+
+ FPU_modrm = code >> 8;
+ FPU_rm = FPU_modrm & 7;
+
+ if (FPU_modrm < 0300) {
+ /* All of these instructions use the mod/rm byte to get a data
+ * address */
+ get_address(FPU_modrm);
+ if (!(code & 1)) {
+ unsigned short status1 = status_word;
+ FPU_st0_ptr = &st(0);
+ FPU_st0_tag = FPU_st0_ptr->tag;
+
+ /* Stack underflow has priority */
+ if (NOT_EMPTY_0) {
+ switch ((code >> 1) & 3) {
+ case 0:
+ reg_load_single();
+ break;
+ case 1:
+ reg_load_int32();
+ break;
+ case 2:
+ reg_load_double();
+ break;
+ case 3:
+ reg_load_int16();
+ break;
+ }
+
+ /* No more access to user memory, it is safe
+ * to use static data now */
+ FPU_st0_ptr = &st(0);
+ FPU_st0_tag = FPU_st0_ptr->tag;
+
+ /* NaN operands have the next priority. */
+ /* We have to delay looking at st(0) until
+ * after loading the data, because that data
+ * might contain an SNaN */
+ if ((FPU_st0_tag == TW_NaN) ||
+ (FPU_loaded_data.tag == TW_NaN)) {
+ /* Restore the status word; we might
+ * have loaded a denormal. */
+ status_word = status1;
+ if ((FPU_modrm & 0x30) == 0x10) {
+ /* fcom or fcomp */
+ EXCEPTION(EX_Invalid);
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ if (FPU_modrm & 0x08)
+ pop(); /* fcomp, so we pop. */
+ } else
+ real_2op_NaN(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr);
+ goto reg_mem_instr_done;
+ }
+ switch ((FPU_modrm >> 3) & 7) {
+ case 0: /* fadd */
+ reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, control_word);
+ break;
+ case 1: /* fmul */
+ reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, control_word);
+ break;
+ case 2: /* fcom */
+ compare_st_data();
+ break;
+ case 3: /* fcomp */
+ compare_st_data();
+ pop();
+ break;
+ case 4: /* fsub */
+ reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, control_word);
+ break;
+ case 5: /* fsubr */
+ reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr, control_word);
+ break;
+ case 6: /* fdiv */
+ reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, control_word);
+ break;
+ case 7: /* fdivr */
+ if (FPU_st0_tag == TW_Zero)
+ status_word = status1; /* Undo any denorm tag,
+ * zero-divide has
+ * priority. */
+ reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr, control_word);
+ break;
+ }
+ } else {
+ if ((FPU_modrm & 0x30) == 0x10) {
+ /* The instruction is fcom or fcomp */
+ EXCEPTION(EX_StackUnder);
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ if (FPU_modrm & 0x08)
+ pop(); /* fcomp, Empty or not,
+ * we pop. */
+ } else
+ stack_underflow();
+ }
+ } else {
+ load_store_instr(((FPU_modrm & 0x38) | (code & 6)) >> 1);
+ }
+
+reg_mem_instr_done:
+
+ data_operand_offset = (unsigned long) FPU_data_address;
+ } else {
+ /* None of these instructions access user memory */
+ unsigned char instr_index = (FPU_modrm & 0x38) | (code & 7);
+
+ FPU_st0_ptr = &st(0);
+ FPU_st0_tag = FPU_st0_ptr->tag;
+ switch (type_table[(int) instr_index]) {
+ case _NONE_: /* also _REGIc: _REGIn */
+ break;
+ case _REG0_:
+ if (!NOT_EMPTY_0) {
+ stack_underflow();
+ goto FPU_instruction_done;
+ }
+ break;
+ case _REGIi:
+ if (!NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm)) {
+ stack_underflow_i(FPU_rm);
+ goto FPU_instruction_done;
+ }
+ break;
+ case _REGIp:
+ if (!NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm)) {
+ stack_underflow_i(FPU_rm);
+ pop();
+ goto FPU_instruction_done;
+ }
+ break;
+ case _REGI_:
+ if (!NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm)) {
+ stack_underflow();
+ goto FPU_instruction_done;
+ }
+ break;
+ case _PUSH_: /* Only used by the fld st(i) instruction */
+ break;
+ case _null_:
+ Un_impl();
+ goto FPU_instruction_done;
+ default:
+ EXCEPTION(EX_INTERNAL | 0x111);
+ goto FPU_instruction_done;
+ }
+ (*st_instr_table[(int) instr_index]) ();
+ }
+
+FPU_instruction_done:
+
+ ip_offset = FPU_entry_eip;
+ bswapw(code);
+ *(1 + (unsigned short *) &cs_selector) = code & 0x7ff;
+
+#ifdef DEBUG
+ REENTRANT_CHECK(OFF);
+ emu_printall();
+ REENTRANT_CHECK(ON);
+#endif /* DEBUG */
+#ifdef LOOKAHEAD_LIMIT
+if (--lookahead_limit)
+#endif
+ if (FPU_lookahead) {
+ unsigned char next;
+
+ /* (This test should generate no machine code) */
+ while (1) {
+ REENTRANT_CHECK(OFF);
+ next = fubyte((u_char *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ if (((next & 0xf8) == 0xd8) || (next == 0x9b)) { /* fwait */
+ goto do_another_FPU_instruction;
+ } else
+ if (next == 0x66) { /* size prefix */
+ REENTRANT_CHECK(OFF);
+ next = fubyte((u_char *) (FPU_EIP + 1));
+ REENTRANT_CHECK(ON);
+ if ((next & 0xf8) == 0xd8) {
+ FPU_EIP++;
+ goto do_another_FPU_instruction;
+ }
+ }
+ break;
+ }
+ }
+ REENTRANT_CHECK(OFF);
+ return (0); /* --pink-- */
+}
diff --git a/sys/gnu/i386/fpemul/fpu_etc.c b/sys/gnu/i386/fpemul/fpu_etc.c
new file mode 100644
index 0000000..f041b43
--- /dev/null
+++ b/sys/gnu/i386/fpemul/fpu_etc.c
@@ -0,0 +1,165 @@
+/*
+ * fpu_etc.c
+ *
+ * Implement a few FPU instructions.
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+#include "param.h"
+#include "proc.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+#include "status_w.h"
+#include "reg_constant.h"
+
+
+static void
+fchs(void)
+{
+ if (NOT_EMPTY_0) {
+ FPU_st0_ptr->sign ^= SIGN_POS ^ SIGN_NEG;
+ status_word &= ~SW_C1;
+ } else
+ stack_underflow();
+}
+
+static void
+fabs(void)
+{
+ if (FPU_st0_tag ^ TW_Empty) {
+ FPU_st0_ptr->sign = SIGN_POS;
+ status_word &= ~SW_C1;
+ } else
+ stack_underflow();
+}
+
+
+static void
+ftst_(void)
+{
+ switch (FPU_st0_tag) {
+ case TW_Zero:
+ setcc(SW_C3);
+ break;
+ case TW_Valid:
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if (FPU_st0_ptr->sign == SIGN_POS)
+ setcc(0);
+ else
+ setcc(SW_C0);
+ break;
+ case TW_NaN:
+ setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */
+ EXCEPTION(EX_Invalid);
+ break;
+ case TW_Infinity:
+ if (FPU_st0_ptr->sign == SIGN_POS)
+ setcc(0);
+ else
+ setcc(SW_C0);
+ EXCEPTION(EX_Invalid);
+ break;
+ case TW_Empty:
+ setcc(SW_C0 | SW_C2 | SW_C3);
+ EXCEPTION(EX_StackUnder);
+ break;
+ default:
+ setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */
+ EXCEPTION(EX_INTERNAL | 0x14);
+ break;
+ }
+}
+
+static void
+fxam(void)
+{
+ int c = 0;
+ switch (FPU_st0_tag) {
+ case TW_Empty:
+ c = SW_C3 | SW_C0;
+ break;
+ case TW_Zero:
+ c = SW_C3;
+ break;
+ case TW_Valid:
+ /* This will need to be changed if TW_Denormal is ever used. */
+ if (FPU_st0_ptr->exp <= EXP_UNDER)
+ c = SW_C2 | SW_C3; /* Denormal */
+ else
+ c = SW_C3;
+ break;
+ case TW_NaN:
+ c = SW_C0;
+ break;
+ case TW_Infinity:
+ c = SW_C2 | SW_C0;
+ break;
+ }
+ if (FPU_st0_ptr->sign == SIGN_NEG)
+ c |= SW_C1;
+ setcc(c);
+}
+
+static FUNC fp_etc_table[] = {
+ fchs, fabs, Un_impl, Un_impl, ftst_, fxam, Un_impl, Un_impl
+};
+
+void
+fp_etc()
+{
+ (fp_etc_table[FPU_rm]) ();
+}
diff --git a/sys/gnu/i386/fpemul/fpu_proto.h b/sys/gnu/i386/fpemul/fpu_proto.h
new file mode 100644
index 0000000..255aa5d
--- /dev/null
+++ b/sys/gnu/i386/fpemul/fpu_proto.h
@@ -0,0 +1,115 @@
+/*
+ *
+ * $Id:$
+ *
+ */
+
+
+/* errors.c */
+extern void Un_impl(void);
+extern void emu_printall(void);
+extern void exception(int n);
+extern void real_2op_NaN(FPU_REG * a, FPU_REG * b, FPU_REG * dest);
+extern void arith_invalid(FPU_REG * dest);
+extern void divide_by_zero(int sign, FPU_REG * dest);
+extern void set_precision_flag_up(void);
+extern void set_precision_flag_down(void);
+extern int denormal_operand(void);
+extern void arith_overflow(FPU_REG * dest);
+extern void arith_underflow(FPU_REG * dest);
+extern void stack_overflow(void);
+extern void stack_underflow(void);
+extern void stack_underflow_i(int i);
+extern void stack_underflow_pop(int i);
+/* fpu_arith.c */
+extern void fadd__(void);
+extern void fmul__(void);
+extern void fsub__(void);
+extern void fsubr_(void);
+extern void fdiv__(void);
+extern void fdivr_(void);
+extern void fadd_i(void);
+extern void fmul_i(void);
+extern void fsubri(void);
+extern void fsub_i(void);
+extern void fdivri(void);
+extern void fdiv_i(void);
+extern void faddp_(void);
+extern void fmulp_(void);
+extern void fsubrp(void);
+extern void fsubp_(void);
+extern void fdivrp(void);
+extern void fdivp_(void);
+/* fpu_aux.c */
+extern void fclex(void);
+extern void finit(void);
+extern void finit_(void);
+extern void fstsw_(void);
+extern void fp_nop(void);
+extern void fld_i_(void);
+extern void fxch_i(void);
+extern void ffree_(void);
+extern void ffreep(void);
+extern void fst_i_(void);
+extern void fstp_i(void);
+/* fpu_entry.c */
+extern int math_emulate(struct trapframe * info);
+/* fpu_etc.c */
+extern void fp_etc(void);
+/* fpu_trig.c */
+extern void convert_l2reg(long *arg, FPU_REG * dest);
+extern void trig_a(void);
+extern void trig_b(void);
+/* get_address.c */
+extern void get_address(unsigned char FPU_modrm);
+/* load_store.c */
+extern void load_store_instr(char type);
+/* poly_2xm1.c */
+extern int poly_2xm1(FPU_REG * arg, FPU_REG * result);
+/* poly_atan.c */
+extern void poly_atan(FPU_REG * arg);
+extern void poly_add_1(FPU_REG * src);
+/* poly_l2.c */
+extern void poly_l2(FPU_REG * arg, FPU_REG * result);
+extern int poly_l2p1(FPU_REG * arg, FPU_REG * result);
+/* poly_sin.c */
+extern void poly_sine(FPU_REG * arg, FPU_REG * result);
+/* poly_tan.c */
+extern void poly_tan(FPU_REG * arg, FPU_REG * y_reg);
+/* reg_add_sub.c */
+extern void reg_add(FPU_REG * a, FPU_REG * b, FPU_REG * dest, int control_w);
+extern void reg_sub(FPU_REG * a, FPU_REG * b, FPU_REG * dest, int control_w);
+/* reg_compare.c */
+extern int compare(FPU_REG * b);
+extern int compare_st_data(void);
+extern void fcom_st(void);
+extern void fcompst(void);
+extern void fcompp(void);
+extern void fucom_(void);
+extern void fucomp(void);
+extern void fucompp(void);
+/* reg_constant.c */
+extern void fconst(void);
+/* reg_ld_str.c */
+extern void reg_load_extended(void);
+extern void reg_load_double(void);
+extern void reg_load_single(void);
+extern void reg_load_int64(void);
+extern void reg_load_int32(void);
+extern void reg_load_int16(void);
+extern void reg_load_bcd(void);
+extern int reg_store_extended(void);
+extern int reg_store_double(void);
+extern int reg_store_single(void);
+extern int reg_store_int64(void);
+extern int reg_store_int32(void);
+extern int reg_store_int16(void);
+extern int reg_store_bcd(void);
+extern int round_to_int(FPU_REG * r);
+extern char *fldenv(void);
+extern void frstor(void);
+extern unsigned short tag_word(void);
+extern char *fstenv(void);
+extern void fsave(void);
+/* reg_mul.c */
+extern void reg_mul(FPU_REG * a, FPU_REG * b, FPU_REG * dest, unsigned int control_w);
diff --git a/sys/gnu/i386/fpemul/fpu_system.h b/sys/gnu/i386/fpemul/fpu_system.h
new file mode 100644
index 0000000..d8fdd61
--- /dev/null
+++ b/sys/gnu/i386/fpemul/fpu_system.h
@@ -0,0 +1,87 @@
+/*
+ * fpu_system.h
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+
+#ifndef _FPU_SYSTEM_H
+#define _FPU_SYSTEM_H
+
+/* system dependent definitions */
+
+/*
+#include <linux/sched.h>
+#include <linux/kernel.h>
+*/
+
+#define I387 (*(union i387_union *)&(((struct pcb *)curproc->p_addr)->pcb_savefpu))
+#define FPU_info (I387.soft.frame)
+
+#define FPU_CS (*(unsigned short *) &(FPU_info->tf_cs))
+#define FPU_DS (*(unsigned short *) &(FPU_info->tf_ds))
+#define FPU_EAX (FPU_info->tf_eax)
+#define FPU_EFLAGS (FPU_info->tf_eflags)
+#define FPU_EIP (FPU_info->tf_eip)
+/*#define FPU_ORIG_EIP (FPU_info->___orig_eip) */
+/*#define FPU_ORIG_EIP (FPU_info->tf_isp)*/
+#define FPU_ORIG_EIP (I387.soft.orig_eip)
+
+#define FPU_lookahead (I387.soft.lookahead)
+#define FPU_entry_eip (I387.soft.entry_eip)
+
+#define status_word (I387.soft.swd)
+#define control_word (I387.soft.cwd)
+#define regs (I387.soft.regs)
+#define top (I387.soft.top)
+
+#define ip_offset (I387.soft.fip)
+#define cs_selector (I387.soft.fcs)
+#define data_operand_offset (I387.soft.foo)
+#define operand_selector (I387.soft.fos)
+
+#endif
diff --git a/sys/gnu/i386/fpemul/fpu_trig.c b/sys/gnu/i386/fpemul/fpu_trig.c
new file mode 100644
index 0000000..e217510
--- /dev/null
+++ b/sys/gnu/i386/fpemul/fpu_trig.c
@@ -0,0 +1,1357 @@
+/*
+ * fpu_trig.c
+ *
+ * Implementation of the FPU "transcendental" functions.
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+
+#include "param.h"
+#include "proc.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+#include "status_w.h"
+#include "reg_constant.h"
+#include "control_w.h"
+
+static int
+trig_arg(FPU_REG * X)
+{
+ FPU_REG tmp, quot;
+ int rv;
+ long long q;
+ int old_cw = control_word;
+
+ control_word &= ~CW_RC;
+ control_word |= RC_CHOP;
+
+ reg_move(X, &quot);
+ reg_div(&quot, &CONST_PI2, &quot, FULL_PRECISION);
+
+ reg_move(&quot, &tmp);
+ round_to_int(&tmp);
+ if (tmp.sigh & 0x80000000)
+ return -1; /* |Arg| is >= 2^63 */
+ tmp.exp = EXP_BIAS + 63;
+ q = *(long long *) &(tmp.sigl);
+ normalize(&tmp);
+
+ reg_sub(&quot, &tmp, X, FULL_PRECISION);
+ rv = q & 7;
+
+ control_word = old_cw;
+ return rv;;
+}
+
+
+/* Convert a long to register */
+void
+convert_l2reg(long *arg, FPU_REG * dest)
+{
+ long num = *arg;
+
+ if (num == 0) {
+ reg_move(&CONST_Z, dest);
+ return;
+ }
+ if (num > 0)
+ dest->sign = SIGN_POS;
+ else {
+ num = -num;
+ dest->sign = SIGN_NEG;
+ }
+
+ dest->sigh = num;
+ dest->sigl = 0;
+ dest->exp = EXP_BIAS + 31;
+ dest->tag = TW_Valid;
+ normalize(dest);
+}
+
+
+static void
+single_arg_error(void)
+{
+ switch (FPU_st0_tag) {
+ case TW_NaN:
+ if (!(FPU_st0_ptr->sigh & 0x40000000)) { /* Signaling ? */
+ EXCEPTION(EX_Invalid);
+ /* Convert to a QNaN */
+ FPU_st0_ptr->sigh |= 0x40000000;
+ }
+ break; /* return with a NaN in st(0) */
+ case TW_Empty:
+ stack_underflow(); /* Puts a QNaN in st(0) */
+ break;
+#ifdef PARANOID
+ default:
+ EXCEPTION(EX_INTERNAL | 0x0112);
+#endif /* PARANOID */
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+static void
+f2xm1(void)
+{
+ switch (FPU_st0_tag) {
+ case TW_Valid:
+ {
+ FPU_REG rv, tmp;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if (FPU_st0_ptr->sign == SIGN_POS) {
+ /* poly_2xm1(x) requires 0 < x < 1. */
+ if (poly_2xm1(FPU_st0_ptr, &rv))
+ return; /* error */
+ reg_mul(&rv, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
+ } else {
+/* **** Should change poly_2xm1() to at least handle numbers near 0 */
+ /* poly_2xm1(x) doesn't handle negative
+ * numbers. */
+ /* So we compute (poly_2xm1(x+1)-1)/2, for -1
+ * < x < 0 */
+ reg_add(FPU_st0_ptr, &CONST_1, &tmp, FULL_PRECISION);
+ poly_2xm1(&tmp, &rv);
+ reg_mul(&rv, &tmp, &tmp, FULL_PRECISION);
+ reg_sub(&tmp, &CONST_1, FPU_st0_ptr, FULL_PRECISION);
+ FPU_st0_ptr->exp--;
+ if (FPU_st0_ptr->exp <= EXP_UNDER)
+ arith_underflow(FPU_st0_ptr);
+ }
+ return;
+ }
+ case TW_Zero:
+ return;
+ case TW_Infinity:
+ if (FPU_st0_ptr->sign == SIGN_NEG) {
+ /* -infinity gives -1 (p16-10) */
+ reg_move(&CONST_1, FPU_st0_ptr);
+ FPU_st0_ptr->sign = SIGN_NEG;
+ }
+ return;
+ default:
+ single_arg_error();
+ }
+}
+
+static void
+fptan(void)
+{
+ FPU_REG *st_new_ptr;
+ int q;
+ char arg_sign = FPU_st0_ptr->sign;
+
+ if (STACK_OVERFLOW) {
+ stack_overflow();
+ return;
+ }
+ switch (FPU_st0_tag) {
+ case TW_Valid:
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ FPU_st0_ptr->sign = SIGN_POS;
+ if ((q = trig_arg(FPU_st0_ptr)) != -1) {
+ if (q & 1)
+ reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
+
+ poly_tan(FPU_st0_ptr, FPU_st0_ptr);
+
+ FPU_st0_ptr->sign = (q & 1) ^ arg_sign;
+
+ if (FPU_st0_ptr->exp <= EXP_UNDER)
+ arith_underflow(FPU_st0_ptr);
+
+ push();
+ reg_move(&CONST_1, FPU_st0_ptr);
+ setcc(0);
+ } else {
+ /* Operand is out of range */
+ setcc(SW_C2);
+ FPU_st0_ptr->sign = arg_sign; /* restore st(0) */
+ return;
+ }
+ break;
+ case TW_Infinity:
+ /* Operand is out of range */
+ setcc(SW_C2);
+ FPU_st0_ptr->sign = arg_sign; /* restore st(0) */
+ return;
+ case TW_Zero:
+ push();
+ reg_move(&CONST_1, FPU_st0_ptr);
+ setcc(0);
+ break;
+ default:
+ single_arg_error();
+ break;
+ }
+}
+
+
+static void
+fxtract(void)
+{
+ FPU_REG *st_new_ptr;
+ register FPU_REG *st1_ptr = FPU_st0_ptr; /* anticipate */
+
+ if (STACK_OVERFLOW) {
+ stack_overflow();
+ return;
+ }
+ if (!(FPU_st0_tag ^ TW_Valid)) {
+ long e;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ push();
+ reg_move(st1_ptr, FPU_st0_ptr);
+ FPU_st0_ptr->exp = EXP_BIAS;
+ e = st1_ptr->exp - EXP_BIAS;
+ convert_l2reg(&e, st1_ptr);
+ return;
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ char sign = FPU_st0_ptr->sign;
+ divide_by_zero(SIGN_NEG, FPU_st0_ptr);
+ push();
+ reg_move(&CONST_Z, FPU_st0_ptr);
+ FPU_st0_ptr->sign = sign;
+ return;
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ char sign = FPU_st0_ptr->sign;
+ FPU_st0_ptr->sign = SIGN_POS;
+ push();
+ reg_move(&CONST_INF, FPU_st0_ptr);
+ FPU_st0_ptr->sign = sign;
+ return;
+ } else
+ if (FPU_st0_tag == TW_NaN) {
+ if (!(FPU_st0_ptr->sigh & 0x40000000)) { /* Signaling ? */
+ EXCEPTION(EX_Invalid);
+ /* Convert to a QNaN */
+ FPU_st0_ptr->sigh |= 0x40000000;
+ }
+ push();
+ reg_move(st1_ptr, FPU_st0_ptr);
+ return;
+ } else
+ if (FPU_st0_tag == TW_Empty) {
+ /* Is this the correct
+ * behaviour? */
+ if (control_word & EX_Invalid) {
+ stack_underflow();
+ push();
+ stack_underflow();
+ } else
+ EXCEPTION(EX_StackUnder);
+ }
+#ifdef PARANOID
+ else
+ EXCEPTION(EX_INTERNAL | 0x119);
+#endif /* PARANOID */
+}
+
+
+static void
+fdecstp(void)
+{
+ top--; /* FPU_st0_ptr will be fixed in math_emulate()
+ * before the next instr */
+}
+
+static void
+fincstp(void)
+{
+ top++; /* FPU_st0_ptr will be fixed in math_emulate()
+ * before the next instr */
+}
+
+
+static void
+fsqrt_(void)
+{
+ if (!(FPU_st0_tag ^ TW_Valid)) {
+ int expon;
+
+ if (FPU_st0_ptr->sign == SIGN_NEG) {
+ arith_invalid(FPU_st0_ptr); /* sqrt(negative) is
+ * invalid */
+ return;
+ }
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ expon = FPU_st0_ptr->exp - EXP_BIAS;
+ FPU_st0_ptr->exp = EXP_BIAS + (expon & 1); /* make st(0) in [1.0
+ * .. 4.0) */
+
+ wm_sqrt(FPU_st0_ptr, control_word); /* Do the computation */
+
+ FPU_st0_ptr->exp += expon >> 1;
+ FPU_st0_ptr->sign = SIGN_POS;
+ } else
+ if (FPU_st0_tag == TW_Zero)
+ return;
+ else
+ if (FPU_st0_tag == TW_Infinity) {
+ if (FPU_st0_ptr->sign == SIGN_NEG)
+ arith_invalid(FPU_st0_ptr); /* sqrt(-Infinity) is
+ * invalid */
+ return;
+ } else {
+ single_arg_error();
+ return;
+ }
+
+}
+
+
+static void
+frndint_(void)
+{
+ if (!(FPU_st0_tag ^ TW_Valid)) {
+ if (FPU_st0_ptr->exp > EXP_BIAS + 63)
+ return;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ round_to_int(FPU_st0_ptr); /* Fortunately, this can't
+ * overflow to 2^64 */
+ FPU_st0_ptr->exp = EXP_BIAS + 63;
+ normalize(FPU_st0_ptr);
+ return;
+ } else
+ if ((FPU_st0_tag == TW_Zero) || (FPU_st0_tag == TW_Infinity))
+ return;
+ else
+ single_arg_error();
+}
+
+
+static void
+fsin(void)
+{
+ char arg_sign = FPU_st0_ptr->sign;
+
+ if (FPU_st0_tag == TW_Valid) {
+ int q;
+ FPU_st0_ptr->sign = SIGN_POS;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if ((q = trig_arg(FPU_st0_ptr)) != -1) {
+ FPU_REG rv;
+
+ if (q & 1)
+ reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
+
+ poly_sine(FPU_st0_ptr, &rv);
+
+ setcc(0);
+ if (q & 2)
+ rv.sign ^= SIGN_POS ^ SIGN_NEG;
+ rv.sign ^= arg_sign;
+ reg_move(&rv, FPU_st0_ptr);
+
+ if (FPU_st0_ptr->exp <= EXP_UNDER)
+ arith_underflow(FPU_st0_ptr);
+
+ set_precision_flag_up(); /* We do not really know
+ * if up or down */
+
+ return;
+ } else {
+ /* Operand is out of range */
+ setcc(SW_C2);
+ FPU_st0_ptr->sign = arg_sign; /* restore st(0) */
+ return;
+ }
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ setcc(0);
+ return;
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ /* Operand is out of range */
+ setcc(SW_C2);
+ FPU_st0_ptr->sign = arg_sign; /* restore st(0) */
+ return;
+ } else
+ single_arg_error();
+}
+
+
+static int
+f_cos(FPU_REG * arg)
+{
+ char arg_sign = arg->sign;
+
+ if (arg->tag == TW_Valid) {
+ int q;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return 1;
+#endif /* DENORM_OPERAND */
+
+ arg->sign = SIGN_POS;
+ if ((q = trig_arg(arg)) != -1) {
+ FPU_REG rv;
+
+ if (!(q & 1))
+ reg_sub(&CONST_1, arg, arg, FULL_PRECISION);
+
+ poly_sine(arg, &rv);
+
+ setcc(0);
+ if ((q + 1) & 2)
+ rv.sign ^= SIGN_POS ^ SIGN_NEG;
+ reg_move(&rv, arg);
+
+ set_precision_flag_up(); /* We do not really know
+ * if up or down */
+
+ return 0;
+ } else {
+ /* Operand is out of range */
+ setcc(SW_C2);
+ arg->sign = arg_sign; /* restore st(0) */
+ return 1;
+ }
+ } else
+ if (arg->tag == TW_Zero) {
+ reg_move(&CONST_1, arg);
+ setcc(0);
+ return 0;
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ /* Operand is out of range */
+ setcc(SW_C2);
+ arg->sign = arg_sign; /* restore st(0) */
+ return 1;
+ } else {
+ single_arg_error(); /* requires arg ==
+ * &st(0) */
+ return 1;
+ }
+}
+
+
+static void
+fcos(void)
+{
+ f_cos(FPU_st0_ptr);
+}
+
+
+static void
+fsincos(void)
+{
+ FPU_REG *st_new_ptr;
+ FPU_REG arg;
+
+ if (STACK_OVERFLOW) {
+ stack_overflow();
+ return;
+ }
+ reg_move(FPU_st0_ptr, &arg);
+ if (!f_cos(&arg)) {
+ fsin();
+ push();
+ reg_move(&arg, FPU_st0_ptr);
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+/* The following all require two arguments: st(0) and st(1) */
+
+/* remainder of st(0) / st(1) */
+/* Assumes that st(0) and st(1) are both TW_Valid */
+static void
+fprem_kernel(int round)
+{
+ FPU_REG *st1_ptr = &st(1);
+ char st1_tag = st1_ptr->tag;
+
+ if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
+ FPU_REG tmp;
+ int old_cw = control_word;
+ int expdif = FPU_st0_ptr->exp - (st1_ptr)->exp;
+
+#ifdef DENORM_OPERAND
+ if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
+ (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ control_word &= ~CW_RC;
+ control_word |= round;
+
+ if (expdif < 64) {
+ /* This should be the most common case */
+ long long q;
+ int c = 0;
+
+ reg_div(FPU_st0_ptr, st1_ptr, &tmp, FULL_PRECISION);
+
+ round_to_int(&tmp); /* Fortunately, this can't
+ * overflow to 2^64 */
+ tmp.exp = EXP_BIAS + 63;
+ q = *(long long *) &(tmp.sigl);
+ normalize(&tmp);
+
+ reg_mul(st1_ptr, &tmp, &tmp, FULL_PRECISION);
+ reg_sub(FPU_st0_ptr, &tmp, FPU_st0_ptr, FULL_PRECISION);
+
+ if (q & 4)
+ c |= SW_C3;
+ if (q & 2)
+ c |= SW_C1;
+ if (q & 1)
+ c |= SW_C0;
+
+ setcc(c);
+ } else {
+ /* There is a large exponent difference ( >= 64 ) */
+ int N_exp;
+
+ reg_div(FPU_st0_ptr, st1_ptr, &tmp, FULL_PRECISION);
+ /* N is 'a number between 32 and 63' (p26-113) */
+ N_exp = (tmp.exp & 31) + 32;
+ tmp.exp = EXP_BIAS + N_exp;
+
+ round_to_int(&tmp); /* Fortunately, this can't
+ * overflow to 2^64 */
+ tmp.exp = EXP_BIAS + 63;
+ normalize(&tmp);
+
+ tmp.exp = EXP_BIAS + expdif - N_exp;
+
+ reg_mul(st1_ptr, &tmp, &tmp, FULL_PRECISION);
+ reg_sub(FPU_st0_ptr, &tmp, FPU_st0_ptr, FULL_PRECISION);
+
+ setcc(SW_C2);
+ }
+ control_word = old_cw;
+
+ if (FPU_st0_ptr->exp <= EXP_UNDER)
+ arith_underflow(FPU_st0_ptr);
+ return;
+ } else
+ if ((FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty)) {
+ stack_underflow();
+ return;
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ if (st1_tag == TW_Valid) {
+
+#ifdef DENORM_OPERAND
+ if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ setcc(0);
+ return;
+ } else
+ if (st1_tag == TW_Zero) {
+ arith_invalid(FPU_st0_ptr);
+ return;
+ }
+ /* fprem(?,0) always invalid */
+ else
+ if (st1_tag == TW_Infinity) {
+ setcc(0);
+ return;
+ }
+ } else
+ if (FPU_st0_tag == TW_Valid) {
+ if (st1_tag == TW_Zero) {
+ arith_invalid(FPU_st0_ptr); /* fprem(Valid,Zero) is
+ * invalid */
+ return;
+ } else
+ if (st1_tag != TW_NaN) {
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if (st1_tag == TW_Infinity) {
+ /* fprem(Valid,
+ * Infinity)
+ * is o.k. */
+ setcc(0);
+ return;
+ }
+ }
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ if (st1_tag != TW_NaN) {
+ arith_invalid(FPU_st0_ptr); /* fprem(Infinity,?) is
+ * invalid */
+ return;
+ }
+ }
+ /* One of the registers must contain a NaN is we got here. */
+
+#ifdef PARANOID
+ if ((FPU_st0_tag != TW_NaN) && (st1_tag != TW_NaN))
+ EXCEPTION(EX_INTERNAL | 0x118);
+#endif /* PARANOID */
+
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
+
+}
+
+
+/* ST(1) <- ST(1) * log ST; pop ST */
+static void
+fyl2x(void)
+{
+ FPU_REG *st1_ptr = &st(1);
+ char st1_tag = st1_ptr->tag;
+
+ if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
+ if (FPU_st0_ptr->sign == SIGN_POS) {
+ int saved_control, saved_status;
+
+#ifdef DENORM_OPERAND
+ if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
+ (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ /* We use the general purpose arithmetic, so we need
+ * to save these. */
+ saved_status = status_word;
+ saved_control = control_word;
+ control_word = FULL_PRECISION;
+
+ poly_l2(FPU_st0_ptr, FPU_st0_ptr);
+
+ /* Enough of the basic arithmetic is done now */
+ control_word = saved_control;
+ status_word = saved_status;
+
+ /* Let the multiply set the flags */
+ reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION);
+
+ pop();
+ FPU_st0_ptr = &st(0);
+ } else {
+ /* negative */
+ pop();
+ FPU_st0_ptr = &st(0);
+ arith_invalid(FPU_st0_ptr); /* st(0) cannot be
+ * negative */
+ return;
+ }
+ } else
+ if ((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty)) {
+ stack_underflow_pop(1);
+ return;
+ } else
+ if ((FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
+ pop();
+ return;
+ } else
+ if ((FPU_st0_tag <= TW_Zero) && (st1_tag <= TW_Zero)) {
+ /* one of the args is zero, the other
+ * valid, or both zero */
+ if (FPU_st0_tag == TW_Zero) {
+ pop();
+ FPU_st0_ptr = &st(0);
+ if (FPU_st0_ptr->tag == TW_Zero)
+ arith_invalid(FPU_st0_ptr); /* Both args zero is
+ * invalid */
+#ifdef PECULIAR_486
+ /* This case is not
+ * specifically covered in the
+ * manual, but divide-by-zero
+ * would seem to be the best
+ * response. However, a real
+ * 80486 does it this way... */
+ else
+ if (FPU_st0_ptr->tag == TW_Infinity) {
+ reg_move(&CONST_INF, FPU_st0_ptr);
+ return;
+ }
+#endif /* PECULIAR_486 */
+ else
+ divide_by_zero(st1_ptr->sign ^ SIGN_NEG ^ SIGN_POS, FPU_st0_ptr);
+ return;
+ } else {
+ /* st(1) contains zero, st(0)
+ * valid <> 0 */
+ /* Zero is the valid answer */
+ char sign = st1_ptr->sign;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+ if (FPU_st0_ptr->sign == SIGN_NEG) {
+ pop();
+ FPU_st0_ptr = &st(0);
+ arith_invalid(FPU_st0_ptr); /* log(negative) */
+ return;
+ }
+ if (FPU_st0_ptr->exp < EXP_BIAS)
+ sign ^= SIGN_NEG ^ SIGN_POS;
+ pop();
+ FPU_st0_ptr = &st(0);
+ reg_move(&CONST_Z, FPU_st0_ptr);
+ FPU_st0_ptr->sign = sign;
+ return;
+ }
+ }
+ /* One or both arg must be an infinity */
+ else
+ if (FPU_st0_tag == TW_Infinity) {
+ if ((FPU_st0_ptr->sign == SIGN_NEG) || (st1_tag == TW_Zero)) {
+ pop();
+ FPU_st0_ptr = &st(0);
+ arith_invalid(FPU_st0_ptr); /* log(-infinity) or
+ * 0*log(infinity) */
+ return;
+ } else {
+ char sign = st1_ptr->sign;
+
+#ifdef DENORM_OPERAND
+ if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ pop();
+ FPU_st0_ptr = &st(0);
+ reg_move(&CONST_INF, FPU_st0_ptr);
+ FPU_st0_ptr->sign = sign;
+ return;
+ }
+ }
+ /* st(1) must be infinity here */
+ else
+ if ((FPU_st0_tag == TW_Valid) && (FPU_st0_ptr->sign == SIGN_POS)) {
+ if (FPU_st0_ptr->exp >= EXP_BIAS) {
+ if ((FPU_st0_ptr->exp == EXP_BIAS) &&
+ (FPU_st0_ptr->sigh == 0x80000000) &&
+ (FPU_st0_ptr->sigl == 0)) {
+ /* st(0
+ * )
+ * hold
+ * s
+ * 1.0 */
+ pop();
+ FPU_st0_ptr = &st(0);
+ arith_invalid(FPU_st0_ptr); /* infinity*log(1) */
+ return;
+ }
+ /* st(0) is
+ * positive
+ * and > 1.0 */
+ pop();
+ } else {
+ /* st(0) is
+ * positive
+ * and < 1.0 */
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ st1_ptr->sign ^= SIGN_NEG;
+ pop();
+ }
+ return;
+ } else {
+ /* st(0) must be zero
+ * or negative */
+ if (FPU_st0_ptr->tag == TW_Zero) {
+ pop();
+ FPU_st0_ptr = st1_ptr;
+ st1_ptr->sign ^= SIGN_NEG ^ SIGN_POS;
+ /* This should
+ * be invalid,
+ * but a real
+ * 80486 is
+ * happy with
+ * it. */
+#ifndef PECULIAR_486
+ divide_by_zero(st1_ptr->sign, FPU_st0_ptr);
+#endif /* PECULIAR_486 */
+ } else {
+ pop();
+ FPU_st0_ptr = st1_ptr;
+ arith_invalid(FPU_st0_ptr); /* log(negative) */
+ }
+ return;
+ }
+}
+
+
+static void
+fpatan(void)
+{
+ FPU_REG *st1_ptr = &st(1);
+ char st1_tag = st1_ptr->tag;
+
+ if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
+ int saved_control, saved_status;
+ FPU_REG sum;
+ int quadrant = st1_ptr->sign | ((FPU_st0_ptr->sign) << 1);
+
+#ifdef DENORM_OPERAND
+ if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
+ (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ /* We use the general purpose arithmetic so we need to save
+ * these. */
+ saved_status = status_word;
+ saved_control = control_word;
+ control_word = FULL_PRECISION;
+
+ st1_ptr->sign = FPU_st0_ptr->sign = SIGN_POS;
+ if (compare(st1_ptr) == COMP_A_lt_B) {
+ quadrant |= 4;
+ reg_div(FPU_st0_ptr, st1_ptr, &sum, FULL_PRECISION);
+ } else
+ reg_div(st1_ptr, FPU_st0_ptr, &sum, FULL_PRECISION);
+
+ poly_atan(&sum);
+
+ if (quadrant & 4) {
+ reg_sub(&CONST_PI2, &sum, &sum, FULL_PRECISION);
+ }
+ if (quadrant & 2) {
+ reg_sub(&CONST_PI, &sum, &sum, FULL_PRECISION);
+ }
+ if (quadrant & 1)
+ sum.sign ^= SIGN_POS ^ SIGN_NEG;
+
+ /* All of the basic arithmetic is done now */
+ control_word = saved_control;
+ status_word = saved_status;
+
+ reg_move(&sum, st1_ptr);
+ } else
+ if ((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty)) {
+ stack_underflow_pop(1);
+ return;
+ } else
+ if ((FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
+ pop();
+ return;
+ } else
+ if ((FPU_st0_tag == TW_Infinity) || (st1_tag == TW_Infinity)) {
+ char sign = st1_ptr->sign;
+ if (FPU_st0_tag == TW_Infinity) {
+ if (st1_tag == TW_Infinity) {
+ if (FPU_st0_ptr->sign == SIGN_POS) {
+ reg_move(&CONST_PI4, st1_ptr);
+ } else
+ reg_add(&CONST_PI4, &CONST_PI2, st1_ptr, FULL_PRECISION);
+ } else {
+
+#ifdef DENORM_OPERAND
+ if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if (FPU_st0_ptr->sign == SIGN_POS) {
+ reg_move(&CONST_Z, st1_ptr);
+ pop();
+ return;
+ } else
+ reg_move(&CONST_PI, st1_ptr);
+ }
+ } else {
+ /* st(1) is infinity, st(0)
+ * not infinity */
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ reg_move(&CONST_PI2, st1_ptr);
+ }
+ st1_ptr->sign = sign;
+ } else
+ if (st1_tag == TW_Zero) {
+ /* st(0) must be valid or zero */
+ char sign = st1_ptr->sign;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if (FPU_st0_ptr->sign == SIGN_POS) {
+ reg_move(&CONST_Z, st1_ptr);
+ pop();
+ return;
+ } else
+ reg_move(&CONST_PI, st1_ptr);
+ st1_ptr->sign = sign;
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ /* st(1) must be
+ * TW_Valid here */
+ char sign = st1_ptr->sign;
+
+#ifdef DENORM_OPERAND
+ if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ reg_move(&CONST_PI2, st1_ptr);
+ st1_ptr->sign = sign;
+ }
+#ifdef PARANOID
+ else
+ EXCEPTION(EX_INTERNAL | 0x220);
+#endif /* PARANOID */
+
+ pop();
+ set_precision_flag_up();/* We do not really know if up or down */
+}
+
+
+static void
+fprem(void)
+{
+ fprem_kernel(RC_CHOP);
+}
+
+
+static void
+fprem1(void)
+{
+ fprem_kernel(RC_RND);
+}
+
+
+static void
+fyl2xp1(void)
+{
+ FPU_REG *st1_ptr = &st(1);
+ char st1_tag = st1_ptr->tag;
+
+ if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
+ int saved_control, saved_status;
+
+#ifdef DENORM_OPERAND
+ if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
+ (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ /* We use the general purpose arithmetic so we need to save
+ * these. */
+ saved_status = status_word;
+ saved_control = control_word;
+ control_word = FULL_PRECISION;
+
+ if (poly_l2p1(FPU_st0_ptr, FPU_st0_ptr)) {
+ arith_invalid(st1_ptr); /* poly_l2p1() returned
+ * invalid */
+ pop();
+ return;
+ }
+ /* Enough of the basic arithmetic is done now */
+ control_word = saved_control;
+ status_word = saved_status;
+
+ /* Let the multiply set the flags */
+ reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION);
+
+ pop();
+ } else
+ if ((FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty)) {
+ stack_underflow_pop(1);
+ return;
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ if (st1_tag <= TW_Zero) {
+
+#ifdef DENORM_OPERAND
+ if ((st1_tag == TW_Valid) && (st1_ptr->exp <= EXP_UNDER) &&
+ (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ st1_ptr->sign ^= FPU_st0_ptr->sign;
+ reg_move(FPU_st0_ptr, st1_ptr);
+ } else
+ if (st1_tag == TW_Infinity) {
+ arith_invalid(st1_ptr); /* Infinity*log(1) */
+ pop();
+ return;
+ } else
+ if (st1_tag == TW_NaN) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
+ pop();
+ return;
+ }
+#ifdef PARANOID
+ else {
+ EXCEPTION(EX_INTERNAL | 0x116);
+ return;
+ }
+#endif /* PARANOID */
+ pop();
+ return;
+ } else
+ if (FPU_st0_tag == TW_Valid) {
+ if (st1_tag == TW_Zero) {
+ if (FPU_st0_ptr->sign == SIGN_NEG) {
+ if (FPU_st0_ptr->exp >= EXP_BIAS) {
+ /* st(0) holds
+ * <= -1.0 */
+ arith_invalid(st1_ptr); /* infinity*log(1) */
+ pop();
+ return;
+ }
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+ st1_ptr->sign ^= SIGN_POS ^ SIGN_NEG;
+ pop();
+ return;
+ }
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+ pop();
+ return;
+ }
+ if (st1_tag == TW_Infinity) {
+ if (FPU_st0_ptr->sign == SIGN_NEG) {
+ if ((FPU_st0_ptr->exp >= EXP_BIAS) &&
+ !((FPU_st0_ptr->sigh == 0x80000000) &&
+ (FPU_st0_ptr->sigl == 0))) {
+ /* st(0) holds
+ * < -1.0 */
+ arith_invalid(st1_ptr);
+ pop();
+ return;
+ }
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+ st1_ptr->sign ^= SIGN_POS ^ SIGN_NEG;
+ pop();
+ return;
+ }
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+ pop();
+ return;
+ }
+ if (st1_tag == TW_NaN) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
+ pop();
+ return;
+ }
+ } else
+ if (FPU_st0_tag == TW_NaN) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
+ pop();
+ return;
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ if (st1_tag == TW_NaN) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
+ pop();
+ return;
+ } else
+ if ((FPU_st0_ptr->sign == SIGN_NEG) ||
+ (st1_tag == TW_Zero)) {
+ arith_invalid(st1_ptr); /* log(infinity) */
+ pop();
+ return;
+ }
+ /* st(1) must be valid
+ * here. */
+
+#ifdef DENORM_OPERAND
+ if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ /* The Manual says
+ * that log(Infinity)
+ * is invalid, but a
+ * real 80486 sensibly
+ * says that it is
+ * o.k. */
+ {
+ char sign = st1_ptr->sign;
+ reg_move(&CONST_INF, st1_ptr);
+ st1_ptr->sign = sign;
+ }
+ pop();
+ return;
+ }
+#ifdef PARANOID
+ else {
+ EXCEPTION(EX_INTERNAL | 0x117);
+ }
+#endif /* PARANOID */
+}
+
+
+static void
+emu_fscale(void)
+{
+ FPU_REG *st1_ptr = &st(1);
+ char st1_tag = st1_ptr->tag;
+ int old_cw = control_word;
+
+ if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
+ long scale;
+ FPU_REG tmp;
+
+#ifdef DENORM_OPERAND
+ if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
+ (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if (st1_ptr->exp > EXP_BIAS + 30) {
+ /* 2^31 is far too large, would require 2^(2^30) or
+ * 2^(-2^30) */
+ char sign;
+
+ if (st1_ptr->sign == SIGN_POS) {
+ EXCEPTION(EX_Overflow);
+ sign = FPU_st0_ptr->sign;
+ reg_move(&CONST_INF, FPU_st0_ptr);
+ FPU_st0_ptr->sign = sign;
+ } else {
+ EXCEPTION(EX_Underflow);
+ sign = FPU_st0_ptr->sign;
+ reg_move(&CONST_Z, FPU_st0_ptr);
+ FPU_st0_ptr->sign = sign;
+ }
+ return;
+ }
+ control_word &= ~CW_RC;
+ control_word |= RC_CHOP;
+ reg_move(st1_ptr, &tmp);
+ round_to_int(&tmp); /* This can never overflow here */
+ control_word = old_cw;
+ scale = st1_ptr->sign ? -tmp.sigl : tmp.sigl;
+ scale += FPU_st0_ptr->exp;
+ FPU_st0_ptr->exp = scale;
+
+ /* Use round_reg() to properly detect under/overflow etc */
+ round_reg(FPU_st0_ptr, 0, control_word);
+
+ return;
+ } else
+ if (FPU_st0_tag == TW_Valid) {
+ if (st1_tag == TW_Zero) {
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ return;
+ }
+ if (st1_tag == TW_Infinity) {
+ char sign = st1_ptr->sign;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if (sign == SIGN_POS) {
+ reg_move(&CONST_INF, FPU_st0_ptr);
+ } else
+ reg_move(&CONST_Z, FPU_st0_ptr);
+ FPU_st0_ptr->sign = sign;
+ return;
+ }
+ if (st1_tag == TW_NaN) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
+ return;
+ }
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ if (st1_tag == TW_Valid) {
+
+#ifdef DENORM_OPERAND
+ if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ return;
+ } else
+ if (st1_tag == TW_Zero) {
+ return;
+ } else
+ if (st1_tag == TW_Infinity) {
+ if (st1_ptr->sign == SIGN_NEG)
+ return;
+ else {
+ arith_invalid(FPU_st0_ptr); /* Zero scaled by
+ * +Infinity */
+ return;
+ }
+ } else
+ if (st1_tag == TW_NaN) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
+ return;
+ }
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ if (st1_tag == TW_Valid) {
+
+#ifdef DENORM_OPERAND
+ if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ return;
+ }
+ if (((st1_tag == TW_Infinity) && (st1_ptr->sign == SIGN_POS))
+ || (st1_tag == TW_Zero))
+ return;
+ else
+ if (st1_tag == TW_Infinity) {
+ arith_invalid(FPU_st0_ptr); /* Infinity scaled by
+ * -Infinity */
+ return;
+ } else
+ if (st1_tag == TW_NaN) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
+ return;
+ }
+ } else
+ if (FPU_st0_tag == TW_NaN) {
+ if (st1_tag != TW_Empty) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
+ return;
+ }
+ }
+#ifdef PARANOID
+ if (!((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty))) {
+ EXCEPTION(EX_INTERNAL | 0x115);
+ return;
+ }
+#endif
+
+ /* At least one of st(0), st(1) must be empty */
+ stack_underflow();
+
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+static FUNC trig_table_a[] = {
+ f2xm1, fyl2x, fptan, fpatan, fxtract, fprem1, fdecstp, fincstp
+};
+
+void
+trig_a(void)
+{
+ (trig_table_a[FPU_rm]) ();
+}
+
+
+static FUNC trig_table_b[] =
+{
+ fprem, fyl2xp1, fsqrt_, fsincos, frndint_, emu_fscale, fsin, fcos
+};
+
+void
+trig_b(void)
+{
+ (trig_table_b[FPU_rm]) ();
+}
diff --git a/sys/gnu/i386/fpemul/get_address.c b/sys/gnu/i386/fpemul/get_address.c
new file mode 100644
index 0000000..f8100ea
--- /dev/null
+++ b/sys/gnu/i386/fpemul/get_address.c
@@ -0,0 +1,193 @@
+/*
+ * get_address.c
+ *
+ * Get the effective address from an FPU instruction.
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | Note: |
+ | The file contains code which accesses user memory. |
+ | Emulator static data may change when user memory is accessed, due to |
+ | other processes using the emulator while swapping is in progress. |
+ +---------------------------------------------------------------------------*/
+
+#include "param.h"
+#include "proc.h"
+#include "systm.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+#include "machine/reg.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+
+static int reg_offset[] = {
+tEAX, tECX, tEDX, tEBX, tESP, tEBP, tESI, tEDI};
+#define REG_(x) (*(((int*)FPU_info) + reg_offset[(x)]))
+
+void *FPU_data_address;
+
+
+/* Decode the SIB byte. This function assumes mod != 0 */
+static void *
+sib(int mod)
+{
+ unsigned char ss, index, base;
+ long offset;
+
+ REENTRANT_CHECK(OFF);
+ base = fubyte((char *) FPU_EIP); /* The SIB byte */
+ REENTRANT_CHECK(ON);
+ FPU_EIP++;
+ ss = base >> 6;
+ index = (base >> 3) & 7;
+ base &= 7;
+
+ if ((mod == 0) && (base == 5))
+ offset = 0; /* No base register */
+ else
+ offset = REG_(base);
+
+ if (index == 4) {
+ /* No index register */
+ /* A non-zero ss is illegal */
+ if (ss)
+ EXCEPTION(EX_Invalid);
+ } else {
+ offset += (REG_(index)) << ss;
+ }
+
+ if (mod == 1) {
+ /* 8 bit signed displacement */
+ REENTRANT_CHECK(OFF);
+ offset += (signed char) fubyte((char *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ FPU_EIP++;
+ } else
+ if (mod == 2 || base == 5) { /* The second condition also
+ * has mod==0 */
+ /* 32 bit displacment */
+ REENTRANT_CHECK(OFF);
+ offset += (signed) fuword((unsigned long *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ FPU_EIP += 4;
+ }
+ return (void *) offset;
+}
+
+
+/*
+ MOD R/M byte: MOD == 3 has a special use for the FPU
+ SIB byte used iff R/M = 100b
+
+ 7 6 5 4 3 2 1 0
+ ..... ......... .........
+ MOD OPCODE(2) R/M
+
+
+ SIB byte
+
+ 7 6 5 4 3 2 1 0
+ ..... ......... .........
+ SS INDEX BASE
+
+*/
+
+void
+get_address(unsigned char FPU_modrm)
+{
+ unsigned char mod;
+ long *cpu_reg_ptr;
+ int offset = 0; /* Initialized just to stop compiler warnings. */
+
+ mod = (FPU_modrm >> 6) & 3;
+
+ if (FPU_rm == 4 && mod != 3) {
+ FPU_data_address = sib(mod);
+ return;
+ }
+ cpu_reg_ptr = (long *) &REG_(FPU_rm);
+ switch (mod) {
+ case 0:
+ if (FPU_rm == 5) {
+ /* Special case: disp32 */
+ REENTRANT_CHECK(OFF);
+ offset = fuword((unsigned long *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ FPU_EIP += 4;
+ FPU_data_address = (void *) offset;
+ return;
+ } else {
+ FPU_data_address = (void *) *cpu_reg_ptr; /* Just return the
+ * contents of the cpu
+ * register */
+ return;
+ }
+ case 1:
+ /* 8 bit signed displacement */
+ REENTRANT_CHECK(OFF);
+ offset = (signed char) fubyte((char *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ FPU_EIP++;
+ break;
+ case 2:
+ /* 32 bit displacement */
+ REENTRANT_CHECK(OFF);
+ offset = (signed) fuword((unsigned long *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ FPU_EIP += 4;
+ break;
+ case 3:
+ /* Not legal for the FPU */
+ EXCEPTION(EX_Invalid);
+ }
+
+ FPU_data_address = offset + (char *) *cpu_reg_ptr;
+}
diff --git a/sys/gnu/i386/fpemul/load_store.c b/sys/gnu/i386/fpemul/load_store.c
new file mode 100644
index 0000000..5f094c3
--- /dev/null
+++ b/sys/gnu/i386/fpemul/load_store.c
@@ -0,0 +1,259 @@
+/*
+ * load_store.c
+ *
+ * This file contains most of the code to interpret the FPU instructions
+ * which load and store from user memory.
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | Note: |
+ | The file contains code which accesses user memory. |
+ | Emulator static data may change when user memory is accessed, due to |
+ | other processes using the emulator while swapping is in progress. |
+ +---------------------------------------------------------------------------*/
+
+#include "param.h"
+#include "proc.h"
+#include "systm.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+#include "status_w.h"
+
+
+#define _NONE_ 0 /* FPU_st0_ptr etc not needed */
+#define _REG0_ 1 /* Will be storing st(0) */
+#define _PUSH_ 3 /* Need to check for space to push onto stack */
+#define _null_ 4 /* Function illegal or not implemented */
+
+#define pop_0() { pop_ptr->tag = TW_Empty; top++; }
+
+
+static unsigned char type_table[32] = {
+ _PUSH_, _PUSH_, _PUSH_, _PUSH_,
+ _null_, _null_, _null_, _null_,
+ _REG0_, _REG0_, _REG0_, _REG0_,
+ _REG0_, _REG0_, _REG0_, _REG0_,
+ _NONE_, _null_, _NONE_, _PUSH_,
+ _NONE_, _PUSH_, _null_, _PUSH_,
+ _NONE_, _null_, _NONE_, _REG0_,
+ _NONE_, _REG0_, _NONE_, _REG0_
+};
+
+void
+load_store_instr(char type)
+{
+ FPU_REG *pop_ptr; /* We need a version of FPU_st0_ptr which
+ * won't change. */
+
+ pop_ptr = NULL; /* Initialized just to stop compiler warnings. */
+
+
+ switch (type_table[(int) (unsigned) type]) {
+ case _NONE_:
+ break;
+ case _REG0_:
+ pop_ptr = &st(0); /* Some of these instructions pop
+ * after storing */
+
+ FPU_st0_ptr = pop_ptr; /* Set the global variables. */
+ FPU_st0_tag = FPU_st0_ptr->tag;
+ break;
+ case _PUSH_:
+ {
+ pop_ptr = &st(-1);
+ if (pop_ptr->tag != TW_Empty) {
+ stack_overflow();
+ return;
+ }
+ top--;
+ }
+ break;
+ case _null_:
+ return Un_impl();
+#ifdef PARANOID
+ default:
+ return EXCEPTION(EX_INTERNAL);
+#endif /* PARANOID */
+ }
+
+ switch (type) {
+ case 000: /* fld m32real */
+ reg_load_single();
+ setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */
+ reg_move(&FPU_loaded_data, pop_ptr);
+ break;
+ case 001: /* fild m32int */
+ reg_load_int32();
+ setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */
+ reg_move(&FPU_loaded_data, pop_ptr);
+ break;
+ case 002: /* fld m64real */
+ reg_load_double();
+ setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */
+ reg_move(&FPU_loaded_data, pop_ptr);
+ break;
+ case 003: /* fild m16int */
+ reg_load_int16();
+ setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */
+ reg_move(&FPU_loaded_data, pop_ptr);
+ break;
+ case 010: /* fst m32real */
+ reg_store_single();
+ break;
+ case 011: /* fist m32int */
+ reg_store_int32();
+ break;
+ case 012: /* fst m64real */
+ reg_store_double();
+ break;
+ case 013: /* fist m16int */
+ reg_store_int16();
+ break;
+ case 014: /* fstp m32real */
+ if (reg_store_single())
+ pop_0();/* pop only if the number was actually stored
+ * (see the 80486 manual p16-28) */
+ break;
+ case 015: /* fistp m32int */
+ if (reg_store_int32())
+ pop_0();/* pop only if the number was actually stored
+ * (see the 80486 manual p16-28) */
+ break;
+ case 016: /* fstp m64real */
+ if (reg_store_double())
+ pop_0();/* pop only if the number was actually stored
+ * (see the 80486 manual p16-28) */
+ break;
+ case 017: /* fistp m16int */
+ if (reg_store_int16())
+ pop_0();/* pop only if the number was actually stored
+ * (see the 80486 manual p16-28) */
+ break;
+ case 020: /* fldenv m14/28byte */
+ fldenv();
+ break;
+ case 022: /* frstor m94/108byte */
+ frstor();
+ break;
+ case 023: /* fbld m80dec */
+ reg_load_bcd();
+ setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */
+ reg_move(&FPU_loaded_data, pop_ptr);
+ break;
+ case 024: /* fldcw */
+ REENTRANT_CHECK(OFF);
+ control_word = fuword((unsigned short *) FPU_data_address);
+ REENTRANT_CHECK(ON);
+#ifdef NO_UNDERFLOW_TRAP
+ if (!(control_word & EX_Underflow)) {
+ control_word |= EX_Underflow;
+ }
+#endif
+ FPU_data_address = (void *) data_operand_offset; /* We want no net effect */
+ FPU_entry_eip = ip_offset; /* We want no net effect */
+ break;
+ case 025: /* fld m80real */
+ reg_load_extended();
+ setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */
+ reg_move(&FPU_loaded_data, pop_ptr);
+ break;
+ case 027: /* fild m64int */
+ reg_load_int64();
+ setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */
+ reg_move(&FPU_loaded_data, pop_ptr);
+ break;
+ case 030: /* fstenv m14/28byte */
+ fstenv();
+ FPU_data_address = (void *) data_operand_offset; /* We want no net effect */
+ FPU_entry_eip = ip_offset; /* We want no net effect */
+ break;
+ case 032: /* fsave */
+ fsave();
+ FPU_data_address = (void *) data_operand_offset; /* We want no net effect */
+ FPU_entry_eip = ip_offset; /* We want no net effect */
+ break;
+ case 033: /* fbstp m80dec */
+ if (reg_store_bcd())
+ pop_0();/* pop only if the number was actually stored
+ * (see the 80486 manual p16-28) */
+ break;
+ case 034: /* fstcw m16int */
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, FPU_data_address, 2);*/
+ suword( (short *) FPU_data_address,control_word);
+ REENTRANT_CHECK(ON);
+ FPU_data_address = (void *) data_operand_offset; /* We want no net effect */
+ FPU_entry_eip = ip_offset; /* We want no net effect */
+ break;
+ case 035: /* fstp m80real */
+ if (reg_store_extended())
+ pop_0();/* pop only if the number was actually stored
+ * (see the 80486 manual p16-28) */
+ break;
+ case 036: /* fstsw m2byte */
+ status_word &= ~SW_Top;
+ status_word |= (top & 7) << SW_Top_Shift;
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, FPU_data_address, 2);*/
+ suword( (short *) FPU_data_address,status_word);
+ REENTRANT_CHECK(ON);
+ FPU_data_address = (void *) data_operand_offset; /* We want no net effect */
+ FPU_entry_eip = ip_offset; /* We want no net effect */
+ break;
+ case 037: /* fistp m64int */
+ if (reg_store_int64())
+ pop_0();/* pop only if the number was actually stored
+ * (see the 80486 manual p16-28) */
+ break;
+ }
+}
diff --git a/sys/gnu/i386/fpemul/math_emu.h b/sys/gnu/i386/fpemul/math_emu.h
new file mode 100644
index 0000000..4dc90b8
--- /dev/null
+++ b/sys/gnu/i386/fpemul/math_emu.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * $Id:$
+ *
+ */
+
+#ifndef _MATH_EMU_H
+#define _MATH_EMU_H
+
+struct fpu_reg {
+ char sign;
+ char tag;
+ long exp;
+ u_long sigl;
+ u_long sigh;
+};
+
+union i387_union {
+ struct i387_hard_struct {
+ long cwd;
+ long swd;
+ long twd;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long st_space[20]; /* 8*10 bytes for each FP-reg = 80
+ * bytes */
+ } hard;
+ struct i387_soft_struct {
+ long cwd;
+ long swd;
+ long twd;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long top;
+ struct fpu_reg regs[8]; /* 8*16 bytes for each FP-reg = 128
+ * bytes */
+ unsigned char lookahead;
+ struct trapframe *frame;
+ unsigned long entry_eip;
+ int orig_eip;
+ } soft;
+};
+#endif
diff --git a/sys/gnu/i386/fpemul/poly_2xm1.c b/sys/gnu/i386/fpemul/poly_2xm1.c
new file mode 100644
index 0000000..fd59398
--- /dev/null
+++ b/sys/gnu/i386/fpemul/poly_2xm1.c
@@ -0,0 +1,131 @@
+/*
+ * poly_2xm1.c
+ *
+ * Function to compute 2^x-1 by a polynomial approximation.
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+
+
+
+#define HIPOWER 13
+static unsigned short lterms[HIPOWER][4] =
+{
+ {0x79b5, 0xd1cf, 0x17f7, 0xb172},
+ {0x1b56, 0x058b, 0x7bff, 0x3d7f},
+ {0x8bb0, 0x8250, 0x846b, 0x0e35},
+ {0xbc65, 0xf747, 0x556d, 0x0276},
+ {0x17cb, 0x9e39, 0x61ff, 0x0057},
+ {0xe018, 0x9776, 0x1848, 0x000a},
+ {0x66f2, 0xff30, 0xffe5, 0x0000},
+ {0x682f, 0xffb6, 0x162b, 0x0000},
+ {0xb7ca, 0x2956, 0x01b5, 0x0000},
+ {0xcd3e, 0x4817, 0x001e, 0x0000},
+ {0xb7e2, 0xecbe, 0x0001, 0x0000},
+ {0x0ed5, 0x1a27, 0x0000, 0x0000},
+ {0x101d, 0x0222, 0x0000, 0x0000},
+};
+
+
+/*--- poly_2xm1() -----------------------------------------------------------+
+ | |
+ +---------------------------------------------------------------------------*/
+int
+poly_2xm1(FPU_REG * arg, FPU_REG * result)
+{
+ short exponent;
+ long long Xll;
+ FPU_REG accum;
+
+
+ exponent = arg->exp - EXP_BIAS;
+
+ if (arg->tag == TW_Zero) {
+ /* Return 0.0 */
+ reg_move(&CONST_Z, result);
+ return 0;
+ }
+ if (exponent >= 0) { /* Can't hack a number >= 1.0 */
+ arith_invalid(result); /* Number too large */
+ return 1;
+ }
+ if (arg->sign != SIGN_POS) { /* Can't hack a number < 0.0 */
+ arith_invalid(result); /* Number negative */
+ return 1;
+ }
+ if (exponent < -64) {
+ reg_move(&CONST_LN2, result);
+ return 0;
+ }
+ *(unsigned *) &Xll = arg->sigl;
+ *(((unsigned *) &Xll) + 1) = arg->sigh;
+ if (exponent < -1) {
+ /* shift the argument right by the required places */
+ if (shrx(&Xll, -1 - exponent) >= (unsigned)0x80000000)
+ Xll++; /* round up */
+ }
+ *(short *) &(accum.sign) = 0; /* will be a valid positive nr with
+ * expon = 0 */
+ accum.exp = 0;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((unsigned *) &accum.sigl, (unsigned *) &Xll, lterms, HIPOWER - 1);
+
+ /* Convert to 64 bit signed-compatible */
+ accum.exp += EXP_BIAS - 1;
+
+ reg_move(&accum, result);
+
+ normalize(result);
+
+ return 0;
+
+}
diff --git a/sys/gnu/i386/fpemul/poly_atan.c b/sys/gnu/i386/fpemul/poly_atan.c
new file mode 100644
index 0000000..d04caa8
--- /dev/null
+++ b/sys/gnu/i386/fpemul/poly_atan.c
@@ -0,0 +1,242 @@
+/*
+ * p_atan.c
+ *
+ * Compute the tan of a FPU_REG, using a polynomial approximation.
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+
+
+#define HIPOWERon 6 /* odd poly, negative terms */
+static unsigned oddnegterms[HIPOWERon][2] =
+{
+ {0x00000000, 0x00000000}, /* for + 1.0 */
+ {0x763b6f3d, 0x1adc4428},
+ {0x20f0630b, 0x0502909d},
+ {0x4e825578, 0x0198ce38},
+ {0x22b7cb87, 0x008da6e3},
+ {0x9b30ca03, 0x00239c79}
+};
+#define HIPOWERop 6 /* odd poly, positive terms */
+static unsigned oddplterms[HIPOWERop][2] =
+{
+ {0xa6f67cb8, 0x94d910bd},
+ {0xa02ffab4, 0x0a43cb45},
+ {0x04265e6b, 0x02bf5655},
+ {0x0a728914, 0x00f280f7},
+ {0x6d640e01, 0x004d6556},
+ {0xf1dd2dbf, 0x000a530a}
+};
+
+
+static unsigned denomterm[2] =
+{0xfc4bd208, 0xea2e6612};
+
+
+
+/*--- poly_atan() -----------------------------------------------------------+
+ | |
+ +---------------------------------------------------------------------------*/
+void
+poly_atan(FPU_REG * arg)
+{
+ char recursions = 0;
+ short exponent;
+ FPU_REG odd_poly, even_poly, pos_poly, neg_poly;
+ FPU_REG argSq;
+ long long arg_signif, argSqSq;
+
+
+#ifdef PARANOID
+ if (arg->sign != 0) { /* Can't hack a number < 0.0 */
+ arith_invalid(arg);
+ return;
+ } /* Need a positive number */
+#endif /* PARANOID */
+
+ exponent = arg->exp - EXP_BIAS;
+
+ if (arg->tag == TW_Zero) {
+ /* Return 0.0 */
+ reg_move(&CONST_Z, arg);
+ return;
+ }
+ if (exponent >= -2) {
+ /* argument is in the range [0.25 .. 1.0] */
+ if (exponent >= 0) {
+#ifdef PARANOID
+ if ((exponent == 0) &&
+ (arg->sigl == 0) && (arg->sigh == 0x80000000))
+#endif /* PARANOID */
+ {
+ reg_move(&CONST_PI4, arg);
+ return;
+ }
+#ifdef PARANOID
+ EXCEPTION(EX_INTERNAL | 0x104); /* There must be a logic
+ * error */
+#endif /* PARANOID */
+ }
+ /* If the argument is greater than sqrt(2)-1 (=0.414213562...) */
+ /* convert the argument by an identity for atan */
+ if ((exponent >= -1) || (arg->sigh > 0xd413ccd0)) {
+ FPU_REG numerator, denom;
+
+ recursions++;
+
+ arg_signif = *(long long *) &(arg->sigl);
+ if (exponent < -1) {
+ if (shrx(&arg_signif, -1 - exponent) >= (unsigned)0x80000000)
+ arg_signif++; /* round up */
+ }
+ *(long long *) &(numerator.sigl) = -arg_signif;
+ numerator.exp = EXP_BIAS - 1;
+ normalize(&numerator); /* 1 - arg */
+
+ arg_signif = *(long long *) &(arg->sigl);
+ if (shrx(&arg_signif, -exponent) >= (unsigned)0x80000000)
+ arg_signif++; /* round up */
+ *(long long *) &(denom.sigl) = arg_signif;
+ denom.sigh |= 0x80000000; /* 1 + arg */
+
+ arg->exp = numerator.exp;
+ reg_u_div(&numerator, &denom, arg, FULL_PRECISION);
+
+ exponent = arg->exp - EXP_BIAS;
+ }
+ }
+ *(long long *) &arg_signif = *(long long *) &(arg->sigl);
+
+#ifdef PARANOID
+ /* This must always be true */
+ if (exponent >= -1) {
+ EXCEPTION(EX_INTERNAL | 0x120); /* There must be a logic error */
+ }
+#endif /* PARANOID */
+
+ /* shift the argument right by the required places */
+ if (shrx(&arg_signif, -1 - exponent) >= (unsigned)0x80000000)
+ arg_signif++; /* round up */
+
+ /* Now have arg_signif with binary point at the left .1xxxxxxxx */
+ mul64(&arg_signif, &arg_signif, (long long *) (&argSq.sigl));
+ mul64((long long *) (&argSq.sigl), (long long *) (&argSq.sigl), &argSqSq);
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(pos_poly.sign) = 0;
+ pos_poly.exp = EXP_BIAS;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &pos_poly.sigl, (unsigned *) &argSqSq,
+ (unsigned short (*)[4]) oddplterms, HIPOWERop - 1);
+ mul64((long long *) (&argSq.sigl), (long long *) (&pos_poly.sigl),
+ (long long *) (&pos_poly.sigl));
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(neg_poly.sign) = 0;
+ neg_poly.exp = EXP_BIAS;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &neg_poly.sigl, (unsigned *) &argSqSq,
+ (unsigned short (*)[4]) oddnegterms, HIPOWERon - 1);
+
+ /* Subtract the mantissas */
+ *((long long *) (&pos_poly.sigl)) -= *((long long *) (&neg_poly.sigl));
+
+ reg_move(&pos_poly, &odd_poly);
+ poly_add_1(&odd_poly);
+
+ /* The complete odd polynomial */
+ reg_u_mul(&odd_poly, arg, &odd_poly, FULL_PRECISION);
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(even_poly.sign) = 0;
+
+ mul64((long long *) (&argSq.sigl),
+ (long long *) (&denomterm), (long long *) (&even_poly.sigl));
+
+ poly_add_1(&even_poly);
+
+ reg_div(&odd_poly, &even_poly, arg, FULL_PRECISION);
+
+ if (recursions)
+ reg_sub(&CONST_PI4, arg, arg, FULL_PRECISION);
+}
+
+
+/* The argument to this function must be polynomial() compatible,
+ i.e. have an exponent (not checked) of EXP_BIAS-1 but need not
+ be normalized.
+ This function adds 1.0 to the (assumed positive) argument. */
+void
+poly_add_1(FPU_REG * src)
+{
+/* Rounding in a consistent direction produces better results
+ for the use of this function in poly_atan. Simple truncation
+ is used here instead of round-to-nearest. */
+
+#ifdef OBSOLETE
+ char round = (src->sigl & 3) == 3;
+#endif /* OBSOLETE */
+
+ shrx(&src->sigl, 1);
+
+#ifdef OBSOLETE
+ if (round)
+ (*(long long *) &src->sigl)++; /* Round to even */
+#endif /* OBSOLETE */
+
+ src->sigh |= 0x80000000;
+
+ src->exp = EXP_BIAS;
+
+}
diff --git a/sys/gnu/i386/fpemul/poly_div.s b/sys/gnu/i386/fpemul/poly_div.s
new file mode 100644
index 0000000..b4ce54e
--- /dev/null
+++ b/sys/gnu/i386/fpemul/poly_div.s
@@ -0,0 +1,134 @@
+ .file "poly_div.S"
+/*
+ * poly_div.S
+ *
+ * A set of functions to divide 64 bit integers by fixed numbers.
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+#include "fpu_asm.h"
+
+.text
+
+/*---------------------------------------------------------------------------*/
+ .align 2,144
+.globl _poly_div2
+_poly_div2:
+ pushl %ebp
+ movl %esp,%ebp
+
+ movl PARAM1,%ecx
+ movw (%ecx),%ax
+
+ shrl $1,4(%ecx)
+ rcrl $1,(%ecx)
+
+ testw $1,%ax
+ je poly_div2_exit
+
+ addl $1,(%ecx)
+ adcl $0,4(%ecx)
+poly_div2_exit:
+
+ leave
+ ret
+/*---------------------------------------------------------------------------*/
+ .align 2,144
+.globl _poly_div4
+_poly_div4:
+ pushl %ebp
+ movl %esp,%ebp
+
+ movl PARAM1,%ecx
+ movw (%ecx),%ax
+
+ movl 4(%ecx),%edx
+ shll $30,%edx
+
+ shrl $2,4(%ecx)
+ shrl $2,(%ecx)
+
+ orl %edx,(%ecx)
+
+ testw $2,%ax
+ je poly_div4_exit
+
+ addl $1,(%ecx)
+ adcl $0,4(%ecx)
+poly_div4_exit:
+
+ leave
+ ret
+/*---------------------------------------------------------------------------*/
+ .align 2,144
+.globl _poly_div16
+_poly_div16:
+ pushl %ebp
+ movl %esp,%ebp
+
+ movl PARAM1,%ecx
+ movw (%ecx),%ax
+
+ movl 4(%ecx),%edx
+ shll $28,%edx
+
+ shrl $4,4(%ecx)
+ shrl $4,(%ecx)
+
+ orl %edx,(%ecx)
+
+ testw $8,%ax
+ je poly_div16_exit
+
+ addl $1,(%ecx)
+ adcl $0,4(%ecx)
+poly_div16_exit:
+
+ leave
+ ret
+/*---------------------------------------------------------------------------*/
diff --git a/sys/gnu/i386/fpemul/poly_l2.c b/sys/gnu/i386/fpemul/poly_l2.c
new file mode 100644
index 0000000..b6691f3
--- /dev/null
+++ b/sys/gnu/i386/fpemul/poly_l2.c
@@ -0,0 +1,308 @@
+/*
+ * poly_l2.c
+ *
+ * Compute the base 2 log of a FPU_REG, using a polynomial approximation.
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id: poly_l2.c,v 1.3 1994/04/29 21:23:28 gclarkii Exp $
+ *
+ */
+
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+
+
+
+#define HIPOWER 9
+static unsigned short lterms[HIPOWER][4] =
+{
+ /* Ideal computation with these coeffs gives about 64.6 bit rel
+ * accuracy. */
+ {0xe177, 0xb82f, 0x7652, 0x7154},
+ {0xee0f, 0xe80f, 0x2770, 0x7b1c},
+ {0x0fc0, 0xbe87, 0xb143, 0x49dd},
+ {0x78b9, 0xdadd, 0xec54, 0x34c2},
+ {0x003a, 0x5de9, 0x628b, 0x2909},
+ {0x5588, 0xed16, 0x4abf, 0x2193},
+ {0xb461, 0x85f7, 0x347a, 0x1c6a},
+ {0x0975, 0x87b3, 0xd5bf, 0x1876},
+ {0xe85c, 0xcec9, 0x84e7, 0x187d}
+};
+
+
+
+
+/*--- poly_l2() -------------------------------------------------------------+
+ | Base 2 logarithm by a polynomial approximation. |
+ +---------------------------------------------------------------------------*/
+void
+poly_l2(FPU_REG * arg, FPU_REG * result)
+{
+ short exponent;
+ char zero; /* flag for an Xx == 0 */
+ unsigned short bits, shift;
+ long long Xsq;
+ FPU_REG accum, denom, num, Xx;
+
+
+ exponent = arg->exp - EXP_BIAS;
+
+ accum.tag = TW_Valid; /* set the tags to Valid */
+
+ if (arg->sigh > (unsigned) 0xb504f334) {
+ /* This is good enough for the computation of the polynomial
+ * sum, but actually results in a loss of precision for the
+ * computation of Xx. This will matter only if exponent
+ * becomes zero. */
+ exponent++;
+ accum.sign = 1; /* sign to negative */
+ num.exp = EXP_BIAS; /* needed to prevent errors in div
+ * routine */
+ reg_u_div(&CONST_1, arg, &num, FULL_PRECISION);
+ } else {
+ accum.sign = 0; /* set the sign to positive */
+ num.sigl = arg->sigl; /* copy the mantissa */
+ num.sigh = arg->sigh;
+ }
+
+
+ /* shift num left, lose the ms bit */
+ num.sigh <<= 1;
+ if (num.sigl & 0x80000000)
+ num.sigh |= 1;
+ num.sigl <<= 1;
+
+ denom.sigl = num.sigl;
+ denom.sigh = num.sigh;
+ poly_div4((long long *) &(denom.sigl));
+ denom.sigh += 0x80000000; /* set the msb */
+ Xx.exp = EXP_BIAS; /* needed to prevent errors in div routine */
+ reg_u_div(&num, &denom, &Xx, FULL_PRECISION);
+
+ zero = !(Xx.sigh | Xx.sigl);
+
+ mul64((long long *) &Xx.sigl, (long long *) &Xx.sigl, &Xsq);
+ poly_div16(&Xsq);
+
+ accum.exp = -1; /* exponent of accum */
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((unsigned *) &accum.sigl, (unsigned *) &Xsq, lterms, HIPOWER - 1);
+
+ if (!exponent) {
+ /* If the exponent is zero, then we would lose precision by
+ * sticking to fixed point computation here */
+ /* We need to re-compute Xx because of loss of precision. */
+ FPU_REG lXx;
+ char sign;
+
+ sign = accum.sign;
+ accum.sign = 0;
+
+ /* make accum compatible and normalize */
+ accum.exp = EXP_BIAS + accum.exp;
+ normalize(&accum);
+
+ if (zero) {
+ reg_move(&CONST_Z, result);
+ } else {
+ /* we need to re-compute lXx to better accuracy */
+ num.tag = TW_Valid; /* set the tags to Vaild */
+ num.sign = 0; /* set the sign to positive */
+ num.exp = EXP_BIAS - 1;
+ if (sign) {
+ /* The argument is of the form 1-x */
+ /* Use 1-1/(1-x) = x/(1-x) */
+ *((long long *) &num.sigl) = -*((long long *) &(arg->sigl));
+ normalize(&num);
+ reg_div(&num, arg, &num, FULL_PRECISION);
+ } else {
+ normalize(&num);
+ }
+
+ denom.tag = TW_Valid; /* set the tags to Valid */
+ denom.sign = SIGN_POS; /* set the sign to positive */
+ denom.exp = EXP_BIAS;
+
+ reg_div(&num, &denom, &lXx, FULL_PRECISION);
+
+ reg_u_mul(&lXx, &accum, &accum, FULL_PRECISION);
+
+ reg_u_add(&lXx, &accum, result, FULL_PRECISION);
+
+ normalize(result);
+ }
+
+ result->sign = sign;
+ return;
+ }
+ mul64((long long *) &accum.sigl,
+ (long long *) &Xx.sigl, (long long *) &accum.sigl);
+
+ *((long long *) (&accum.sigl)) += *((long long *) (&Xx.sigl));
+
+ if (Xx.sigh > accum.sigh) {
+ /* There was an overflow */
+
+ poly_div2((long long *) &accum.sigl);
+ accum.sigh |= 0x80000000;
+ accum.exp++;
+ }
+ /* When we add the exponent to the accum result later, we will require
+ * that their signs are the same. Here we ensure that this is so. */
+ if (exponent && ((exponent < 0) ^ (accum.sign))) {
+ /* signs are different */
+
+ accum.sign = !accum.sign;
+
+ /* An exceptional case is when accum is zero */
+ if (accum.sigl | accum.sigh) {
+ /* find 1-accum */
+ /* Shift to get exponent == 0 */
+ if (accum.exp < 0) {
+ poly_div2((long long *) &accum.sigl);
+ accum.exp++;
+ }
+ /* Just negate, but throw away the sign */
+ *((long long *) &(accum.sigl)) = -*((long long *) &(accum.sigl));
+ if (exponent < 0)
+ exponent++;
+ else
+ exponent--;
+ }
+ }
+ shift = exponent >= 0 ? exponent : -exponent;
+ bits = 0;
+ if (shift) {
+ if (accum.exp) {
+ accum.exp++;
+ poly_div2((long long *) &accum.sigl);
+ }
+ while (shift) {
+ poly_div2((long long *) &accum.sigl);
+ if (shift & 1)
+ accum.sigh |= 0x80000000;
+ shift >>= 1;
+ bits++;
+ }
+ }
+ /* Convert to 64 bit signed-compatible */
+ accum.exp += bits + EXP_BIAS - 1;
+
+ reg_move(&accum, result);
+ normalize(result);
+
+ return;
+}
+
+
+/*--- poly_l2p1() -----------------------------------------------------------+
+ | Base 2 logarithm by a polynomial approximation. |
+ | log2(x+1) |
+ +---------------------------------------------------------------------------*/
+int
+poly_l2p1(FPU_REG * arg, FPU_REG * result)
+{
+ char sign = 0;
+ long long Xsq;
+ FPU_REG arg_pl1, denom, accum, local_arg, poly_arg;
+
+
+ sign = arg->sign;
+
+ reg_add(arg, &CONST_1, &arg_pl1, FULL_PRECISION);
+
+ if ((arg_pl1.sign) | (arg_pl1.tag)) { /* We need a valid positive
+ * number! */
+ return 1;
+ }
+ reg_add(&CONST_1, &arg_pl1, &denom, FULL_PRECISION);
+ reg_div(arg, &denom, &local_arg, FULL_PRECISION);
+ local_arg.sign = 0; /* Make the sign positive */
+
+ /* Now we need to check that |local_arg| is less than 3-2*sqrt(2) =
+ * 0.17157.. = .0xafb0ccc0 * 2^-2 */
+
+ if (local_arg.exp >= EXP_BIAS - 3) {
+ if ((local_arg.exp > EXP_BIAS - 3) ||
+ (local_arg.sigh > (unsigned) 0xafb0ccc0)) {
+ /* The argument is large */
+ poly_l2(&arg_pl1, result);
+ return 0;
+ }
+ }
+ /* Make a copy of local_arg */
+ reg_move(&local_arg, &poly_arg);
+
+ /* Get poly_arg bits aligned as required */
+ shrx((unsigned *) &(poly_arg.sigl), -(poly_arg.exp - EXP_BIAS + 3));
+
+ mul64((long long *) &(poly_arg.sigl), (long long *) &(poly_arg.sigl), &Xsq);
+ poly_div16(&Xsq);
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &accum.sigl, (unsigned *) &Xsq, lterms, HIPOWER - 1);
+
+ accum.tag = TW_Valid; /* set the tags to Valid */
+ accum.sign = SIGN_POS; /* and make accum positive */
+
+ /* make accum compatible and normalize */
+ accum.exp = EXP_BIAS - 1;
+ normalize(&accum);
+
+ reg_u_mul(&local_arg, &accum, &accum, FULL_PRECISION);
+
+ reg_u_add(&local_arg, &accum, result, FULL_PRECISION);
+
+ /* Multiply the result by 2 */
+ result->exp++;
+
+ result->sign = sign;
+
+ return 0;
+}
diff --git a/sys/gnu/i386/fpemul/poly_mul64.s b/sys/gnu/i386/fpemul/poly_mul64.s
new file mode 100644
index 0000000..b5b325f
--- /dev/null
+++ b/sys/gnu/i386/fpemul/poly_mul64.s
@@ -0,0 +1,114 @@
+/*
+ * poly_mul64.S
+ *
+ * Multiply two 64 bit integers.
+ *
+ * Call from C as:
+ * void mul64(long long *a, long long *b, long long *result)
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+
+#include "fpu_asm.h"
+
+.text
+ .align 2,144
+.globl _mul64
+_mul64:
+ pushl %ebp
+ movl %esp,%ebp
+ subl $16,%esp
+ pushl %esi
+ pushl %ebx
+
+ movl PARAM1,%esi
+ movl PARAM2,%ecx
+ movl PARAM3,%ebx
+
+ xor %eax,%eax
+ movl %eax,-4(%ebp)
+ movl %eax,-8(%ebp)
+
+ movl (%esi),%eax
+ mull (%ecx)
+ movl %eax,-16(%ebp) /* Not used */
+ movl %edx,-12(%ebp)
+
+ movl (%esi),%eax
+ mull 4(%ecx)
+ addl %eax,-12(%ebp)
+ adcl %edx,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+ movl 4(%esi),%eax
+ mull (%ecx)
+ addl %eax,-12(%ebp)
+ adcl %edx,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+ movl 4(%esi),%eax
+ mull 4(%ecx)
+ addl %eax,-8(%ebp)
+ adcl %edx,-4(%ebp)
+
+ testb $128,-9(%ebp)
+ je L_no_round
+
+ addl $1,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+L_no_round:
+ movl -8(%ebp),%esi
+ movl %esi,(%ebx)
+ movl -4(%ebp),%esi
+ movl %esi,4(%ebx)
+
+ popl %ebx
+ popl %esi
+ leave
+ ret
diff --git a/sys/gnu/i386/fpemul/poly_sin.c b/sys/gnu/i386/fpemul/poly_sin.c
new file mode 100644
index 0000000..715f9c3
--- /dev/null
+++ b/sys/gnu/i386/fpemul/poly_sin.c
@@ -0,0 +1,182 @@
+/*
+ * poly_sin.c
+ *
+ * Computation of an approximation of the sin function by a polynomial
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+
+
+#define HIPOWER 5
+static unsigned short lterms[HIPOWER][4] =
+{
+ {0x846a, 0x42d1, 0xb544, 0x921f},
+ {0xe110, 0x75aa, 0xbc67, 0x1466},
+ {0x503d, 0xa43f, 0x83c1, 0x000a},
+ {0x8f9d, 0x7a19, 0x00f4, 0x0000},
+ {0xda03, 0x06aa, 0x0000, 0x0000},
+};
+
+static unsigned short negterms[HIPOWER][4] =
+{
+ {0x95ed, 0x2df2, 0xe731, 0xa55d},
+ {0xd159, 0xe62b, 0xd2cc, 0x0132},
+ {0x6342, 0xe9fb, 0x3c60, 0x0000},
+ {0x6256, 0xdf5a, 0x0002, 0x0000},
+ {0xf279, 0x000b, 0x0000, 0x0000},
+};
+
+
+/*--- poly_sine() -----------------------------------------------------------+
+ | |
+ +---------------------------------------------------------------------------*/
+void
+poly_sine(FPU_REG * arg, FPU_REG * result)
+{
+ short exponent;
+ FPU_REG Xx, Xx2, Xx4, accum, negaccum;
+
+
+ exponent = arg->exp - EXP_BIAS;
+
+ if (arg->tag == TW_Zero) {
+ /* Return 0.0 */
+ reg_move(&CONST_Z, result);
+ return;
+ }
+#ifdef PARANOID
+ if (arg->sign != 0) { /* Can't hack a number < 0.0 */
+ EXCEPTION(EX_Invalid);
+ reg_move(&CONST_QNaN, result);
+ return;
+ }
+ if (exponent >= 0) { /* Can't hack a number > 1.0 */
+ if ((exponent == 0) && (arg->sigl == 0) && (arg->sigh == 0x80000000)) {
+ reg_move(&CONST_1, result);
+ return;
+ }
+ EXCEPTION(EX_Invalid);
+ reg_move(&CONST_QNaN, result);
+ return;
+ }
+#endif /* PARANOID */
+
+ Xx.sigl = arg->sigl;
+ Xx.sigh = arg->sigh;
+ if (exponent < -1) {
+ /* shift the argument right by the required places */
+ if (shrx(&(Xx.sigl), -1 - exponent) >= (unsigned)0x80000000)
+ (*((long long *) (&(Xx.sigl))))++; /* round up */
+ }
+ mul64((long long *) &(Xx.sigl), (long long *) &(Xx.sigl),
+ (long long *) &(Xx2.sigl));
+ mul64((long long *) &(Xx2.sigl), (long long *) &(Xx2.sigl),
+ (long long *) &(Xx4.sigl));
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(accum.sign) = 0;
+ accum.exp = 0;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &(accum.sigl), &(Xx4.sigl), lterms, HIPOWER - 1);
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(negaccum.sign) = 0;
+ negaccum.exp = 0;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &(negaccum.sigl), &(Xx4.sigl), negterms, HIPOWER - 1);
+ mul64((long long *) &(Xx2.sigl), (long long *) &(negaccum.sigl),
+ (long long *) &(negaccum.sigl));
+
+ /* Subtract the mantissas */
+ *((long long *) (&(accum.sigl))) -= *((long long *) (&(negaccum.sigl)));
+
+ /* Convert to 64 bit signed-compatible */
+ accum.exp = EXP_BIAS - 1 + accum.exp;
+
+ *(short *) &(result->sign) = *(short *) &(accum.sign);
+ result->exp = accum.exp;
+ result->sigl = accum.sigl;
+ result->sigh = accum.sigh;
+
+ normalize(result);
+
+ reg_mul(result, arg, result, FULL_PRECISION);
+ reg_u_add(result, arg, result, FULL_PRECISION);
+
+ /* A small overflow may be possible... but an illegal result. */
+ if (result->exp >= EXP_BIAS) {
+ if ((result->exp > EXP_BIAS) /* Larger or equal 2.0 */
+ ||(result->sigl > 1) /* Larger than 1.0+msb */
+ ||(result->sigh != 0x80000000) /* Much > 1.0 */
+ ) {
+#ifdef DEBUGGING
+ RE_ENTRANT_CHECK_OFF
+ printk("\nEXP=%d, MS=%08x, LS=%08x\n", result->exp,
+ result->sigh, result->sigl);
+ RE_ENTRANT_CHECK_ON
+#endif /* DEBUGGING */
+ EXCEPTION(EX_INTERNAL | 0x103);
+ }
+#ifdef DEBUGGING
+ RE_ENTRANT_CHECK_OFF
+ printk("\n***CORRECTING ILLEGAL RESULT*** in poly_sin() computation\n");
+ printk("EXP=%d, MS=%08x, LS=%08x\n", result->exp,
+ result->sigh, result->sigl);
+ RE_ENTRANT_CHECK_ON
+#endif /* DEBUGGING */
+
+ result->sigl = 0; /* Truncate the result to 1.00 */
+ }
+}
diff --git a/sys/gnu/i386/fpemul/poly_tan.c b/sys/gnu/i386/fpemul/poly_tan.c
new file mode 100644
index 0000000..495de5a
--- /dev/null
+++ b/sys/gnu/i386/fpemul/poly_tan.c
@@ -0,0 +1,219 @@
+/*
+ * poly_tan.c
+ *
+ * Compute the tan of a FPU_REG, using a polynomial approximation.
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+
+
+#define HIPOWERop 3 /* odd poly, positive terms */
+static unsigned short oddplterms[HIPOWERop][4] =
+{
+ {0x846a, 0x42d1, 0xb544, 0x921f},
+ {0x6fb2, 0x0215, 0x95c0, 0x099c},
+ {0xfce6, 0x0cc8, 0x1c9a, 0x0000}
+};
+#define HIPOWERon 2 /* odd poly, negative terms */
+static unsigned short oddnegterms[HIPOWERon][4] =
+{
+ {0x6906, 0xe205, 0x25c8, 0x8838},
+ {0x1dd7, 0x3fe3, 0x944e, 0x002c}
+};
+#define HIPOWERep 2 /* even poly, positive terms */
+static unsigned short evenplterms[HIPOWERep][4] =
+{
+ {0xdb8f, 0x3761, 0x1432, 0x2acf},
+ {0x16eb, 0x13c1, 0x3099, 0x0003}
+};
+#define HIPOWERen 2 /* even poly, negative terms */
+static unsigned short evennegterms[HIPOWERen][4] =
+{
+ {0x3a7c, 0xe4c5, 0x7f87, 0x2945},
+ {0x572b, 0x664c, 0xc543, 0x018c}
+};
+
+
+/*--- poly_tan() ------------------------------------------------------------+
+ | |
+ +---------------------------------------------------------------------------*/
+void
+poly_tan(FPU_REG * arg, FPU_REG * y_reg)
+{
+ char invert = 0;
+ short exponent;
+ FPU_REG odd_poly, even_poly, pos_poly, neg_poly;
+ FPU_REG argSq;
+ long long arg_signif, argSqSq;
+
+
+ exponent = arg->exp - EXP_BIAS;
+
+ if (arg->tag == TW_Zero) {
+ /* Return 0.0 */
+ reg_move(&CONST_Z, y_reg);
+ return;
+ }
+ if (exponent >= -1) {
+ /* argument is in the range [0.5 .. 1.0] */
+ if (exponent >= 0) {
+#ifdef PARANOID
+ if ((exponent == 0) &&
+ (arg->sigl == 0) && (arg->sigh == 0x80000000))
+#endif /* PARANOID */
+ {
+ arith_overflow(y_reg);
+ return;
+ }
+#ifdef PARANOID
+ EXCEPTION(EX_INTERNAL | 0x104); /* There must be a logic
+ * error */
+ return;
+#endif /* PARANOID */
+ }
+ /* The argument is in the range [0.5 .. 1.0) */
+ /* Convert the argument to a number in the range (0.0 .. 0.5] */
+ *((long long *) (&arg->sigl)) = -*((long long *) (&arg->sigl));
+ normalize(arg); /* Needed later */
+ exponent = arg->exp - EXP_BIAS;
+ invert = 1;
+ }
+#ifdef PARANOID
+ if (arg->sign != 0) { /* Can't hack a number < 0.0 */
+ arith_invalid(y_reg);
+ return;
+ } /* Need a positive number */
+#endif /* PARANOID */
+
+ *(long long *) &arg_signif = *(long long *) &(arg->sigl);
+ if (exponent < -1) {
+ /* shift the argument right by the required places */
+ if (shrx(&arg_signif, -1 - exponent) >= (unsigned)0x80000000)
+ arg_signif++; /* round up */
+ }
+ mul64(&arg_signif, &arg_signif, (long long *) (&argSq.sigl));
+ mul64((long long *) (&argSq.sigl), (long long *) (&argSq.sigl), &argSqSq);
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(pos_poly.sign) = 0;
+ pos_poly.exp = EXP_BIAS;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &pos_poly.sigl, (unsigned *) &argSqSq, oddplterms, HIPOWERop - 1);
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(neg_poly.sign) = 0;
+ neg_poly.exp = EXP_BIAS;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &neg_poly.sigl, (unsigned *) &argSqSq, oddnegterms, HIPOWERon - 1);
+ mul64((long long *) (&argSq.sigl), (long long *) (&neg_poly.sigl),
+ (long long *) (&neg_poly.sigl));
+
+ /* Subtract the mantissas */
+ *((long long *) (&pos_poly.sigl)) -= *((long long *) (&neg_poly.sigl));
+
+ /* Convert to 64 bit signed-compatible */
+ pos_poly.exp -= 1;
+
+ reg_move(&pos_poly, &odd_poly);
+ normalize(&odd_poly);
+
+ reg_mul(&odd_poly, arg, &odd_poly, FULL_PRECISION);
+ reg_u_add(&odd_poly, arg, &odd_poly, FULL_PRECISION); /* This is just the odd
+ * polynomial */
+
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(pos_poly.sign) = 0;
+ pos_poly.exp = EXP_BIAS;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &pos_poly.sigl, (unsigned *) &argSqSq, evenplterms, HIPOWERep - 1);
+ mul64((long long *) (&argSq.sigl),
+ (long long *) (&pos_poly.sigl), (long long *) (&pos_poly.sigl));
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(neg_poly.sign) = 0;
+ neg_poly.exp = EXP_BIAS;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &neg_poly.sigl, (unsigned *) &argSqSq, evennegterms, HIPOWERen - 1);
+
+ /* Subtract the mantissas */
+ *((long long *) (&neg_poly.sigl)) -= *((long long *) (&pos_poly.sigl));
+ /* and multiply by argSq */
+
+ /* Convert argSq to a valid reg number */
+ *(short *) &(argSq.sign) = 0;
+ argSq.exp = EXP_BIAS - 1;
+ normalize(&argSq);
+
+ /* Convert to 64 bit signed-compatible */
+ neg_poly.exp -= 1;
+
+ reg_move(&neg_poly, &even_poly);
+ normalize(&even_poly);
+
+ reg_mul(&even_poly, &argSq, &even_poly, FULL_PRECISION);
+ reg_add(&even_poly, &argSq, &even_poly, FULL_PRECISION);
+ reg_sub(&CONST_1, &even_poly, &even_poly, FULL_PRECISION); /* This is just the even
+ * polynomial */
+
+ /* Now ready to copy the results */
+ if (invert) {
+ reg_div(&even_poly, &odd_poly, y_reg, FULL_PRECISION);
+ } else {
+ reg_div(&odd_poly, &even_poly, y_reg, FULL_PRECISION);
+ }
+
+}
diff --git a/sys/gnu/i386/fpemul/polynomial.s b/sys/gnu/i386/fpemul/polynomial.s
new file mode 100644
index 0000000..5588a84
--- /dev/null
+++ b/sys/gnu/i386/fpemul/polynomial.s
@@ -0,0 +1,182 @@
+/*
+ * polynomial.S
+ *
+ * Fixed point arithmetic polynomial evaluation.
+ *
+ * Call from C as:
+ * void polynomial(unsigned accum[], unsigned x[], unsigned terms[][2],
+ * int n)
+ *
+ * Computes:
+ * terms[0] + (terms[1] + (terms[2] + ... + (terms[n-1]*x)*x)*x)*x) ... )*x
+ * The result is returned in accum.
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+ .file "fpolynom.s"
+
+#include "fpu_asm.h"
+
+
+/* #define EXTRA_PRECISE*/
+
+#define TERM_SIZE $8
+
+
+.text
+ .align 2,144
+.globl _polynomial
+_polynomial:
+ pushl %ebp
+ movl %esp,%ebp
+ subl $32,%esp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi /* accum */
+ movl PARAM2,%edi /* x */
+ movl PARAM3,%ebx /* terms */
+ movl PARAM4,%ecx /* n */
+
+ movl TERM_SIZE,%eax
+ mull %ecx
+ movl %eax,%ecx
+
+ movl 4(%ebx,%ecx,1),%edx /* terms[n] */
+ movl %edx,-20(%ebp)
+ movl (%ebx,%ecx,1),%edx /* terms[n] */
+ movl %edx,-24(%ebp)
+ xor %eax,%eax
+ movl %eax,-28(%ebp)
+
+ subl TERM_SIZE,%ecx
+ js L_accum_done
+
+L_accum_loop:
+ xor %eax,%eax
+ movl %eax,-4(%ebp)
+ movl %eax,-8(%ebp)
+
+#ifdef EXTRA_PRECISE
+ movl -28(%ebp),%eax
+ mull 4(%edi) /* x ms long */
+ movl %edx,-12(%ebp)
+#endif EXTRA_PRECISE
+
+ movl -24(%ebp),%eax
+ mull (%edi) /* x ls long */
+/* movl %eax,-16(%ebp) */ /* Not needed */
+ addl %edx,-12(%ebp)
+ adcl $0,-8(%ebp)
+
+ movl -24(%ebp),%eax
+ mull 4(%edi) /* x ms long */
+ addl %eax,-12(%ebp)
+ adcl %edx,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+ movl -20(%ebp),%eax
+ mull (%edi)
+ addl %eax,-12(%ebp)
+ adcl %edx,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+ movl -20(%ebp),%eax
+ mull 4(%edi)
+ addl %eax,-8(%ebp)
+ adcl %edx,-4(%ebp)
+
+/* Now add the next term */
+ movl (%ebx,%ecx,1),%eax
+ addl %eax,-8(%ebp)
+ movl 4(%ebx,%ecx,1),%eax
+ adcl %eax,-4(%ebp)
+
+/* And put into the second register */
+ movl -4(%ebp),%eax
+ movl %eax,-20(%ebp)
+ movl -8(%ebp),%eax
+ movl %eax,-24(%ebp)
+
+#ifdef EXTRA_PRECISE
+ movl -12(%ebp),%eax
+ movl %eax,-28(%ebp)
+#else
+ testb $128,-25(%ebp)
+ je L_no_poly_round
+
+ addl $1,-24(%ebp)
+ adcl $0,-20(%ebp)
+L_no_poly_round:
+#endif EXTRA_PRECISE
+
+ subl TERM_SIZE,%ecx
+ jns L_accum_loop
+
+L_accum_done:
+#ifdef EXTRA_PRECISE
+/* And round the result */
+ testb $128,-25(%ebp)
+ je L_poly_done
+
+ addl $1,-24(%ebp)
+ adcl $0,-20(%ebp)
+#endif EXTRA_PRECISE
+
+L_poly_done:
+ movl -24(%ebp),%eax
+ movl %eax,(%esi)
+ movl -20(%ebp),%eax
+ movl %eax,4(%esi)
+
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
diff --git a/sys/gnu/i386/fpemul/reg_add_sub.c b/sys/gnu/i386/fpemul/reg_add_sub.c
new file mode 100644
index 0000000..aca1b34
--- /dev/null
+++ b/sys/gnu/i386/fpemul/reg_add_sub.c
@@ -0,0 +1,293 @@
+/*
+ * reg_add_sub.c
+ *
+ * Functions to add or subtract two registers and put the result in a third.
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | For each function, the destination may be any FPU_REG, including one of |
+ | the source FPU_REGs. |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "control_w.h"
+#include "fpu_system.h"
+
+
+void
+reg_add(FPU_REG * a, FPU_REG * b, FPU_REG * dest, int control_w)
+{
+ int diff;
+
+ if (!(a->tag | b->tag)) {
+ /* Both registers are valid */
+ if (!(a->sign ^ b->sign)) {
+ /* signs are the same */
+ reg_u_add(a, b, dest, control_w);
+ dest->sign = a->sign;
+ return;
+ }
+ /* The signs are different, so do a subtraction */
+ diff = a->exp - b->exp;
+ if (!diff) {
+ diff = a->sigh - b->sigh; /* Works only if ms bits
+ * are identical */
+ if (!diff) {
+ diff = a->sigl > b->sigl;
+ if (!diff)
+ diff = -(a->sigl < b->sigl);
+ }
+ }
+ if (diff > 0) {
+ reg_u_sub(a, b, dest, control_w);
+ dest->sign = a->sign;
+ } else
+ if (diff == 0) {
+ reg_move(&CONST_Z, dest);
+ /* sign depends upon rounding mode */
+ dest->sign = ((control_w & CW_RC) != RC_DOWN)
+ ? SIGN_POS : SIGN_NEG;
+ } else {
+ reg_u_sub(b, a, dest, control_w);
+ dest->sign = b->sign;
+ }
+ return;
+ } else {
+ if ((a->tag == TW_NaN) || (b->tag == TW_NaN)) {
+ real_2op_NaN(a, b, dest);
+ return;
+ } else
+ if (a->tag == TW_Zero) {
+ if (b->tag == TW_Zero) {
+ char different_signs = a->sign ^ b->sign;
+ /* Both are zero, result will be zero. */
+ reg_move(a, dest);
+ if (different_signs) {
+ /* Signs are different. */
+ /* Sign of answer depends upon
+ * rounding mode. */
+ dest->sign = ((control_w & CW_RC) != RC_DOWN)
+ ? SIGN_POS : SIGN_NEG;
+ }
+ } else {
+#ifdef DENORM_OPERAND
+ if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(b, dest);
+ }
+ return;
+ } else
+ if (b->tag == TW_Zero) {
+#ifdef DENORM_OPERAND
+ if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(a, dest);
+ return;
+ } else
+ if (a->tag == TW_Infinity) {
+ if (b->tag != TW_Infinity) {
+#ifdef DENORM_OPERAND
+ if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(a, dest);
+ return;
+ }
+ if (a->sign == b->sign) {
+ /* They are both + or
+ * - infinity */
+ reg_move(a, dest);
+ return;
+ }
+ arith_invalid(dest); /* Infinity-Infinity is
+ * undefined. */
+ return;
+ } else
+ if (b->tag == TW_Infinity) {
+#ifdef DENORM_OPERAND
+ if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(b, dest);
+ return;
+ }
+ }
+#ifdef PARANOID
+ EXCEPTION(EX_INTERNAL | 0x101);
+#endif
+}
+
+
+/* Subtract b from a. (a-b) -> dest */
+void
+reg_sub(FPU_REG * a, FPU_REG * b, FPU_REG * dest, int control_w)
+{
+ int diff;
+
+ if (!(a->tag | b->tag)) {
+ /* Both registers are valid */
+ diff = a->exp - b->exp;
+ if (!diff) {
+ diff = a->sigh - b->sigh; /* Works only if ms bits
+ * are identical */
+ if (!diff) {
+ diff = a->sigl > b->sigl;
+ if (!diff)
+ diff = -(a->sigl < b->sigl);
+ }
+ }
+ switch (a->sign * 2 + b->sign) {
+ case 0: /* P - P */
+ case 3: /* N - N */
+ if (diff > 0) {
+ reg_u_sub(a, b, dest, control_w);
+ dest->sign = a->sign;
+ } else
+ if (diff == 0) {
+#ifdef DENORM_OPERAND
+ if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(&CONST_Z, dest);
+ /* sign depends upon rounding mode */
+ dest->sign = ((control_w & CW_RC) != RC_DOWN)
+ ? SIGN_POS : SIGN_NEG;
+ } else {
+ reg_u_sub(b, a, dest, control_w);
+ dest->sign = a->sign ^ SIGN_POS ^ SIGN_NEG;
+ }
+ return;
+ case 1: /* P - N */
+ reg_u_add(a, b, dest, control_w);
+ dest->sign = SIGN_POS;
+ return;
+ case 2: /* N - P */
+ reg_u_add(a, b, dest, control_w);
+ dest->sign = SIGN_NEG;
+ return;
+ }
+ } else {
+ if ((a->tag == TW_NaN) || (b->tag == TW_NaN)) {
+ real_2op_NaN(a, b, dest);
+ return;
+ } else
+ if (b->tag == TW_Zero) {
+ if (a->tag == TW_Zero) {
+ char same_signs = !(a->sign ^ b->sign);
+ /* Both are zero, result will be zero. */
+ reg_move(a, dest); /* Answer for different
+ * signs. */
+ if (same_signs) {
+ /* Sign depends upon rounding
+ * mode */
+ dest->sign = ((control_w & CW_RC) != RC_DOWN)
+ ? SIGN_POS : SIGN_NEG;
+ }
+ } else {
+#ifdef DENORM_OPERAND
+ if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(a, dest);
+ }
+ return;
+ } else
+ if (a->tag == TW_Zero) {
+#ifdef DENORM_OPERAND
+ if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(b, dest);
+ dest->sign ^= SIGN_POS ^ SIGN_NEG;
+ return;
+ } else
+ if (a->tag == TW_Infinity) {
+ if (b->tag != TW_Infinity) {
+#ifdef DENORM_OPERAND
+ if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(a, dest);
+ return;
+ }
+ /* Both args are Infinity */
+ if (a->sign == b->sign) {
+ arith_invalid(dest); /* Infinity-Infinity is
+ * undefined. */
+ return;
+ }
+ reg_move(a, dest);
+ return;
+ } else
+ if (b->tag == TW_Infinity) {
+#ifdef DENORM_OPERAND
+ if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(b, dest);
+ dest->sign ^= SIGN_POS ^ SIGN_NEG;
+ return;
+ }
+ }
+#ifdef PARANOID
+ EXCEPTION(EX_INTERNAL | 0x110);
+#endif
+}
diff --git a/sys/gnu/i386/fpemul/reg_compare.c b/sys/gnu/i386/fpemul/reg_compare.c
new file mode 100644
index 0000000..8f65000
--- /dev/null
+++ b/sys/gnu/i386/fpemul/reg_compare.c
@@ -0,0 +1,374 @@
+/*
+ * reg_compare.c
+ *
+ * Compare two floating point registers
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | compare() is the core FPU_REG comparison function |
+ +---------------------------------------------------------------------------*/
+#include "param.h"
+#include "proc.h"
+#include "systm.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+#include "control_w.h"
+#include "status_w.h"
+
+
+int
+compare(FPU_REG * b)
+{
+ int diff;
+
+ if (FPU_st0_ptr->tag | b->tag) {
+ if (FPU_st0_ptr->tag == TW_Zero) {
+ if (b->tag == TW_Zero)
+ return COMP_A_eq_B;
+ if (b->tag == TW_Valid) {
+#ifdef DENORM_OPERAND
+ if ((b->exp <= EXP_UNDER) && (denormal_operand()))
+ return COMP_Denormal;
+#endif /* DENORM_OPERAND */
+ return (b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B;
+ }
+ } else
+ if (b->tag == TW_Zero) {
+ if (FPU_st0_ptr->tag == TW_Valid) {
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return COMP_Denormal;
+#endif /* DENORM_OPERAND */
+ return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B;
+ }
+ }
+ if (FPU_st0_ptr->tag == TW_Infinity) {
+ if ((b->tag == TW_Valid) || (b->tag == TW_Zero)) {
+#ifdef DENORM_OPERAND
+ if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)
+ && (denormal_operand()))
+ return COMP_Denormal;
+#endif /* DENORM_OPERAND */
+ return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B;
+ } else
+ if (b->tag == TW_Infinity) {
+ /* The 80486 book says that infinities
+ * can be equal! */
+ return (FPU_st0_ptr->sign == b->sign) ? COMP_A_eq_B :
+ ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
+ }
+ /* Fall through to the NaN code */
+ } else
+ if (b->tag == TW_Infinity) {
+ if ((FPU_st0_ptr->tag == TW_Valid) || (FPU_st0_ptr->tag == TW_Zero)) {
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->tag == TW_Valid)
+ && (FPU_st0_ptr->exp <= EXP_UNDER)
+ && (denormal_operand()))
+ return COMP_Denormal;
+#endif /* DENORM_OPERAND */
+ return (b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B;
+ }
+ /* Fall through to the NaN code */
+ }
+ /* The only possibility now should be that one of the
+ * arguments is a NaN */
+ if ((FPU_st0_ptr->tag == TW_NaN) || (b->tag == TW_NaN)) {
+ if (((FPU_st0_ptr->tag == TW_NaN) && !(FPU_st0_ptr->sigh & 0x40000000))
+ || ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)))
+ /* At least one arg is a signaling NaN */
+ return COMP_No_Comp | COMP_SNaN | COMP_NaN;
+ else
+ /* Neither is a signaling NaN */
+ return COMP_No_Comp | COMP_NaN;
+ }
+ EXCEPTION(EX_Invalid);
+ }
+#ifdef PARANOID
+ if (!(FPU_st0_ptr->sigh & 0x80000000))
+ EXCEPTION(EX_Invalid);
+ if (!(b->sigh & 0x80000000))
+ EXCEPTION(EX_Invalid);
+#endif /* PARANOID */
+
+#ifdef DENORM_OPERAND
+ if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
+ (b->exp <= EXP_UNDER)) && (denormal_operand()))
+ return COMP_Denormal;
+#endif /* DENORM_OPERAND */
+
+ if (FPU_st0_ptr->sign != b->sign)
+ return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B;
+
+ diff = FPU_st0_ptr->exp - b->exp;
+ if (diff == 0) {
+ diff = FPU_st0_ptr->sigh - b->sigh; /* Works only if ms bits
+ * are identical */
+ if (diff == 0) {
+ diff = FPU_st0_ptr->sigl > b->sigl;
+ if (diff == 0)
+ diff = -(FPU_st0_ptr->sigl < b->sigl);
+ }
+ }
+ if (diff > 0)
+ return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B;
+ if (diff < 0)
+ return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B;
+ return COMP_A_eq_B;
+
+}
+
+
+/* This function requires that st(0) is not empty */
+int
+compare_st_data(void)
+{
+ int f, c;
+
+ c = compare(&FPU_loaded_data);
+
+ if (c & (COMP_NaN | COMP_Denormal)) {
+ if (c & COMP_NaN) {
+ EXCEPTION(EX_Invalid);
+ f = SW_C3 | SW_C2 | SW_C0;
+ } else {
+ /* One of the operands is a de-normal */
+ return 0;
+ }
+ } else
+ switch (c) {
+ case COMP_A_lt_B:
+ f = SW_C0;
+ break;
+ case COMP_A_eq_B:
+ f = SW_C3;
+ break;
+ case COMP_A_gt_B:
+ f = 0;
+ break;
+ case COMP_No_Comp:
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#ifdef PARANOID
+ default:
+ EXCEPTION(EX_INTERNAL | 0x121);
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#endif /* PARANOID */
+ }
+ setcc(f);
+ return 1;
+}
+
+
+static int
+compare_st_st(int nr)
+{
+ int f, c;
+
+ if (!NOT_EMPTY_0 || !NOT_EMPTY(nr)) {
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ /* Stack fault */
+ EXCEPTION(EX_StackUnder);
+ return control_word & CW_Invalid;
+ }
+ c = compare(&st(nr));
+ if (c & (COMP_NaN | COMP_Denormal)) {
+ if (c & COMP_NaN) {
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ EXCEPTION(EX_Invalid);
+ return control_word & CW_Invalid;
+ } else {
+ /* One of the operands is a de-normal */
+ return control_word & CW_Denormal;
+ }
+ } else
+ switch (c) {
+ case COMP_A_lt_B:
+ f = SW_C0;
+ break;
+ case COMP_A_eq_B:
+ f = SW_C3;
+ break;
+ case COMP_A_gt_B:
+ f = 0;
+ break;
+ case COMP_No_Comp:
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#ifdef PARANOID
+ default:
+ EXCEPTION(EX_INTERNAL | 0x122);
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#endif /* PARANOID */
+ }
+ setcc(f);
+ return 1;
+}
+
+
+static int
+compare_u_st_st(int nr)
+{
+ int f, c;
+
+ if (!NOT_EMPTY_0 || !NOT_EMPTY(nr)) {
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ /* Stack fault */
+ EXCEPTION(EX_StackUnder);
+ return control_word & CW_Invalid;
+ }
+ c = compare(&st(nr));
+ if (c & (COMP_NaN | COMP_Denormal)) {
+ if (c & COMP_NaN) {
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ if (c & COMP_SNaN) { /* This is the only difference
+ * between un-ordered and
+ * ordinary comparisons */
+ EXCEPTION(EX_Invalid);
+ return control_word & CW_Invalid;
+ }
+ return 1;
+ } else {
+ /* One of the operands is a de-normal */
+ return control_word & CW_Denormal;
+ }
+ } else
+ switch (c) {
+ case COMP_A_lt_B:
+ f = SW_C0;
+ break;
+ case COMP_A_eq_B:
+ f = SW_C3;
+ break;
+ case COMP_A_gt_B:
+ f = 0;
+ break;
+ case COMP_No_Comp:
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#ifdef PARANOID
+ default:
+ EXCEPTION(EX_INTERNAL | 0x123);
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#endif /* PARANOID */
+ }
+ setcc(f);
+ return 1;
+}
+/*---------------------------------------------------------------------------*/
+
+void
+fcom_st()
+{
+ /* fcom st(i) */
+ compare_st_st(FPU_rm);
+}
+
+
+void
+fcompst()
+{
+ /* fcomp st(i) */
+ if (compare_st_st(FPU_rm))
+ pop();
+}
+
+
+void
+fcompp()
+{
+ /* fcompp */
+ if (FPU_rm != 1)
+ return Un_impl();
+ if (compare_st_st(1)) {
+ pop();
+ FPU_st0_ptr = &st(0);
+ pop();
+ }
+}
+
+
+void
+fucom_()
+{
+ /* fucom st(i) */
+ compare_u_st_st(FPU_rm);
+
+}
+
+
+void
+fucomp()
+{
+ /* fucomp st(i) */
+ if (compare_u_st_st(FPU_rm))
+ pop();
+}
+
+
+void
+fucompp()
+{
+ /* fucompp */
+ if (FPU_rm == 1) {
+ if (compare_u_st_st(1)) {
+ pop();
+ FPU_st0_ptr = &st(0);
+ pop();
+ }
+ } else
+ Un_impl();
+}
diff --git a/sys/gnu/i386/fpemul/reg_constant.c b/sys/gnu/i386/fpemul/reg_constant.c
new file mode 100644
index 0000000..8c767af
--- /dev/null
+++ b/sys/gnu/i386/fpemul/reg_constant.c
@@ -0,0 +1,165 @@
+/*
+ * reg_constant.c
+ *
+ * All of the constant FPU_REGs
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $id:$
+ *
+ */
+
+
+
+#include "param.h"
+#include "proc.h"
+#include "systm.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "status_w.h"
+#include "reg_constant.h"
+
+
+FPU_REG CONST_1 = {SIGN_POS, TW_Valid, EXP_BIAS,
+0x00000000, 0x80000000};
+FPU_REG CONST_2 = {SIGN_POS, TW_Valid, EXP_BIAS + 1,
+0x00000000, 0x80000000};
+FPU_REG CONST_HALF = {SIGN_POS, TW_Valid, EXP_BIAS - 1,
+0x00000000, 0x80000000};
+FPU_REG CONST_L2T = {SIGN_POS, TW_Valid, EXP_BIAS + 1,
+0xcd1b8afe, 0xd49a784b};
+FPU_REG CONST_L2E = {SIGN_POS, TW_Valid, EXP_BIAS,
+0x5c17f0bc, 0xb8aa3b29};
+FPU_REG CONST_PI = {SIGN_POS, TW_Valid, EXP_BIAS + 1,
+0x2168c235, 0xc90fdaa2};
+FPU_REG CONST_PI2 = {SIGN_POS, TW_Valid, EXP_BIAS,
+0x2168c235, 0xc90fdaa2};
+FPU_REG CONST_PI4 = {SIGN_POS, TW_Valid, EXP_BIAS - 1,
+0x2168c235, 0xc90fdaa2};
+FPU_REG CONST_LG2 = {SIGN_POS, TW_Valid, EXP_BIAS - 2,
+0xfbcff799, 0x9a209a84};
+FPU_REG CONST_LN2 = {SIGN_POS, TW_Valid, EXP_BIAS - 1,
+0xd1cf79ac, 0xb17217f7};
+/* Only the sign (and tag) is used in internal zeroes */
+FPU_REG CONST_Z = {SIGN_POS, TW_Zero, 0, 0x0, 0x0};
+/* Only the sign and significand (and tag) are used in internal NaNs */
+/* The 80486 never generates one of these
+FPU_REG CONST_SNAN = { SIGN_POS, TW_NaN, EXP_OVER, 0x00000001, 0x80000000 };
+ */
+/* This is the real indefinite QNaN */
+FPU_REG CONST_QNaN = {SIGN_NEG, TW_NaN, EXP_OVER, 0x00000000, 0xC0000000};
+/* Only the sign (and tag) is used in internal infinities */
+FPU_REG CONST_INF = {SIGN_POS, TW_Infinity, EXP_OVER, 0x00000000, 0x80000000};
+
+
+
+static void
+fld_const(FPU_REG * c)
+{
+ FPU_REG *st_new_ptr;
+
+ if (STACK_OVERFLOW) {
+ stack_overflow();
+ return;
+ }
+ push();
+ reg_move(c, FPU_st0_ptr);
+ status_word &= ~SW_C1;
+}
+
+
+static void
+fld1(void)
+{
+ fld_const(&CONST_1);
+}
+
+static void
+fldl2t(void)
+{
+ fld_const(&CONST_L2T);
+}
+
+static void
+fldl2e(void)
+{
+ fld_const(&CONST_L2E);
+}
+
+static void
+fldpi(void)
+{
+ fld_const(&CONST_PI);
+}
+
+static void
+fldlg2(void)
+{
+ fld_const(&CONST_LG2);
+}
+
+static void
+fldln2(void)
+{
+ fld_const(&CONST_LN2);
+}
+
+static void
+fldz(void)
+{
+ fld_const(&CONST_Z);
+}
+
+static FUNC constants_table[] = {
+ fld1, fldl2t, fldl2e, fldpi, fldlg2, fldln2, fldz, Un_impl
+};
+
+void
+fconst(void)
+{
+ (constants_table[FPU_rm]) ();
+}
diff --git a/sys/gnu/i386/fpemul/reg_constant.h b/sys/gnu/i386/fpemul/reg_constant.h
new file mode 100644
index 0000000..2ec19e4
--- /dev/null
+++ b/sys/gnu/i386/fpemul/reg_constant.h
@@ -0,0 +1,72 @@
+/*
+ * reg_constant.h
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+#ifndef _REG_CONSTANT_H_
+#define _REG_CONSTANT_H_
+
+#include "fpu_emu.h"
+
+extern FPU_REG CONST_1;
+extern FPU_REG CONST_2;
+extern FPU_REG CONST_HALF;
+extern FPU_REG CONST_L2T;
+extern FPU_REG CONST_L2E;
+extern FPU_REG CONST_PI;
+extern FPU_REG CONST_PI2;
+extern FPU_REG CONST_PI4;
+extern FPU_REG CONST_LG2;
+extern FPU_REG CONST_LN2;
+extern FPU_REG CONST_Z;
+extern FPU_REG CONST_PINF;
+extern FPU_REG CONST_INF;
+extern FPU_REG CONST_MINF;
+extern FPU_REG CONST_QNaN;
+
+#endif /* _REG_CONSTANT_H_ */
diff --git a/sys/gnu/i386/fpemul/reg_div.s b/sys/gnu/i386/fpemul/reg_div.s
new file mode 100644
index 0000000..2c1ffc1
--- /dev/null
+++ b/sys/gnu/i386/fpemul/reg_div.s
@@ -0,0 +1,285 @@
+ .file "reg_div.S"
+/*
+ * reg_div.S
+ *
+ * Divide one FPU_REG by another and put the result in a destination FPU_REG.
+ *
+ * Call from C as:
+ * void reg_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest,
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+#include "exception.h"
+#include "fpu_asm.h"
+#include "control_w.h"
+
+.text
+ .align 2
+
+.globl _reg_div
+_reg_div:
+ pushl %ebp
+ movl %esp,%ebp
+
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi
+ movl PARAM2,%ebx
+ movl PARAM3,%edi
+
+ movb TAG(%esi),%al
+ orb TAG(%ebx),%al
+
+ jne L_div_special /* Not (both numbers TW_Valid) */
+
+#ifdef DENORM_OPERAND
+/* Check for denormals */
+ cmpl EXP_UNDER,EXP(%esi)
+ jg xL_arg1_not_denormal
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xL_arg1_not_denormal:
+ cmpl EXP_UNDER,EXP(%ebx)
+ jg xL_arg2_not_denormal
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xL_arg2_not_denormal:
+#endif DENORM_OPERAND
+
+/* Both arguments are TW_Valid */
+ movb TW_Valid,TAG(%edi)
+
+ movb SIGN(%esi),%cl
+ cmpb %cl,SIGN(%ebx)
+ setne (%edi) /* Set the sign, requires SIGN_NEG=1, SIGN_POS=0 */
+
+ movl EXP(%esi),%edx
+ movl EXP(%ebx),%eax
+ subl %eax,%edx
+ addl EXP_BIAS,%edx
+ movl %edx,EXP(%edi)
+
+ jmp _divide_kernel
+
+
+/*-----------------------------------------------------------------------*/
+L_div_special:
+ cmpb TW_NaN,TAG(%esi) /* A NaN with anything to give NaN */
+ je L_arg1_NaN
+
+ cmpb TW_NaN,TAG(%ebx) /* A NaN with anything to give NaN */
+ jne L_no_NaN_arg
+
+/* Operations on NaNs */
+L_arg1_NaN:
+L_arg2_NaN:
+ pushl %edi /* Destination */
+ pushl %ebx
+ pushl %esi
+ call _real_2op_NaN
+ jmp LDiv_exit
+
+/* Invalid operations */
+L_zero_zero:
+L_inf_inf:
+ pushl %edi /* Destination */
+ call _arith_invalid /* 0/0 or Infinity/Infinity */
+ jmp LDiv_exit
+
+L_no_NaN_arg:
+ cmpb TW_Infinity,TAG(%esi)
+ jne L_arg1_not_inf
+
+ cmpb TW_Infinity,TAG(%ebx)
+ je L_inf_inf /* invalid operation */
+
+ cmpb TW_Valid,TAG(%ebx)
+ je L_inf_valid
+
+#ifdef PARANOID
+ /* arg2 must be zero or valid */
+ cmpb TW_Zero,TAG(%ebx)
+ ja L_unknown_tags
+#endif PARANOID
+
+ /* Note that p16-9 says that infinity/0 returns infinity */
+ jmp L_copy_arg1 /* Answer is Inf */
+
+L_inf_valid:
+#ifdef DENORM_OPERAND
+ cmpl EXP_UNDER,EXP(%ebx)
+ jg L_copy_arg1 /* Answer is Inf */
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+#endif DENORM_OPERAND
+
+ jmp L_copy_arg1 /* Answer is Inf */
+
+L_arg1_not_inf:
+ cmpb TW_Zero,TAG(%ebx) /* Priority to div-by-zero error */
+ jne L_arg2_not_zero
+
+ cmpb TW_Zero,TAG(%esi)
+ je L_zero_zero /* invalid operation */
+
+#ifdef PARANOID
+ /* arg1 must be valid */
+ cmpb TW_Valid,TAG(%esi)
+ ja L_unknown_tags
+#endif PARANOID
+
+/* Division by zero error */
+ pushl %edi /* destination */
+ movb SIGN(%esi),%al
+ xorb SIGN(%ebx),%al
+ pushl %eax /* lower 8 bits have the sign */
+ call _divide_by_zero
+ jmp LDiv_exit
+
+L_arg2_not_zero:
+ cmpb TW_Infinity,TAG(%ebx)
+ jne L_arg2_not_inf
+
+#ifdef DENORM_OPERAND
+ cmpb TW_Valid,TAG(%esi)
+ jne L_return_zero
+
+ cmpl EXP_UNDER,EXP(%esi)
+ jg L_return_zero /* Answer is zero */
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+#endif DENORM_OPERAND
+
+ jmp L_return_zero /* Answer is zero */
+
+L_arg2_not_inf:
+
+#ifdef PARANOID
+ cmpb TW_Zero,TAG(%esi)
+ jne L_unknown_tags
+#endif PARANOID
+
+ /* arg1 is zero, arg2 is not Infinity or a NaN */
+
+#ifdef DENORM_OPERAND
+ cmpl EXP_UNDER,EXP(%ebx)
+ jg L_copy_arg1 /* Answer is zero */
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+#endif DENORM_OPERAND
+
+L_copy_arg1:
+ movb TAG(%esi),%ax
+ movb %ax,TAG(%edi)
+ movl EXP(%esi),%eax
+ movl %eax,EXP(%edi)
+ movl SIGL(%esi),%eax
+ movl %eax,SIGL(%edi)
+ movl SIGH(%esi),%eax
+ movl %eax,SIGH(%edi)
+
+ movb SIGN(%esi),%cl
+ cmpb %cl,SIGN(%ebx)
+ jne LDiv_negative_result
+
+ movb SIGN_POS,SIGN(%edi)
+ jmp LDiv_exit
+
+LDiv_set_result_sign:
+ movb SIGN(%esi),%cl
+ cmpb %cl,SIGN(%edi)
+ jne LDiv_negative_result
+
+ movb SIGN_POS,SIGN(%ebx)
+ jmp LDiv_exit
+
+LDiv_negative_result:
+ movb SIGN_NEG,SIGN(%edi)
+
+LDiv_exit:
+ leal -12(%ebp),%esp
+
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
+
+
+L_return_zero:
+ movb TW_Zero,TAG(%edi)
+ jmp LDiv_set_result_sign
+
+#ifdef PARANOID
+L_unknown_tags:
+ push EX_INTERNAL | 0x208
+ call EXCEPTION
+
+ /* Generate a NaN for unknown tags */
+ movl _CONST_QNaN,%eax
+ movl %eax,(%edi)
+ movl _CONST_QNaN+4,%eax
+ movl %eax,SIGL(%edi)
+ movl _CONST_QNaN+8,%eax
+ movl %eax,SIGH(%edi)
+ jmp LDiv_exit
+#endif PARANOID
diff --git a/sys/gnu/i386/fpemul/reg_ld_str.c b/sys/gnu/i386/fpemul/reg_ld_str.c
new file mode 100644
index 0000000..b7a2d8a
--- /dev/null
+++ b/sys/gnu/i386/fpemul/reg_ld_str.c
@@ -0,0 +1,1377 @@
+/*
+ * reg_ld_str.c
+ *
+ * All of the functions which transfer data between user memory and FPU_REGs.
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+
+/*---------------------------------------------------------------------------+
+ | Note: |
+ | The file contains code which accesses user memory. |
+ | Emulator static data may change when user memory is accessed, due to |
+ | other processes using the emulator while swapping is in progress. |
+ +---------------------------------------------------------------------------*/
+#include "param.h"
+#include "proc.h"
+#include "systm.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+
+#include "fpu_emu.h"
+#include "fpu_system.h"
+#include "exception.h"
+#include "reg_constant.h"
+#include "control_w.h"
+#include "status_w.h"
+
+
+#define EXTENDED_Emax 0x3fff /* largest valid exponent */
+#define EXTENDED_Ebias 0x3fff
+#define EXTENDED_Emin (-0x3ffe) /* smallest valid exponent */
+
+#define DOUBLE_Emax 1023 /* largest valid exponent */
+#define DOUBLE_Ebias 1023
+#define DOUBLE_Emin (-1022) /* smallest valid exponent */
+
+#define SINGLE_Emax 127 /* largest valid exponent */
+#define SINGLE_Ebias 127
+#define SINGLE_Emin (-126) /* smallest valid exponent */
+
+#define LOST_UP (EX_Precision | SW_C1)
+#define LOST_DOWN EX_Precision
+
+FPU_REG FPU_loaded_data;
+
+
+/* Get a long double from user memory */
+void
+reg_load_extended(void)
+{
+ long double *s = (long double *) FPU_data_address;
+ unsigned long sigl, sigh, exp;
+
+ REENTRANT_CHECK(OFF);
+ /* Use temporary variables here because FPU_loaded data is static and
+ * hence re-entrancy problems can arise */
+ sigl = fuword((unsigned long *) s);
+ sigh = fuword(1 + (unsigned long *) s);
+ exp = fuword(4 + (unsigned short *) s);
+ REENTRANT_CHECK(ON);
+
+ FPU_loaded_data.sigl = sigl;
+ FPU_loaded_data.sigh = sigh;
+ FPU_loaded_data.exp = exp;
+
+ if (FPU_loaded_data.exp & 0x8000)
+ FPU_loaded_data.sign = SIGN_NEG;
+ else
+ FPU_loaded_data.sign = SIGN_POS;
+ if ((FPU_loaded_data.exp &= 0x7fff) == 0) {
+ if (!(FPU_loaded_data.sigl | FPU_loaded_data.sigh)) {
+ FPU_loaded_data.tag = TW_Zero;
+ return;
+ }
+ /* The number is a de-normal or pseudodenormal. */
+ /* The 80486 doesn't regard pseudodenormals as denormals here. */
+ if (!(FPU_loaded_data.sigh & 0x80000000))
+ EXCEPTION(EX_Denormal);
+ FPU_loaded_data.exp++;
+
+ /* The default behaviour will now take care of it. */
+ } else
+ if (FPU_loaded_data.exp == 0x7fff) {
+ FPU_loaded_data.exp = EXTENDED_Emax;
+ if ((FPU_loaded_data.sigh == 0x80000000)
+ && (FPU_loaded_data.sigl == 0)) {
+ FPU_loaded_data.tag = TW_Infinity;
+ return;
+ } else
+ if (!(FPU_loaded_data.sigh & 0x80000000)) {
+ /* Unsupported NaN data type */
+ EXCEPTION(EX_Invalid);
+ FPU_loaded_data.tag = TW_NaN;
+ return;
+ }
+ FPU_loaded_data.tag = TW_NaN;
+ return;
+ }
+ FPU_loaded_data.exp = (FPU_loaded_data.exp & 0x7fff) - EXTENDED_Ebias
+ + EXP_BIAS;
+ FPU_loaded_data.tag = TW_Valid;
+
+ if (!(sigh & 0x80000000)) {
+ /* Unsupported data type */
+ EXCEPTION(EX_Invalid);
+ normalize_nuo(&FPU_loaded_data);
+ }
+}
+
+
+/* Get a double from user memory */
+void
+reg_load_double(void)
+{
+ double *dfloat = (double *) FPU_data_address;
+ int exp;
+ unsigned m64, l64;
+
+ REENTRANT_CHECK(OFF);
+ m64 = fuword(1 + (unsigned long *) dfloat);
+ l64 = fuword((unsigned long *) dfloat);
+ REENTRANT_CHECK(ON);
+
+ if (m64 & 0x80000000)
+ FPU_loaded_data.sign = SIGN_NEG;
+ else
+ FPU_loaded_data.sign = SIGN_POS;
+ exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias;
+ m64 &= 0xfffff;
+ if (exp > DOUBLE_Emax) {
+ /* Infinity or NaN */
+ if ((m64 == 0) && (l64 == 0)) {
+ /* +- infinity */
+ FPU_loaded_data.exp = EXTENDED_Emax;
+ FPU_loaded_data.tag = TW_Infinity;
+ return;
+ } else {
+ /* Must be a signaling or quiet NaN */
+ FPU_loaded_data.exp = EXTENDED_Emax;
+ FPU_loaded_data.tag = TW_NaN;
+ FPU_loaded_data.sigh = (m64 << 11) | 0x80000000;
+ FPU_loaded_data.sigh |= l64 >> 21;
+ FPU_loaded_data.sigl = l64 << 11;
+ return;
+ }
+ } else
+ if (exp < DOUBLE_Emin) {
+ /* Zero or de-normal */
+ if ((m64 == 0) && (l64 == 0)) {
+ /* Zero */
+ int c = FPU_loaded_data.sign;
+ reg_move(&CONST_Z, &FPU_loaded_data);
+ FPU_loaded_data.sign = c;
+ return;
+ } else {
+ /* De-normal */
+ EXCEPTION(EX_Denormal);
+ FPU_loaded_data.exp = DOUBLE_Emin + EXP_BIAS;
+ FPU_loaded_data.tag = TW_Valid;
+ FPU_loaded_data.sigh = m64 << 11;
+ FPU_loaded_data.sigh |= l64 >> 21;
+ FPU_loaded_data.sigl = l64 << 11;
+ normalize_nuo(&FPU_loaded_data);
+ return;
+ }
+ } else {
+ FPU_loaded_data.exp = exp + EXP_BIAS;
+ FPU_loaded_data.tag = TW_Valid;
+ FPU_loaded_data.sigh = (m64 << 11) | 0x80000000;
+ FPU_loaded_data.sigh |= l64 >> 21;
+ FPU_loaded_data.sigl = l64 << 11;
+
+ return;
+ }
+}
+
+
+/* Get a float from user memory */
+void
+reg_load_single(void)
+{
+ float *single = (float *) FPU_data_address;
+ unsigned m32;
+ int exp;
+
+ REENTRANT_CHECK(OFF);
+ m32 = fuword((unsigned long *) single);
+ REENTRANT_CHECK(ON);
+
+ if (m32 & 0x80000000)
+ FPU_loaded_data.sign = SIGN_NEG;
+ else
+ FPU_loaded_data.sign = SIGN_POS;
+ if (!(m32 & 0x7fffffff)) {
+ /* Zero */
+ int c = FPU_loaded_data.sign;
+ reg_move(&CONST_Z, &FPU_loaded_data);
+ FPU_loaded_data.sign = c;
+ return;
+ }
+ exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias;
+ m32 = (m32 & 0x7fffff) << 8;
+ if (exp < SINGLE_Emin) {
+ /* De-normals */
+ EXCEPTION(EX_Denormal);
+ FPU_loaded_data.exp = SINGLE_Emin + EXP_BIAS;
+ FPU_loaded_data.tag = TW_Valid;
+ FPU_loaded_data.sigh = m32;
+ FPU_loaded_data.sigl = 0;
+ normalize_nuo(&FPU_loaded_data);
+ return;
+ } else
+ if (exp > SINGLE_Emax) {
+ /* Infinity or NaN */
+ if (m32 == 0) {
+ /* +- infinity */
+ FPU_loaded_data.exp = EXTENDED_Emax;
+ FPU_loaded_data.tag = TW_Infinity;
+ return;
+ } else {
+ /* Must be a signaling or quiet NaN */
+ FPU_loaded_data.exp = EXTENDED_Emax;
+ FPU_loaded_data.tag = TW_NaN;
+ FPU_loaded_data.sigh = m32 | 0x80000000;
+ FPU_loaded_data.sigl = 0;
+ return;
+ }
+ } else {
+ FPU_loaded_data.exp = exp + EXP_BIAS;
+ FPU_loaded_data.sigh = m32 | 0x80000000;
+ FPU_loaded_data.sigl = 0;
+ FPU_loaded_data.tag = TW_Valid;
+ }
+}
+
+
+/* Get a long long from user memory */
+void
+reg_load_int64(void)
+{
+ long long *_s = (long long *) FPU_data_address;
+ int e;
+ long long s;
+
+ REENTRANT_CHECK(OFF);
+ ((unsigned long *) &s)[0] = fuword((unsigned long *) _s);
+ ((unsigned long *) &s)[1] = fuword(1 + (unsigned long *) _s);
+ REENTRANT_CHECK(ON);
+
+ if (s == 0) {
+ reg_move(&CONST_Z, &FPU_loaded_data);
+ return;
+ }
+ if (s > 0)
+ FPU_loaded_data.sign = SIGN_POS;
+ else {
+ s = -s;
+ FPU_loaded_data.sign = SIGN_NEG;
+ }
+
+ e = EXP_BIAS + 63;
+ *((long long *) &FPU_loaded_data.sigl) = s;
+ FPU_loaded_data.exp = e;
+ FPU_loaded_data.tag = TW_Valid;
+ normalize_nuo(&FPU_loaded_data);
+}
+
+
+/* Get a long from user memory */
+void
+reg_load_int32(void)
+{
+ long *_s = (long *) FPU_data_address;
+ long s;
+ int e;
+
+ REENTRANT_CHECK(OFF);
+ s = (long) fuword((unsigned long *) _s);
+ REENTRANT_CHECK(ON);
+
+ if (s == 0) {
+ reg_move(&CONST_Z, &FPU_loaded_data);
+ return;
+ }
+ if (s > 0)
+ FPU_loaded_data.sign = SIGN_POS;
+ else {
+ s = -s;
+ FPU_loaded_data.sign = SIGN_NEG;
+ }
+
+ e = EXP_BIAS + 31;
+ FPU_loaded_data.sigh = s;
+ FPU_loaded_data.sigl = 0;
+ FPU_loaded_data.exp = e;
+ FPU_loaded_data.tag = TW_Valid;
+ normalize_nuo(&FPU_loaded_data);
+}
+
+
+/* Get a short from user memory */
+void
+reg_load_int16(void)
+{
+ short *_s = (short *) FPU_data_address;
+ int s, e;
+
+ REENTRANT_CHECK(OFF);
+ /* Cast as short to get the sign extended. */
+ s = (short) fuword((unsigned short *) _s);
+ REENTRANT_CHECK(ON);
+
+ if (s == 0) {
+ reg_move(&CONST_Z, &FPU_loaded_data);
+ return;
+ }
+ if (s > 0)
+ FPU_loaded_data.sign = SIGN_POS;
+ else {
+ s = -s;
+ FPU_loaded_data.sign = SIGN_NEG;
+ }
+
+ e = EXP_BIAS + 15;
+ FPU_loaded_data.sigh = s << 16;
+
+ FPU_loaded_data.sigl = 0;
+ FPU_loaded_data.exp = e;
+ FPU_loaded_data.tag = TW_Valid;
+ normalize_nuo(&FPU_loaded_data);
+}
+
+
+/* Get a packed bcd array from user memory */
+void
+reg_load_bcd(void)
+{
+ char *s = (char *) FPU_data_address;
+ int pos;
+ unsigned char bcd;
+ long long l = 0;
+
+ for (pos = 8; pos >= 0; pos--) {
+ l *= 10;
+ REENTRANT_CHECK(OFF);
+ bcd = (unsigned char) fubyte((unsigned char *) s + pos);
+ REENTRANT_CHECK(ON);
+ l += bcd >> 4;
+ l *= 10;
+ l += bcd & 0x0f;
+ }
+
+ /* Finish all access to user memory before putting stuff into the
+ * static FPU_loaded_data */
+ REENTRANT_CHECK(OFF);
+ FPU_loaded_data.sign =
+ ((unsigned char) fubyte((unsigned char *) s + 9)) & 0x80 ?
+ SIGN_NEG : SIGN_POS;
+ REENTRANT_CHECK(ON);
+
+ if (l == 0) {
+ char sign = FPU_loaded_data.sign;
+ reg_move(&CONST_Z, &FPU_loaded_data);
+ FPU_loaded_data.sign = sign;
+ } else {
+ *((long long *) &FPU_loaded_data.sigl) = l;
+ FPU_loaded_data.exp = EXP_BIAS + 63;
+ FPU_loaded_data.tag = TW_Valid;
+ normalize_nuo(&FPU_loaded_data);
+ }
+}
+/*===========================================================================*/
+
+/* Put a long double into user memory */
+int
+reg_store_extended(void)
+{
+ long double *d = (long double *) FPU_data_address;
+ long e = FPU_st0_ptr->exp - EXP_BIAS + EXTENDED_Ebias;
+ unsigned short sign = FPU_st0_ptr->sign * 0x8000;
+ unsigned long ls, ms;
+
+
+ if (FPU_st0_tag == TW_Valid) {
+ if (e >= 0x7fff) {
+ EXCEPTION(EX_Overflow); /* Overflow */
+ /* This is a special case: see sec 16.2.5.1 of the
+ * 80486 book */
+ if (control_word & EX_Overflow) {
+ /* Overflow to infinity */
+ ls = 0;
+ ms = 0x80000000;
+ e = 0x7fff;
+ } else
+ return 0;
+ } else
+ if (e <= 0) {
+ if (e > -63) {
+ /* Correctly format the de-normal */
+ int precision_loss;
+ FPU_REG tmp;
+
+ EXCEPTION(EX_Denormal);
+ reg_move(FPU_st0_ptr, &tmp);
+ tmp.exp += -EXTENDED_Emin + 63; /* largest exp to be 62 */
+ if ((precision_loss = round_to_int(&tmp))) {
+ EXCEPTION(EX_Underflow | precision_loss);
+ /* This is a special case: see
+ * sec 16.2.5.1 of the 80486
+ * book */
+ if (!(control_word & EX_Underflow))
+ return 0;
+ }
+ e = 0;
+ ls = tmp.sigl;
+ ms = tmp.sigh;
+ } else {
+ /* ****** ??? This should not be
+ * possible */
+ EXCEPTION(EX_Underflow); /* Underflow */
+ /* This is a special case: see sec
+ * 16.2.5.1 of the 80486 book */
+ if (control_word & EX_Underflow) {
+ /* Underflow to zero */
+ ls = 0;
+ ms = 0;
+ e = FPU_st0_ptr->sign == SIGN_POS ? 0x7fff : 0xffff;
+ } else
+ return 0;
+ }
+ } else {
+ ls = FPU_st0_ptr->sigl;
+ ms = FPU_st0_ptr->sigh;
+ }
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ ls = ms = 0;
+ e = 0;
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ ls = 0;
+ ms = 0x80000000;
+ e = 0x7fff;
+ } else
+ if (FPU_st0_tag == TW_NaN) {
+ ls = FPU_st0_ptr->sigl;
+ ms = FPU_st0_ptr->sigh;
+ e = 0x7fff;
+ } else
+ if (FPU_st0_tag == TW_Empty) {
+ /* Empty register (stack
+ * underflow) */
+ EXCEPTION(EX_StackUnder);
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ /* Put out the QNaN
+ * indefinite */
+ ls = 0;
+ ms = 0xc0000000;
+ e = 0xffff;
+ } else
+ return 0;
+ } else {
+ /* We don't use TW_Denormal
+ * yet ... perhaps never! */
+ EXCEPTION(EX_Invalid);
+ /* Store a NaN */
+ e = 0x7fff;
+ ls = 1;
+ ms = 0x80000000;
+ }
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, d, 10); */
+ suword((unsigned long *) d, ls);
+ suword(1 + (unsigned long *) d, ms);
+ suword(4 + (short *) d, (unsigned short) e | sign);
+ REENTRANT_CHECK(ON);
+
+ return 1;
+
+}
+
+
+/* Put a double into user memory */
+int
+reg_store_double(void)
+{
+ double *dfloat = (double *) FPU_data_address;
+ unsigned long l[2];
+ if (FPU_st0_tag == TW_Valid) {
+ int exp;
+ FPU_REG tmp;
+
+ reg_move(FPU_st0_ptr, &tmp);
+ exp = tmp.exp - EXP_BIAS;
+
+ if (exp < DOUBLE_Emin) { /* It may be a denormal */
+ /* Make a de-normal */
+ int precision_loss;
+
+ if (exp <= -EXTENDED_Ebias)
+ EXCEPTION(EX_Denormal);
+
+ tmp.exp += -DOUBLE_Emin + 52; /* largest exp to be 51 */
+
+ if ((precision_loss = round_to_int(&tmp))) {
+#ifdef PECULIAR_486
+ /* Did it round to a non-denormal ? */
+ /* This behaviour might be regarded as
+ * peculiar, it appears that the 80486 rounds
+ * to the dest precision, then converts to
+ * decide underflow. */
+ if ((tmp.sigh == 0x00100000) && (tmp.sigl == 0) &&
+ (FPU_st0_ptr->sigl & 0x000007ff))
+ EXCEPTION(precision_loss);
+ else
+#endif /* PECULIAR_486 */
+ {
+ EXCEPTION(EX_Underflow | precision_loss);
+ /* This is a special case: see sec
+ * 16.2.5.1 of the 80486 book */
+ if (!(control_word & EX_Underflow))
+ return 0;
+ }
+ }
+ l[0] = tmp.sigl;
+ l[1] = tmp.sigh;
+ } else {
+ if (tmp.sigl & 0x000007ff) {
+ unsigned long increment = 0; /* avoid gcc warnings */
+
+ switch (control_word & CW_RC) {
+ case RC_RND:
+ /* Rounding can get a little messy.. */
+ increment = ((tmp.sigl & 0x7ff) > 0x400) | /* nearest */
+ ((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */
+ break;
+ case RC_DOWN: /* towards -infinity */
+ increment = (tmp.sign == SIGN_POS) ? 0 : tmp.sigl & 0x7ff;
+ break;
+ case RC_UP: /* towards +infinity */
+ increment = (tmp.sign == SIGN_POS) ? tmp.sigl & 0x7ff : 0;
+ break;
+ case RC_CHOP:
+ increment = 0;
+ break;
+ }
+
+ /* Truncate the mantissa */
+ tmp.sigl &= 0xfffff800;
+
+ if (increment) {
+ set_precision_flag_up();
+
+ if (tmp.sigl >= 0xfffff800) {
+ /* the sigl part overflows */
+ if (tmp.sigh == 0xffffffff) {
+ /* The sigh part
+ * overflows */
+ tmp.sigh = 0x80000000;
+ exp++;
+ if (exp >= EXP_OVER)
+ goto overflow;
+ } else {
+ tmp.sigh++;
+ }
+ tmp.sigl = 0x00000000;
+ } else {
+ /* We only need to increment
+ * sigl */
+ tmp.sigl += 0x00000800;
+ }
+ } else
+ set_precision_flag_down();
+ }
+ l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
+ l[1] = ((tmp.sigh >> 11) & 0xfffff);
+
+ if (exp > DOUBLE_Emax) {
+ overflow:
+ EXCEPTION(EX_Overflow);
+ /* This is a special case: see sec 16.2.5.1 of
+ * the 80486 book */
+ if (control_word & EX_Overflow) {
+ /* Overflow to infinity */
+ l[0] = 0x00000000; /* Set to */
+ l[1] = 0x7ff00000; /* + INF */
+ } else
+ return 0;
+ } else {
+ /* Add the exponent */
+ l[1] |= (((exp + DOUBLE_Ebias) & 0x7ff) << 20);
+ }
+ }
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ /* Number is zero */
+ l[0] = 0;
+ l[1] = 0;
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ l[0] = 0;
+ l[1] = 0x7ff00000;
+ } else
+ if (FPU_st0_tag == TW_NaN) {
+ /* See if we can get a valid NaN from
+ * the FPU_REG */
+ l[0] = (FPU_st0_ptr->sigl >> 11) | (FPU_st0_ptr->sigh << 21);
+ l[1] = ((FPU_st0_ptr->sigh >> 11) & 0xfffff);
+ if (!(l[0] | l[1])) {
+ /* This case does not seem to
+ * be handled by the 80486
+ * specs */
+ EXCEPTION(EX_Invalid);
+ /* Make the quiet NaN "real
+ * indefinite" */
+ goto put_indefinite;
+ }
+ l[1] |= 0x7ff00000;
+ } else
+ if (FPU_st0_tag == TW_Empty) {
+ /* Empty register (stack
+ * underflow) */
+ EXCEPTION(EX_StackUnder);
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ /* Put out the QNaN
+ * indefinite */
+ put_indefinite:
+ REENTRANT_CHECK(OFF);
+ /* verify_area(VERIFY_W
+ * RITE, (void *)
+ * dfloat, 8); */
+ suword((unsigned long *) dfloat, 0);
+ suword(1 + (unsigned long *) dfloat, 0xfff80000);
+ REENTRANT_CHECK(ON);
+ return 1;
+ } else
+ return 0;
+ }
+#if 0 /* TW_Denormal is not used yet, and probably
+ * won't be */
+ else
+ if (FPU_st0_tag == TW_Denormal) {
+ /* Extended real ->
+ * double real will
+ * always underflow */
+ l[0] = l[1] = 0;
+ EXCEPTION(EX_Underflow);
+ }
+#endif
+ if (FPU_st0_ptr->sign)
+ l[1] |= 0x80000000;
+
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, (void *) dfloat, 8);*/
+ suword((u_long *) dfloat, l[0]);
+ suword((u_long *) dfloat + 1, l[1]);
+/*
+ suword(l[0], (unsigned long *) dfloat);
+ suword(l[1], 1 + (unsigned long *) dfloat);*/
+ REENTRANT_CHECK(ON);
+
+ return 1;
+}
+
+
+/* Put a float into user memory */
+int
+reg_store_single(void)
+{
+ float *single = (float *) FPU_data_address;
+ long templ;
+
+ if (FPU_st0_tag == TW_Valid) {
+ int exp;
+ FPU_REG tmp;
+
+ reg_move(FPU_st0_ptr, &tmp);
+ exp = tmp.exp - EXP_BIAS;
+
+ if (exp < SINGLE_Emin) {
+ /* Make a de-normal */
+ int precision_loss;
+
+ if (exp <= -EXTENDED_Ebias)
+ EXCEPTION(EX_Denormal);
+
+ tmp.exp += -SINGLE_Emin + 23; /* largest exp to be 22 */
+
+ if ((precision_loss = round_to_int(&tmp))) {
+#ifdef PECULIAR_486
+ /* Did it round to a non-denormal ? */
+ /* This behaviour might be regarded as
+ * peculiar, it appears that the 80486 rounds
+ * to the dest precision, then converts to
+ * decide underflow. */
+ if ((tmp.sigl == 0x00800000) &&
+ ((FPU_st0_ptr->sigh & 0x000000ff) || FPU_st0_ptr->sigl))
+ EXCEPTION(precision_loss);
+ else
+#endif /* PECULIAR_486 */
+ {
+ EXCEPTION(EX_Underflow | precision_loss);
+ /* This is a special case: see sec
+ * 16.2.5.1 of the 80486 book */
+ if (!(control_word & EX_Underflow))
+ return 0;
+ }
+ }
+ templ = tmp.sigl;
+ } else {
+ if (tmp.sigl | (tmp.sigh & 0x000000ff)) {
+ unsigned long increment = 0; /* avoid gcc warnings */
+ unsigned long sigh = tmp.sigh;
+ unsigned long sigl = tmp.sigl;
+
+ switch (control_word & CW_RC) {
+ case RC_RND:
+ increment = ((sigh & 0xff) > 0x80) /* more than half */
+ ||(((sigh & 0xff) == 0x80) && sigl) /* more than half */
+ ||((sigh & 0x180) == 0x180); /* round to even */
+ break;
+ case RC_DOWN: /* towards -infinity */
+ increment = (tmp.sign == SIGN_POS)
+ ? 0 : (sigl | (sigh & 0xff));
+ break;
+ case RC_UP: /* towards +infinity */
+ increment = (tmp.sign == SIGN_POS)
+ ? (sigl | (sigh & 0xff)) : 0;
+ break;
+ case RC_CHOP:
+ increment = 0;
+ break;
+ }
+
+ /* Truncate part of the mantissa */
+ tmp.sigl = 0;
+
+ if (increment) {
+ set_precision_flag_up();
+
+ if (sigh >= 0xffffff00) {
+ /* The sigh part overflows */
+ tmp.sigh = 0x80000000;
+ exp++;
+ if (exp >= EXP_OVER)
+ goto overflow;
+ } else {
+ tmp.sigh &= 0xffffff00;
+ tmp.sigh += 0x100;
+ }
+ } else {
+ set_precision_flag_down();
+ tmp.sigh &= 0xffffff00; /* Finish the truncation */
+ }
+ }
+ templ = (tmp.sigh >> 8) & 0x007fffff;
+
+ if (exp > SINGLE_Emax) {
+ overflow:
+ EXCEPTION(EX_Overflow);
+ /* This is a special case: see sec 16.2.5.1 of
+ * the 80486 book */
+ if (control_word & EX_Overflow) {
+ /* Overflow to infinity */
+ templ = 0x7f800000;
+ } else
+ return 0;
+ } else
+ templ |= ((exp + SINGLE_Ebias) & 0xff) << 23;
+ }
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ templ = 0;
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ templ = 0x7f800000;
+ } else
+ if (FPU_st0_tag == TW_NaN) {
+ /* See if we can get a valid NaN from
+ * the FPU_REG */
+ templ = FPU_st0_ptr->sigh >> 8;
+ if (!(templ & 0x3fffff)) {
+ /* This case does not seem to
+ * be handled by the 80486
+ * specs */
+ EXCEPTION(EX_Invalid);
+ /* Make the quiet NaN "real
+ * indefinite" */
+ goto put_indefinite;
+ }
+ templ |= 0x7f800000;
+ } else
+ if (FPU_st0_tag == TW_Empty) {
+ /* Empty register (stack
+ * underflow) */
+ EXCEPTION(EX_StackUnder);
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ /* Put out the QNaN
+ * indefinite */
+ put_indefinite:
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, (void *) single, 4); */
+ suword((unsigned long *) single, 0xffc00000);
+ REENTRANT_CHECK(ON);
+ return 1;
+ } else
+ return 0;
+ }
+#if 0 /* TW_Denormal is not used yet, and probably
+ * won't be */
+ else
+ if (FPU_st0_tag == TW_Denormal) {
+ /* Extended real ->
+ * real will always
+ * underflow */
+ templ = 0;
+ EXCEPTION(EX_Underflow);
+ }
+#endif
+#ifdef PARANOID
+ else {
+ EXCEPTION(EX_INTERNAL | 0x106);
+ return 0;
+ }
+#endif
+ if (FPU_st0_ptr->sign)
+ templ |= 0x80000000;
+
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, (void *) single, 4); */
+ suword((unsigned long *) single, templ);
+ REENTRANT_CHECK(ON);
+
+ return 1;
+}
+
+
+/* Put a long long into user memory */
+int
+reg_store_int64(void)
+{
+ long long *d = (long long *) FPU_data_address;
+ FPU_REG t;
+ long long tll;
+
+ if (FPU_st0_tag == TW_Empty) {
+ /* Empty register (stack underflow) */
+ EXCEPTION(EX_StackUnder);
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ /* Put out the QNaN indefinite */
+ goto put_indefinite;
+ } else
+ return 0;
+ }
+ reg_move(FPU_st0_ptr, &t);
+ round_to_int(&t);
+ ((long *) &tll)[0] = t.sigl;
+ ((long *) &tll)[1] = t.sigh;
+ if ((t.sigh & 0x80000000) &&
+ !((t.sigh == 0x80000000) && (t.sigl == 0) && (t.sign == SIGN_NEG))) {
+ EXCEPTION(EX_Invalid);
+ /* This is a special case: see sec 16.2.5.1 of the 80486 book */
+ if (control_word & EX_Invalid) {
+ /* Produce "indefinite" */
+ put_indefinite:
+ ((long *) &tll)[1] = 0x80000000;
+ ((long *) &tll)[0] = 0;
+ } else
+ return 0;
+ } else
+ if (t.sign)
+ tll = -tll;
+
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, (void *) d, 8); */
+ suword((unsigned long *) d, ((long *) &tll)[0]);
+ suword(1 + (unsigned long *) d, ((long *) &tll)[1]);
+ REENTRANT_CHECK(ON);
+
+ return 1;
+}
+
+
+/* Put a long into user memory */
+int
+reg_store_int32(void)
+{
+ long *d = (long *) FPU_data_address;
+ FPU_REG t;
+
+ if (FPU_st0_tag == TW_Empty) {
+ /* Empty register (stack underflow) */
+ EXCEPTION(EX_StackUnder);
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ /* Put out the QNaN indefinite */
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, d, 4);*/
+ suword((unsigned long *) d, 0x80000000);
+ REENTRANT_CHECK(ON);
+ return 1;
+ } else
+ return 0;
+ }
+ reg_move(FPU_st0_ptr, &t);
+ round_to_int(&t);
+ if (t.sigh ||
+ ((t.sigl & 0x80000000) &&
+ !((t.sigl == 0x80000000) && (t.sign == SIGN_NEG)))) {
+ EXCEPTION(EX_Invalid);
+ /* This is a special case: see sec 16.2.5.1 of the 80486 book */
+ if (control_word & EX_Invalid) {
+ /* Produce "indefinite" */
+ t.sigl = 0x80000000;
+ } else
+ return 0;
+ } else
+ if (t.sign)
+ t.sigl = -(long) t.sigl;
+
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, d, 4); */
+ suword((unsigned long *) d, t.sigl);
+ REENTRANT_CHECK(ON);
+
+ return 1;
+}
+
+
+/* Put a short into user memory */
+int
+reg_store_int16(void)
+{
+ short *d = (short *) FPU_data_address;
+ FPU_REG t;
+ short ts;
+
+ if (FPU_st0_tag == TW_Empty) {
+ /* Empty register (stack underflow) */
+ EXCEPTION(EX_StackUnder);
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ /* Put out the QNaN indefinite */
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, d, 2);*/
+ suword((unsigned short *) d, 0x8000);
+ REENTRANT_CHECK(ON);
+ return 1;
+ } else
+ return 0;
+ }
+ reg_move(FPU_st0_ptr, &t);
+ round_to_int(&t);
+ if (t.sigh ||
+ ((t.sigl & 0xffff8000) &&
+ !((t.sigl == 0x8000) && (t.sign == SIGN_NEG)))) {
+ EXCEPTION(EX_Invalid);
+ /* This is a special case: see sec 16.2.5.1 of the 80486 book */
+ if (control_word & EX_Invalid) {
+ /* Produce "indefinite" */
+ ts = 0x8000;
+ } else
+ return 0;
+ } else
+ if (t.sign)
+ t.sigl = -t.sigl;
+
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, d, 2); */
+ suword((short *) d, (short) t.sigl);
+ REENTRANT_CHECK(ON);
+
+ return 1;
+}
+
+
+/* Put a packed bcd array into user memory */
+int
+reg_store_bcd(void)
+{
+ char *d = (char *) FPU_data_address;
+ FPU_REG t;
+ long long ll;
+ unsigned char b;
+ int i;
+ unsigned char sign = (FPU_st0_ptr->sign == SIGN_NEG) ? 0x80 : 0;
+
+ if (FPU_st0_tag == TW_Empty) {
+ /* Empty register (stack underflow) */
+ EXCEPTION(EX_StackUnder);
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ /* Put out the QNaN indefinite */
+ goto put_indefinite;
+ } else
+ return 0;
+ }
+ reg_move(FPU_st0_ptr, &t);
+ round_to_int(&t);
+ ll = *(long long *) (&t.sigl);
+
+ /* Check for overflow, by comparing with 999999999999999999 decimal. */
+ if ((t.sigh > 0x0de0b6b3) ||
+ ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff))) {
+ EXCEPTION(EX_Invalid);
+ /* This is a special case: see sec 16.2.5.1 of the 80486 book */
+ if (control_word & EX_Invalid) {
+ put_indefinite:
+ /* Produce "indefinite" */
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, d, 10);*/
+ subyte((unsigned char *) d + 7, 0xff);
+ subyte((unsigned char *) d + 8, 0xff);
+ subyte((unsigned char *) d + 9, 0xff);
+ REENTRANT_CHECK(ON);
+ return 1;
+ } else
+ return 0;
+ }
+/* verify_area(VERIFY_WRITE, d, 10);*/
+ for (i = 0; i < 9; i++) {
+ b = div_small(&ll, 10);
+ b |= (div_small(&ll, 10)) << 4;
+ REENTRANT_CHECK(OFF);
+ subyte((unsigned char *) d + i, b);
+ REENTRANT_CHECK(ON);
+ }
+ REENTRANT_CHECK(OFF);
+ subyte((unsigned char *) d + 9, sign);
+ REENTRANT_CHECK(ON);
+
+ return 1;
+}
+/*===========================================================================*/
+
+/* r gets mangled such that sig is int, sign:
+ it is NOT normalized */
+/* The return value (in eax) is zero if the result is exact,
+ if bits are changed due to rounding, truncation, etc, then
+ a non-zero value is returned */
+/* Overflow is signalled by a non-zero return value (in eax).
+ In the case of overflow, the returned significand always has the
+ the largest possible value */
+/* The value returned in eax is never actually needed :-) */
+int
+round_to_int(FPU_REG * r)
+{
+ char very_big;
+ unsigned eax;
+
+ if (r->tag == TW_Zero) {
+ /* Make sure that zero is returned */
+ *(long long *) &r->sigl = 0;
+ return 0; /* o.k. */
+ }
+ if (r->exp > EXP_BIAS + 63) {
+ r->sigl = r->sigh = ~0; /* The largest representable number */
+ return 1; /* overflow */
+ }
+ eax = shrxs(&r->sigl, EXP_BIAS + 63 - r->exp);
+ very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */
+#define half_or_more (eax & 0x80000000)
+#define frac_part (eax)
+#define more_than_half ((eax & 0x80000001) == 0x80000001)
+ switch (control_word & CW_RC) {
+ case RC_RND:
+ if (more_than_half /* nearest */
+ || (half_or_more && (r->sigl & 1))) { /* odd -> even */
+ if (very_big)
+ return 1; /* overflow */
+ (*(long long *) (&r->sigl))++;
+ return LOST_UP;
+ }
+ break;
+ case RC_DOWN:
+ if (frac_part && r->sign) {
+ if (very_big)
+ return 1; /* overflow */
+ (*(long long *) (&r->sigl))++;
+ return LOST_UP;
+ }
+ break;
+ case RC_UP:
+ if (frac_part && !r->sign) {
+ if (very_big)
+ return 1; /* overflow */
+ (*(long long *) (&r->sigl))++;
+ return LOST_UP;
+ }
+ break;
+ case RC_CHOP:
+ break;
+ }
+
+ return eax ? LOST_DOWN : 0;
+
+}
+/*===========================================================================*/
+
+char *
+fldenv(void)
+{
+ char *s = (char *) FPU_data_address;
+ unsigned short tag_word = 0;
+ unsigned char tag;
+ int i;
+
+ REENTRANT_CHECK(OFF);
+ control_word = fuword((unsigned short *) s);
+ status_word = fuword((unsigned short *) (s + 4));
+ tag_word = fuword((unsigned short *) (s + 8));
+ ip_offset = fuword((unsigned long *) (s + 0x0c));
+ cs_selector = fuword((unsigned long *) (s + 0x10));
+ data_operand_offset = fuword((unsigned long *) (s + 0x14));
+ operand_selector = fuword((unsigned long *) (s + 0x18));
+ REENTRANT_CHECK(ON);
+
+ top = (status_word >> SW_Top_Shift) & 7;
+
+ for (i = 0; i < 8; i++) {
+ tag = tag_word & 3;
+ tag_word >>= 2;
+
+ switch (tag) {
+ case 0:
+ regs[i].tag = TW_Valid;
+ break;
+ case 1:
+ regs[i].tag = TW_Zero;
+ break;
+ case 2:
+ regs[i].tag = TW_NaN;
+ break;
+ case 3:
+ regs[i].tag = TW_Empty;
+ break;
+ }
+ }
+
+ FPU_data_address = (void *) data_operand_offset; /* We want no net effect */
+ FPU_entry_eip = ip_offset; /* We want no net effect */
+
+ return s + 0x1c;
+}
+
+
+void
+frstor(void)
+{
+ int i, stnr;
+ unsigned char tag;
+ unsigned short saved_status, saved_control;
+ char *s = (char *) fldenv();
+
+ saved_status = status_word;
+ saved_control = control_word;
+ control_word = 0x037f; /* Mask all interrupts while we load. */
+ for (i = 0; i < 8; i++) {
+ /* load each register */
+ FPU_data_address = (void *) (s + i * 10);
+ reg_load_extended();
+ stnr = (i + top) & 7;
+ tag = regs[stnr].tag; /* derived from the loaded tag word */
+ reg_move(&FPU_loaded_data, &regs[stnr]);
+ if (tag == TW_NaN) {
+ /* The current data is a special, i.e. NaN,
+ * unsupported, infinity, or denormal */
+ unsigned char t = regs[stnr].tag; /* derived from the new
+ * data */
+ if ( /* (t == TW_Valid) || *** */ (t == TW_Zero))
+ regs[stnr].tag = TW_NaN;
+ } else
+ regs[stnr].tag = tag;
+ }
+ control_word = saved_control;
+ status_word = saved_status;
+
+ FPU_data_address = (void *) data_operand_offset; /* We want no net effect */
+}
+
+
+unsigned short
+tag_word(void)
+{
+ unsigned short word = 0;
+ unsigned char tag;
+ int i;
+
+ for (i = 7; i >= 0; i--) {
+ switch (tag = regs[i].tag) {
+#if 0 /* TW_Denormal is not used yet, and probably
+ * won't be */
+ case TW_Denormal:
+#endif
+ case TW_Valid:
+ if (regs[i].exp <= (EXP_BIAS - EXTENDED_Ebias))
+ tag = 2;
+ break;
+ case TW_Infinity:
+ case TW_NaN:
+ tag = 2;
+ break;
+ case TW_Empty:
+ tag = 3;
+ break;
+ /* TW_Valid and TW_Zero already have the correct value */
+ }
+ word <<= 2;
+ word |= tag;
+ }
+ return word;
+}
+
+
+char *
+fstenv(void)
+{
+ char *d = (char *) FPU_data_address;
+
+/* verify_area(VERIFY_WRITE, d, 28);*/
+
+#if 0 /****/
+ *(unsigned short *) &cs_selector = fpu_cs;
+ *(unsigned short *) &operand_selector = fpu_os;
+#endif /****/
+
+ REENTRANT_CHECK(OFF);
+ suword((unsigned short *) d, control_word);
+ suword((unsigned short *) (d + 4), (status_word & ~SW_Top) | ((top & 7) << SW_Top_Shift));
+ suword((unsigned short *) (d + 8), tag_word());
+ suword((unsigned long *) (d + 0x0c), ip_offset);
+ suword((unsigned long *) (d + 0x10), cs_selector);
+ suword((unsigned long *) (d + 0x14), data_operand_offset);
+ suword((unsigned long *) (d + 0x18), operand_selector);
+ REENTRANT_CHECK(ON);
+
+ return d + 0x1c;
+}
+
+
+void
+fsave(void)
+{
+ char *d;
+ FPU_REG tmp, *rp;
+ int i;
+ short e;
+
+ d = fstenv();
+/* verify_area(VERIFY_WRITE, d, 80);*/
+ for (i = 0; i < 8; i++) {
+ /* Store each register in the order: st(0), st(1), ... */
+ rp = &regs[(top + i) & 7];
+
+ e = rp->exp - EXP_BIAS + EXTENDED_Ebias;
+
+ if (rp->tag == TW_Valid) {
+ if (e >= 0x7fff) {
+ /* Overflow to infinity */
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), 0);
+ suword((unsigned long *) (d + i * 10 + 4), 0);
+ REENTRANT_CHECK(ON);
+ e = 0x7fff;
+ } else
+ if (e <= 0) {
+ if (e > -63) {
+ /* Make a de-normal */
+ reg_move(rp, &tmp);
+ tmp.exp += -EXTENDED_Emin + 63; /* largest exp to be 62 */
+ round_to_int(&tmp);
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), tmp.sigl);
+ suword((unsigned long *) (d + i * 10 + 4), tmp.sigh);
+ REENTRANT_CHECK(ON);
+ } else {
+ /* Underflow to zero */
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), 0);
+ suword((unsigned long *) (d + i * 10 + 4), 0);
+ REENTRANT_CHECK(ON);
+ }
+ e = 0;
+ } else {
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), rp->sigl);
+ suword((unsigned long *) (d + i * 10 + 4), rp->sigh);
+ REENTRANT_CHECK(ON);
+ }
+ } else
+ if (rp->tag == TW_Zero) {
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), 0);
+ suword((unsigned long *) (d + i * 10 + 4), 0);
+ REENTRANT_CHECK(ON);
+ e = 0;
+ } else
+ if (rp->tag == TW_Infinity) {
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), 0);
+ suword((unsigned long *) (d + i * 10 + 4), 0x80000000);
+ REENTRANT_CHECK(ON);
+ e = 0x7fff;
+ } else
+ if (rp->tag == TW_NaN) {
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), rp->sigl);
+ suword((unsigned long *) (d + i * 10 + 4), rp->sigh);
+ REENTRANT_CHECK(ON);
+ e = 0x7fff;
+ } else
+ if (rp->tag == TW_Empty) {
+ /* just copy the reg */
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), rp->sigl);
+ suword((unsigned long *) (d + i * 10 + 4), rp->sigh);
+ REENTRANT_CHECK(ON);
+ }
+ e |= rp->sign == SIGN_POS ? 0 : 0x8000;
+ REENTRANT_CHECK(OFF);
+ suword((unsigned short *) (d + i * 10 + 8), e);
+ REENTRANT_CHECK(ON);
+ }
+
+ finit();
+
+}
+/*===========================================================================*/
diff --git a/sys/gnu/i386/fpemul/reg_mul.c b/sys/gnu/i386/fpemul/reg_mul.c
new file mode 100644
index 0000000..d694ae4
--- /dev/null
+++ b/sys/gnu/i386/fpemul/reg_mul.c
@@ -0,0 +1,152 @@
+/*
+ * reg_mul.c
+ *
+ * Multiply one FPU_REG by another, put the result in a destination FPU_REG.
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | The destination may be any FPU_REG, including one of the source FPU_REGs. |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "reg_constant.h"
+#include "fpu_emu.h"
+#include "fpu_system.h"
+
+
+/* This routine must be called with non-empty source registers */
+void
+reg_mul(FPU_REG * a, FPU_REG * b, FPU_REG * dest, unsigned int control_w)
+{
+ char sign = (a->sign ^ b->sign);
+
+ if (!(a->tag | b->tag)) {
+ /* This should be the most common case */
+ reg_u_mul(a, b, dest, control_w);
+ dest->sign = sign;
+ return;
+ } else
+ if ((a->tag <= TW_Zero) && (b->tag <= TW_Zero)) {
+#ifdef DENORM_OPERAND
+ if (((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) ||
+ ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER))) {
+ if (denormal_operand())
+ return;
+ }
+#endif /* DENORM_OPERAND */
+ /* Must have either both arguments == zero, or one
+ * valid and the other zero. The result is therefore
+ * zero. */
+ reg_move(&CONST_Z, dest);
+#ifdef PECULIAR_486
+ /* The 80486 book says that the answer is +0, but a
+ * real 80486 appears to behave this way... */
+ dest->sign = sign;
+#endif /* PECULIAR_486 */
+ return;
+ }
+#if 0 /* TW_Denormal is not used yet... perhaps
+ * never will be. */
+ else
+ if ((a->tag <= TW_Denormal) && (b->tag <= TW_Denormal)) {
+ /* One or both arguments are de-normalized */
+ /* Internal de-normalized numbers are not
+ * supported yet */
+ EXCEPTION(EX_INTERNAL | 0x105);
+ reg_move(&CONST_Z, dest);
+ }
+#endif
+ else {
+ /* Must have infinities, NaNs, etc */
+ if ((a->tag == TW_NaN) || (b->tag == TW_NaN)) {
+ real_2op_NaN(a, b, dest);
+ return;
+ } else
+ if (a->tag == TW_Infinity) {
+ if (b->tag == TW_Zero) {
+ arith_invalid(dest);
+ return;
+ }
+ /* Zero*Infinity is invalid */
+ else {
+#ifdef DENORM_OPERAND
+ if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(a, dest);
+ dest->sign = sign;
+ }
+ return;
+ } else
+ if (b->tag == TW_Infinity) {
+ if (a->tag == TW_Zero) {
+ arith_invalid(dest);
+ return;
+ }
+ /* Zero*Infinity is
+ * invalid */
+ else {
+#ifdef DENORM_OPERAND
+ if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(b, dest);
+ dest->sign = sign;
+ }
+ return;
+ }
+#ifdef PARANOID
+ else {
+ EXCEPTION(EX_INTERNAL | 0x102);
+ }
+#endif /* PARANOID */
+ }
+}
diff --git a/sys/gnu/i386/fpemul/reg_norm.s b/sys/gnu/i386/fpemul/reg_norm.s
new file mode 100644
index 0000000..55f75b9
--- /dev/null
+++ b/sys/gnu/i386/fpemul/reg_norm.s
@@ -0,0 +1,172 @@
+/*
+ * reg_norm.s
+ *
+ * Normalize the value in a FPU_REG.
+ *
+ * Call from C as:
+ * void normalize(FPU_REG *n)
+ *
+ * void normalize_nuo(FPU_REG *n)
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+
+#include "fpu_asm.h"
+
+
+.text
+
+ .align 2,144
+.globl _normalize
+
+_normalize:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %ebx
+
+ movl PARAM1,%ebx
+
+ movl SIGH(%ebx),%edx
+ movl SIGL(%ebx),%eax
+
+ orl %edx,%edx /* ms bits */
+ js L_done /* Already normalized */
+ jnz L_shift_1 /* Shift left 1 - 31 bits */
+
+ orl %eax,%eax
+ jz L_zero /* The contents are zero */
+
+/* L_shift_32: */
+ movl %eax,%edx
+ xorl %eax,%eax
+ subl $32,EXP(%ebx) /* This can cause an underflow */
+
+/* We need to shift left by 1 - 31 bits */
+L_shift_1:
+ bsrl %edx,%ecx /* get the required shift in %ecx */
+ subl $31,%ecx
+ negl %ecx
+ shld %cl,%eax,%edx
+ shl %cl,%eax
+ subl %ecx,EXP(%ebx) /* This can cause an underflow */
+
+ movl %edx,SIGH(%ebx)
+ movl %eax,SIGL(%ebx)
+
+L_done:
+ cmpl EXP_OVER,EXP(%ebx)
+ jge L_overflow
+
+ cmpl EXP_UNDER,EXP(%ebx)
+ jle L_underflow
+
+L_exit:
+ popl %ebx
+ leave
+ ret
+
+
+L_zero:
+ movl EXP_UNDER,EXP(%ebx)
+ movb TW_Zero,TAG(%ebx)
+ jmp L_exit
+
+L_underflow:
+ push %ebx
+ call _arith_underflow
+ pop %ebx
+ jmp L_exit
+
+L_overflow:
+ push %ebx
+ call _arith_overflow
+ pop %ebx
+ jmp L_exit
+
+
+
+/* Normalise without reporting underflow or overflow */
+ .align 2,144
+.globl _normalize_nuo
+
+_normalize_nuo:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %ebx
+
+ movl PARAM1,%ebx
+
+ movl SIGH(%ebx),%edx
+ movl SIGL(%ebx),%eax
+
+ orl %edx,%edx /* ms bits */
+ js L_exit /* Already normalized */
+ jnz L_nuo_shift_1 /* Shift left 1 - 31 bits */
+
+ orl %eax,%eax
+ jz L_zero /* The contents are zero */
+
+/* L_nuo_shift_32: */
+ movl %eax,%edx
+ xorl %eax,%eax
+ subl $32,EXP(%ebx) /* This can cause an underflow */
+
+/* We need to shift left by 1 - 31 bits */
+L_nuo_shift_1:
+ bsrl %edx,%ecx /* get the required shift in %ecx */
+ subl $31,%ecx
+ negl %ecx
+ shld %cl,%eax,%edx
+ shl %cl,%eax
+ subl %ecx,EXP(%ebx) /* This can cause an underflow */
+
+ movl %edx,SIGH(%ebx)
+ movl %eax,SIGL(%ebx)
+ jmp L_exit
+
+
diff --git a/sys/gnu/i386/fpemul/reg_round.s b/sys/gnu/i386/fpemul/reg_round.s
new file mode 100644
index 0000000..55bbaff
--- /dev/null
+++ b/sys/gnu/i386/fpemul/reg_round.s
@@ -0,0 +1,643 @@
+ .file "reg_round.S"
+/*
+ * reg_round.S
+ *
+ * Rounding/truncation/etc for FPU basic arithmetic functions.
+ *
+ * This code has four possible entry points.
+ * The following must be entered by a jmp intruction:
+ * FPU_round, FPU_round_sqrt, and FPU_Arith_exit.
+ *
+ * The _round_reg entry point is intended to be used by C code.
+ * From C, call as:
+ * void round_reg(FPU_REG *arg, unsigned int extent, unsigned int control_w)
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+
+/*---------------------------------------------------------------------------+
+ | Four entry points. |
+ | |
+ | Needed by both the FPU_round and FPU_round_sqrt entry points: |
+ | %eax:%ebx 64 bit significand |
+ | %edx 32 bit extension of the significand |
+ | %edi pointer to an FPU_REG for the result to be stored |
+ | stack calling function must have set up a C stack frame and |
+ | pushed %esi, %edi, and %ebx |
+ | |
+ | Needed just for the FPU_round_sqrt entry point: |
+ | %cx A control word in the same format as the FPU control word. |
+ | Otherwise, PARAM4 must give such a value. |
+ | |
+ | |
+ | The significand and its extension are assumed to be exact in the |
+ | following sense: |
+ | If the significand by itself is the exact result then the significand |
+ | extension (%edx) must contain 0, otherwise the significand extension |
+ | must be non-zero. |
+ | If the significand extension is non-zero then the significand is |
+ | smaller than the magnitude of the correct exact result by an amount |
+ | greater than zero and less than one ls bit of the significand. |
+ | The significand extension is only required to have three possible |
+ | non-zero values: |
+ | less than 0x80000000 <=> the significand is less than 1/2 an ls |
+ | bit smaller than the magnitude of the |
+ | true exact result. |
+ | exactly 0x80000000 <=> the significand is exactly 1/2 an ls bit |
+ | smaller than the magnitude of the true |
+ | exact result. |
+ | greater than 0x80000000 <=> the significand is more than 1/2 an ls |
+ | bit smaller than the magnitude of the |
+ | true exact result. |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | The code in this module has become quite complex, but it should handle |
+ | all of the FPU flags which are set at this stage of the basic arithmetic |
+ | computations. |
+ | There are a few rare cases where the results are not set identically to |
+ | a real FPU. These require a bit more thought because at this stage the |
+ | results of the code here appear to be more consistent... |
+ | This may be changed in a future version. |
+ +---------------------------------------------------------------------------*/
+
+
+#include "fpu_asm.h"
+#include "exception.h"
+#include "control_w.h"
+
+#define LOST_DOWN $1
+#define LOST_UP $2
+#define DENORMAL $1
+#define UNMASKED_UNDERFLOW $2
+
+.data
+ .align 2,0
+FPU_bits_lost:
+ .byte 0
+FPU_denormal:
+ .byte 0
+
+.text
+ .align 2,144
+.globl FPU_round
+.globl FPU_round_sqrt
+.globl FPU_Arith_exit
+.globl _round_reg
+
+/* Entry point when called from C */
+_round_reg:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%edi
+ movl SIGH(%edi),%eax
+ movl SIGL(%edi),%ebx
+ movl PARAM2,%edx
+ movl PARAM3,%ecx
+ jmp FPU_round_sqrt
+
+FPU_round: /* Normal entry point */
+ movl PARAM4,%ecx
+
+FPU_round_sqrt: /* Entry point from wm_sqrt.S */
+
+#ifdef PARANOID
+/* Cannot use this here yet */
+/* orl %eax,%eax */
+/* jns L_entry_bugged */
+#endif PARANOID
+
+ cmpl EXP_UNDER,EXP(%edi)
+ jle xMake_denorm /* The number is a de-normal*/
+
+ movb $0,FPU_denormal /* 0 -> not a de-normal*/
+
+xDenorm_done:
+ movb $0,FPU_bits_lost /*No bits yet lost in rounding*/
+
+ movl %ecx,%esi
+ andl CW_PC,%ecx
+ cmpl PR_64_BITS,%ecx
+ je LRound_To_64
+
+ cmpl PR_53_BITS,%ecx
+ je LRound_To_53
+
+ cmpl PR_24_BITS,%ecx
+ je LRound_To_24
+
+#ifdef PARANOID
+ jmp L_bugged /* There is no bug, just a bad control word */
+#endif PARANOID
+
+
+/* Round etc to 24 bit precision */
+LRound_To_24:
+ movl %esi,%ecx
+ andl CW_RC,%ecx
+ cmpl RC_RND,%ecx
+ je LRound_nearest_24
+
+ cmpl RC_CHOP,%ecx
+ je LCheck_truncate_24
+
+ cmpl RC_UP,%ecx /* Towards +infinity */
+ je LUp_24
+
+ cmpl RC_DOWN,%ecx /* Towards -infinity */
+ je LDown_24
+
+#ifdef PARANOID
+ jmp L_bugged
+#endif PARANOID
+
+LUp_24:
+ cmpb SIGN_POS,SIGN(%edi)
+ jne LCheck_truncate_24 /* If negative then up==truncate */
+
+ jmp LCheck_24_round_up
+
+LDown_24:
+ cmpb SIGN_POS,SIGN(%edi)
+ je LCheck_truncate_24 /* If positive then down==truncate */
+
+LCheck_24_round_up:
+ movl %eax,%ecx
+ andl $0x000000ff,%ecx
+ orl %ebx,%ecx
+ orl %edx,%ecx
+ jnz LDo_24_round_up
+ jmp LRe_normalise
+
+LRound_nearest_24:
+ /* Do rounding of the 24th bit if needed (nearest or even) */
+ movl %eax,%ecx
+ andl $0x000000ff,%ecx
+ cmpl $0x00000080,%ecx
+ jc LCheck_truncate_24 /*less than half, no increment needed*/
+
+ jne LGreater_Half_24 /* greater than half, increment needed*/
+
+ /* Possibly half, we need to check the ls bits */
+ orl %ebx,%ebx
+ jnz LGreater_Half_24 /* greater than half, increment needed*/
+
+ orl %edx,%edx
+ jnz LGreater_Half_24 /* greater than half, increment needed*/
+
+ /* Exactly half, increment only if 24th bit is 1 (round to even)*/
+ testl $0x00000100,%eax
+ jz LDo_truncate_24
+
+LGreater_Half_24: /*Rounding: increment at the 24th bit*/
+LDo_24_round_up:
+ andl $0xffffff00,%eax /*Truncate to 24 bits*/
+ xorl %ebx,%ebx
+ movb LOST_UP,FPU_bits_lost
+ addl $0x00000100,%eax
+ jmp LCheck_Round_Overflow
+
+LCheck_truncate_24:
+ movl %eax,%ecx
+ andl $0x000000ff,%ecx
+ orl %ebx,%ecx
+ orl %edx,%ecx
+ jz LRe_normalise /* No truncation needed*/
+
+LDo_truncate_24:
+ andl $0xffffff00,%eax /* Truncate to 24 bits*/
+ xorl %ebx,%ebx
+ movb LOST_DOWN,FPU_bits_lost
+ jmp LRe_normalise
+
+
+/* Round etc to 53 bit precision */
+LRound_To_53:
+ movl %esi,%ecx
+ andl CW_RC,%ecx
+ cmpl RC_RND,%ecx
+ je LRound_nearest_53
+
+ cmpl RC_CHOP,%ecx
+ je LCheck_truncate_53
+
+ cmpl RC_UP,%ecx /* Towards +infinity*/
+ je LUp_53
+
+ cmpl RC_DOWN,%ecx /* Towards -infinity*/
+ je LDown_53
+
+#ifdef PARANOID
+ jmp L_bugged
+#endif PARANOID
+
+LUp_53:
+ cmpb SIGN_POS,SIGN(%edi)
+ jne LCheck_truncate_53 /* If negative then up==truncate*/
+
+ jmp LCheck_53_round_up
+
+LDown_53:
+ cmpb SIGN_POS,SIGN(%edi)
+ je LCheck_truncate_53 /* If positive then down==truncate*/
+
+LCheck_53_round_up:
+ movl %ebx,%ecx
+ andl $0x000007ff,%ecx
+ orl %edx,%ecx
+ jnz LDo_53_round_up
+ jmp LRe_normalise
+
+LRound_nearest_53:
+ /*Do rounding of the 53rd bit if needed (nearest or even)*/
+ movl %ebx,%ecx
+ andl $0x000007ff,%ecx
+ cmpl $0x00000400,%ecx
+ jc LCheck_truncate_53 /* less than half, no increment needed*/
+
+ jnz LGreater_Half_53 /* greater than half, increment needed*/
+
+ /*Possibly half, we need to check the ls bits*/
+ orl %edx,%edx
+ jnz LGreater_Half_53 /* greater than half, increment needed*/
+
+ /* Exactly half, increment only if 53rd bit is 1 (round to even)*/
+ testl $0x00000800,%ebx
+ jz LTruncate_53
+
+LGreater_Half_53: /*Rounding: increment at the 53rd bit*/
+LDo_53_round_up:
+ movb LOST_UP,FPU_bits_lost
+ andl $0xfffff800,%ebx /* Truncate to 53 bits*/
+ addl $0x00000800,%ebx
+ adcl $0,%eax
+ jmp LCheck_Round_Overflow
+
+LCheck_truncate_53:
+ movl %ebx,%ecx
+ andl $0x000007ff,%ecx
+ orl %edx,%ecx
+ jz LRe_normalise
+
+LTruncate_53:
+ movb LOST_DOWN,FPU_bits_lost
+ andl $0xfffff800,%ebx /* Truncate to 53 bits*/
+ jmp LRe_normalise
+
+
+/* Round etc to 64 bit precision*/
+LRound_To_64:
+ movl %esi,%ecx
+ andl CW_RC,%ecx
+ cmpl RC_RND,%ecx
+ je LRound_nearest_64
+
+ cmpl RC_CHOP,%ecx
+ je LCheck_truncate_64
+
+ cmpl RC_UP,%ecx /* Towards +infinity*/
+ je LUp_64
+
+ cmpl RC_DOWN,%ecx /* Towards -infinity*/
+ je LDown_64
+
+#ifdef PARANOID
+ jmp L_bugged
+#endif PARANOID
+
+LUp_64:
+ cmpb SIGN_POS,SIGN(%edi)
+ jne LCheck_truncate_64 /* If negative then up==truncate*/
+
+ orl %edx,%edx
+ jnz LDo_64_round_up
+ jmp LRe_normalise
+
+LDown_64:
+ cmpb SIGN_POS,SIGN(%edi)
+ je LCheck_truncate_64 /*If positive then down==truncate*/
+
+ orl %edx,%edx
+ jnz LDo_64_round_up
+ jmp LRe_normalise
+
+LRound_nearest_64:
+ cmpl $0x80000000,%edx
+ jc LCheck_truncate_64
+
+ jne LDo_64_round_up
+
+ /* Now test for round-to-even */
+ testb $1,%ebx
+ jz LCheck_truncate_64
+
+LDo_64_round_up:
+ movb LOST_UP,FPU_bits_lost
+ addl $1,%ebx
+ adcl $0,%eax
+
+LCheck_Round_Overflow:
+ jnc LRe_normalise /* Rounding done, no overflow */
+
+ /* Overflow, adjust the result (to 1.0) */
+ rcrl $1,%eax
+ rcrl $1,%ebx
+ incl EXP(%edi)
+ jmp LRe_normalise
+
+LCheck_truncate_64:
+ orl %edx,%edx
+ jz LRe_normalise
+
+LTruncate_64:
+ movb LOST_DOWN,FPU_bits_lost
+
+LRe_normalise:
+ testb $0xff,FPU_denormal
+ jnz xNormalise_result
+
+xL_Normalised:
+ cmpb LOST_UP,FPU_bits_lost
+ je xL_precision_lost_up
+
+ cmpb LOST_DOWN,FPU_bits_lost
+ je xL_precision_lost_down
+
+xL_no_precision_loss:
+ cmpl EXP_OVER,EXP(%edi)
+ jge L_overflow
+
+ /* store the result */
+ movb TW_Valid,TAG(%edi)
+
+xL_Store_significand:
+ movl %eax,SIGH(%edi)
+ movl %ebx,SIGL(%edi)
+
+FPU_Arith_exit:
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
+
+
+/* Set the FPU status flags to represent precision loss due to*/
+/* round-up.*/
+xL_precision_lost_up:
+ push %eax
+ call _set_precision_flag_up
+ popl %eax
+ jmp xL_no_precision_loss
+
+/* Set the FPU status flags to represent precision loss due to*/
+/* truncation.*/
+xL_precision_lost_down:
+ push %eax
+ call _set_precision_flag_down
+ popl %eax
+ jmp xL_no_precision_loss
+
+
+/* The number is a denormal (which might get rounded up to a normal)
+// Shift the number right the required number of bits, which will
+// have to be undone later...*/
+xMake_denorm:
+ /* The action to be taken depends upon whether the underflow
+ // exception is masked*/
+ testb CW_Underflow,%cl /* Underflow mask.*/
+ jz xUnmasked_underflow /* Do not make a denormal.*/
+
+ movb DENORMAL,FPU_denormal
+
+ pushl %ecx /* Save*/
+ movl EXP(%edi),%ecx
+ subl EXP_UNDER+1,%ecx
+ negl %ecx
+
+ cmpl $64,%ecx /* shrd only works for 0..31 bits */
+ jnc xDenorm_shift_more_than_63
+
+ cmpl $32,%ecx /* shrd only works for 0..31 bits */
+ jnc xDenorm_shift_more_than_32
+
+/* We got here without jumps by assuming that the most common requirement
+// is for a small de-normalising shift.
+// Shift by [1..31] bits */
+ addl %ecx,EXP(%edi)
+ orl %edx,%edx /* extension*/
+ setne %ch
+ xorl %edx,%edx
+ shrd %cl,%ebx,%edx
+ shrd %cl,%eax,%ebx
+ shr %cl,%eax
+ orb %ch,%dl
+ popl %ecx
+ jmp xDenorm_done
+
+/* Shift by [32..63] bits*/
+xDenorm_shift_more_than_32:
+ addl %ecx,EXP(%edi)
+ subb $32,%cl
+ orl %edx,%edx
+ setne %ch
+ orb %ch,%bl
+ xorl %edx,%edx
+ shrd %cl,%ebx,%edx
+ shrd %cl,%eax,%ebx
+ shr %cl,%eax
+ orl %edx,%edx /*test these 32 bits*/
+ setne %cl
+ orb %ch,%bl
+ orb %cl,%bl
+ movl %ebx,%edx
+ movl %eax,%ebx
+ xorl %eax,%eax
+ popl %ecx
+ jmp xDenorm_done
+
+/* Shift by [64..) bits*/
+xDenorm_shift_more_than_63:
+ cmpl $64,%ecx
+ jne xDenorm_shift_more_than_64
+
+/* Exactly 64 bit shift*/
+ addl %ecx,EXP(%edi)
+ xorl %ecx,%ecx
+ orl %edx,%edx
+ setne %cl
+ orl %ebx,%ebx
+ setne %ch
+ orb %ch,%cl
+ orb %cl,%al
+ movl %eax,%edx
+ xorl %eax,%eax
+ xorl %ebx,%ebx
+ popl %ecx
+ jmp xDenorm_done
+
+xDenorm_shift_more_than_64:
+ movl EXP_UNDER+1,EXP(%edi)
+/* This is easy, %eax must be non-zero, so..*/
+ movl $1,%edx
+ xorl %eax,%eax
+ xorl %ebx,%ebx
+ popl %ecx
+ jmp xDenorm_done
+
+
+xUnmasked_underflow:
+ /* Increase the exponent by the magic number*/
+ addl $(3*(1<<13)),EXP(%edi)
+ movb UNMASKED_UNDERFLOW,FPU_denormal
+ jmp xDenorm_done
+
+
+/* Undo the de-normalisation.*/
+xNormalise_result:
+ cmpb UNMASKED_UNDERFLOW,FPU_denormal
+ je xSignal_underflow
+
+/* The number must be a denormal if we got here.*/
+#ifdef PARANOID
+ /* But check it... just in case.*/
+ cmpl EXP_UNDER+1,EXP(%edi)
+ jne L_norm_bugged
+#endif PARANOID
+
+ orl %eax,%eax /* ms bits*/
+ jnz LNormalise_shift_up_to_31 /* Shift left 0 - 31 bits*/
+
+ orl %ebx,%ebx
+ jz L_underflow_to_zero /* The contents are zero*/
+
+/* Shift left 32 - 63 bits*/
+ movl %ebx,%eax
+ xorl %ebx,%ebx
+ subl $32,EXP(%edi)
+
+LNormalise_shift_up_to_31:
+ bsrl %eax,%ecx /* get the required shift in %ecx */
+ subl $31,%ecx
+ negl %ecx
+ shld %cl,%ebx,%eax
+ shl %cl,%ebx
+ subl %ecx,EXP(%edi)
+
+LNormalise_shift_done:
+ testb $0xff,FPU_bits_lost /* bits lost == underflow*/
+ jz xL_Normalised
+
+ /* There must be a masked underflow*/
+ push %eax
+ pushl EX_Underflow
+ call _exception
+ popl %eax
+ popl %eax
+ jmp xL_Normalised
+
+
+/* The operations resulted in a number too small to represent.
+// Masked response.*/
+L_underflow_to_zero:
+ push %eax
+ call _set_precision_flag_down
+ popl %eax
+
+ push %eax
+ pushl EX_Underflow
+ call _exception
+ popl %eax
+ popl %eax
+
+ movb TW_Zero,TAG(%edi)
+ jmp xL_Store_significand
+
+
+/* The operations resulted in a number too large to represent.*/
+L_overflow:
+ push %edi
+ call _arith_overflow
+ pop %edi
+ jmp FPU_Arith_exit
+
+
+xSignal_underflow:
+ push %eax
+ pushl EX_Underflow
+ call EXCEPTION
+ popl %eax
+ popl %eax
+ jmp xL_Normalised
+
+
+#ifdef PARANOID
+/* If we ever get here then we have problems! */
+L_bugged:
+ pushl EX_INTERNAL|0x201
+ call EXCEPTION
+ popl %ebx
+ jmp FPU_Arith_exit
+
+L_norm_bugged:
+ pushl EX_INTERNAL|0x216
+ call EXCEPTION
+ popl %ebx
+ jmp FPU_Arith_exit
+
+L_entry_bugged:
+ pushl EX_INTERNAL|0x217
+ call EXCEPTION
+ popl %ebx
+ jmp FPU_Arith_exit
+#endif PARANOID
diff --git a/sys/gnu/i386/fpemul/reg_u_add.s b/sys/gnu/i386/fpemul/reg_u_add.s
new file mode 100644
index 0000000..28e30bc
--- /dev/null
+++ b/sys/gnu/i386/fpemul/reg_u_add.s
@@ -0,0 +1,234 @@
+ .file "reg_u_add.S"
+/*
+ * reg_u_add.S
+ *
+ * Add two valid (TW_Valid) FPU_REG numbers, of the same sign, and put the
+ * result in a destination FPU_REG.
+ *
+ * Call from C as:
+ * void reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
+ * int control_w)
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+
+/*
+ | Kernel addition routine reg_u_add(reg *arg1, reg *arg2, reg *answ).
+ | Takes two valid reg f.p. numbers (TW_Valid), which are
+ | treated as unsigned numbers,
+ | and returns their sum as a TW_Valid or TW_S f.p. number.
+ | The returned number is normalized.
+ | Basic checks are performed if PARANOID is defined.
+ */
+
+#include "exception.h"
+#include "fpu_asm.h"
+#include "control_w.h"
+
+.text
+ .align 2,144
+.globl _reg_u_add
+_reg_u_add:
+ pushl %ebp
+ movl %esp,%ebp
+/* subl $16,%esp*/
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi /* source 1 */
+ movl PARAM2,%edi /* source 2 */
+
+#ifdef DENORM_OPERAND
+ cmpl EXP_UNDER,EXP(%esi)
+ jg xOp1_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp1_not_denorm:
+ cmpl EXP_UNDER,EXP(%edi)
+ jg xOp2_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp2_not_denorm:
+#endif DENORM_OPERAND
+
+/* xorl %ecx,%ecx*/
+ movl EXP(%esi),%ecx
+ subl EXP(%edi),%ecx /* exp1 - exp2 */
+/* jnc L_arg1_larger*/
+ jge L_arg1_larger
+
+ /* num1 is smaller */
+ movl SIGL(%esi),%ebx
+ movl SIGH(%esi),%eax
+
+ movl %edi,%esi
+ negw %cx
+ jmp L_accum_loaded
+
+L_arg1_larger:
+ /* num1 has larger or equal exponent */
+ movl SIGL(%edi),%ebx
+ movl SIGH(%edi),%eax
+
+L_accum_loaded:
+ movl PARAM3,%edi /* destination */
+ movb SIGN(%esi),%dl
+ movb %dl,SIGN(%edi) /* Copy the sign from the first arg */
+
+
+ movl EXP(%esi),%edx
+ movl %edx,EXP(%edi) /* Copy exponent to destination */
+
+ xorl %edx,%edx /* clear the extension */
+
+#ifdef PARANOID
+ testl $0x80000000,%eax
+ je L_bugged
+
+ testl $0x80000000,SIGH(%esi)
+ je L_bugged
+#endif PARANOID
+
+/* The number to be shifted is in %eax:%ebx:%edx*/
+ cmpw $32,%cx /* shrd only works for 0..31 bits */
+ jnc L_more_than_31
+
+/* less than 32 bits */
+ shrd %cl,%ebx,%edx
+ shrd %cl,%eax,%ebx
+ shr %cl,%eax
+ jmp L_shift_done
+
+L_more_than_31:
+ cmpw $64,%cx
+ jnc L_more_than_63
+
+ subb $32,%cl
+ jz L_exactly_32
+
+ shrd %cl,%eax,%edx
+ shr %cl,%eax
+ orl %ebx,%ebx
+ jz L_more_31_no_low /* none of the lowest bits is set*/
+
+ orl $1,%edx /* record the fact in the extension*/
+
+L_more_31_no_low:
+ movl %eax,%ebx
+ xorl %eax,%eax
+ jmp L_shift_done
+
+L_exactly_32:
+ movl %ebx,%edx
+ movl %eax,%ebx
+ xorl %eax,%eax
+ jmp L_shift_done
+
+L_more_than_63:
+ cmpw $65,%cx
+ jnc L_more_than_64
+
+ movl %eax,%edx
+ orl %ebx,%ebx
+ jz L_more_63_no_low
+
+ orl $1,%edx
+ jmp L_more_63_no_low
+
+L_more_than_64:
+ movl $1,%edx /* The shifted nr always at least one '1'*/
+
+L_more_63_no_low:
+ xorl %ebx,%ebx
+ xorl %eax,%eax
+
+L_shift_done:
+ /* Now do the addition */
+ addl SIGL(%esi),%ebx
+ adcl SIGH(%esi),%eax
+ jnc L_round_the_result
+
+ /* Overflow, adjust the result */
+ rcrl $1,%eax
+ rcrl $1,%ebx
+ rcrl $1,%edx
+ jnc L_no_bit_lost
+
+ orl $1,%edx
+
+L_no_bit_lost:
+ incl EXP(%edi)
+
+L_round_the_result:
+ jmp FPU_round /* Round the result*/
+
+
+
+#ifdef PARANOID
+/* If we ever get here then we have problems! */
+L_bugged:
+ pushl EX_INTERNAL|0x201
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+#endif PARANOID
+
+
+L_exit:
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
diff --git a/sys/gnu/i386/fpemul/reg_u_div.s b/sys/gnu/i386/fpemul/reg_u_div.s
new file mode 100644
index 0000000..decfd43
--- /dev/null
+++ b/sys/gnu/i386/fpemul/reg_u_div.s
@@ -0,0 +1,496 @@
+ .file "reg_u_div.S"
+/*
+ * reg_u_div.S
+ *
+ * Core division routines
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | Kernel for the division routines. |
+ | |
+ | void reg_u_div(FPU_REG *a, FPU_REG *a, |
+ | FPU_REG *dest, unsigned int control_word) |
+ | |
+ | Does not compute the destination exponent, but does adjust it. |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "fpu_asm.h"
+#include "control_w.h"
+
+
+/* #define dSIGL(x) (x) */
+/* #define dSIGH(x) 4(x) */
+
+
+.data
+/*
+ Local storage:
+ Result: accum_3:accum_2:accum_1:accum_0
+ Overflow flag: ovfl_flag
+ */
+ .align 2,0
+accum_3:
+ .long 0
+accum_2:
+ .long 0
+accum_1:
+ .long 0
+accum_0:
+ .long 0
+result_1:
+ .long 0
+result_2:
+ .long 0
+ovfl_flag:
+ .byte 0
+
+
+.text
+ .align 2,144
+
+.globl _reg_u_div
+
+.globl _divide_kernel
+
+_reg_u_div:
+ pushl %ebp
+ movl %esp,%ebp
+
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi /* pointer to num */
+ movl PARAM2,%ebx /* pointer to denom */
+ movl PARAM3,%edi /* pointer to answer */
+
+#ifdef DENORM_OPERAND
+ movl EXP(%esi),%eax
+ cmpl EXP_UNDER,%eax
+ jg xOp1_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp1_not_denorm:
+ movl EXP(%ebx),%eax
+ cmpl EXP_UNDER,%eax
+ jg xOp2_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp2_not_denorm:
+#endif DENORM_OPERAND
+
+_divide_kernel:
+#ifdef PARANOID
+/* testl $0x80000000, SIGH(%esi) *//* Dividend */
+/* je L_bugged */
+ testl $0x80000000, SIGH(%ebx) /* Divisor*/
+ je L_bugged
+#endif PARANOID
+
+/* Check if the divisor can be treated as having just 32 bits */
+ cmpl $0,SIGL(%ebx)
+ jnz L_Full_Division /* Can't do a quick divide */
+
+/* We should be able to zip through the division here */
+ movl SIGH(%ebx),%ecx /* The divisor */
+ movl SIGH(%esi),%edx /* Dividend */
+ movl SIGL(%esi),%eax /* Dividend */
+
+ cmpl %ecx,%edx
+ setaeb ovfl_flag /* Keep a record */
+ jb L_no_adjust
+
+ subl %ecx,%edx /* Prevent the overflow */
+
+L_no_adjust:
+ /* Divide the 64 bit number by the 32 bit denominator */
+ divl %ecx
+ movl %eax,result_2
+
+ /* Work on the remainder of the first division */
+ xorl %eax,%eax
+ divl %ecx
+ movl %eax,result_1
+
+ /* Work on the remainder of the 64 bit division */
+ xorl %eax,%eax
+ divl %ecx
+
+ testb $255,ovfl_flag /* was the num > denom ? */
+ je L_no_overflow
+
+ /* Do the shifting here */
+ /* increase the exponent */
+ incl EXP(%edi)
+
+ /* shift the mantissa right one bit */
+ stc /* To set the ms bit */
+ rcrl result_2
+ rcrl result_1
+ rcrl %eax
+
+L_no_overflow:
+ jmp LRound_precision /* Do the rounding as required*/
+
+
+/*---------------------------------------------------------------------------+
+ | Divide: Return arg1/arg2 to arg3. |
+ | |
+ | This routine does not use the exponents of arg1 and arg2, but does |
+ | adjust the exponent of arg3. |
+ | |
+ | The maximum returned value is (ignoring exponents) |
+ | .ffffffff ffffffff |
+ | ------------------ = 1.ffffffff fffffffe |
+ | .80000000 00000000 |
+ | and the minimum is |
+ | .80000000 00000000 |
+ | ------------------ = .80000000 00000001 (rounded) |
+ | .ffffffff ffffffff |
+ | |
+ +---------------------------------------------------------------------------*/
+
+
+L_Full_Division:
+ /* Save extended dividend in local register*/
+ movl SIGL(%esi),%eax
+ movl %eax,accum_2
+ movl SIGH(%esi),%eax
+ movl %eax,accum_3
+ xorl %eax,%eax
+ movl %eax,accum_1 /* zero the extension */
+ movl %eax,accum_0 /* zero the extension */
+
+ movl SIGL(%esi),%eax /* Get the current num */
+ movl SIGH(%esi),%edx
+
+/*----------------------------------------------------------------------*/
+/* Initialization done */
+/* Do the first 32 bits */
+
+ movb $0,ovfl_flag
+ cmpl SIGH(%ebx),%edx /* Test for imminent overflow */
+ jb LLess_than_1
+ ja LGreater_than_1
+
+ cmpl SIGL(%ebx),%eax
+ jb LLess_than_1
+
+LGreater_than_1:
+/* The dividend is greater or equal, would cause overflow */
+ setaeb ovfl_flag /* Keep a record */
+
+ subl SIGL(%ebx),%eax
+ sbbl SIGH(%ebx),%edx /* Prevent the overflow */
+ movl %eax,accum_2
+ movl %edx,accum_3
+
+LLess_than_1:
+/* At this point, we have a dividend < divisor, with a record of
+ adjustment in ovfl_flag */
+
+ /* We will divide by a number which is too large */
+ movl SIGH(%ebx),%ecx
+ addl $1,%ecx
+ jnc LFirst_div_not_1
+
+ /* here we need to divide by 100000000h,
+ i.e., no division at all.. */
+ mov %edx,%eax
+ jmp LFirst_div_done
+
+LFirst_div_not_1:
+ divl %ecx /* Divide the numerator by the augmented
+ denom ms dw */
+
+LFirst_div_done:
+ movl %eax,result_2 /* Put the result in the answer */
+
+ mull SIGH(%ebx) /* mul by the ms dw of the denom */
+
+ subl %eax,accum_2 /* Subtract from the num local reg */
+ sbbl %edx,accum_3
+
+ movl result_2,%eax /* Get the result back */
+ mull SIGL(%ebx) /* now mul the ls dw of the denom */
+
+ subl %eax,accum_1 /* Subtract from the num local reg */
+ sbbl %edx,accum_2
+ sbbl $0,accum_3
+ je LDo_2nd_32_bits /* Must check for non-zero result here */
+
+#ifdef PARANOID
+ jb L_bugged_1
+#endif PARANOID
+
+ /* need to subtract another once of the denom */
+ incl result_2 /* Correct the answer */
+
+ movl SIGL(%ebx),%eax
+ movl SIGH(%ebx),%edx
+ subl %eax,accum_1 /* Subtract from the num local reg */
+ sbbl %edx,accum_2
+
+#ifdef PARANOID
+ sbbl $0,accum_3
+ jne L_bugged_1 /* Must check for non-zero result here */
+#endif PARANOID
+
+/*----------------------------------------------------------------------*/
+/* Half of the main problem is done, there is just a reduced numerator
+ to handle now */
+/* Work with the second 32 bits, accum_0 not used from now on */
+LDo_2nd_32_bits:
+ movl accum_2,%edx /* get the reduced num */
+ movl accum_1,%eax
+
+ /* need to check for possible subsequent overflow */
+ cmpl SIGH(%ebx),%edx
+ jb LDo_2nd_div
+ ja LPrevent_2nd_overflow
+
+ cmpl SIGL(%ebx),%eax
+ jb LDo_2nd_div
+
+LPrevent_2nd_overflow:
+/* The numerator is greater or equal, would cause overflow */
+ /* prevent overflow */
+ subl SIGL(%ebx),%eax
+ sbbl SIGH(%ebx),%edx
+ movl %edx,accum_2
+ movl %eax,accum_1
+
+ incl result_2 /* Reflect the subtraction in the answer */
+
+#ifdef PARANOID
+ je L_bugged_2 /* Can't bump the result to 1.0 */
+#endif PARANOID
+
+LDo_2nd_div:
+ cmpl $0,%ecx /* augmented denom msw*/
+ jnz LSecond_div_not_1
+
+ /* %ecx == 0, we are dividing by 1.0 */
+ mov %edx,%eax
+ jmp LSecond_div_done
+
+LSecond_div_not_1:
+ divl %ecx /* Divide the numerator by the denom ms dw */
+
+LSecond_div_done:
+ movl %eax,result_1 /* Put the result in the answer */
+
+ mull SIGH(%ebx) /* mul by the ms dw of the denom */
+
+ subl %eax,accum_1 /* Subtract from the num local reg */
+ sbbl %edx,accum_2
+
+#ifdef PARANOID
+ jc L_bugged_2
+#endif PARANOID
+
+ movl result_1,%eax /* Get the result back */
+ mull SIGL(%ebx) /* now mul the ls dw of the denom */
+
+ subl %eax,accum_0 /* Subtract from the num local reg */
+ sbbl %edx,accum_1 /* Subtract from the num local reg */
+ sbbl $0,accum_2
+
+#ifdef PARANOID
+ jc L_bugged_2
+#endif PARANOID
+
+ jz LDo_3rd_32_bits
+
+#ifdef PARANOID
+ cmpl $1,accum_2
+ jne L_bugged_2
+#endif PARANOID
+
+ /* need to subtract another once of the denom */
+ movl SIGL(%ebx),%eax
+ movl SIGH(%ebx),%edx
+ subl %eax,accum_0 /* Subtract from the num local reg */
+ sbbl %edx,accum_1
+ sbbl $0,accum_2
+
+#ifdef PARANOID
+ jc L_bugged_2
+ jne L_bugged_2
+#endif PARANOID
+
+ addl $1,result_1 /* Correct the answer */
+ adcl $0,result_2
+
+#ifdef PARANOID
+ jc L_bugged_2 /* Must check for non-zero result here */
+#endif PARANOID
+
+/*----------------------------------------------------------------------*/
+/* The division is essentially finished here, we just need to perform
+ tidying operations. */
+/* deal with the 3rd 32 bits */
+LDo_3rd_32_bits:
+ movl accum_1,%edx /* get the reduced num */
+ movl accum_0,%eax
+
+ /* need to check for possible subsequent overflow */
+ cmpl SIGH(%ebx),%edx /* denom*/
+ jb LRound_prep
+ ja LPrevent_3rd_overflow
+
+ cmpl SIGL(%ebx),%eax /* denom */
+ jb LRound_prep
+
+LPrevent_3rd_overflow:
+ /* prevent overflow */
+ subl SIGL(%ebx),%eax
+ sbbl SIGH(%ebx),%edx
+ movl %edx,accum_1
+ movl %eax,accum_0
+
+ addl $1,result_1 /* Reflect the subtraction in the answer */
+ adcl $0,result_2
+ jne LRound_prep
+ jnc LRound_prep
+
+ /* This is a tricky spot, there is an overflow of the answer */
+ movb $255,ovfl_flag /* Overflow -> 1.000 */
+
+LRound_prep:
+/* Prepare for rounding.
+// To test for rounding, we just need to compare 2*accum with the
+// denom. */
+ movl accum_0,%ecx
+ movl accum_1,%edx
+ movl %ecx,%eax
+ orl %edx,%eax
+ jz LRound_ovfl /* The accumulator contains zero.*/
+
+ /* Multiply by 2 */
+ clc
+ rcll $1,%ecx
+ rcll $1,%edx
+ jc LRound_large /* No need to compare, denom smaller */
+
+ subl SIGL(%ebx),%ecx
+ sbbl SIGH(%ebx),%edx
+ jnc LRound_not_small
+
+ movl $0x70000000,%eax /* Denom was larger */
+ jmp LRound_ovfl
+
+LRound_not_small:
+ jnz LRound_large
+
+ movl $0x80000000,%eax /* Remainder was exactly 1/2 denom */
+ jmp LRound_ovfl
+
+LRound_large:
+ movl $0xff000000,%eax /* Denom was smaller */
+
+LRound_ovfl:
+/* We are now ready to deal with rounding, but first we must get
+ the bits properly aligned */
+ testb $255,ovfl_flag /* was the num > denom ? */
+ je LRound_precision
+
+ incl EXP(%edi)
+
+ /* shift the mantissa right one bit */
+ stc /* Will set the ms bit */
+ rcrl result_2
+ rcrl result_1
+ rcrl %eax
+
+/* Round the result as required */
+LRound_precision:
+ decl EXP(%edi) /* binary point between 1st & 2nd bits */
+
+ movl %eax,%edx
+ movl result_1,%ebx
+ movl result_2,%eax
+ jmp FPU_round
+
+
+#ifdef PARANOID
+/* The logic is wrong if we got here */
+L_bugged:
+ pushl EX_INTERNAL|0x202
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged_1:
+ pushl EX_INTERNAL|0x203
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged_2:
+ pushl EX_INTERNAL|0x204
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_exit:
+ popl %ebx
+ popl %edi
+ popl %esi
+
+ leave
+ ret
+#endif PARANOID
diff --git a/sys/gnu/i386/fpemul/reg_u_mul.s b/sys/gnu/i386/fpemul/reg_u_mul.s
new file mode 100644
index 0000000..ef53357
--- /dev/null
+++ b/sys/gnu/i386/fpemul/reg_u_mul.s
@@ -0,0 +1,189 @@
+ .file "reg_u_mul.S"
+/*
+ * reg_u_mul.S
+ *
+ * Core multiplication routine
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | Basic multiplication routine. |
+ | Does not check the resulting exponent for overflow/underflow |
+ | |
+ | reg_u_mul(FPU_REG *a, FPU_REG *b, FPU_REG *c, unsigned int cw); |
+ | |
+ | Internal working is at approx 128 bits. |
+ | Result is rounded to nearest 53 or 64 bits, using "nearest or even". |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "fpu_asm.h"
+#include "control_w.h"
+
+
+.data
+ .align 2,0
+accum_0:
+ .long 0
+accum_1:
+ .long 0
+
+
+.text
+ .align 2,144
+
+.globl _reg_u_mul
+_reg_u_mul:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi
+ movl PARAM2,%edi
+
+#ifdef PARANOID
+ testl $0x80000000,SIGH(%esi)
+ jz L_bugged
+ testl $0x80000000,SIGH(%edi)
+ jz L_bugged
+#endif PARANOID
+
+#ifdef DENORM_OPERAND
+ movl EXP(%esi),%eax
+ cmpl EXP_UNDER,%eax
+ jg xOp1_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp1_not_denorm:
+ movl EXP(%edi),%eax
+ cmpl EXP_UNDER,%eax
+ jg xOp2_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp2_not_denorm:
+#endif DENORM_OPERAND
+
+ xorl %ecx,%ecx
+ xorl %ebx,%ebx
+
+ movl SIGL(%esi),%eax
+ mull SIGL(%edi)
+ movl %eax,accum_0
+ movl %edx,accum_1
+
+ movl SIGL(%esi),%eax
+ mull SIGH(%edi)
+ addl %eax,accum_1
+ adcl %edx,%ebx
+/* adcl $0,%ecx *//* overflow here is not possible */
+
+ movl SIGH(%esi),%eax
+ mull SIGL(%edi)
+ addl %eax,accum_1
+ adcl %edx,%ebx
+ adcl $0,%ecx
+
+ movl SIGH(%esi),%eax
+ mull SIGH(%edi)
+ addl %eax,%ebx
+ adcl %edx,%ecx
+
+ movl EXP(%esi),%eax /* Compute the exponent */
+ addl EXP(%edi),%eax
+ subl EXP_BIAS-1,%eax
+/* Have now finished with the sources */
+ movl PARAM3,%edi /* Point to the destination */
+ movl %eax,EXP(%edi)
+
+/* Now make sure that the result is normalized */
+ testl $0x80000000,%ecx
+ jnz LResult_Normalised
+
+ /* Normalize by shifting left one bit */
+ shll $1,accum_0
+ rcll $1,accum_1
+ rcll $1,%ebx
+ rcll $1,%ecx
+ decl EXP(%edi)
+
+LResult_Normalised:
+ movl accum_0,%eax
+ movl accum_1,%edx
+ orl %eax,%eax
+ jz L_extent_zero
+
+ orl $1,%edx
+
+L_extent_zero:
+ movl %ecx,%eax
+ jmp FPU_round
+
+
+#ifdef PARANOID
+L_bugged:
+ pushl EX_INTERNAL|0x205
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_exit:
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
+#endif PARANOID
+
diff --git a/sys/gnu/i386/fpemul/reg_u_sub.s b/sys/gnu/i386/fpemul/reg_u_sub.s
new file mode 100644
index 0000000..92c9344
--- /dev/null
+++ b/sys/gnu/i386/fpemul/reg_u_sub.s
@@ -0,0 +1,351 @@
+ .file "reg_u_sub.S"
+/*
+ * reg_u_sub.S
+ *
+ * Core floating point subtraction routine.
+ *
+ * Call from C as:
+ * void reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
+ * int control_w)
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+/*
+ | Kernel subtraction routine reg_u_sub(reg *arg1, reg *arg2, reg *answ).
+ | Takes two valid reg f.p. numbers (TW_Valid), which are
+ | treated as unsigned numbers,
+ | and returns their difference as a TW_Valid or TW_Zero f.p.
+ | number.
+ | The first number (arg1) must be the larger.
+ | The returned number is normalized.
+ | Basic checks are performed if PARANOID is defined.
+ */
+
+#include "exception.h"
+#include "fpu_asm.h"
+#include "control_w.h"
+
+.text
+ .align 2,144
+.globl _reg_u_sub
+_reg_u_sub:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi /* source 1 */
+ movl PARAM2,%edi /* source 2 */
+
+#ifdef DENORM_OPERAND
+ cmpl EXP_UNDER,EXP(%esi)
+ jg xOp1_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp1_not_denorm:
+ cmpl EXP_UNDER,EXP(%edi)
+ jg xOp2_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp2_not_denorm:
+#endif DENORM_OPERAND
+
+/* xorl %ecx,%ecx */
+ movl EXP(%esi),%ecx
+ subl EXP(%edi),%ecx /* exp1 - exp2 */
+
+#ifdef PARANOID
+ /* source 2 is always smaller than source 1 */
+/* jc L_bugged */
+ js L_bugged_1
+
+ testl $0x80000000,SIGH(%edi) /* The args are assumed to be be normalized */
+ je L_bugged_2
+
+ testl $0x80000000,SIGH(%esi)
+ je L_bugged_2
+#endif PARANOID
+
+/*--------------------------------------+
+ | Form a register holding the |
+ | smaller number |
+ +--------------------------------------*/
+ movl SIGH(%edi),%eax /* register ms word */
+ movl SIGL(%edi),%ebx /* register ls word */
+
+ movl PARAM3,%edi /* destination */
+ movl EXP(%esi),%edx
+ movl %edx,EXP(%edi) /* Copy exponent to destination */
+ movb SIGN(%esi),%dl
+ movb %dl,SIGN(%edi) /* Copy the sign from the first arg */
+
+ xorl %edx,%edx /* register extension */
+
+/*--------------------------------------+
+ | Shift the temporary register |
+ | right the required number of |
+ | places. |
+ +--------------------------------------*/
+L_shift_r:
+ cmpl $32,%ecx /* shrd only works for 0..31 bits */
+ jnc L_more_than_31
+
+/* less than 32 bits */
+ shrd %cl,%ebx,%edx
+ shrd %cl,%eax,%ebx
+ shr %cl,%eax
+ jmp L_shift_done
+
+L_more_than_31:
+ cmpl $64,%ecx
+ jnc L_more_than_63
+
+ subb $32,%cl
+ jz L_exactly_32
+
+ shrd %cl,%eax,%edx
+ shr %cl,%eax
+ orl %ebx,%ebx
+ jz L_more_31_no_low /* none of the lowest bits is set */
+
+ orl $1,%edx /* record the fact in the extension */
+
+L_more_31_no_low:
+ movl %eax,%ebx
+ xorl %eax,%eax
+ jmp L_shift_done
+
+L_exactly_32:
+ movl %ebx,%edx
+ movl %eax,%ebx
+ xorl %eax,%eax
+ jmp L_shift_done
+
+L_more_than_63:
+ cmpw $65,%cx
+ jnc L_more_than_64
+
+ /* Shift right by 64 bits */
+ movl %eax,%edx
+ orl %ebx,%ebx
+ jz L_more_63_no_low
+
+ orl $1,%edx
+ jmp L_more_63_no_low
+
+L_more_than_64:
+ jne L_more_than_65
+
+ /* Shift right by 65 bits */
+ /* Carry is clear if we get here */
+ movl %eax,%edx
+ rcrl %edx
+ jnc L_shift_65_nc
+
+ orl $1,%edx
+ jmp L_more_63_no_low
+
+L_shift_65_nc:
+ orl %ebx,%ebx
+ jz L_more_63_no_low
+
+ orl $1,%edx
+ jmp L_more_63_no_low
+
+L_more_than_65:
+ movl $1,%edx /* The shifted nr always at least one '1' */
+
+L_more_63_no_low:
+ xorl %ebx,%ebx
+ xorl %eax,%eax
+
+L_shift_done:
+L_subtr:
+/*------------------------------+
+ | Do the subtraction |
+ +------------------------------*/
+ xorl %ecx,%ecx
+ subl %edx,%ecx
+ movl %ecx,%edx
+ movl SIGL(%esi),%ecx
+ sbbl %ebx,%ecx
+ movl %ecx,%ebx
+ movl SIGH(%esi),%ecx
+ sbbl %eax,%ecx
+ movl %ecx,%eax
+
+#ifdef PARANOID
+ /* We can never get a borrow */
+ jc L_bugged
+#endif PARANOID
+
+/*--------------------------------------+
+ | Normalize the result |
+ +--------------------------------------*/
+ testl $0x80000000,%eax
+ jnz L_round /* no shifting needed */
+
+ orl %eax,%eax
+ jnz L_shift_1 /* shift left 1 - 31 bits */
+
+ orl %ebx,%ebx
+ jnz L_shift_32 /* shift left 32 - 63 bits */
+
+/* A rare case, the only one which is non-zero if we got here
+// is: 1000000 .... 0000
+// -0111111 .... 1111 1
+// --------------------
+// 0000000 .... 0000 1 */
+
+ cmpl $0x80000000,%edx
+ jnz L_must_be_zero
+
+ /* Shift left 64 bits */
+ subl $64,EXP(%edi)
+ movl %edx,%eax
+ jmp L_store
+
+L_must_be_zero:
+#ifdef PARANOID
+ orl %edx,%edx
+ jnz L_bugged_3
+#endif PARANOID
+
+ /* The result is zero */
+ movb TW_Zero,TAG(%edi)
+ movl $0,EXP(%edi) /* exponent */
+ movl $0,SIGL(%edi)
+ movl $0,SIGH(%edi)
+ jmp L_exit /* Does not underflow */
+
+L_shift_32:
+ movl %ebx,%eax
+ movl %edx,%ebx
+ movl $0,%edx
+ subl $32,EXP(%edi) /* Can get underflow here */
+
+/* We need to shift left by 1 - 31 bits */
+L_shift_1:
+ bsrl %eax,%ecx /* get the required shift in %ecx */
+ subl $31,%ecx
+ negl %ecx
+ shld %cl,%ebx,%eax
+ shld %cl,%edx,%ebx
+ shl %cl,%edx
+ subl %ecx,EXP(%edi) /* Can get underflow here */
+
+L_round:
+ jmp FPU_round /* Round the result */
+
+
+#ifdef PARANOID
+L_bugged_1:
+ pushl EX_INTERNAL|0x206
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged_2:
+ pushl EX_INTERNAL|0x209
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged_3:
+ pushl EX_INTERNAL|0x210
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged_4:
+ pushl EX_INTERNAL|0x211
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged:
+ pushl EX_INTERNAL|0x212
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+#endif PARANOID
+
+
+L_store:
+/*------------------------------+
+ | Store the result |
+ +------------------------------*/
+ movl %eax,SIGH(%edi)
+ movl %ebx,SIGL(%edi)
+
+ movb TW_Valid,TAG(%edi) /* Set the tags to TW_Valid */
+
+ cmpl EXP_UNDER,EXP(%edi)
+ jle L_underflow
+
+L_exit:
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
+
+
+L_underflow:
+ push %edi
+ call _arith_underflow
+ pop %ebx
+ jmp L_exit
+
diff --git a/sys/gnu/i386/fpemul/status_w.h b/sys/gnu/i386/fpemul/status_w.h
new file mode 100644
index 0000000..5c6523d
--- /dev/null
+++ b/sys/gnu/i386/fpemul/status_w.h
@@ -0,0 +1,96 @@
+/*
+ * status_w.h
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+
+#ifndef _STATUS_H_
+#define _STATUS_H_
+
+
+#ifdef LOCORE
+#define Const__(x) $/**/x
+#else
+#define Const__(x) x
+#endif
+
+#define SW_Backward Const__(0x8000) /* backward compatibility */
+#define SW_C3 Const__(0x4000) /* condition bit 3 */
+#define SW_Top Const__(0x3800) /* top of stack */
+#define SW_Top_Shift Const__(11) /* shift for top of stack bits */
+#define SW_C2 Const__(0x0400) /* condition bit 2 */
+#define SW_C1 Const__(0x0200) /* condition bit 1 */
+#define SW_C0 Const__(0x0100) /* condition bit 0 */
+#define SW_Summary Const__(0x0080) /* exception summary */
+#define SW_Stack_Fault Const__(0x0040) /* stack fault */
+#define SW_Precision Const__(0x0020) /* loss of precision */
+#define SW_Underflow Const__(0x0010) /* underflow */
+#define SW_Overflow Const__(0x0008) /* overflow */
+#define SW_Zero_Div Const__(0x0004) /* divide by zero */
+#define SW_Denorm_Op Const__(0x0002) /* denormalized operand */
+#define SW_Invalid Const__(0x0001) /* invalid operation */
+
+#define SW_Exc_Mask Const__(0x27f) /* Status word exception bit mask */
+
+#ifndef LOCORE
+
+#define COMP_A_gt_B 1
+#define COMP_A_eq_B 2
+#define COMP_A_lt_B 3
+#define COMP_No_Comp 4
+#define COMP_Denormal 0x20
+#define COMP_NaN 0x40
+#define COMP_SNaN 0x80
+
+#define setcc(cc) ({ \
+ status_word &= ~(SW_C0|SW_C1|SW_C2|SW_C3); \
+ status_word |= (cc) & (SW_C0|SW_C1|SW_C2|SW_C3); })
+
+#endif /* LOCORE */
+
+#endif /* _STATUS_H_ */
diff --git a/sys/gnu/i386/fpemul/version.h b/sys/gnu/i386/fpemul/version.h
new file mode 100644
index 0000000..4d73be7
--- /dev/null
+++ b/sys/gnu/i386/fpemul/version.h
@@ -0,0 +1,51 @@
+/*
+ * version.h
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+#define FPU_VERSION "wm-FPU-emu version BETA 1.4"
diff --git a/sys/gnu/i386/fpemul/wm_shrx.s b/sys/gnu/i386/fpemul/wm_shrx.s
new file mode 100644
index 0000000..97392be
--- /dev/null
+++ b/sys/gnu/i386/fpemul/wm_shrx.s
@@ -0,0 +1,251 @@
+ .file "wm_shrx.S"
+/*
+ * wm_shrx.S
+ *
+ * 64 bit right shift functions
+ *
+ * Call from C as:
+ * unsigned shrx(void *arg1, unsigned arg2)
+ * and
+ * unsigned shrxs(void *arg1, unsigned arg2)
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+
+#include "fpu_asm.h"
+
+.text
+ .align 2,144
+
+/*---------------------------------------------------------------------------+
+ | unsigned shrx(void *arg1, unsigned arg2) |
+ | |
+ | Extended shift right function. |
+ | Fastest for small shifts. |
+ | Shifts the 64 bit quantity pointed to by the first arg (arg1) |
+ | right by the number of bits specified by the second arg (arg2). |
+ | Forms a 96 bit quantity from the 64 bit arg and eax: |
+ | [ 64 bit arg ][ eax ] |
+ | shift right ---------> |
+ | The eax register is initialized to 0 before the shifting. |
+ | Results returned in the 64 bit arg and eax. |
+ +---------------------------------------------------------------------------*/
+
+ .globl _shrx
+
+_shrx:
+ push %ebp
+ movl %esp,%ebp
+ pushl %esi
+ movl PARAM2,%ecx
+ movl PARAM1,%esi
+ cmpl $32,%ecx /* shrd only works for 0..31 bits */
+ jnc L_more_than_31
+
+/* less than 32 bits */
+ pushl %ebx
+ movl (%esi),%ebx /* lsl */
+ movl 4(%esi),%edx /* msl */
+ xorl %eax,%eax /* extension */
+ shrd %cl,%ebx,%eax
+ shrd %cl,%edx,%ebx
+ shr %cl,%edx
+ movl %ebx,(%esi)
+ movl %edx,4(%esi)
+ popl %ebx
+ popl %esi
+ leave
+ ret
+
+L_more_than_31:
+ cmpl $64,%ecx
+ jnc L_more_than_63
+
+ subb $32,%cl
+ movl (%esi),%eax /* lsl */
+ movl 4(%esi),%edx /* msl */
+ shrd %cl,%edx,%eax
+ shr %cl,%edx
+ movl %edx,(%esi)
+ movl $0,4(%esi)
+ popl %esi
+ leave
+ ret
+
+L_more_than_63:
+ cmpl $96,%ecx
+ jnc L_more_than_95
+
+ subb $64,%cl
+ movl 4(%esi),%eax /* msl */
+ shr %cl,%eax
+ xorl %edx,%edx
+ movl %edx,(%esi)
+ movl %edx,4(%esi)
+ popl %esi
+ leave
+ ret
+
+L_more_than_95:
+ xorl %eax,%eax
+ movl %eax,(%esi)
+ movl %eax,4(%esi)
+ popl %esi
+ leave
+ ret
+
+
+/*---------------------------------------------------------------------------+
+ | unsigned shrxs(void *arg1, unsigned arg2) |
+ | |
+ | Extended shift right function (optimized for small floating point |
+ | integers). |
+ | Shifts the 64 bit quantity pointed to by the first arg (arg1) |
+ | right by the number of bits specified by the second arg (arg2). |
+ | Forms a 96 bit quantity from the 64 bit arg and eax: |
+ | [ 64 bit arg ][ eax ] |
+ | shift right ---------> |
+ | The eax register is initialized to 0 before the shifting. |
+ | The lower 8 bits of eax are lost and replaced by a flag which is |
+ | set (to 0x01) if any bit, apart from the first one, is set in the |
+ | part which has been shifted out of the arg. |
+ | Results returned in the 64 bit arg and eax. |
+ +---------------------------------------------------------------------------*/
+ .globl _shrxs
+_shrxs:
+ push %ebp
+ movl %esp,%ebp
+ pushl %esi
+ pushl %ebx
+ movl PARAM2,%ecx
+ movl PARAM1,%esi
+ cmpl $64,%ecx /* shrd only works for 0..31 bits */
+ jnc Ls_more_than_63
+
+ cmpl $32,%ecx /* shrd only works for 0..31 bits */
+ jc Ls_less_than_32
+
+/* We got here without jumps by assuming that the most common requirement
+ is for small integers */
+/* Shift by [32..63] bits */
+ subb $32,%cl
+ movl (%esi),%eax /* lsl */
+ movl 4(%esi),%edx /* msl */
+ xorl %ebx,%ebx
+ shrd %cl,%eax,%ebx
+ shrd %cl,%edx,%eax
+ shr %cl,%edx
+ orl %ebx,%ebx /* test these 32 bits */
+ setne %bl
+ test $0x7fffffff,%eax /* and 31 bits here */
+ setne %bh
+ orw %bx,%bx /* Any of the 63 bit set ? */
+ setne %al
+ movl %edx,(%esi)
+ movl $0,4(%esi)
+ popl %ebx
+ popl %esi
+ leave
+ ret
+
+/* Shift by [0..31] bits */
+Ls_less_than_32:
+ movl (%esi),%ebx /* lsl */
+ movl 4(%esi),%edx /* msl */
+ xorl %eax,%eax /* extension */
+ shrd %cl,%ebx,%eax
+ shrd %cl,%edx,%ebx
+ shr %cl,%edx
+ test $0x7fffffff,%eax /* only need to look at eax here */
+ setne %al
+ movl %ebx,(%esi)
+ movl %edx,4(%esi)
+ popl %ebx
+ popl %esi
+ leave
+ ret
+
+/* Shift by [64..95] bits */
+Ls_more_than_63:
+ cmpl $96,%ecx
+ jnc Ls_more_than_95
+
+ subb $64,%cl
+ movl (%esi),%ebx /* lsl */
+ movl 4(%esi),%eax /* msl */
+ xorl %edx,%edx /* extension */
+ shrd %cl,%ebx,%edx
+ shrd %cl,%eax,%ebx
+ shr %cl,%eax
+ orl %ebx,%edx
+ setne %bl
+ test $0x7fffffff,%eax /* only need to look at eax here */
+ setne %bh
+ orw %bx,%bx
+ setne %al
+ xorl %edx,%edx
+ movl %edx,(%esi) /* set to zero */
+ movl %edx,4(%esi) /* set to zero */
+ popl %ebx
+ popl %esi
+ leave
+ ret
+
+Ls_more_than_95:
+/* Shift by [96..inf) bits */
+ xorl %eax,%eax
+ movl (%esi),%ebx
+ orl 4(%esi),%ebx
+ setne %al
+ xorl %ebx,%ebx
+ movl %ebx,(%esi)
+ movl %ebx,4(%esi)
+ popl %ebx
+ popl %esi
+ leave
+ ret
diff --git a/sys/gnu/i386/fpemul/wm_sqrt.s b/sys/gnu/i386/fpemul/wm_sqrt.s
new file mode 100644
index 0000000..0dd39cb
--- /dev/null
+++ b/sys/gnu/i386/fpemul/wm_sqrt.s
@@ -0,0 +1,486 @@
+ .file "wm_sqrt.S"
+/*
+ * wm_sqrt.S
+ *
+ * Fixed point arithmetic square root evaluation.
+ *
+ * Call from C as:
+ * void wm_sqrt(FPU_REG *n, unsigned int control_word)
+ *
+ *
+ * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
+ * Vic 3163, Australia.
+ * E-mail apm233m@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD operating system. Any other use is not permitted
+ * under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * $Id:$
+ *
+ */
+
+
+/*---------------------------------------------------------------------------+
+ | wm_sqrt(FPU_REG *n, unsigned int control_word) |
+ | returns the square root of n in n. |
+ | |
+ | Use Newton's method to compute the square root of a number, which must |
+ | be in the range [1.0 .. 4.0), to 64 bits accuracy. |
+ | Does not check the sign or tag of the argument. |
+ | Sets the exponent, but not the sign or tag of the result. |
+ | |
+ | The guess is kept in %esi:%edi |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "fpu_asm.h"
+
+
+.data
+/*
+ Local storage:
+ */
+ .align 4,0
+accum_3:
+ .long 0 /* ms word */
+accum_2:
+ .long 0
+accum_1:
+ .long 0
+accum_0:
+ .long 0
+
+/* The de-normalised argument:
+// sq_2 sq_1 sq_0
+// b b b b b b b ... b b b b b b .... b b b b 0 0 0 ... 0
+// ^ binary point here */
+fsqrt_arg_2:
+ .long 0 /* ms word */
+fsqrt_arg_1:
+ .long 0
+fsqrt_arg_0:
+ .long 0 /* ls word, at most the ms bit is set */
+
+.text
+ .align 2,144
+
+.globl _wm_sqrt
+
+_wm_sqrt:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi
+
+ movl SIGH(%esi),%eax
+ movl SIGL(%esi),%ecx
+ xorl %edx,%edx
+
+/* We use a rough linear estimate for the first guess.. */
+
+ cmpl EXP_BIAS,EXP(%esi)
+ jnz sqrt_arg_ge_2
+
+ shrl $1,%eax /* arg is in the range [1.0 .. 2.0) */
+ rcrl $1,%ecx
+ rcrl $1,%edx
+
+sqrt_arg_ge_2:
+/* From here on, n is never accessed directly again until it is
+// replaced by the answer. */
+
+ movl %eax,fsqrt_arg_2 /* ms word of n */
+ movl %ecx,fsqrt_arg_1
+ movl %edx,fsqrt_arg_0
+
+/* Make a linear first estimate */
+ shrl $1,%eax
+ addl $0x40000000,%eax
+ movl $0xaaaaaaaa,%ecx
+ mull %ecx
+ shll %edx /* max result was 7fff... */
+ testl $0x80000000,%edx /* but min was 3fff... */
+ jnz sqrt_prelim_no_adjust
+
+ movl $0x80000000,%edx /* round up */
+
+sqrt_prelim_no_adjust:
+ movl %edx,%esi /* Our first guess */
+
+/* We have now computed (approx) (2 + x) / 3, which forms the basis
+ for a few iterations of Newton's method */
+
+ movl fsqrt_arg_2,%ecx /* ms word */
+
+/* From our initial estimate, three iterations are enough to get us
+// to 30 bits or so. This will then allow two iterations at better
+// precision to complete the process.
+
+// Compute (g + n/g)/2 at each iteration (g is the guess). */
+ shrl %ecx /* Doing this first will prevent a divide */
+ /* overflow later. */
+
+ movl %ecx,%edx /* msw of the arg / 2 */
+ divl %esi /* current estimate */
+ shrl %esi /* divide by 2 */
+ addl %eax,%esi /* the new estimate */
+
+ movl %ecx,%edx
+ divl %esi
+ shrl %esi
+ addl %eax,%esi
+
+ movl %ecx,%edx
+ divl %esi
+ shrl %esi
+ addl %eax,%esi
+
+/* Now that an estimate accurate to about 30 bits has been obtained (in %esi),
+// we improve it to 60 bits or so.
+
+// The strategy from now on is to compute new estimates from
+// guess := guess + (n - guess^2) / (2 * guess) */
+
+/* First, find the square of the guess */
+ movl %esi,%eax
+ mull %esi
+/* guess^2 now in %edx:%eax */
+
+ movl fsqrt_arg_1,%ecx
+ subl %ecx,%eax
+ movl fsqrt_arg_2,%ecx /* ms word of normalized n */
+ sbbl %ecx,%edx
+ jnc sqrt_stage_2_positive
+/* subtraction gives a negative result
+// negate the result before division */
+ notl %edx
+ notl %eax
+ addl $1,%eax
+ adcl $0,%edx
+
+ divl %esi
+ movl %eax,%ecx
+
+ movl %edx,%eax
+ divl %esi
+ jmp sqrt_stage_2_finish
+
+sqrt_stage_2_positive:
+ divl %esi
+ movl %eax,%ecx
+
+ movl %edx,%eax
+ divl %esi
+
+ notl %ecx
+ notl %eax
+ addl $1,%eax
+ adcl $0,%ecx
+
+sqrt_stage_2_finish:
+ sarl $1,%ecx /* divide by 2 */
+ rcrl $1,%eax
+
+ /* Form the new estimate in %esi:%edi */
+ movl %eax,%edi
+ addl %ecx,%esi
+
+ jnz sqrt_stage_2_done /* result should be [1..2) */
+
+#ifdef PARANOID
+/* It should be possible to get here only if the arg is ffff....ffff*/
+ cmp $0xffffffff,fsqrt_arg_1
+ jnz sqrt_stage_2_error
+#endif PARANOID
+
+/* The best rounded result.*/
+ xorl %eax,%eax
+ decl %eax
+ movl %eax,%edi
+ movl %eax,%esi
+ movl $0x7fffffff,%eax
+ jmp sqrt_round_result
+
+#ifdef PARANOID
+sqrt_stage_2_error:
+ pushl EX_INTERNAL|0x213
+ call EXCEPTION
+#endif PARANOID
+
+sqrt_stage_2_done:
+
+/* Now the square root has been computed to better than 60 bits */
+
+/* Find the square of the guess*/
+ movl %edi,%eax /* ls word of guess*/
+ mull %edi
+ movl %edx,accum_1
+
+ movl %esi,%eax
+ mull %esi
+ movl %edx,accum_3
+ movl %eax,accum_2
+
+ movl %edi,%eax
+ mull %esi
+ addl %eax,accum_1
+ adcl %edx,accum_2
+ adcl $0,accum_3
+
+/* movl %esi,%eax*/
+/* mull %edi*/
+ addl %eax,accum_1
+ adcl %edx,accum_2
+ adcl $0,accum_3
+
+/* guess^2 now in accum_3:accum_2:accum_1*/
+
+ movl fsqrt_arg_0,%eax /* get normalized n*/
+ subl %eax,accum_1
+ movl fsqrt_arg_1,%eax
+ sbbl %eax,accum_2
+ movl fsqrt_arg_2,%eax /* ms word of normalized n*/
+ sbbl %eax,accum_3
+ jnc sqrt_stage_3_positive
+
+/* subtraction gives a negative result*/
+/* negate the result before division */
+ notl accum_1
+ notl accum_2
+ notl accum_3
+ addl $1,accum_1
+ adcl $0,accum_2
+
+#ifdef PARANOID
+ adcl $0,accum_3 /* This must be zero */
+ jz sqrt_stage_3_no_error
+
+sqrt_stage_3_error:
+ pushl EX_INTERNAL|0x207
+ call EXCEPTION
+
+sqrt_stage_3_no_error:
+#endif PARANOID
+
+ movl accum_2,%edx
+ movl accum_1,%eax
+ divl %esi
+ movl %eax,%ecx
+
+ movl %edx,%eax
+ divl %esi
+
+ sarl $1,%ecx / divide by 2*/
+ rcrl $1,%eax
+
+ /* prepare to round the result*/
+
+ addl %ecx,%edi
+ adcl $0,%esi
+
+ jmp sqrt_stage_3_finished
+
+sqrt_stage_3_positive:
+ movl accum_2,%edx
+ movl accum_1,%eax
+ divl %esi
+ movl %eax,%ecx
+
+ movl %edx,%eax
+ divl %esi
+
+ sarl $1,%ecx /* divide by 2*/
+ rcrl $1,%eax
+
+ /* prepare to round the result*/
+
+ notl %eax /* Negate the correction term*/
+ notl %ecx
+ addl $1,%eax
+ adcl $0,%ecx /* carry here ==> correction == 0*/
+ adcl $0xffffffff,%esi
+
+ addl %ecx,%edi
+ adcl $0,%esi
+
+sqrt_stage_3_finished:
+
+/* The result in %esi:%edi:%esi should be good to about 90 bits here,
+// and the rounding information here does not have sufficient accuracy
+// in a few rare cases. */
+ cmpl $0xffffffe0,%eax
+ ja sqrt_near_exact_x
+
+ cmpl $0x00000020,%eax
+ jb sqrt_near_exact
+
+ cmpl $0x7fffffe0,%eax
+ jb sqrt_round_result
+
+ cmpl $0x80000020,%eax
+ jb sqrt_get_more_precision
+
+sqrt_round_result:
+/* Set up for rounding operations*/
+ movl %eax,%edx
+ movl %esi,%eax
+ movl %edi,%ebx
+ movl PARAM1,%edi
+ movl EXP_BIAS,EXP(%edi) /* Result is in [1.0 .. 2.0)*/
+ movl PARAM2,%ecx
+ jmp FPU_round_sqrt
+
+
+sqrt_near_exact_x:
+/* First, the estimate must be rounded up.*/
+ addl $1,%edi
+ adcl $0,%esi
+
+sqrt_near_exact:
+/* This is an easy case because x^1/2 is monotonic.
+// We need just find the square of our estimate, compare it
+// with the argument, and deduce whether our estimate is
+// above, below, or exact. We use the fact that the estimate
+// is known to be accurate to about 90 bits. */
+ movl %edi,%eax /* ls word of guess*/
+ mull %edi
+ movl %edx,%ebx /* 2nd ls word of square*/
+ movl %eax,%ecx /* ls word of square*/
+
+ movl %edi,%eax
+ mull %esi
+ addl %eax,%ebx
+ addl %eax,%ebx
+
+#ifdef PARANOID
+ cmp $0xffffffb0,%ebx
+ jb sqrt_near_exact_ok
+
+ cmp $0x00000050,%ebx
+ ja sqrt_near_exact_ok
+
+ pushl EX_INTERNAL|0x214
+ call EXCEPTION
+
+sqrt_near_exact_ok:
+#endif PARANOID
+
+ or %ebx,%ebx
+ js sqrt_near_exact_small
+
+ jnz sqrt_near_exact_large
+
+ or %ebx,%edx
+ jnz sqrt_near_exact_large
+
+/* Our estimate is exactly the right answer*/
+ xorl %eax,%eax
+ jmp sqrt_round_result
+
+sqrt_near_exact_small:
+/* Our estimate is too small*/
+ movl $0x000000ff,%eax
+ jmp sqrt_round_result
+
+sqrt_near_exact_large:
+/* Our estimate is too large, we need to decrement it*/
+ subl $1,%edi
+ sbbl $0,%esi
+ movl $0xffffff00,%eax
+ jmp sqrt_round_result
+
+
+sqrt_get_more_precision:
+/* This case is almost the same as the above, except we start*/
+/* with an extra bit of precision in the estimate.*/
+ stc /* The extra bit.*/
+ rcll $1,%edi /* Shift the estimate left one bit*/
+ rcll $1,%esi
+
+ movl %edi,%eax /* ls word of guess*/
+ mull %edi
+ movl %edx,%ebx /* 2nd ls word of square*/
+ movl %eax,%ecx /* ls word of square*/
+
+ movl %edi,%eax
+ mull %esi
+ addl %eax,%ebx
+ addl %eax,%ebx
+
+/* Put our estimate back to its original value*/
+ stc /* The ms bit.*/
+ rcrl $1,%esi /* Shift the estimate left one bit*/
+ rcrl $1,%edi
+
+#ifdef PARANOID
+ cmp $0xffffff60,%ebx
+ jb sqrt_more_prec_ok
+
+ cmp $0x000000a0,%ebx
+ ja sqrt_more_prec_ok
+
+ pushl EX_INTERNAL|0x215
+ call EXCEPTION
+
+sqrt_more_prec_ok:
+#endif PARANOID
+
+ or %ebx,%ebx
+ js sqrt_more_prec_small
+
+ jnz sqrt_more_prec_large
+
+ or %ebx,%ecx
+ jnz sqrt_more_prec_large
+
+/* Our estimate is exactly the right answer*/
+ movl $0x80000000,%eax
+ jmp sqrt_round_result
+
+sqrt_more_prec_small:
+/* Our estimate is too small*/
+ movl $0x800000ff,%eax
+ jmp sqrt_round_result
+
+sqrt_more_prec_large:
+/* Our estimate is too large*/
+ movl $0x7fffff00,%eax
+ jmp sqrt_round_result
diff --git a/sys/i386/Makefile b/sys/i386/Makefile
new file mode 100644
index 0000000..4ad5a34
--- /dev/null
+++ b/sys/i386/Makefile
@@ -0,0 +1,25 @@
+# from: @(#)Makefile 7.3 (Berkeley) 6/9/91
+# $Id$
+
+# Makefile for i386 tags file
+
+all:
+ @echo "make tags or links only"
+
+TI386= ../i386/tags
+SI386= ../i386/i386/*.[ch] ../i386/include/*.h ../i386/isa/*.[ch]
+AI386= ../i386/i386/*.s
+
+# Directories in which to place i386 tags links
+DI386= eisa isa mca include
+
+tags:
+ -ctags -dtf ${TI386} ${COMM} ${SI386}
+ egrep "^ENTRY(.*)|^ALTENTRY(.*)" ${AI386} | \
+ sed "s;\([^:]*\):\([^(]*\)(\([^, )]*\)\(.*\);\3 \1 /^\2(\3\4$$/;" \
+ >> ${TI386}
+ sort -o ${TI386} ${TI386}
+
+links:
+ -for i in ${DI386}; do \
+ cd $$i && rm -f tags; ln -s ../tags tags; done
diff --git a/sys/i386/boot/Makefile b/sys/i386/boot/Makefile
new file mode 100644
index 0000000..4f7915d
--- /dev/null
+++ b/sys/i386/boot/Makefile
@@ -0,0 +1,103 @@
+#
+# Permission to use, copy, modify and distribute this software and its
+# documentation is hereby granted, provided that both the copyright
+# notice and this permission notice appear in all copies of the
+# software, derivative works or modified versions, and any portions
+# thereof, and that both notices appear in supporting documentation.
+#
+# CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+# CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+# ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+#
+# Carnegie Mellon requests users of this software to return to
+#
+# Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+# School of Computer Science
+# Carnegie Mellon University
+# Pittsburgh PA 15213-3890
+#
+# any improvements or extensions that they make and grant Carnegie Mellon
+# the rights to redistribute these changes.
+#
+# from: Mach, Revision 2.2 92/04/04 11:33:46 rpd
+# $Id: Makefile,v 1.4 1993/11/16 02:02:05 ache Exp $
+#
+
+wd0:
+ dd if=boot of=biosboot count=1
+ dd if=boot of=bootbios skip=1
+ disklabel -r -w wd0 nec5655 newboot biosboot bootbios
+ rm biosboot bootbios
+
+NOPROG= noprog
+NOMAN= noman
+
+CFLAGS = -O -DDO_BAD144 -I${.CURDIR}
+LIBS= -lc
+INC= -I${.CURDIR}/../..
+
+# start.o should be first
+OBJS = start.o table.o boot2.o boot.o asm.o bios.o io.o disk.o sys.o
+
+.SUFFIXES: .S .c .o
+
+.c.o:
+ $(CC) $(CFLAGS) $(INC) -c $<
+
+.S.o:
+ $(CC) $(CFLAGS) -c $<
+
+boot: $(OBJS)
+ $(LD) -Bstatic -N -T 0 -o boot $(OBJS) $(LIBS)
+ cp boot boot.sym
+ @strip boot
+ @sh ${.CURDIR}/rmaouthdr boot boot.tmp
+ @mv -f boot.tmp boot
+ @ls -l boot
+
+biosboot: boot
+ dd if=boot of=biosboot count=1
+
+bootbios: boot
+ dd if=boot of=bootbios skip=1
+
+/usr/mdec/bootsd: bootbios
+ cp bootbios /usr/mdec/bootsd
+
+/usr/mdec/sdboot: biosboot
+ cp biosboot /usr/mdec/sdboot
+
+/usr/mdec/bootwd: /usr/mdec/bootsd
+ rm -f /usr/mdec/bootwd
+ ln /usr/mdec/bootsd /usr/mdec/bootwd
+
+/usr/mdec/wdboot: /usr/mdec/sdboot
+ rm -f /usr/mdec/wdboot
+ ln /usr/mdec/sdboot /usr/mdec/wdboot
+
+/usr/mdec/bootfd: /usr/mdec/bootsd
+ rm -f /usr/mdec/bootfd
+ ln /usr/mdec/bootsd /usr/mdec/bootfd
+
+/usr/mdec/fdboot: /usr/mdec/sdboot
+ rm -f /usr/mdec/fdboot
+ ln /usr/mdec/sdboot /usr/mdec/fdboot
+
+sd: /usr/mdec/bootsd /usr/mdec/sdboot
+wd: /usr/mdec/bootwd /usr/mdec/wdboot
+fd: /usr/mdec/bootfd /usr/mdec/fdboot
+
+all: biosboot bootbios
+
+fd0:
+ dd if=boot of=biosboot count=1
+ dd if=boot of=bootbios skip=1
+ disklabel -r -w fd0 floppy bootflpy biosboot bootbios
+ rm biosboot bootbios
+
+install: wd sd fd
+
+clean:
+ /bin/rm -f *.o *.d boot bootbios biosboot boot.sym
+
+.include <bsd.prog.mk>
diff --git a/sys/i386/boot/README.386BSD b/sys/i386/boot/README.386BSD
new file mode 100644
index 0000000..cc5cb8f
--- /dev/null
+++ b/sys/i386/boot/README.386BSD
@@ -0,0 +1,151 @@
+This Boot code is different from the original boot code that came with
+386BSD in that it uses the BIOS to load the kernel and to provide all i/o
+services. The advantage ofthis is that the same boot code exactly, can run
+on any device that is supported by the BIOS. (That's most of them)
+This is important for the 'generic scsi' project because it means we can
+write drivers for new scsi adapters without having to develop an new
+set of boot blocks for each.
+
+At this point you should read the first part of README.MACH... come back here
+when you have done that:
+
+In normal operation, when co-existing with other operating systems, the
+following operations occur:
+
+1/ the BIOS loads the first block of the disk (called the Master Boot Record
+or MBR) and if it has the correct magic numbers, jumps into it:
+
+2/ The MBR code, looks at the Partition table that is embedded within it,
+to detirmine which is the partition to boot from. If you are using the os-bs
+bootblocks (highly recommended) then it will give you a menu to choose from.
+
+3/ The MBR will load the first record of the selected partition and
+if it has (the same) magic numbers, jumps into it. In 386bsd this is the
+first stage boot, (or boot1) it is represented in /usr/mdec by
+wdboot, asboot and sdboot. If the disk has been set up without DOS partitioning
+then this block will be at block zero, and will have been loaded directly by
+the BIOS.
+
+4/ Boot1 will look at block0 (which might be itself if there are no DOS
+partitions) and will find the 386bsd partition, and using the information
+regarding the start position of that partition, will load the next 13 sectors
+or so, to around 90000 (640k - 64k). and will jump into it at the appropriate
+entry point. Since boot1 and boot2 were compiled together as one file
+and then split later, boot1 knows the exact position within boot2 of the
+entry point.
+
+Boot 1 also contains a compiled in DOS partition table
+(in case it is at block 0), which contains a 386bsd partition starting
+at 0. This ensures that the same code can work whether or not
+boot1 is at block 0.
+
+5/ Boot2 asks the user for a boot device, partition and filename, and then
+loads the MBR of the selected device. This may or may not be the device
+which was originally used to boot the first MBR. The partition table
+of the new MBR is searched for a 386bsd partition, and if one is found,
+that is then in turn searched for the disklabel. This could all be on the
+second disk at this point, if the user selected it.
+
+6/On finding the disklabel, boot2 can find the correct unix partition
+within the 386bsd partition, and using cutdown filesystem code,
+look for the file to boot (e.g. 386bsd).
+
+7/ Boot2 loads this file starting at the location specified by the a.out header,
+(see later) and leaps into it at the location specified in he header.
+
+if the file does not exist or cannot be loaded, boot2 goes back to step 5.
+
+386bsd is now running and will hopefully start vm etc. and get to multi-user
+mode.
+
+##########################################################################
+During all these steps, all i/o is performed using the BIOS. This has a number
+of side effects:
+
+1/ Since BIOS disk calls are specified in terms of cylinder,head and sector,
+and the BIOS read the disk information from either the CMOS or from some other
+location which is un-available to us, we must use the cyl,head,sec information
+that is given in the MBR, rather than the start address in the MBR, because
+we cannot guarentee that we can corectly calculate C,H,S from the start address.
+
+Therefore, the C,H,S information in the MBR must be as correct for this boot
+to work as it would be for DOS to boot. For example, adaptec BIOS routines
+assume a layout of 64 heads and 32 sectors giving 1MB per ficticious cylinder.
+You must use these figures to calculate the correct values. Luckily, the DOS
+fdisk program will do all this for you if you tell it to give you a DOS
+partition, and you can change it to a 386BSD partition later. If you use
+no DOS partitioning, then the compiled in table in Boot1 will do just fine.
+
+If you want to do it by hand remember that BIOS counts sectors starting at 1.
+(cylinders and heads start at 0 (??))
+
+2/ you cannot overwrite the bottom 4k of ram until you have finished ALL
+bios calls, as BIOS uses this area as scratch memory.
+
+3/ Since BIOS runs in REAL mode, and Boot2 runs in protected mode,
+Boot 2 switches back to real mode just before each BIOS call and then
+back to protected mode on each return. Touch this at your peril.!
+
+#########################################################################
+In answering the prompt from Boot2:
+you can,
+1/ leave it alone.. it will boot the indicated file from the first
+partition of the first drive seen by the BIOS (C:)
+
+2/ enter only "-s" to boot the default to single user mode
+
+3/ enter only a filename (optionally with -s) to boot that kernel,
+
+4/ enter a whole line of the form shown in the prompt. This allows you to
+boot some other partition, possibly on the second drive, as root.
+
+
+##########################################################################
+In the case you have two drives the same type (both scsi or bith IDE/ESDI),
+wd(0,a)xxx
+ will boot xxx from drive 0, a partition.
+wd(1,a)xxx
+ will boot xxx from drive 1, a partition.
+
+similarly for sd.
+
+if you have one wd drive and one scsi drive, then you MUST
+use device 'hd'
+
+otherwise the following will happen:
+
+with wd0 and sd0, you specify sd1 or wd1 to indicate the 2nd drive.
+it boots the kernel correctly, then tells the kernel to use sd1 as root.
+you however may not have an sd1, and problems arise.
+
+hd is special in that the kernel is always told to use unit 0,
+The correct TYPE of device will be specified too, so the kernel
+will be told either sd0 or wd0.
+
+Whether sd or wd is specified to the kernel is read from the disklabel,
+so ensure that all SCSI disks have type SCSI in their disklabel or the
+boot code will assume they are ESDI or IDE. (Remember, because it is
+working through the BIOS it has ho idea what kind of disk it is.
+
+##########################################################################
+Installing:
+The makefile supplied has a target install which will create the
+files wdboot,bootwd ,sdboot and bootsd in /usr/mdec.
+BEWARE these will overwrite the existing wdboot and bootwd. (so back
+them up)
+
+there are also targets wd and sd which wil only do one of them
+
+The commented out targets wd0 and sd0 are examples of how to
+load the new bootblocks, however,make sure you change the
+device type and label to suit your drive if you uncomment them.
+(see 'man disklabel')
+
+If you already have made partitions using the old bootblocks
+these should install painlessly.
+
+Before you do this ensure you have a booting floppy with correct
+disktab and bootblock files on it so that if it doesn't work, you can
+re-disklabel from the floppy.
+
+$Id$
diff --git a/sys/i386/boot/README.MACH b/sys/i386/boot/README.MACH
new file mode 100644
index 0000000..cb62329
--- /dev/null
+++ b/sys/i386/boot/README.MACH
@@ -0,0 +1,210 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:33:55 rpd
+ * $Id$
+ */
+
+********NOTE: This is not all relevant to the 386BSD version**********
+
+ AT386 Protected Mode Bootstrap Loader
+ =====================================
+
+1. Overview of Startup
+ -------------------
+
+ After the system is rebooted, the BIOS bootstrap routine reads Sector
+ 1, Track 0 into memory at location 0000:7C00H. If location 0000:7DFEH
+ (last two bytes of that sector) contains the value AA55H, the BIOS
+ bootstrap routine will transfer control to 0000:7C00H. Otherwise, the
+ boot code in that sector is bad and the boot routine stops.
+
+ For DOS compatibility reason, one extra stage of boot is required if
+ the boot device is a hard disk. The first sector of the hard disk will
+ contain the MOS-DOS boot code and a boot record partition table.
+ When this sector is loaded into 0000:7C00H, it will relocate itself
+ to somewhere else and then load the first sector of the active
+ partition into 0000:7C00H. Both UNIX and DOS use the command "fdisk"
+[ 386bsd does not have an 'fdisk' (yet) ]
+ to install this first sector into the hard disk and to manipulate
+ the hard disk partitions.
+
+
+
+2. The First Stage Bootstrap Loader
+ --------------------------------
+
+ After startup, the first stage boot is loaded at 0000:7C00H. This
+ first stage boot will load itself and the second stage boot into
+ memory at location 0000:1000H. For floppy disks, the first cylinder
+ is reserved as the boot cylinder, and the boot code (first and second)
+ will be loaded from there. Currently, only double sided, high density
+ (15 sectors per track) floppies are supported. For hard disks, the
+ first 29 sectors of the active partition is reserved for boot code
+ which will be loaded by the first stage boot. All the disk types
+ recognized by BIOS are supported by this bootstrap loader.
+[for 386bsd we load the second stage booter to 9000:0]
+
+
+
+3. The Second Stage Bootstrap Loader
+ --------------------------------
+
+ After the boot code is loaded, the control is passed to the second
+ stage bootstrap loader "boot2()". In order to be able to load the
+ big kernel image (bigger than 512K or 640K, depends on the memory
+ configuration), the second stage boot loader will run on the protected
+ mode. This bootstarp loader does not have any stand alone device
+ drivers, all the I/O's are through the BIOS calls. Since the first
+ stage boot code will no longer be used at this moment, the memory
+ location of the first stage boot code (0000:1000H to 0000:1200H) will
+ be used as an internal buffer for BIOS calls. Immediately after this
+ internal buffer is the GDT table for the second stage boot loader.
+ Since this boot loader needs to switch back and forth between protected
+ and real mode in order to use BIOS calls, the limit of the boot code
+ and boot data segments must not be greater than 64K.
+
+ The boot loader loads the kernel image at memory location above 1 MB
+ to skip the memory hole between 521K/640K and 1MB. After the kernel
+ is loaded, the boot loader stores the information in the stack and
+ then passes control to kernel. Currently, the three information passed
+ fromm the boot loader to the kernel are type of the boot device, size
+ of the base memory and size of the extended memory.
+
+[ 386bsd receives: howto, bootdev]
+
+[ 386bsd is loaded where-ever the "MByte" bits of the load address specify,
+so if you link it for FE100000 it will load to 1MB, but if you link
+it for FE000000 it will load ad 0MB]
+
+[for machines with only 512KB normal ram the kernel will need to be linked
+for 1MB and the bootblocks modified to run below 512KB. (8000:0)]
+
+
+4. The UNIX Startup
+ ----------------
+
+ Since the boot loader loads the kernel image at memory location above
+ 1MB, the kernel has to start as protected mode. In addition, the
+ link editor description file (vuifile) has to indicate that
+ the text and data segments start above 1MB. Also, the boot loader
+ passes the infomation to the kernel through the stack.
+
+[MOST of what is mentionned below is NOT relevant to 386bsd]
+
+5. Disk Layout and Bad Block Handling
+ ---------------------------------
+
+ The System V/386 Release 3.2 (AT) disk layout will be used as the disk
+ layout for the MACH System on the AT platform.
+
+ This disk layout is as follows:
+
+ * Reserve the first sector of cylinder 0 for the DOS boot record which
+ contains the master boot code (446 bytes) and the partition table.
+ (Refer to DOS Technical Reference Manual page 9-6 to 9-10).
+
+ * Reserve the first 29 sectors of the UNIX partition for the first
+ and the second stage bootstrap.
+
+ * Reserve the 30th sector of the UNIX partition for the pdinfo and
+ the vtoc tables.
+
+ * Reserve the 31st to the 34th sectors of the UNIX partition for the
+ bad track and the bad block mapping tables.
+
+ * Reserve up to 253 consecutive tracks when required, beginning with
+ the 35th sector of the UNIX partition, for alternate tracks.
+
+ * Reserve up to 253 consecutive blocks, beginning with the first
+ sector after the alternate tracks area, for alternate blocks.
+
+ SEC
+ 1
+ ----------------------------------------------------
+ | X | | CYL 0, TRK 0
+ ---------------- .......... --------------------
+ | .......... |
+ ---------------- .......... --------------------
+ | .......... |
+ ===============================================================
+ ^ | BOOTSTRAP | CYL N, TRK M
+ | ----------------------------------------------------
+ | | |30 |31 |32 |33 |34 |
+ ---------------------------------------------------- ---
+ U | .......... | ^
+ N ---------------- .......... --------------------- |
+ I | .......... | Alternate Tracks
+ X ---------------- .......... --------------------- |
+ | .......... | V
+ P ---------------------------------------------------- ---
+ A | .......... | ^
+ R ---------------- .......... --------------------- |
+ T | .......... | Alternate Blocks
+ I ---------------- .......... -------------------- |
+ T | .......... | V
+ I ---------------------------------------------------- ---
+ O | Unix root partition starts from here |
+ N ---------------- -----------------
+ | |
+ ----------------------------------------------------
+ | |
+ ----------------------------------------------------
+ | |
+ | ---------------------------------------------------
+ | | |
+ | ----------------------------------------------------
+ V | |
+ ===============================================================
+ | ........ |
+ --------------- ........ --------------
+ | ........ |
+ ----------------------------------------------------
+
+
+ The bad block handling mechanism is as follows:
+
+ * Use the alternate track in the alternate tracks area if the
+ track containing the target sector is bad.
+
+ * Use the alternate block in the alternate blocks area if the
+ target sector is bad.
+
+
+
+
+6. How to make:
+ -----------
+
+ Since the kernel image is loaded above 1 MB, the kernel must start
+ as protected mode. This means that this bootstrap loader will work
+ only when the corresponding changes on the kernel startup code are done.
+
+ The make command to generate this bootstrap loader is:
+
+ make -f boot.mk fdboot (floppy boot loader)
+ make -f boot.mk hdboot (wini boot loader)
+[to make 386bsd bootblocks "make sd wd" (warning: they will be installed
+in /dev/mdec.. take backups)]
diff --git a/sys/i386/boot/asm.S b/sys/i386/boot/asm.S
new file mode 100644
index 0000000..b291428
--- /dev/null
+++ b/sys/i386/boot/asm.S
@@ -0,0 +1,260 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:34:13 rpd
+ * $Id$
+ */
+
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+ .file "asm.s"
+
+#include "asm.h"
+
+
+CR0_PE_ON = 0x1
+CR0_PE_OFF = 0xfffffffe
+
+.globl _ouraddr
+ .text
+
+/*
+#
+# real_to_prot()
+# transfer from real mode to protected mode.
+*/
+
+ENTRY(real_to_prot)
+ # guarantee that interrupt is disabled when in prot mode
+ cli
+
+ # load the gdtr
+ addr32
+ data32
+ lgdt EXT(Gdtr)
+
+ # set the PE bit of CR0
+ mov %cr0, %eax
+
+ data32
+ or $CR0_PE_ON, %eax
+ mov %eax, %cr0
+
+ # make intrasegment jump to flush the processor pipeline and
+ # reload CS register
+ data32
+ ljmp $0x18, $xprot
+
+xprot:
+ # we are in USE32 mode now
+ # set up the protected mode segment registers : DS, SS, ES
+ mov $0x20, %eax
+ movw %ax, %ds
+ movw %ax, %ss
+ movw %ax, %es
+
+ # load idtr so we can debug
+ lidt EXT(Idtr_prot)
+
+ ret
+
+/*
+#
+# prot_to_real()
+# transfer from protected mode to real mode
+#
+*/
+
+ENTRY(prot_to_real)
+
+ # set up a dummy stack frame for the second seg change.
+ movl _ouraddr, %eax
+ sarl $4, %eax
+ pushw %ax
+ movw $xreal, %ax # gas botches pushw $xreal - extra bytes 0, 0
+ pushw %ax # decode to add %al, (%eax) (%al usually 0)
+
+ # Change to use16 mode.
+ ljmp $0x28, $x16
+
+x16:
+ # clear the PE bit of CR0
+ mov %cr0, %eax
+ data32
+ and $CR0_PE_OFF, %eax
+ mov %eax, %cr0
+
+ # make intersegment jmp to flush the processor pipeline
+ # using the fake stack frame set up earlier
+ # and reload CS register
+ lret
+
+xreal:
+ # we are in real mode now
+ # set up the real mode segment registers : DS, SS, ES
+ movw %cs, %ax
+ movw %ax, %ds
+ movw %ax, %ss
+ movw %ax, %es
+
+ # load idtr so we can debug
+ addr32
+ data32
+ lidt EXT(Idtr_real)
+
+ data32
+ ret
+
+/*
+#
+# startprog(phyaddr)
+# start the program on protected mode where phyaddr is the entry point
+#
+*/
+
+ENTRY(startprog)
+ push %ebp
+ mov %esp, %ebp
+
+ # get things we need into registers
+ movl 0x8(%ebp), %ecx # entry offset
+ movl 0x0c(%ebp), %eax # &argv
+
+ # make a new stack at 0:0xa0000 (big segs)
+ mov $0x10, %ebx
+ movw %bx, %ss
+ movl $0xa0000, %ebx
+ movl %ebx, %esp
+
+ # push some number of args onto the stack
+ pushl $0 # nominally a cyl offset in the boot.
+ pushl 0x8(%eax) # argv[2] = bootdev
+ pushl 0x4(%eax) # argv[1] = howto
+ pushl $0 # dummy 'return' address
+
+ # push on our entry address
+ mov $0x08, %ebx # segment
+ pushl %ebx
+ pushl %ecx
+
+ # convert over the other data segs
+ mov $0x10, %ebx
+ movw %bx, %ds
+ movw %bx, %es
+
+ # convert the PC (and code seg)
+ lret
+/*
+#
+# pbzero( dst, cnt)
+# where src is a virtual address and dst is a physical address
+*/
+
+ENTRY(pbzero)
+ push %ebp
+ mov %esp, %ebp
+ push %es
+ push %esi
+ push %edi
+ push %ecx
+
+ cld
+
+ # set %es to point at the flat segment
+ mov $0x10, %eax
+ movw %ax, %es
+
+ mov 0x8(%ebp), %edi # destination
+ mov 0xc(%ebp), %ecx # count
+ mov $0x0, %eax # value
+
+ rep
+ stosb
+
+ pop %ecx
+ pop %edi
+ pop %esi
+ pop %es
+ pop %ebp
+
+ ret
+/*
+#
+# pcpy(src, dst, cnt)
+# where src is a virtual address and dst is a physical address
+#
+*/
+
+ENTRY(pcpy)
+ push %ebp
+ mov %esp, %ebp
+ push %es
+ push %esi
+ push %edi
+ push %ecx
+
+ cld
+
+ # set %es to point at the flat segment
+ mov $0x10, %eax
+ movw %ax, %es
+
+ mov 0x8(%ebp), %esi # source
+ mov 0xc(%ebp), %edi # destination
+ mov 0x10(%ebp), %ecx # count
+
+ rep
+ movsb
+
+ pop %ecx
+ pop %edi
+ pop %esi
+ pop %es
+ pop %ebp
+
+ ret
+
diff --git a/sys/i386/boot/asm.h b/sys/i386/boot/asm.h
new file mode 100644
index 0000000..43242bd
--- /dev/null
+++ b/sys/i386/boot/asm.h
@@ -0,0 +1,144 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.7 92/02/29 15:33:41 rpd
+ * $Id$
+ */
+
+#define S_ARG0 4(%esp)
+#define S_ARG1 8(%esp)
+#define S_ARG2 12(%esp)
+#define S_ARG3 16(%esp)
+
+#define FRAME pushl %ebp; movl %esp, %ebp
+#define EMARF leave
+
+#define B_ARG0 8(%ebp)
+#define B_ARG1 12(%ebp)
+#define B_ARG2 16(%ebp)
+#define B_ARG3 20(%ebp)
+
+#ifdef wheeze
+
+#define ALIGN 4
+#define EXT(x) x
+#define LEXT(x) x:
+#define LCL(x) ./**/x
+
+#define LB(x,n) ./**/x
+#define LBb(x,n) ./**/x
+#define LBf(x,n) ./**/x
+
+#define SVC lcall $7,$0
+
+#define String .string
+#define Value .value
+#define Times(a,b) [a\*b]
+#define Divide(a,b) [a\\b]
+
+#define INB inb (%dx)
+#define OUTB outb (%dx)
+#define INL inl (%dx)
+#define OUTL outl (%dx)
+
+#else wheeze
+#define ALIGN
+#define LCL(x) x
+
+#define LB(x,n) n
+#ifdef __STDC__
+#define EXT(x) _ ## x
+#define LEXT(x) _ ## x ## :
+
+#define LBb(x,n) n ## b
+#define LBf(x,n) n ## f
+#else __STDC__
+#define EXT(x) _/**/x
+#define LEXT(x) _/**/x/**/:
+#define LBb(x,n) n/**/b
+#define LBf(x,n) n/**/f
+#endif __STDC__
+#define SVC .byte 0x9a; .long 0; .word 0x7
+
+#define String .ascii
+#define Value .word
+#define Times(a,b) (a*b)
+#define Divide(a,b) (a/b)
+
+#define INB inb %dx, %al
+#define OUTB outb %al, %dx
+#define INL inl %dx, %eax
+#define OUTL outl %eax, %dx
+
+#endif wheeze
+
+#define addr32 .byte 0x67
+#define data32 .byte 0x66
+
+#ifdef GPROF
+#ifdef __STDC__
+
+#define MCOUNT .data; LB(x, 9); .long 0; .text; lea LBb(x, 9),%edx; call mcount
+#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \
+ .align ALIGN; LEXT(x) LEXT(y) ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+#define ASENTRY(x) .globl x; .align ALIGN; x ## : ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+
+#else __STDC__
+
+#define MCOUNT .data; LB(x, 9): .long 0; .text; lea LBb(x, 9),%edx; call mcount
+#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \
+ .align ALIGN; LEXT(x) LEXT(y)
+#define ASENTRY(x) .globl x; .align ALIGN; x: ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+
+#endif __STDC__
+#else GPROF
+#ifdef __STDC__
+
+#define MCOUNT
+#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x)
+#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \
+ .align ALIGN; LEXT(x) LEXT(y)
+#define ASENTRY(x) .globl x; .align ALIGN; x ## :
+
+#else __STDC__
+
+#define MCOUNT
+#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x)
+#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \
+ .align ALIGN; LEXT(x) LEXT(y)
+#define ASENTRY(x) .globl x; .align ALIGN; x:
+
+#endif __STDC__
+#endif GPROF
+
+#define Entry(x) .globl EXT(x); .align ALIGN; LEXT(x)
+#define DATA(x) .globl EXT(x); .align ALIGN; LEXT(x)
diff --git a/sys/i386/boot/asm.s b/sys/i386/boot/asm.s
new file mode 100644
index 0000000..8802b13
--- /dev/null
+++ b/sys/i386/boot/asm.s
@@ -0,0 +1,270 @@
+/*
+ * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/*
+ * HISTORY
+ * $Log: asm.s,v $
+ * Revision 2.2 92/04/04 11:34:13 rpd
+ * Fix Intel Copyright as per B. Davies authorization.
+ * [92/04/03 rvb]
+ * From 2.5 boot: pruned inb(), outb(), and pzero().
+ * [92/03/30 rvb]
+ *
+ * Revision 2.2 91/04/02 14:35:10 mbj
+ * Added _sp() => where is the stack at. [kupfer]
+ * Add Intel copyright
+ * [90/02/09 rvb]
+ *
+ */
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+ .file "asm.s"
+
+#include "asm.h"
+
+
+CR0_PE_ON = 0x1
+CR0_PE_OFF = 0xfffffffe
+
+.globl _ouraddr
+ .text
+
+/*
+#
+# real_to_prot()
+# transfer from real mode to protected mode.
+*/
+
+ENTRY(real_to_prot)
+ # guarantee that interrupt is disabled when in prot mode
+ cli
+
+ # load the gdtr
+ addr16
+ data32
+ lgdt EXT(Gdtr)
+
+ # set the PE bit of CR0
+ mov %cr0, %eax
+
+ data32
+ or $CR0_PE_ON, %eax
+ mov %eax, %cr0
+
+ # make intrasegment jump to flush the processor pipeline and
+ # reload CS register
+ data32
+ ljmp $0x18, $xprot
+
+xprot:
+ # we are in USE32 mode now
+ # set up the protective mode segment registers : DS, SS, ES
+ mov $0x20, %eax
+ movw %ax, %ds
+ movw %ax, %ss
+ movw %ax, %es
+
+ ret
+
+/*
+#
+# prot_to_real()
+# transfer from protected mode to real mode
+#
+*/
+
+ENTRY(prot_to_real)
+
+ # set up a dummy stack frame for the second seg change.
+ movl _ouraddr, %eax
+ sarl $4, %eax
+ pushw %ax
+ pushw $xreal
+
+ # Change to use16 mode.
+ ljmp $0x28, $x16
+
+x16:
+ # clear the PE bit of CR0
+ mov %cr0, %eax
+ data32
+ and $CR0_PE_OFF, %eax
+ mov %eax, %cr0
+
+
+ # make intersegment jmp to flush the processor pipeline
+ # using the fake stack frame set up earlier
+ # and reload CS register
+ lret
+
+
+xreal:
+ # we are in real mode now
+ # set up the real mode segment registers : DS, SS, ES
+ movw %cs, %ax
+ movw %ax, %ds
+ movw %ax, %ss
+ movw %ax, %es
+
+ data32
+ ret
+
+/*
+#
+# startprog(phyaddr)
+# start the program on protected mode where phyaddr is the entry point
+#
+*/
+
+ENTRY(startprog)
+ push %ebp
+ mov %esp, %ebp
+
+
+
+ # get things we need into registers
+ movl 0x8(%ebp), %ecx # entry offset
+ movl 0x0c(%ebp), %eax # &argv
+
+ # make a new stack at 0:0xa0000 (big segs)
+ mov $0x10, %ebx
+ movw %bx, %ss
+ movl $0xa0000,%ebx
+ movl %ebx,%esp
+
+
+ # push some number of args onto the stack
+ pushl $0 # nominally a cyl offset in the boot.
+ pushl 0x8(%eax) # argv[2] = bootdev
+ pushl 0x4(%eax) # argv[1] = howto
+ pushl $0 # dummy 'return' address
+
+ # push on our entry address
+ mov $0x08, %ebx # segment
+ pushl %ebx
+ pushl %ecx
+
+ # convert over the other data segs
+ mov $0x10, %ebx
+ movw %bx, %ds
+ movw %bx, %es
+
+ # convert the PC (and code seg)
+ lret
+/*
+#
+# pbzero( dst, cnt)
+# where src is a virtual address and dst is a physical address
+*/
+
+ENTRY(pbzero)
+ push %ebp
+ mov %esp, %ebp
+ push %es
+ push %esi
+ push %edi
+ push %ecx
+
+ cld
+
+ # set %es to point at the flat segment
+ mov $0x10, %eax
+ movw %ax, %es
+
+ mov 0x8(%ebp), %edi # destination
+ mov 0xc(%ebp), %ecx # count
+ mov $0x0,%eax # value
+
+ rep
+ stosb
+
+ pop %ecx
+ pop %edi
+ pop %esi
+ pop %es
+ pop %ebp
+
+ ret
+/*
+#
+# pcpy(src, dst, cnt)
+# where src is a virtual address and dst is a physical address
+#
+*/
+
+ENTRY(pcpy)
+ push %ebp
+ mov %esp, %ebp
+ push %es
+ push %esi
+ push %edi
+ push %ecx
+
+ cld
+
+ # set %es to point at the flat segment
+ mov $0x10, %eax
+ movw %ax, %es
+
+ mov 0x8(%ebp), %esi # source
+ mov 0xc(%ebp), %edi # destination
+ mov 0x10(%ebp), %ecx # count
+
+ rep
+ movsb
+
+ pop %ecx
+ pop %edi
+ pop %esi
+ pop %es
+ pop %ebp
+
+ ret
+
diff --git a/sys/i386/boot/bios.S b/sys/i386/boot/bios.S
new file mode 100644
index 0000000..687ca18
--- /dev/null
+++ b/sys/i386/boot/bios.S
@@ -0,0 +1,329 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:34:26 rpd
+ * $Id$
+ */
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+ .file "bios.s"
+
+#include "asm.h"
+ .text
+
+/*
+# biosread(dev, cyl, head, sec, nsec, offset)
+# Read "nsec" sectors from disk to offset "offset" in boot segment
+# BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
+# Call with %ah = 0x2
+# %al = number of sectors
+# %ch = cylinder
+# %cl = sector
+# %dh = head
+# %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
+# %es:%bx = segment:offset of buffer
+# Return:
+# %al = 0x0 on success; err code on failure
+*/
+
+ENTRY(biosread)
+ push %ebp
+ mov %esp, %ebp
+
+ push %ebx
+ push %ecx
+ push %edx
+ push %es
+
+ movb 0x10(%ebp), %dh
+ movw 0x0c(%ebp), %cx
+ xchgb %ch, %cl # cylinder; the highest 2 bits of cyl is in %cl
+ rorb $2, %cl
+ movb 0x14(%ebp), %al
+ orb %al, %cl
+ incb %cl # sector; sec starts from 1, not 0
+ movb 0x8(%ebp), %dl # device
+ movl 0x1c(%ebp), %ebx # offset
+ # prot_to_real will set %es to BOOTSEG
+
+ call EXT(prot_to_real) # enter real mode
+ movb $0x2, %ah # subfunction
+ addr32
+ movb 0x18(%ebp), %al # number of sectors
+
+ sti
+ int $0x13
+ cli
+
+ mov %eax, %ebx # save return value (actually movw %ax, %bx)
+
+ data32
+ call EXT(real_to_prot) # back to protected mode
+
+ xor %eax, %eax
+ movb %bh, %al # return value in %ax
+
+ pop %es
+ pop %edx
+ pop %ecx
+ pop %ebx
+ pop %ebp
+
+ ret
+
+
+/*
+# putc(ch)
+# BIOS call "INT 10H Function 0Eh" to write character to console
+# Call with %ah = 0x0e
+# %al = character
+# %bh = page
+# %bl = foreground color ( graphics modes)
+*/
+
+
+ENTRY(putc)
+ push %ebp
+ mov %esp, %ebp
+ push %ebx
+ push %ecx
+
+ movb 0x8(%ebp), %cl
+
+ call EXT(prot_to_real)
+
+ data32
+ mov $0x1, %ebx # %bh=0, %bl=1 (blue)
+ movb $0xe, %ah
+ movb %cl, %al
+ sti
+ int $0x10 # display a byte
+ cli
+
+ data32
+ call EXT(real_to_prot)
+
+ pop %ecx
+ pop %ebx
+ pop %ebp
+ ret
+
+
+/*
+# getc()
+# BIOS call "INT 16H Function 00H" to read character from keyboard
+# Call with %ah = 0x0
+# Return: %ah = keyboard scan code
+# %al = ASCII character
+*/
+
+ENTRY(getc)
+ push %ebp
+ mov %esp, %ebp
+ push %ebx # save %ebx
+
+ call EXT(prot_to_real)
+
+ movb $0x0, %ah
+ sti
+ int $0x16
+ cli
+
+ movb %al, %bl # real_to_prot uses %eax
+
+ data32
+ call EXT(real_to_prot)
+
+ xor %eax, %eax
+ movb %bl, %al
+
+ pop %ebx
+ pop %ebp
+ ret
+/*
+# ischar()
+# if there is a character pending, return it; otherwise return 0
+# BIOS call "INT 16H Function 01H" to check whether a character is pending
+# Call with %ah = 0x1
+# Return:
+# If key waiting to be input:
+# %ah = keyboard scan code
+# %al = ASCII character
+# Zero flag = clear
+# else
+# Zero flag = set
+*/
+ENTRY(ischar)
+ push %ebp
+ mov %esp, %ebp
+ push %ebx
+
+ call EXT(prot_to_real) # enter real mode
+
+ xor %ebx, %ebx
+ movb $0x1, %ah
+ sti
+ int $0x16
+ cli
+ data32
+ jz nochar
+ movb %al, %bl
+
+nochar:
+ data32
+ call EXT(real_to_prot)
+
+ xor %eax, %eax
+ movb %bl, %al
+
+ pop %ebx
+ pop %ebp
+ ret
+
+/*
+#
+# get_diskinfo(): return a word that represents the
+# max number of sectors and heads and drives for this device
+#
+*/
+
+ENTRY(get_diskinfo)
+ push %ebp
+ mov %esp, %ebp
+ push %es
+ push %ebx
+ push %ecx
+ push %edx
+
+ movb 0x8(%ebp), %dl # diskinfo(drive #)
+ call EXT(prot_to_real) # enter real mode
+
+ movb $0x8, %ah # ask for disk info
+
+ sti
+ int $0x13
+ cli
+
+ jnc ok
+ /*
+ * Urk. Call failed. It is not supported for floppies by old BIOS's.
+ * Guess it's a 15-sector floppy. Initialize all the registers for
+ * documentation, although we only need head and sector counts.
+ */
+ subb %ah, %ah # %ax = 0
+ movb %al, %al
+ movb %ah, %bh # %bh = 0
+ movb $2, %bl # %bl bits 0-3 = drive type, 2 = 1.2M
+ movb $79, %ch # max track
+ movb $15, %cl # max sector
+ movb $1, %dh # max head
+ movb $1, %dl # # floppy drives installed
+ # es:di = parameter table
+ # carry = 0
+ok:
+
+ data32
+ call EXT(real_to_prot) # back to protected mode
+
+ xor %eax, %eax
+
+ /*form a longword representing all this gunk*/
+ movb %dh, %ah # max head
+ andb $0x3f, %cl # mask of cylinder gunk
+ movb %cl, %al # max sector (and # sectors)
+
+ pop %edx
+ pop %ecx
+ pop %ebx
+ pop %es
+ pop %ebp
+ ret
+
+/*
+#
+# memsize(i) : return the memory size in KB. i == 0 for conventional memory,
+# i == 1 for extended memory
+# BIOS call "INT 12H" to get conventional memory size
+# BIOS call "INT 15H, AH=88H" to get extended memory size
+# Both have the return value in AX.
+#
+*/
+
+ENTRY(memsize)
+ push %ebp
+ mov %esp, %ebp
+ push %ebx
+
+ mov 8(%ebp), %ebx
+
+ call EXT(prot_to_real) # enter real mode
+
+ cmpb $0x1, %bl
+ data32
+ je xext
+
+ sti
+ int $0x12
+ cli
+ data32
+ jmp xdone
+
+xext: movb $0x88, %ah
+ sti
+ int $0x15
+ cli
+
+xdone:
+ mov %eax, %ebx
+
+ data32
+ call EXT(real_to_prot)
+
+ mov %ebx, %eax
+ pop %ebx
+ pop %ebp
+ ret
diff --git a/sys/i386/boot/bios.s b/sys/i386/boot/bios.s
new file mode 100644
index 0000000..d1673a5
--- /dev/null
+++ b/sys/i386/boot/bios.s
@@ -0,0 +1,326 @@
+/*
+ * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/*
+ * HISTORY
+ * $Log: bios.s,v $
+ * Revision 2.2 92/04/04 11:34:26 rpd
+ * Fix Intel Copyright as per B. Davies authorization.
+ * [92/04/03 rvb]
+ * From 2.5 version
+ * [92/03/30 mg32]
+ *
+ * Revision 2.2 91/04/02 14:35:21 mbj
+ * Add Intel copyright
+ * [90/02/09 rvb]
+ *
+ */
+
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+ .file "bios.s"
+
+#include "asm.h"
+ .text
+
+/*
+# biosread(dev, cyl, head, sec)
+# Read one sector from disk into the internal buffer "intbuf" which
+# is the first 512 bytes of the boot loader.
+# BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
+# Call with %ah = 0x2
+# %al = number of sectors
+# %ch = cylinder
+# %cl = sector
+# %dh = head
+# %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
+# %es:%bx = segment:offset of buffer
+# Return:
+# %al = 0x0 on success; err code on failure
+*/
+
+ENTRY(biosread)
+ push %ebp
+ mov %esp, %ebp
+
+ push %ebx
+ push %ecx
+ push %edx
+ push %es
+
+ movb 0x10(%ebp), %dh
+ movw 0x0c(%ebp), %cx
+ xchgb %ch, %cl # cylinder; the highest 2 bits of cyl is in %cl
+ rorb $2, %cl
+ movb 0x14(%ebp), %al
+ orb %al, %cl
+ incb %cl # sector; sec starts from 1, not 0
+ movb 0x8(%ebp), %dl # device
+ xor %ebx, %ebx # offset -- 0
+ # prot_to_real will set %es to BOOTSEG
+
+ call EXT(prot_to_real) # enter real mode
+ movb $0x2, %ah # subfunction
+ movb $0x1, %al # number of sectors -- one
+
+ sti
+ int $0x13
+ cli
+
+ mov %eax, %ebx # save return value
+
+ data16
+ call EXT(real_to_prot) # back to protected mode
+
+ xor %eax, %eax
+ movb %bh, %al # return value in %ax
+
+ pop %es
+ pop %edx
+ pop %ecx
+ pop %ebx
+ pop %ebp
+
+ ret
+
+
+/*
+# putc(ch)
+# BIOS call "INT 10H Function 0Eh" to write character to console
+# Call with %ah = 0x0e
+# %al = character
+# %bh = page
+# %bl = foreground color ( graphics modes)
+*/
+
+
+ENTRY(putc)
+ push %ebp
+ mov %esp, %ebp
+ push %ebx
+ push %ecx
+
+ movb 0x8(%ebp), %cl
+
+ call EXT(prot_to_real)
+
+ data16
+ mov $0x1, %ebx # %bh=0, %bl=1 (blue)
+ movb $0xe, %ah
+ movb %cl, %al
+ sti
+ int $0x10 # display a byte
+ cli
+
+ data16
+ call EXT(real_to_prot)
+
+ pop %ecx
+ pop %ebx
+ pop %ebp
+ ret
+
+
+/*
+# getc()
+# BIOS call "INT 16H Function 00H" to read character from keyboard
+# Call with %ah = 0x0
+# Return: %ah = keyboard scan code
+# %al = ASCII character
+*/
+
+ENTRY(getc)
+ push %ebp
+ mov %esp, %ebp
+ push %ebx # save %ebx
+
+ call EXT(prot_to_real)
+
+ movb $0x0, %ah
+ sti
+ int $0x16
+ cli
+
+ movb %al, %bl # real_to_prot uses %eax
+
+ data16
+ call EXT(real_to_prot)
+
+ xor %eax, %eax
+ movb %bl, %al
+
+ pop %ebx
+ pop %ebp
+ ret
+/*
+# ischar()
+# if there is a character pending, return it; otherwise return 0
+# BIOS call "INT 16H Function 01H" to check whether a character is pending
+# Call with %ah = 0x1
+# Return:
+# If key waiting to be input:
+# %ah = keyboard scan code
+# %al = ASCII character
+# Zero flag = clear
+# else
+# Zero flag = set
+*/
+ENTRY(ischar)
+ push %ebp
+ mov %esp, %ebp
+ push %ebx
+
+ call EXT(prot_to_real) # enter real mode
+
+ xor %ebx, %ebx
+ movb $0x1, %ah
+ sti
+ int $0x16
+ cli
+ data16
+ jz nochar
+ movb %al, %bl
+
+nochar:
+ data16
+ call EXT(real_to_prot)
+
+ xor %eax, %eax
+ movb %bl, %al
+
+ pop %ebx
+ pop %ebp
+ ret
+
+/*
+#
+# get_diskinfo(): return a word that represents the
+# max number of sectors and heads and drives for this device
+#
+*/
+
+ENTRY(get_diskinfo)
+ push %ebp
+ mov %esp, %ebp
+ push %es
+ push %ebx
+ push %ecx
+ push %edx
+
+ movb 0x8(%ebp), %dl # diskinfo(drive #)
+ call EXT(prot_to_real) # enter real mode
+
+ movb $0x8, %ah # ask for disk info
+
+ sti
+ int $0x13
+ cli
+
+ data16
+ call EXT(real_to_prot) # back to protected mode
+
+ xor %eax, %eax
+
+ /*form a longword representing all this gunk*/
+ movb %dh, %ah # # heads
+ andb $0x3f, %cl # mask of cylinder gunk
+ movb %cl, %al # # sectors
+
+ pop %edx
+ pop %ecx
+ pop %ebx
+ pop %es
+ pop %ebp
+ ret
+
+/*
+#
+# memsize(i) : return the memory size in KB. i == 0 for conventional memory,
+# i == 1 for extended memory
+# BIOS call "INT 12H" to get conventional memory size
+# BIOS call "INT 15H, AH=88H" to get extended memory size
+# Both have the return value in AX.
+#
+*/
+
+ENTRY(memsize)
+ push %ebp
+ mov %esp, %ebp
+ push %ebx
+
+ mov 8(%ebp), %ebx
+
+ call EXT(prot_to_real) # enter real mode
+
+ cmpb $0x1, %bl
+ data16
+ je xext
+
+ sti
+ int $0x12
+ cli
+ data16
+ jmp xdone
+
+xext: movb $0x88, %ah
+ sti
+ int $0x15
+ cli
+
+xdone:
+ mov %eax, %ebx
+
+ data16
+ call EXT(real_to_prot)
+
+ mov %ebx, %eax
+ pop %ebx
+ pop %ebp
+ ret
diff --git a/sys/i386/boot/biosboot/Makefile b/sys/i386/boot/biosboot/Makefile
new file mode 100644
index 0000000..4f7915d
--- /dev/null
+++ b/sys/i386/boot/biosboot/Makefile
@@ -0,0 +1,103 @@
+#
+# Permission to use, copy, modify and distribute this software and its
+# documentation is hereby granted, provided that both the copyright
+# notice and this permission notice appear in all copies of the
+# software, derivative works or modified versions, and any portions
+# thereof, and that both notices appear in supporting documentation.
+#
+# CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+# CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+# ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+#
+# Carnegie Mellon requests users of this software to return to
+#
+# Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+# School of Computer Science
+# Carnegie Mellon University
+# Pittsburgh PA 15213-3890
+#
+# any improvements or extensions that they make and grant Carnegie Mellon
+# the rights to redistribute these changes.
+#
+# from: Mach, Revision 2.2 92/04/04 11:33:46 rpd
+# $Id: Makefile,v 1.4 1993/11/16 02:02:05 ache Exp $
+#
+
+wd0:
+ dd if=boot of=biosboot count=1
+ dd if=boot of=bootbios skip=1
+ disklabel -r -w wd0 nec5655 newboot biosboot bootbios
+ rm biosboot bootbios
+
+NOPROG= noprog
+NOMAN= noman
+
+CFLAGS = -O -DDO_BAD144 -I${.CURDIR}
+LIBS= -lc
+INC= -I${.CURDIR}/../..
+
+# start.o should be first
+OBJS = start.o table.o boot2.o boot.o asm.o bios.o io.o disk.o sys.o
+
+.SUFFIXES: .S .c .o
+
+.c.o:
+ $(CC) $(CFLAGS) $(INC) -c $<
+
+.S.o:
+ $(CC) $(CFLAGS) -c $<
+
+boot: $(OBJS)
+ $(LD) -Bstatic -N -T 0 -o boot $(OBJS) $(LIBS)
+ cp boot boot.sym
+ @strip boot
+ @sh ${.CURDIR}/rmaouthdr boot boot.tmp
+ @mv -f boot.tmp boot
+ @ls -l boot
+
+biosboot: boot
+ dd if=boot of=biosboot count=1
+
+bootbios: boot
+ dd if=boot of=bootbios skip=1
+
+/usr/mdec/bootsd: bootbios
+ cp bootbios /usr/mdec/bootsd
+
+/usr/mdec/sdboot: biosboot
+ cp biosboot /usr/mdec/sdboot
+
+/usr/mdec/bootwd: /usr/mdec/bootsd
+ rm -f /usr/mdec/bootwd
+ ln /usr/mdec/bootsd /usr/mdec/bootwd
+
+/usr/mdec/wdboot: /usr/mdec/sdboot
+ rm -f /usr/mdec/wdboot
+ ln /usr/mdec/sdboot /usr/mdec/wdboot
+
+/usr/mdec/bootfd: /usr/mdec/bootsd
+ rm -f /usr/mdec/bootfd
+ ln /usr/mdec/bootsd /usr/mdec/bootfd
+
+/usr/mdec/fdboot: /usr/mdec/sdboot
+ rm -f /usr/mdec/fdboot
+ ln /usr/mdec/sdboot /usr/mdec/fdboot
+
+sd: /usr/mdec/bootsd /usr/mdec/sdboot
+wd: /usr/mdec/bootwd /usr/mdec/wdboot
+fd: /usr/mdec/bootfd /usr/mdec/fdboot
+
+all: biosboot bootbios
+
+fd0:
+ dd if=boot of=biosboot count=1
+ dd if=boot of=bootbios skip=1
+ disklabel -r -w fd0 floppy bootflpy biosboot bootbios
+ rm biosboot bootbios
+
+install: wd sd fd
+
+clean:
+ /bin/rm -f *.o *.d boot bootbios biosboot boot.sym
+
+.include <bsd.prog.mk>
diff --git a/sys/i386/boot/biosboot/README.386BSD b/sys/i386/boot/biosboot/README.386BSD
new file mode 100644
index 0000000..cc5cb8f
--- /dev/null
+++ b/sys/i386/boot/biosboot/README.386BSD
@@ -0,0 +1,151 @@
+This Boot code is different from the original boot code that came with
+386BSD in that it uses the BIOS to load the kernel and to provide all i/o
+services. The advantage ofthis is that the same boot code exactly, can run
+on any device that is supported by the BIOS. (That's most of them)
+This is important for the 'generic scsi' project because it means we can
+write drivers for new scsi adapters without having to develop an new
+set of boot blocks for each.
+
+At this point you should read the first part of README.MACH... come back here
+when you have done that:
+
+In normal operation, when co-existing with other operating systems, the
+following operations occur:
+
+1/ the BIOS loads the first block of the disk (called the Master Boot Record
+or MBR) and if it has the correct magic numbers, jumps into it:
+
+2/ The MBR code, looks at the Partition table that is embedded within it,
+to detirmine which is the partition to boot from. If you are using the os-bs
+bootblocks (highly recommended) then it will give you a menu to choose from.
+
+3/ The MBR will load the first record of the selected partition and
+if it has (the same) magic numbers, jumps into it. In 386bsd this is the
+first stage boot, (or boot1) it is represented in /usr/mdec by
+wdboot, asboot and sdboot. If the disk has been set up without DOS partitioning
+then this block will be at block zero, and will have been loaded directly by
+the BIOS.
+
+4/ Boot1 will look at block0 (which might be itself if there are no DOS
+partitions) and will find the 386bsd partition, and using the information
+regarding the start position of that partition, will load the next 13 sectors
+or so, to around 90000 (640k - 64k). and will jump into it at the appropriate
+entry point. Since boot1 and boot2 were compiled together as one file
+and then split later, boot1 knows the exact position within boot2 of the
+entry point.
+
+Boot 1 also contains a compiled in DOS partition table
+(in case it is at block 0), which contains a 386bsd partition starting
+at 0. This ensures that the same code can work whether or not
+boot1 is at block 0.
+
+5/ Boot2 asks the user for a boot device, partition and filename, and then
+loads the MBR of the selected device. This may or may not be the device
+which was originally used to boot the first MBR. The partition table
+of the new MBR is searched for a 386bsd partition, and if one is found,
+that is then in turn searched for the disklabel. This could all be on the
+second disk at this point, if the user selected it.
+
+6/On finding the disklabel, boot2 can find the correct unix partition
+within the 386bsd partition, and using cutdown filesystem code,
+look for the file to boot (e.g. 386bsd).
+
+7/ Boot2 loads this file starting at the location specified by the a.out header,
+(see later) and leaps into it at the location specified in he header.
+
+if the file does not exist or cannot be loaded, boot2 goes back to step 5.
+
+386bsd is now running and will hopefully start vm etc. and get to multi-user
+mode.
+
+##########################################################################
+During all these steps, all i/o is performed using the BIOS. This has a number
+of side effects:
+
+1/ Since BIOS disk calls are specified in terms of cylinder,head and sector,
+and the BIOS read the disk information from either the CMOS or from some other
+location which is un-available to us, we must use the cyl,head,sec information
+that is given in the MBR, rather than the start address in the MBR, because
+we cannot guarentee that we can corectly calculate C,H,S from the start address.
+
+Therefore, the C,H,S information in the MBR must be as correct for this boot
+to work as it would be for DOS to boot. For example, adaptec BIOS routines
+assume a layout of 64 heads and 32 sectors giving 1MB per ficticious cylinder.
+You must use these figures to calculate the correct values. Luckily, the DOS
+fdisk program will do all this for you if you tell it to give you a DOS
+partition, and you can change it to a 386BSD partition later. If you use
+no DOS partitioning, then the compiled in table in Boot1 will do just fine.
+
+If you want to do it by hand remember that BIOS counts sectors starting at 1.
+(cylinders and heads start at 0 (??))
+
+2/ you cannot overwrite the bottom 4k of ram until you have finished ALL
+bios calls, as BIOS uses this area as scratch memory.
+
+3/ Since BIOS runs in REAL mode, and Boot2 runs in protected mode,
+Boot 2 switches back to real mode just before each BIOS call and then
+back to protected mode on each return. Touch this at your peril.!
+
+#########################################################################
+In answering the prompt from Boot2:
+you can,
+1/ leave it alone.. it will boot the indicated file from the first
+partition of the first drive seen by the BIOS (C:)
+
+2/ enter only "-s" to boot the default to single user mode
+
+3/ enter only a filename (optionally with -s) to boot that kernel,
+
+4/ enter a whole line of the form shown in the prompt. This allows you to
+boot some other partition, possibly on the second drive, as root.
+
+
+##########################################################################
+In the case you have two drives the same type (both scsi or bith IDE/ESDI),
+wd(0,a)xxx
+ will boot xxx from drive 0, a partition.
+wd(1,a)xxx
+ will boot xxx from drive 1, a partition.
+
+similarly for sd.
+
+if you have one wd drive and one scsi drive, then you MUST
+use device 'hd'
+
+otherwise the following will happen:
+
+with wd0 and sd0, you specify sd1 or wd1 to indicate the 2nd drive.
+it boots the kernel correctly, then tells the kernel to use sd1 as root.
+you however may not have an sd1, and problems arise.
+
+hd is special in that the kernel is always told to use unit 0,
+The correct TYPE of device will be specified too, so the kernel
+will be told either sd0 or wd0.
+
+Whether sd or wd is specified to the kernel is read from the disklabel,
+so ensure that all SCSI disks have type SCSI in their disklabel or the
+boot code will assume they are ESDI or IDE. (Remember, because it is
+working through the BIOS it has ho idea what kind of disk it is.
+
+##########################################################################
+Installing:
+The makefile supplied has a target install which will create the
+files wdboot,bootwd ,sdboot and bootsd in /usr/mdec.
+BEWARE these will overwrite the existing wdboot and bootwd. (so back
+them up)
+
+there are also targets wd and sd which wil only do one of them
+
+The commented out targets wd0 and sd0 are examples of how to
+load the new bootblocks, however,make sure you change the
+device type and label to suit your drive if you uncomment them.
+(see 'man disklabel')
+
+If you already have made partitions using the old bootblocks
+these should install painlessly.
+
+Before you do this ensure you have a booting floppy with correct
+disktab and bootblock files on it so that if it doesn't work, you can
+re-disklabel from the floppy.
+
+$Id$
diff --git a/sys/i386/boot/biosboot/README.MACH b/sys/i386/boot/biosboot/README.MACH
new file mode 100644
index 0000000..cb62329
--- /dev/null
+++ b/sys/i386/boot/biosboot/README.MACH
@@ -0,0 +1,210 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:33:55 rpd
+ * $Id$
+ */
+
+********NOTE: This is not all relevant to the 386BSD version**********
+
+ AT386 Protected Mode Bootstrap Loader
+ =====================================
+
+1. Overview of Startup
+ -------------------
+
+ After the system is rebooted, the BIOS bootstrap routine reads Sector
+ 1, Track 0 into memory at location 0000:7C00H. If location 0000:7DFEH
+ (last two bytes of that sector) contains the value AA55H, the BIOS
+ bootstrap routine will transfer control to 0000:7C00H. Otherwise, the
+ boot code in that sector is bad and the boot routine stops.
+
+ For DOS compatibility reason, one extra stage of boot is required if
+ the boot device is a hard disk. The first sector of the hard disk will
+ contain the MOS-DOS boot code and a boot record partition table.
+ When this sector is loaded into 0000:7C00H, it will relocate itself
+ to somewhere else and then load the first sector of the active
+ partition into 0000:7C00H. Both UNIX and DOS use the command "fdisk"
+[ 386bsd does not have an 'fdisk' (yet) ]
+ to install this first sector into the hard disk and to manipulate
+ the hard disk partitions.
+
+
+
+2. The First Stage Bootstrap Loader
+ --------------------------------
+
+ After startup, the first stage boot is loaded at 0000:7C00H. This
+ first stage boot will load itself and the second stage boot into
+ memory at location 0000:1000H. For floppy disks, the first cylinder
+ is reserved as the boot cylinder, and the boot code (first and second)
+ will be loaded from there. Currently, only double sided, high density
+ (15 sectors per track) floppies are supported. For hard disks, the
+ first 29 sectors of the active partition is reserved for boot code
+ which will be loaded by the first stage boot. All the disk types
+ recognized by BIOS are supported by this bootstrap loader.
+[for 386bsd we load the second stage booter to 9000:0]
+
+
+
+3. The Second Stage Bootstrap Loader
+ --------------------------------
+
+ After the boot code is loaded, the control is passed to the second
+ stage bootstrap loader "boot2()". In order to be able to load the
+ big kernel image (bigger than 512K or 640K, depends on the memory
+ configuration), the second stage boot loader will run on the protected
+ mode. This bootstarp loader does not have any stand alone device
+ drivers, all the I/O's are through the BIOS calls. Since the first
+ stage boot code will no longer be used at this moment, the memory
+ location of the first stage boot code (0000:1000H to 0000:1200H) will
+ be used as an internal buffer for BIOS calls. Immediately after this
+ internal buffer is the GDT table for the second stage boot loader.
+ Since this boot loader needs to switch back and forth between protected
+ and real mode in order to use BIOS calls, the limit of the boot code
+ and boot data segments must not be greater than 64K.
+
+ The boot loader loads the kernel image at memory location above 1 MB
+ to skip the memory hole between 521K/640K and 1MB. After the kernel
+ is loaded, the boot loader stores the information in the stack and
+ then passes control to kernel. Currently, the three information passed
+ fromm the boot loader to the kernel are type of the boot device, size
+ of the base memory and size of the extended memory.
+
+[ 386bsd receives: howto, bootdev]
+
+[ 386bsd is loaded where-ever the "MByte" bits of the load address specify,
+so if you link it for FE100000 it will load to 1MB, but if you link
+it for FE000000 it will load ad 0MB]
+
+[for machines with only 512KB normal ram the kernel will need to be linked
+for 1MB and the bootblocks modified to run below 512KB. (8000:0)]
+
+
+4. The UNIX Startup
+ ----------------
+
+ Since the boot loader loads the kernel image at memory location above
+ 1MB, the kernel has to start as protected mode. In addition, the
+ link editor description file (vuifile) has to indicate that
+ the text and data segments start above 1MB. Also, the boot loader
+ passes the infomation to the kernel through the stack.
+
+[MOST of what is mentionned below is NOT relevant to 386bsd]
+
+5. Disk Layout and Bad Block Handling
+ ---------------------------------
+
+ The System V/386 Release 3.2 (AT) disk layout will be used as the disk
+ layout for the MACH System on the AT platform.
+
+ This disk layout is as follows:
+
+ * Reserve the first sector of cylinder 0 for the DOS boot record which
+ contains the master boot code (446 bytes) and the partition table.
+ (Refer to DOS Technical Reference Manual page 9-6 to 9-10).
+
+ * Reserve the first 29 sectors of the UNIX partition for the first
+ and the second stage bootstrap.
+
+ * Reserve the 30th sector of the UNIX partition for the pdinfo and
+ the vtoc tables.
+
+ * Reserve the 31st to the 34th sectors of the UNIX partition for the
+ bad track and the bad block mapping tables.
+
+ * Reserve up to 253 consecutive tracks when required, beginning with
+ the 35th sector of the UNIX partition, for alternate tracks.
+
+ * Reserve up to 253 consecutive blocks, beginning with the first
+ sector after the alternate tracks area, for alternate blocks.
+
+ SEC
+ 1
+ ----------------------------------------------------
+ | X | | CYL 0, TRK 0
+ ---------------- .......... --------------------
+ | .......... |
+ ---------------- .......... --------------------
+ | .......... |
+ ===============================================================
+ ^ | BOOTSTRAP | CYL N, TRK M
+ | ----------------------------------------------------
+ | | |30 |31 |32 |33 |34 |
+ ---------------------------------------------------- ---
+ U | .......... | ^
+ N ---------------- .......... --------------------- |
+ I | .......... | Alternate Tracks
+ X ---------------- .......... --------------------- |
+ | .......... | V
+ P ---------------------------------------------------- ---
+ A | .......... | ^
+ R ---------------- .......... --------------------- |
+ T | .......... | Alternate Blocks
+ I ---------------- .......... -------------------- |
+ T | .......... | V
+ I ---------------------------------------------------- ---
+ O | Unix root partition starts from here |
+ N ---------------- -----------------
+ | |
+ ----------------------------------------------------
+ | |
+ ----------------------------------------------------
+ | |
+ | ---------------------------------------------------
+ | | |
+ | ----------------------------------------------------
+ V | |
+ ===============================================================
+ | ........ |
+ --------------- ........ --------------
+ | ........ |
+ ----------------------------------------------------
+
+
+ The bad block handling mechanism is as follows:
+
+ * Use the alternate track in the alternate tracks area if the
+ track containing the target sector is bad.
+
+ * Use the alternate block in the alternate blocks area if the
+ target sector is bad.
+
+
+
+
+6. How to make:
+ -----------
+
+ Since the kernel image is loaded above 1 MB, the kernel must start
+ as protected mode. This means that this bootstrap loader will work
+ only when the corresponding changes on the kernel startup code are done.
+
+ The make command to generate this bootstrap loader is:
+
+ make -f boot.mk fdboot (floppy boot loader)
+ make -f boot.mk hdboot (wini boot loader)
+[to make 386bsd bootblocks "make sd wd" (warning: they will be installed
+in /dev/mdec.. take backups)]
diff --git a/sys/i386/boot/biosboot/asm.S b/sys/i386/boot/biosboot/asm.S
new file mode 100644
index 0000000..b291428
--- /dev/null
+++ b/sys/i386/boot/biosboot/asm.S
@@ -0,0 +1,260 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:34:13 rpd
+ * $Id$
+ */
+
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+ .file "asm.s"
+
+#include "asm.h"
+
+
+CR0_PE_ON = 0x1
+CR0_PE_OFF = 0xfffffffe
+
+.globl _ouraddr
+ .text
+
+/*
+#
+# real_to_prot()
+# transfer from real mode to protected mode.
+*/
+
+ENTRY(real_to_prot)
+ # guarantee that interrupt is disabled when in prot mode
+ cli
+
+ # load the gdtr
+ addr32
+ data32
+ lgdt EXT(Gdtr)
+
+ # set the PE bit of CR0
+ mov %cr0, %eax
+
+ data32
+ or $CR0_PE_ON, %eax
+ mov %eax, %cr0
+
+ # make intrasegment jump to flush the processor pipeline and
+ # reload CS register
+ data32
+ ljmp $0x18, $xprot
+
+xprot:
+ # we are in USE32 mode now
+ # set up the protected mode segment registers : DS, SS, ES
+ mov $0x20, %eax
+ movw %ax, %ds
+ movw %ax, %ss
+ movw %ax, %es
+
+ # load idtr so we can debug
+ lidt EXT(Idtr_prot)
+
+ ret
+
+/*
+#
+# prot_to_real()
+# transfer from protected mode to real mode
+#
+*/
+
+ENTRY(prot_to_real)
+
+ # set up a dummy stack frame for the second seg change.
+ movl _ouraddr, %eax
+ sarl $4, %eax
+ pushw %ax
+ movw $xreal, %ax # gas botches pushw $xreal - extra bytes 0, 0
+ pushw %ax # decode to add %al, (%eax) (%al usually 0)
+
+ # Change to use16 mode.
+ ljmp $0x28, $x16
+
+x16:
+ # clear the PE bit of CR0
+ mov %cr0, %eax
+ data32
+ and $CR0_PE_OFF, %eax
+ mov %eax, %cr0
+
+ # make intersegment jmp to flush the processor pipeline
+ # using the fake stack frame set up earlier
+ # and reload CS register
+ lret
+
+xreal:
+ # we are in real mode now
+ # set up the real mode segment registers : DS, SS, ES
+ movw %cs, %ax
+ movw %ax, %ds
+ movw %ax, %ss
+ movw %ax, %es
+
+ # load idtr so we can debug
+ addr32
+ data32
+ lidt EXT(Idtr_real)
+
+ data32
+ ret
+
+/*
+#
+# startprog(phyaddr)
+# start the program on protected mode where phyaddr is the entry point
+#
+*/
+
+ENTRY(startprog)
+ push %ebp
+ mov %esp, %ebp
+
+ # get things we need into registers
+ movl 0x8(%ebp), %ecx # entry offset
+ movl 0x0c(%ebp), %eax # &argv
+
+ # make a new stack at 0:0xa0000 (big segs)
+ mov $0x10, %ebx
+ movw %bx, %ss
+ movl $0xa0000, %ebx
+ movl %ebx, %esp
+
+ # push some number of args onto the stack
+ pushl $0 # nominally a cyl offset in the boot.
+ pushl 0x8(%eax) # argv[2] = bootdev
+ pushl 0x4(%eax) # argv[1] = howto
+ pushl $0 # dummy 'return' address
+
+ # push on our entry address
+ mov $0x08, %ebx # segment
+ pushl %ebx
+ pushl %ecx
+
+ # convert over the other data segs
+ mov $0x10, %ebx
+ movw %bx, %ds
+ movw %bx, %es
+
+ # convert the PC (and code seg)
+ lret
+/*
+#
+# pbzero( dst, cnt)
+# where src is a virtual address and dst is a physical address
+*/
+
+ENTRY(pbzero)
+ push %ebp
+ mov %esp, %ebp
+ push %es
+ push %esi
+ push %edi
+ push %ecx
+
+ cld
+
+ # set %es to point at the flat segment
+ mov $0x10, %eax
+ movw %ax, %es
+
+ mov 0x8(%ebp), %edi # destination
+ mov 0xc(%ebp), %ecx # count
+ mov $0x0, %eax # value
+
+ rep
+ stosb
+
+ pop %ecx
+ pop %edi
+ pop %esi
+ pop %es
+ pop %ebp
+
+ ret
+/*
+#
+# pcpy(src, dst, cnt)
+# where src is a virtual address and dst is a physical address
+#
+*/
+
+ENTRY(pcpy)
+ push %ebp
+ mov %esp, %ebp
+ push %es
+ push %esi
+ push %edi
+ push %ecx
+
+ cld
+
+ # set %es to point at the flat segment
+ mov $0x10, %eax
+ movw %ax, %es
+
+ mov 0x8(%ebp), %esi # source
+ mov 0xc(%ebp), %edi # destination
+ mov 0x10(%ebp), %ecx # count
+
+ rep
+ movsb
+
+ pop %ecx
+ pop %edi
+ pop %esi
+ pop %es
+ pop %ebp
+
+ ret
+
diff --git a/sys/i386/boot/biosboot/asm.h b/sys/i386/boot/biosboot/asm.h
new file mode 100644
index 0000000..43242bd
--- /dev/null
+++ b/sys/i386/boot/biosboot/asm.h
@@ -0,0 +1,144 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.7 92/02/29 15:33:41 rpd
+ * $Id$
+ */
+
+#define S_ARG0 4(%esp)
+#define S_ARG1 8(%esp)
+#define S_ARG2 12(%esp)
+#define S_ARG3 16(%esp)
+
+#define FRAME pushl %ebp; movl %esp, %ebp
+#define EMARF leave
+
+#define B_ARG0 8(%ebp)
+#define B_ARG1 12(%ebp)
+#define B_ARG2 16(%ebp)
+#define B_ARG3 20(%ebp)
+
+#ifdef wheeze
+
+#define ALIGN 4
+#define EXT(x) x
+#define LEXT(x) x:
+#define LCL(x) ./**/x
+
+#define LB(x,n) ./**/x
+#define LBb(x,n) ./**/x
+#define LBf(x,n) ./**/x
+
+#define SVC lcall $7,$0
+
+#define String .string
+#define Value .value
+#define Times(a,b) [a\*b]
+#define Divide(a,b) [a\\b]
+
+#define INB inb (%dx)
+#define OUTB outb (%dx)
+#define INL inl (%dx)
+#define OUTL outl (%dx)
+
+#else wheeze
+#define ALIGN
+#define LCL(x) x
+
+#define LB(x,n) n
+#ifdef __STDC__
+#define EXT(x) _ ## x
+#define LEXT(x) _ ## x ## :
+
+#define LBb(x,n) n ## b
+#define LBf(x,n) n ## f
+#else __STDC__
+#define EXT(x) _/**/x
+#define LEXT(x) _/**/x/**/:
+#define LBb(x,n) n/**/b
+#define LBf(x,n) n/**/f
+#endif __STDC__
+#define SVC .byte 0x9a; .long 0; .word 0x7
+
+#define String .ascii
+#define Value .word
+#define Times(a,b) (a*b)
+#define Divide(a,b) (a/b)
+
+#define INB inb %dx, %al
+#define OUTB outb %al, %dx
+#define INL inl %dx, %eax
+#define OUTL outl %eax, %dx
+
+#endif wheeze
+
+#define addr32 .byte 0x67
+#define data32 .byte 0x66
+
+#ifdef GPROF
+#ifdef __STDC__
+
+#define MCOUNT .data; LB(x, 9); .long 0; .text; lea LBb(x, 9),%edx; call mcount
+#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \
+ .align ALIGN; LEXT(x) LEXT(y) ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+#define ASENTRY(x) .globl x; .align ALIGN; x ## : ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+
+#else __STDC__
+
+#define MCOUNT .data; LB(x, 9): .long 0; .text; lea LBb(x, 9),%edx; call mcount
+#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \
+ .align ALIGN; LEXT(x) LEXT(y)
+#define ASENTRY(x) .globl x; .align ALIGN; x: ; \
+ pushl %ebp; movl %esp, %ebp; MCOUNT; popl %ebp;
+
+#endif __STDC__
+#else GPROF
+#ifdef __STDC__
+
+#define MCOUNT
+#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x)
+#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \
+ .align ALIGN; LEXT(x) LEXT(y)
+#define ASENTRY(x) .globl x; .align ALIGN; x ## :
+
+#else __STDC__
+
+#define MCOUNT
+#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x)
+#define ENTRY2(x,y) .globl EXT(x); .globl EXT(y); \
+ .align ALIGN; LEXT(x) LEXT(y)
+#define ASENTRY(x) .globl x; .align ALIGN; x:
+
+#endif __STDC__
+#endif GPROF
+
+#define Entry(x) .globl EXT(x); .align ALIGN; LEXT(x)
+#define DATA(x) .globl EXT(x); .align ALIGN; LEXT(x)
diff --git a/sys/i386/boot/biosboot/bios.S b/sys/i386/boot/biosboot/bios.S
new file mode 100644
index 0000000..687ca18
--- /dev/null
+++ b/sys/i386/boot/biosboot/bios.S
@@ -0,0 +1,329 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:34:26 rpd
+ * $Id$
+ */
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+ .file "bios.s"
+
+#include "asm.h"
+ .text
+
+/*
+# biosread(dev, cyl, head, sec, nsec, offset)
+# Read "nsec" sectors from disk to offset "offset" in boot segment
+# BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
+# Call with %ah = 0x2
+# %al = number of sectors
+# %ch = cylinder
+# %cl = sector
+# %dh = head
+# %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
+# %es:%bx = segment:offset of buffer
+# Return:
+# %al = 0x0 on success; err code on failure
+*/
+
+ENTRY(biosread)
+ push %ebp
+ mov %esp, %ebp
+
+ push %ebx
+ push %ecx
+ push %edx
+ push %es
+
+ movb 0x10(%ebp), %dh
+ movw 0x0c(%ebp), %cx
+ xchgb %ch, %cl # cylinder; the highest 2 bits of cyl is in %cl
+ rorb $2, %cl
+ movb 0x14(%ebp), %al
+ orb %al, %cl
+ incb %cl # sector; sec starts from 1, not 0
+ movb 0x8(%ebp), %dl # device
+ movl 0x1c(%ebp), %ebx # offset
+ # prot_to_real will set %es to BOOTSEG
+
+ call EXT(prot_to_real) # enter real mode
+ movb $0x2, %ah # subfunction
+ addr32
+ movb 0x18(%ebp), %al # number of sectors
+
+ sti
+ int $0x13
+ cli
+
+ mov %eax, %ebx # save return value (actually movw %ax, %bx)
+
+ data32
+ call EXT(real_to_prot) # back to protected mode
+
+ xor %eax, %eax
+ movb %bh, %al # return value in %ax
+
+ pop %es
+ pop %edx
+ pop %ecx
+ pop %ebx
+ pop %ebp
+
+ ret
+
+
+/*
+# putc(ch)
+# BIOS call "INT 10H Function 0Eh" to write character to console
+# Call with %ah = 0x0e
+# %al = character
+# %bh = page
+# %bl = foreground color ( graphics modes)
+*/
+
+
+ENTRY(putc)
+ push %ebp
+ mov %esp, %ebp
+ push %ebx
+ push %ecx
+
+ movb 0x8(%ebp), %cl
+
+ call EXT(prot_to_real)
+
+ data32
+ mov $0x1, %ebx # %bh=0, %bl=1 (blue)
+ movb $0xe, %ah
+ movb %cl, %al
+ sti
+ int $0x10 # display a byte
+ cli
+
+ data32
+ call EXT(real_to_prot)
+
+ pop %ecx
+ pop %ebx
+ pop %ebp
+ ret
+
+
+/*
+# getc()
+# BIOS call "INT 16H Function 00H" to read character from keyboard
+# Call with %ah = 0x0
+# Return: %ah = keyboard scan code
+# %al = ASCII character
+*/
+
+ENTRY(getc)
+ push %ebp
+ mov %esp, %ebp
+ push %ebx # save %ebx
+
+ call EXT(prot_to_real)
+
+ movb $0x0, %ah
+ sti
+ int $0x16
+ cli
+
+ movb %al, %bl # real_to_prot uses %eax
+
+ data32
+ call EXT(real_to_prot)
+
+ xor %eax, %eax
+ movb %bl, %al
+
+ pop %ebx
+ pop %ebp
+ ret
+/*
+# ischar()
+# if there is a character pending, return it; otherwise return 0
+# BIOS call "INT 16H Function 01H" to check whether a character is pending
+# Call with %ah = 0x1
+# Return:
+# If key waiting to be input:
+# %ah = keyboard scan code
+# %al = ASCII character
+# Zero flag = clear
+# else
+# Zero flag = set
+*/
+ENTRY(ischar)
+ push %ebp
+ mov %esp, %ebp
+ push %ebx
+
+ call EXT(prot_to_real) # enter real mode
+
+ xor %ebx, %ebx
+ movb $0x1, %ah
+ sti
+ int $0x16
+ cli
+ data32
+ jz nochar
+ movb %al, %bl
+
+nochar:
+ data32
+ call EXT(real_to_prot)
+
+ xor %eax, %eax
+ movb %bl, %al
+
+ pop %ebx
+ pop %ebp
+ ret
+
+/*
+#
+# get_diskinfo(): return a word that represents the
+# max number of sectors and heads and drives for this device
+#
+*/
+
+ENTRY(get_diskinfo)
+ push %ebp
+ mov %esp, %ebp
+ push %es
+ push %ebx
+ push %ecx
+ push %edx
+
+ movb 0x8(%ebp), %dl # diskinfo(drive #)
+ call EXT(prot_to_real) # enter real mode
+
+ movb $0x8, %ah # ask for disk info
+
+ sti
+ int $0x13
+ cli
+
+ jnc ok
+ /*
+ * Urk. Call failed. It is not supported for floppies by old BIOS's.
+ * Guess it's a 15-sector floppy. Initialize all the registers for
+ * documentation, although we only need head and sector counts.
+ */
+ subb %ah, %ah # %ax = 0
+ movb %al, %al
+ movb %ah, %bh # %bh = 0
+ movb $2, %bl # %bl bits 0-3 = drive type, 2 = 1.2M
+ movb $79, %ch # max track
+ movb $15, %cl # max sector
+ movb $1, %dh # max head
+ movb $1, %dl # # floppy drives installed
+ # es:di = parameter table
+ # carry = 0
+ok:
+
+ data32
+ call EXT(real_to_prot) # back to protected mode
+
+ xor %eax, %eax
+
+ /*form a longword representing all this gunk*/
+ movb %dh, %ah # max head
+ andb $0x3f, %cl # mask of cylinder gunk
+ movb %cl, %al # max sector (and # sectors)
+
+ pop %edx
+ pop %ecx
+ pop %ebx
+ pop %es
+ pop %ebp
+ ret
+
+/*
+#
+# memsize(i) : return the memory size in KB. i == 0 for conventional memory,
+# i == 1 for extended memory
+# BIOS call "INT 12H" to get conventional memory size
+# BIOS call "INT 15H, AH=88H" to get extended memory size
+# Both have the return value in AX.
+#
+*/
+
+ENTRY(memsize)
+ push %ebp
+ mov %esp, %ebp
+ push %ebx
+
+ mov 8(%ebp), %ebx
+
+ call EXT(prot_to_real) # enter real mode
+
+ cmpb $0x1, %bl
+ data32
+ je xext
+
+ sti
+ int $0x12
+ cli
+ data32
+ jmp xdone
+
+xext: movb $0x88, %ah
+ sti
+ int $0x15
+ cli
+
+xdone:
+ mov %eax, %ebx
+
+ data32
+ call EXT(real_to_prot)
+
+ mov %ebx, %eax
+ pop %ebx
+ pop %ebp
+ ret
diff --git a/sys/i386/boot/biosboot/boot.c b/sys/i386/boot/biosboot/boot.c
new file mode 100644
index 0000000..50f39df
--- /dev/null
+++ b/sys/i386/boot/biosboot/boot.c
@@ -0,0 +1,310 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, [92/04/03 16:51:14 rvb]
+ * $Id: boot.c,v 1.10 1994/04/20 22:06:24 phk Exp $
+ */
+
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include <sys/param.h>
+#include "boot.h"
+#include <a.out.h>
+#include <sys/reboot.h>
+
+struct exec head;
+int argv[10], esym;
+char *name;
+char *names[] = {
+ "/386bsd", "/o386bsd", "/386bsd.old",
+ "/vmunix", "/ovmunix", "/vmunix.old"
+};
+#define NUMNAMES (sizeof(names)/sizeof(char *))
+
+extern int end;
+boot(drive)
+int drive;
+{
+ int loadflags, currname = 0;
+ char *t;
+
+ printf("\n>> FreeBSD BOOT @ 0x%x: %d/%d k of memory [%s]\n",
+ ouraddr,
+ argv[7] = memsize(0),
+ argv[8] = memsize(1),
+ "$Revision: 1.10 $");
+ printf("use hd(1,a)/386bsd to boot sd0 when wd0 is also installed\n");
+ gateA20();
+loadstart:
+ /***************************************************************\
+ * As a default set it to the first partition of the first *
+ * floppy or hard drive *
+ \***************************************************************/
+ part = unit = 0;
+ maj = (drive&0x80 ? 0 : 2); /* a good first bet */
+ name = names[currname++];
+
+ loadflags = 0;
+ if (currname == NUMNAMES)
+ currname = 0;
+ getbootdev(&loadflags);
+ if (openrd()) {
+ printf("Can't find %s\n", name);
+ goto loadstart;
+ }
+/* if (inode.i_mode&IEXEC)
+ loadflags |= RB_KDB;
+*/
+ loadprog(loadflags);
+ goto loadstart;
+}
+
+loadprog(howto)
+ int howto;
+{
+ long int startaddr;
+ long int addr; /* physical address.. not directly useable */
+ long int addr0;
+ int i;
+ static int (*x_entry)() = 0;
+ unsigned char tmpbuf[4096]; /* we need to load the first 4k here */
+
+ argv[3] = 0;
+ argv[4] = 0;
+ read(&head, sizeof(head));
+ if ( N_BADMAG(head)) {
+ printf("Invalid format!\n");
+ return;
+ }
+
+ poff = N_TXTOFF(head);
+ /*if(poff==0)
+ poff = 32;*/
+
+ startaddr = (int)head.a_entry;
+ addr = (startaddr & 0x00ffffff); /* some MEG boundary */
+ addr0 = addr;
+ printf("Booting %s(%d,%c)%s @ 0x%x\n"
+ , devs[maj]
+ , unit
+ , 'a'+part
+ , name
+ , addr);
+ if(addr < ouraddr)
+ {
+ if((addr + head.a_text + head.a_data) > ouraddr)
+ {
+ printf("kernel will not fit below loader\n");
+ return;
+ }
+ if((addr + head.a_text + head.a_data + head.a_bss) > 0xa0000)
+ {
+ printf("kernel too big, won't fit in 640K with bss\n");
+ printf("Only hope is to link the kernel for > 1MB\n");
+ return;
+ }
+ }
+ printf("text=0x%x ", head.a_text);
+ /********************************************************/
+ /* LOAD THE TEXT SEGMENT */
+ /* don't clobber the first 4k yet (BIOS NEEDS IT) */
+ /********************************************************/
+ read(tmpbuf,4096);
+ addr += 4096;
+ xread(addr, head.a_text - 4096);
+ addr += head.a_text - 4096;
+
+ /********************************************************/
+ /* Load the Initialised data after the text */
+ /********************************************************/
+ while (addr & CLOFSET)
+ *(char *)addr++ = 0;
+
+ printf("data=0x%x ", head.a_data);
+ xread(addr, head.a_data);
+ addr += head.a_data;
+
+ /********************************************************/
+ /* Skip over the uninitialised data */
+ /* (but clear it) */
+ /********************************************************/
+ printf("bss=0x%x ", head.a_bss);
+ if( (addr < ouraddr) && ((addr + head.a_bss) > ouraddr))
+ {
+ pbzero(addr,ouraddr - (int)addr);
+ }
+ else
+ {
+ pbzero(addr,head.a_bss);
+ }
+ argv[3] = (addr += head.a_bss);
+
+#ifdef LOADSYMS /* not yet, haven't worked this out yet */
+ if (addr > 0x100000)
+ {
+ /********************************************************/
+ /*copy in the symbol header */
+ /********************************************************/
+ pcpy(&head.a_syms, addr, sizeof(head.a_syms));
+ addr += sizeof(head.a_syms);
+
+ /********************************************************/
+ /* READ in the symbol table */
+ /********************************************************/
+ printf("symbols=[+0x%x", head.a_syms);
+ xread(addr, head.a_syms);
+ addr += head.a_syms;
+
+ /********************************************************/
+ /* Followed by the next integer (another header) */
+ /* more debug symbols? */
+ /********************************************************/
+ read(&i, sizeof(int));
+ pcpy(&i, addr, sizeof(int));
+ i -= sizeof(int);
+ addr += sizeof(int);
+
+
+ /********************************************************/
+ /* and that many bytes of (debug symbols?) */
+ /********************************************************/
+ printf("+0x%x] ", i);
+ xread(addr, i);
+ addr += i;
+ }
+#endif LOADSYMS
+ /********************************************************/
+ /* and note the end address of all this */
+ /********************************************************/
+
+ argv[4] = ((addr+sizeof(int)-1))&~(sizeof(int)-1);
+ printf("total=0x%x ",argv[4]);
+
+
+ /*
+ * We now pass the various bootstrap parameters to the loaded
+ * image via the argument list
+ * (THIS IS A BIT OF HISTORY FROM MACH.. LEAVE FOR NOW)
+ * arg1 = boot flags
+ * arg2 = boot device
+ * arg3 = start of symbol table (0 if not loaded)
+ * arg4 = end of symbol table (0 if not loaded)
+ * arg5 = transfer address from image
+ * arg6 = transfer address for next image pointer
+ */
+ switch(maj)
+ {
+ case 2:
+ printf("\n\nInsert file system floppy in drive A or B\n");
+ printf("Press 'A', 'B' or any other key for the default ");
+ printf("%c: ", unit+'A');
+ i = getchar();
+ if (i=='0' || i=='A' || i=='a')
+ unit = 0;
+ if (i=='1' || i=='B' || i=='b')
+ unit = 1;
+ printf("\n");
+ break;
+ case 4:
+ break;
+ }
+ argv[1] = howto;
+ argv[2] = (MAKEBOOTDEV(maj, 0, 0, unit, part)) ;
+ argv[5] = (head.a_entry &= 0xfffffff);
+ argv[6] = (int) &x_entry;
+ argv[0] = 8;
+ /****************************************************************/
+ /* copy that first page and overwrite any BIOS variables */
+ /****************************************************************/
+ printf("entry point=0x%x\n" ,((int)startaddr) & 0xffffff);
+ /* Under no circumstances overwrite precious BIOS variables! */
+ pcpy(tmpbuf, addr0, 0x400);
+ pcpy(tmpbuf + 0x500, addr0 + 0x500, 4096 - 0x500);
+ startprog(((int)startaddr & 0xffffff),argv);
+}
+
+char namebuf[100];
+getbootdev(howto)
+ int *howto;
+{
+ char c, *ptr = namebuf;
+ printf("Boot: [[[%s(%d,%c)]%s][-s][-a][-d]] :- "
+ , devs[maj]
+ , unit
+ , 'a'+part
+ , name);
+ if (gets(namebuf)) {
+ while (c=*ptr) {
+ while (c==' ')
+ c = *++ptr;
+ if (!c)
+ return;
+ if (c=='-')
+ while ((c = *++ptr) && c!=' ')
+ switch (c) {
+ case 'r':
+ *howto |= RB_DFLTROOT; continue;
+ case 'a':
+ *howto |= RB_ASKNAME; continue;
+ case 's':
+ *howto |= RB_SINGLE; continue;
+ case 'd':
+ *howto |= RB_KDB; continue;
+ case 'b':
+ *howto |= RB_HALT; continue;
+ }
+ else {
+ name = ptr;
+ while ((c = *++ptr) && c!=' ');
+ if (c)
+ *ptr++ = 0;
+ }
+ }
+ } else
+ printf("\n");
+}
+
diff --git a/sys/i386/boot/biosboot/boot.h b/sys/i386/boot/biosboot/boot.h
new file mode 100644
index 0000000..f77f882
--- /dev/null
+++ b/sys/i386/boot/biosboot/boot.h
@@ -0,0 +1,40 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:35:03 rpd
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <ufs/quota.h>
+#include <ufs/fs.h>
+#include <ufs/inode.h>
+
+extern char *devs[], *name, *iodest;
+extern struct fs *fs;
+extern struct inode inode;
+extern int dosdev, unit, part, maj, boff, poff, bnum, cnt;
+extern long int ouraddr;
diff --git a/sys/i386/boot/biosboot/boot2.S b/sys/i386/boot/biosboot/boot2.S
new file mode 100644
index 0000000..b3c96da
--- /dev/null
+++ b/sys/i386/boot/biosboot/boot2.S
@@ -0,0 +1,169 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:35:26 rpd
+ * $Id: boot2.S,v 1.2 1993/10/16 19:11:33 rgrimes Exp $
+ */
+
+#include "asm.h"
+
+/* Conventional GDT indexes. */
+#define BOOT_CS_INDEX 3
+#define BOOT_CS16_INDEX 5
+#define BOOT_DS_INDEX 4
+#define DB_CS_INDEX 14
+#define DB_CS16_INDEX 15
+#define DB_DS_INDEX 16
+#define GDT_INDEX 17
+
+/* Vector numbers. */
+#define BREAKPOINT_VECTOR 3
+#define DEBUG_VECTOR 1
+
+/*
+ * boot2() -- second stage boot
+ */
+
+.globl EXT(ouraddr)
+
+ENTRY(boot2)
+ data32
+ subl %eax, %eax
+ mov %cs, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ data32
+ shll $4, %eax
+ addr32
+ data32
+ movl %eax, EXT(ouraddr)
+
+ /* fix up GDT entries for bootstrap */
+#define FIXUP(gdt_index) \
+ addr32; \
+ movl %eax, EXT(Gdt)+(8*gdt_index)+2; /* actually movw %ax */ \
+ addr32; \
+ movb %bl, EXT(Gdt)+(8*gdt_index)+4
+
+ data32
+ shld $16, %eax, %ebx
+ FIXUP(BOOT_CS_INDEX)
+ FIXUP(BOOT_CS16_INDEX)
+ FIXUP(BOOT_DS_INDEX)
+
+ /* fix up GDT entry for GDT, and GDT and IDT pointers */
+ data32
+ movl %eax, %ecx
+ data32
+ addl $ EXT(Gdt), %eax
+ data32
+ shld $16, %eax, %ebx
+ FIXUP(GDT_INDEX)
+ addr32
+ data32
+ movl %eax, EXT(Gdtr)+2
+ data32
+ addl $ EXT(Idt), %ecx
+ addr32
+ data32
+ movl %ecx, EXT(Idtr_prot)+2
+
+ /* %es = vector table segment for a while */
+ push %es
+ data32
+ subl %eax, %eax
+ mov %ax, %es
+
+ /* fix up GDT entries for bdb */
+ data32
+ movl $4*DEBUG_VECTOR, %esi
+ addr32
+ movl %es: 2(%esi), %eax /* actually movw to %ax */
+ data32
+ shll $4, %eax
+ data32
+ shld $16, %eax, %ebx
+ FIXUP(DB_CS_INDEX)
+ FIXUP(DB_CS16_INDEX)
+ FIXUP(DB_DS_INDEX)
+
+ /* Fetch entry points of bdb's protected mode trap handlers. These
+ * are stored at 2 before the corresponding entry points for real mode.
+ */
+ data32
+ subl %ebx, %ebx
+ addr32
+ movl %es: (%esi), %ebx /* actually movw to %bx */
+ data32
+ subl %ecx, %ecx
+ addr32
+ movl %es: 4*(BREAKPOINT_VECTOR-DEBUG_VECTOR)(%esi), %ecx
+ /* actually movw to %cx */
+
+ /* %es = bdb segment for a while */
+ data32
+ shrl $4, %eax
+ mov %ax, %es
+
+ /* fix up IDT entries for bdb */
+ subl $2, %ebx
+ movl %es: (%ebx), %eax /* actually movw to %ax */
+ addr32
+ movl %eax, EXT(Idt)+8*DEBUG_VECTOR /* actually movw %ax */
+ subl $2, %ecx
+ movl %es: (%ecx), %eax /* actually movw to %ax */
+ addr32
+ movl %eax, EXT(Idt)+8*BREAKPOINT_VECTOR /* actually movw %ax */
+
+ /* finished with groping in real mode segments */
+ pop %es
+
+ /* change to protected mode */
+ data32
+ call EXT(real_to_prot)
+
+ /* clear the bss */
+ movl $ EXT(edata), %edi /* no EXT(_edata) - krufty ld */
+ movl $ EXT(end), %ecx /* or EXT(_end) */
+ subl %edi, %ecx
+ subb %al, %al
+ rep
+ stosb
+
+ movzbl %dl, %edx /* discard head (%dh) and random high bits */
+ pushl %edx
+ call EXT(boot)
+oops:
+ hlt
+ jmp oops
+
+ .data
+ .align 2
+#if 0 /* XXX this would give losing "_ouraddr :". Better declared in C */
+EXT(ouraddr):
+#else
+_ouraddr:
+#endif
+ .long 0
diff --git a/sys/i386/boot/biosboot/disk.c b/sys/i386/boot/biosboot/disk.c
new file mode 100644
index 0000000..a63ca5a
--- /dev/null
+++ b/sys/i386/boot/biosboot/disk.c
@@ -0,0 +1,281 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:35:49 rpd
+ * $Id: disk.c,v 1.4 1994/02/22 22:59:40 rgrimes Exp $
+ */
+
+/*
+ * 93/10/08 bde
+ * If there is no 386BSD partition, initialize the label sector with
+ * LABELSECTOR instead of with garbage.
+ *
+ * 93/08/22 bde
+ * Fixed reading of bad sector table. It is at the end of the 'c'
+ * partition, which is not always at the end of the disk.
+ */
+
+#include "boot.h"
+#ifdef DO_BAD144
+#include <sys/dkbad.h>
+#endif DO_BAD144
+#include <sys/disklabel.h>
+
+#define BIOS_DEV_FLOPPY 0x0
+#define BIOS_DEV_WIN 0x80
+
+#define BPS 512
+#define SPT(di) ((di)&0xff)
+#define HEADS(di) ((((di)>>8)&0xff)+1)
+
+char *devs[] = {"wd", "hd", "fd", "wt", "sd", 0};
+
+#ifdef DO_BAD144
+struct dkbad dkb;
+int do_bad144;
+int bsize;
+#endif DO_BAD144
+
+int spt, spc;
+
+char *iodest;
+struct fs *fs;
+struct inode inode;
+int dosdev, unit, part, maj, boff, poff, bnum, cnt;
+
+/*#define EMBEDDED_DISKLABEL 1*/
+extern struct disklabel disklabel;
+/*struct disklabel disklabel;*/
+
+devopen()
+{
+ struct dos_partition *dptr;
+ struct disklabel *dl;
+ int dosdev = inode.i_dev;
+ int i, sector, di;
+
+ di = get_diskinfo(dosdev);
+ spc = (spt = SPT(di)) * HEADS(di);
+ if (dosdev == 2)
+ {
+ boff = 0;
+ part = (spt == 15 ? 3 : 1);
+ }
+ else
+ {
+#ifdef EMBEDDED_DISKLABEL
+ dl = &disklabel;
+#else EMBEDDED_DISKLABEL
+ Bread(dosdev, 0);
+ dptr = (struct dos_partition *)(((char *)0)+DOSPARTOFF);
+ sector = LABELSECTOR;
+ for (i = 0; i < NDOSPART; i++, dptr++)
+ if (dptr->dp_typ == DOSPTYP_386BSD) {
+ sector = dptr->dp_start + LABELSECTOR;
+ break;
+ }
+ Bread(dosdev, sector++);
+ dl=((struct disklabel *)0);
+ disklabel = *dl; /* structure copy (maybe useful later)*/
+#endif EMBEDDED_DISKLABEL
+ if (dl->d_magic != DISKMAGIC) {
+ printf("bad disklabel");
+ return 1;
+ }
+ if( (maj == 4) || (maj == 0) || (maj == 1))
+ {
+ if (dl->d_type == DTYPE_SCSI)
+ {
+ maj = 4; /* use scsi as boot dev */
+ }
+ else
+ {
+ maj = 0; /* must be ESDI/IDE */
+ }
+ }
+ boff = dl->d_partitions[part].p_offset;
+#ifdef DO_BAD144
+ bsize = dl->d_partitions[part].p_size;
+ do_bad144 = 0;
+ if (dl->d_flags & D_BADSECT) {
+ /* this disk uses bad144 */
+ int i;
+ int dkbbnum;
+ struct dkbad *dkbptr;
+
+ /* find the first readable bad sector table */
+ /* some of this code is copied from ufs/ufs_disksubr.c */
+ /* including the bugs :-( */
+ /* read a bad sector table */
+
+#define BAD144_PART 2 /* XXX scattered magic numbers */
+#define BSD_PART 0 /* XXX should be 2 but bad144.c uses 0 */
+ if (dl->d_partitions[BSD_PART].p_offset != 0)
+ dkbbnum = dl->d_partitions[BAD144_PART].p_offset
+ + dl->d_partitions[BAD144_PART].p_size;
+ else
+ dkbbnum = dl->d_secperunit;
+ dkbbnum -= dl->d_nsectors;
+
+ if (dl->d_secsize > DEV_BSIZE)
+ dkbbnum *= dl->d_secsize / DEV_BSIZE;
+ else
+ dkbbnum /= DEV_BSIZE / dl->d_secsize;
+ i = 0;
+ do_bad144 = 0;
+ do {
+ /* XXX: what if the "DOS sector" < 512 bytes ??? */
+ Bread(dosdev, dkbbnum + i);
+ dkbptr = (struct dkbad *) 0;
+/* XXX why is this not in <sys/dkbad.h> ??? */
+#define DKBAD_MAGIC 0x4321
+ if (dkbptr->bt_mbz == 0 &&
+ dkbptr->bt_flag == DKBAD_MAGIC) {
+ dkb = *dkbptr; /* structure copy */
+ do_bad144 = 1;
+ break;
+ }
+ i += 2;
+ } while (i < 10 && i < dl->d_nsectors);
+ if (!do_bad144)
+ printf("Bad bad sector table\n");
+ else
+ printf("Using bad sector table at %d\n", dkbbnum+i);
+ }
+#endif DO_BAD144
+ }
+ return 0;
+}
+
+devread()
+{
+ int offset, sector = bnum;
+ int dosdev = inode.i_dev;
+ for (offset = 0; offset < cnt; offset += BPS)
+ {
+ Bread(dosdev, badsect(dosdev, sector++));
+ bcopy(0, iodest+offset, BPS);
+ }
+}
+
+#define I_ADDR ((void *) 0) /* XXX where all reads go */
+
+/* Read ahead buffer large enough for one track on a 1440K floppy. For
+ * reading from floppies, the bootstrap has to be loaded on a 64K boundary
+ * to ensure that this buffer doesn't cross a 64K DMA boundary.
+ */
+#define RA_SECTORS 18
+static char ra_buf[RA_SECTORS * BPS];
+static int ra_dev;
+static int ra_end;
+static int ra_first;
+
+Bread(dosdev,sector)
+ int dosdev,sector;
+{
+ if (dosdev != ra_dev || sector < ra_first || sector >= ra_end)
+ {
+ int cyl, head, sec, nsec;
+
+ cyl = sector/spc;
+ head = (sector % spc) / spt;
+ sec = sector % spt;
+ nsec = spt - sec;
+ if (nsec > RA_SECTORS)
+ nsec = RA_SECTORS;
+ twiddle();
+ if (biosread(dosdev, cyl, head, sec, nsec, ra_buf) != 0)
+ {
+ nsec = 1;
+ twiddle();
+ while (biosread(dosdev, cyl, head, sec, nsec, ra_buf) != 0) {
+ printf("Error: C:%d H:%d S:%d\n", cyl, head, sec);
+ twiddle();
+ }
+ }
+ ra_dev = dosdev;
+ ra_first = sector;
+ ra_end = sector + nsec;
+ }
+ bcopy(ra_buf + (sector - ra_first) * BPS, I_ADDR, BPS);
+}
+
+badsect(dosdev, sector)
+ int dosdev, sector;
+{
+ int i;
+#ifdef DO_BAD144
+ if (do_bad144) {
+ u_short cyl;
+ u_short head;
+ u_short sec;
+ int newsec;
+ struct disklabel *dl = &disklabel;
+
+ /* XXX */
+ /* from wd.c */
+ /* bt_cyl = cylinder number in sorted order */
+ /* bt_trksec is actually (head << 8) + sec */
+
+ /* only remap sectors in the partition */
+ if (sector < boff || sector >= boff + bsize) {
+ goto no_remap;
+ }
+
+ cyl = sector / dl->d_secpercyl;
+ head = (sector % dl->d_secpercyl) / dl->d_nsectors;
+ sec = sector % dl->d_nsectors;
+ sec = (head<<8) + sec;
+
+ /* now, look in the table for a possible bad sector */
+ for (i=0; i<126; i++) {
+ if (dkb.bt_bad[i].bt_cyl == cyl) {
+ /* found same cylinder */
+ if (dkb.bt_bad[i].bt_trksec == sec) {
+ /* FOUND! */
+ break;
+ }
+ } else if (dkb.bt_bad[i].bt_cyl > cyl) {
+ i = 126;
+ break;
+ }
+ }
+ if (i == 126) {
+ /* didn't find bad sector */
+ goto no_remap;
+ }
+ /* otherwise find replacement sector */
+ if (dl->d_partitions[BSD_PART].p_offset != 0)
+ newsec = dl->d_partitions[BAD144_PART].p_offset
+ + dl->d_partitions[BAD144_PART].p_size;
+ else
+ newsec = dl->d_secperunit;
+ newsec -= dl->d_nsectors + i + 1;
+ return newsec;
+ }
+#endif DO_BAD144
+ no_remap:
+ return sector;
+}
diff --git a/sys/i386/boot/biosboot/io.c b/sys/i386/boot/biosboot/io.c
new file mode 100644
index 0000000..6a5a58a
--- /dev/null
+++ b/sys/i386/boot/biosboot/io.c
@@ -0,0 +1,202 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:35:57 rpd
+ * $Id$
+ */
+
+#include <i386/include/pio.h>
+
+#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */
+#define K_STATUS 0x64 /* keyboard status */
+#define K_CMD 0x64 /* keybd ctlr command (write-only) */
+
+#define K_OBUF_FUL 0x01 /* output buffer full */
+#define K_IBUF_FUL 0x02 /* input buffer full */
+
+#define KC_CMD_WIN 0xd0 /* read output port */
+#define KC_CMD_WOUT 0xd1 /* write output port */
+#define KB_A20 0x9f /* enable A20,
+ enable output buffer full interrupt
+ enable data line
+ disable clock line */
+
+/*
+ * Gate A20 for high memory
+ */
+unsigned char x_20 = KB_A20;
+gateA20()
+{
+#ifdef IBM_L40
+ outb(0x92, 0x2);
+#else IBM_L40
+ while (inb(K_STATUS) & K_IBUF_FUL);
+ while (inb(K_STATUS) & K_OBUF_FUL)
+ (void)inb(K_RDWR);
+
+ outb(K_CMD, KC_CMD_WOUT);
+ while (inb(K_STATUS) & K_IBUF_FUL);
+ outb(K_RDWR, x_20);
+ while (inb(K_STATUS) & K_IBUF_FUL);
+#endif IBM_L40
+}
+
+/* printf - only handles %d as decimal, %c as char, %s as string */
+
+printf(format,data)
+ char *format;
+ int data;
+{
+ int *dataptr = &data;
+ char c;
+
+ reset_twiddle();
+ while (c = *format++)
+ if (c != '%')
+ putchar(c);
+ else
+ switch (c = *format++) {
+ case 'd': {
+ int num = *dataptr++;
+ char buf[10], *ptr = buf;
+ if (num<0) {
+ num = -num;
+ putchar('-');
+ }
+ do
+ *ptr++ = '0'+num%10;
+ while (num /= 10);
+ do
+ putchar(*--ptr);
+ while (ptr != buf);
+ break;
+ }
+ case 'x': {
+ int num = *dataptr++, dig;
+ char buf[8], *ptr = buf;
+ do
+ *ptr++ = (dig=(num&0xf)) > 9?
+ 'a' + dig - 10 :
+ '0' + dig;
+ while (num >>= 4);
+ do
+ putchar(*--ptr);
+ while (ptr != buf);
+ break;
+ }
+ case 'c': putchar((*dataptr++)&0xff); break;
+ case 's': {
+ char *ptr = (char *)*dataptr++;
+ while (c = *ptr++)
+ putchar(c);
+ break;
+ }
+ }
+}
+
+putchar(c)
+{
+ if (c == '\n')
+ putc('\r');
+ putc(c);
+}
+
+getchar()
+{
+ int c;
+
+ if ((c=getc()) == '\r')
+ c = '\n';
+ if (c == '\b') {
+ putchar('\b');
+ putchar(' ');
+ }
+ putchar(c);
+ return(c);
+}
+
+gets(buf)
+char *buf;
+{
+ int i;
+ char *ptr=buf;
+
+ for (i = 240000; i>0; i--)
+ if (ischar())
+ for (;;)
+ switch(*ptr = getchar() & 0xff) {
+ case '\n':
+ case '\r':
+ *ptr = '\0';
+ return 1;
+ case '\b':
+ if (ptr > buf) ptr--;
+ continue;
+ default:
+ ptr++;
+ }
+ return 0;
+}
+
+strcmp(s1, s2)
+char *s1, *s2;
+{
+ while (*s1 == *s2) {
+ if (!*s1++)
+ return 0;
+ s2++;
+ }
+ return 1;
+}
+
+bcopy(from, to, len)
+char *from, *to;
+int len;
+{
+ while (len-- > 0)
+ *to++ = *from++;
+}
+
+static int tw_on;
+static int tw_pos;
+static char tw_chars[] = "|/-\\";
+
+reset_twiddle()
+{
+ if (tw_on)
+ putchar('\b');
+ tw_on = 0;
+ tw_pos = 0;
+}
+
+twiddle()
+{
+ if (tw_on)
+ putchar('\b');
+ else
+ tw_on = 1;
+ putchar(tw_chars[tw_pos++]);
+ tw_pos %= (sizeof(tw_chars) - 1);
+}
diff --git a/sys/i386/boot/biosboot/start.S b/sys/i386/boot/biosboot/start.S
new file mode 100644
index 0000000..62b93ac
--- /dev/null
+++ b/sys/i386/boot/biosboot/start.S
@@ -0,0 +1,291 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:36:29 rpd
+ * $Id$
+ */
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+#include "asm.h"
+
+ .file "start.s"
+
+BOOTSEG = 0x9000 # boot will be loaded here (below 640K)
+BOOTSTACK = 0xe000 # boot stack
+SIGNATURE = 0xaa55
+LOADSZ = 15 # size of unix boot
+PARTSTART = 0x1be # starting address of partition table
+NUMPART = 4 # number of partitions in partition table
+PARTSZ = 16 # each partition table entry is 16 bytes
+BSDPART = 0xA5 # value of boot_ind, means bootable partition
+BOOTABLE = 0x80 # value of boot_ind, means bootable partition
+
+ .text
+
+ENTRY(boot1)
+ # start (aka boot1) is loaded at 0x0:0x7c00 but we want 0x7c0:0
+ # ljmp to the next instruction to adjust %cs
+ data32
+ ljmp $0x7c0, $start
+
+start:
+ # set up %ds
+ mov %cs, %ax
+ mov %ax, %ds
+
+ # set up %ss and %esp
+ data32
+ mov $BOOTSEG, %eax
+ mov %ax, %ss
+ data32
+ mov $BOOTSTACK, %esp
+
+ /*** set up %es, (where we will load boot2 to) ***/
+ mov %ax, %es
+
+#ifdef DEBUG
+ data32
+ mov $one, %esi
+ data32
+ call message
+#endif
+
+ # bootstrap passes us drive number in %dl
+ cmpb $0x80, %dl
+ data32
+ jae hd
+
+fd:
+# reset the disk system
+#ifdef DEBUG
+ data32
+ mov $two, %esi
+ data32
+ call message
+#endif
+ movb $0x0, %ah
+ int $0x13
+ data32
+ mov $0x0001, %ecx # cyl 0, sector 1
+ movb $0, %dh # head
+#ifdef DEBUG
+ data32
+ mov $three, %esi
+ data32
+ call message
+#endif
+ data32
+ jmp load
+
+hd: /**** load sector 0 into the BOOTSEG ****/
+#ifdef DEBUG
+ data32
+ mov $four, %esi
+ data32
+ call message
+#endif
+ data32
+ mov $0x0201, %eax
+ xor %ebx, %ebx # %bx = 0
+ data32
+ mov $0x0001, %ecx
+#ifdef DEBUG
+ data32
+ mov $five, %esi
+ data32
+ call message
+#endif
+ data32
+ andl $0xff, %edx
+ /*mov $0x0080, %edx*/
+ int $0x13
+ data32
+ jb read_error
+
+ /***# find the first 386BSD partition *****/
+ data32
+ mov $PARTSTART, %ebx
+ data32
+ mov $NUMPART, %ecx
+again:
+ addr32
+ movb %es:4(%ebx), %al
+ cmpb $BSDPART, %al
+ data32
+ je found
+ data32
+ add $PARTSZ, %ebx
+ data32
+ loop again
+ data32
+ mov $enoboot, %esi
+ data32
+ jmp err_stop
+
+
+/*
+# BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
+# Call with %ah = 0x2
+# %al = number of sectors
+# %ch = cylinder
+# %cl = sector
+# %dh = head
+# %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
+# %es:%bx = segment:offset of buffer
+# Return:
+# %al = 0x0 on success; err code on failure
+*/
+
+found:
+ addr32
+ movb %es:1(%ebx), %dh /* head */
+ addr32
+ movl %es:2(%ebx), %ecx /*sect, cyl (+ 2 bytes junk in top word) */
+
+load:
+ movb $0x2, %ah /* function 2 */
+ movb $LOADSZ, %al /* number of blocks */
+ xor %ebx, %ebx /* %bx = 0, put it at 0 in the BOOTSEG */
+ int $0x13
+ data32
+ jb read_error
+
+ # ljmp to the second stage boot loader (boot2).
+ # After ljmp, %cs is BOOTSEG and boot1 (512 bytes) will be used
+ # as an internal buffer "intbuf".
+
+#ifdef DEBUG
+ data32
+ mov $six, %esi
+ data32
+ call message
+#endif
+ data32
+ ljmp $BOOTSEG, $ EXT(boot2)
+
+#
+# read_error
+#
+
+read_error:
+ data32
+ mov $eread, %esi
+err_stop:
+ data32
+ call message
+ data32
+ jmp stop
+
+#
+# message: write the error message in %ds:%esi to console
+#
+
+message:
+/*
+ # Use BIOS "int 10H Function 0Eh" to write character in teletype mode
+ # %ah = 0xe %al = character
+ # %bh = page %bl = foreground color (graphics modes)
+*/
+
+ data32
+ push %eax
+ data32
+ push %ebx
+ data32
+ mov $0x0001, %ebx
+ cld
+
+nextb:
+ lodsb # load a byte into %al
+ cmpb $0x0, %al
+ data32
+ je done
+ movb $0xe, %ah
+ int $0x10 # display a byte
+ data32
+ jmp nextb
+done:
+ data32
+ pop %ebx
+ data32
+ pop %eax
+ data32
+ ret
+
+stop: hlt
+ data32
+ jmp stop # halt doesnt actually halt forever
+
+/* error messages */
+
+#ifdef DEBUG
+one: String "1\r\n\0"
+two: String "2\r\n\0"
+three: String "3\r\n\0"
+four: String "4\r\n\0"
+five: String "5\r\n\0"
+six: String "6\r\n\0"
+seven: String "7\r\n\0"
+#endif DEBUG
+eread: String "Read error\r\n\0"
+enoboot: String "No bootable partition\r\n\0"
+endofcode:
+/* throw in a partition in case we are block0 as well */
+/* flag, head, sec, cyl, typ, ehead, esect, ecyl, start, len */
+ . = EXT(boot1) + PARTSTART
+ .byte 0x0,0,0,0,0,0,0,0
+ .long 0,0
+ .byte 0x0,0,0,0,0,0,0,0
+ .long 0,0
+ .byte 0x0,0,0,0,0,0,0,0
+ .long 0,0
+ .byte BOOTABLE,0,1,0,BSDPART,255,255,255
+ .long 0,50000
+/* the last 2 bytes in the sector 0 contain the signature */
+ . = EXT(boot1) + 0x1fe
+ .value SIGNATURE
+ENTRY(disklabel)
+ . = EXT(boot1) + 0x400
diff --git a/sys/i386/boot/biosboot/sys.c b/sys/i386/boot/biosboot/sys.c
new file mode 100644
index 0000000..4ffe171
--- /dev/null
+++ b/sys/i386/boot/biosboot/sys.c
@@ -0,0 +1,232 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:36:34 rpd
+ * $Id$
+ */
+
+#include "boot.h"
+#include <sys/dir.h>
+#include <sys/reboot.h>
+
+/* #define BUFSIZE 4096 */
+#define BUFSIZE MAXBSIZE
+
+char buf[BUFSIZE], fsbuf[SBSIZE], iobuf[MAXBSIZE];
+
+int xread(addr, size)
+ char * addr;
+ int size;
+{
+ int count = BUFSIZE;
+ while (size > 0) {
+ if (BUFSIZE > size)
+ count = size;
+ read(buf, count);
+ pcpy(buf, addr, count);
+ size -= count;
+ addr += count;
+ }
+}
+
+read(buffer, count)
+ int count;
+ char *buffer;
+{
+ int logno, off, size;
+ int cnt2, bnum2;
+
+ while (count) {
+ off = blkoff(fs, poff);
+ logno = lblkno(fs, poff);
+ cnt2 = size = blksize(fs, &inode, logno);
+ bnum2 = fsbtodb(fs, block_map(logno)) + boff;
+ cnt = cnt2;
+ bnum = bnum2;
+ if ( (!off) && (size <= count))
+ {
+ iodest = buffer;
+ devread();
+ }
+ else
+ {
+ iodest = iobuf;
+ size -= off;
+ if (size > count)
+ size = count;
+ devread();
+ bcopy(iodest+off,buffer,size);
+ }
+ buffer += size;
+ count -= size;
+ poff += size;
+ }
+}
+
+find(path)
+ char *path;
+{
+ char *rest, ch;
+ int block, off, loc, ino = ROOTINO;
+ struct direct *dp;
+loop: iodest = iobuf;
+ cnt = fs->fs_bsize;
+ bnum = fsbtodb(fs,itod(fs,ino)) + boff;
+ devread();
+ bcopy(&((struct dinode *)iodest)[ino % fs->fs_inopb],
+ &inode.i_din,
+ sizeof (struct dinode));
+ if (!*path)
+ return 1;
+ while (*path == '/')
+ path++;
+ if (!inode.i_size || ((inode.i_mode&IFMT) != IFDIR))
+ return 0;
+ for (rest = path; (ch = *rest) && ch != '/'; rest++) ;
+ *rest = 0;
+ loc = 0;
+ do {
+ if (loc >= inode.i_size)
+ return 0;
+ if (!(off = blkoff(fs, loc))) {
+ block = lblkno(fs, loc);
+ cnt = blksize(fs, &inode, block);
+ bnum = fsbtodb(fs, block_map(block)) + boff;
+ iodest = iobuf;
+ devread();
+ }
+ dp = (struct direct *)(iodest + off);
+ loc += dp->d_reclen;
+ } while (!dp->d_ino || strcmp(path, dp->d_name));
+ ino = dp->d_ino;
+ *(path = rest) = ch;
+ goto loop;
+}
+
+char mapbuf[MAXBSIZE];
+int mapblock = 0;
+
+block_map(file_block)
+ int file_block;
+{
+ if (file_block < NDADDR)
+ return(inode.i_db[file_block]);
+ if ((bnum=fsbtodb(fs, inode.i_ib[0])+boff) != mapblock) {
+ iodest = mapbuf;
+ cnt = fs->fs_bsize;
+ devread();
+ mapblock = bnum;
+ }
+ return (((int *)mapbuf)[(file_block - NDADDR) % NINDIR(fs)]);
+}
+
+openrd()
+{
+ char **devp, *cp = name;
+ /*******************************************************\
+ * If bracket given look for preceding device name *
+ \*******************************************************/
+ while (*cp && *cp!='(')
+ cp++;
+ if (!*cp)
+ {
+ cp = name;
+ }
+ else
+ {
+ if (cp++ != name)
+ {
+ for (devp = devs; *devp; devp++)
+ if (name[0] == (*devp)[0] &&
+ name[1] == (*devp)[1])
+ break;
+ if (!*devp)
+ {
+ printf("Unknown device\n");
+ return 1;
+ }
+ maj = devp-devs;
+ }
+ /*******************************************************\
+ * Look inside brackets for unit number, and partition *
+ \*******************************************************/
+ if (*cp >= '0' && *cp <= '9')
+ if ((unit = *cp++ - '0') > 1)
+ {
+ printf("Bad unit\n");
+ return 1;
+ }
+ if (!*cp || (*cp == ',' && !*++cp))
+ return 1;
+ if (*cp >= 'a' && *cp <= 'p')
+ part = *cp++ - 'a';
+ while (*cp && *cp++!=')') ;
+ if (!*cp)
+ return 1;
+ }
+ switch(maj)
+ {
+ case 1:
+ dosdev = unit | 0x80;
+ unit = 0;
+ break;
+ case 0:
+ case 4:
+ dosdev = unit | 0x80;
+ break;
+ case 2:
+ dosdev = unit;
+ break;
+ case 3:
+ printf("Wangtek unsupported\n");
+ return 1;
+ break;
+ }
+ inode.i_dev = dosdev;
+ /***********************************************\
+ * Now we know the disk unit and part, *
+ * Load disk info, (open the device) *
+ \***********************************************/
+ if (devopen())
+ return 1;
+
+ /***********************************************\
+ * Load Filesystem info (mount the device) *
+ \***********************************************/
+ iodest = (char *)(fs = (struct fs *)fsbuf);
+ cnt = SBSIZE;
+ bnum = SBLOCK + boff;
+ devread();
+ /***********************************************\
+ * Find the actual FILE on the mounted device *
+ \***********************************************/
+ if (!find(cp))
+ {
+ return 1;
+ }
+ poff = 0;
+ name = cp;
+ return 0;
+}
diff --git a/sys/i386/boot/biosboot/table.c b/sys/i386/boot/biosboot/table.c
new file mode 100644
index 0000000..c53173d
--- /dev/null
+++ b/sys/i386/boot/biosboot/table.c
@@ -0,0 +1,125 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:36:43 rpd
+ * $Id$
+ */
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/* Segment Descriptor
+ *
+ * 31 24 19 16 7 0
+ * ------------------------------------------------------------
+ * | | |B| |A| | | |1|0|E|W|A| |
+ * | BASE 31..24 |G|/|0|V| LIMIT |P|DPL| TYPE | BASE 23:16 |
+ * | | |D| |L| 19..16| | |1|1|C|R|A| |
+ * ------------------------------------------------------------
+ * | | |
+ * | BASE 15..0 | LIMIT 15..0 |
+ * | | |
+ * ------------------------------------------------------------
+ */
+
+struct seg_desc {
+ unsigned short limit_15_0;
+ unsigned short base_15_0;
+ unsigned char base_23_16;
+ unsigned char p_dpl_type;
+ unsigned char g_b_a_limit;
+ unsigned char base_31_24;
+ };
+
+#define RUN 0 /* not really 0, but filled in at boot time */
+
+struct seg_desc Gdt[] = {
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* 0x0 : null */
+ {0xFFFF, 0x0, 0x0, 0x9F, 0xCF, 0x0}, /* 0x08 : kernel code */
+ /* 0x9E? */
+ {0xFFFF, 0x0, 0x0, 0x93, 0xCF, 0x0}, /* 0x10 : kernel data */
+ /* 0x92? */
+ {0xFFFF, RUN, RUN, 0x9E, 0x40, 0x0}, /* 0x18 : boot code */
+ {0xFFFF, RUN, RUN, 0x92, 0x40, 0x0}, /* 0x20 : boot data */
+ {0xFFFF, RUN, RUN, 0x9E, 0x0, 0x0}, /* 0x28 : boot code, 16 bits */
+ /* More for bdb. */
+ {}, /* BIOS_CS_INDEX = 6 : null */
+ {}, /* BIOS_TMP_INDEX = 7 : null */
+ {}, /* TSS_INDEX = 8 : null */
+ {0xFFFF, 0x0, 0x0, 0xB2, 0x40, 0x0}, /* DS_286_INDEX = 9 */
+ {0xFFFF, 0x0, 0x0, 0xB2, 0x40, 0x0}, /* ES_286_INDEX = 10 */
+ {}, /* Unused = 11 : null */
+ {0x7FFF, 0x8000, 0xB, 0xB2, 0x40, 0x0}, /* COLOR_INDEX = 12 */
+ {0x7FFF, 0x0, 0xB, 0xB2, 0x40, 0x0}, /* MONO_INDEX = 13 */
+ {0xFFFF, RUN, RUN, 0x9A, 0x40, 0x0}, /* DB_CS_INDEX = 14 */
+ {0xFFFF, RUN, RUN, 0x9A, 0x0, 0x0}, /* DB_CS16_INDEX = 15 */
+ {0xFFFF, RUN, RUN, 0x92, 0x40, 0x0}, /* DB_DS_INDEX = 16 */
+ {8*18-1, RUN, RUN, 0x92, 0x40, 0x0}, /* GDT_INDEX = 17 */
+};
+
+struct idt_desc {
+ unsigned short entry_15_0;
+ unsigned short selector;
+ unsigned char padding;
+ unsigned char p_dpl_type;
+ unsigned short entry_31_16;
+};
+
+struct idt_desc Idt[] = {
+ {}, /* Null (int 0) */
+ {RUN, 0x70, 0, 0x8E, 0}, /* DEBUG_VECTOR = 1 */
+ {}, /* Null (int 2) */
+ {RUN, 0x70, 0, 0xEE, 0}, /* BREAKPOINT_VECTOR = 3 */
+};
+
+struct pseudo_desc {
+ unsigned short limit;
+ unsigned short base_low;
+ unsigned short base_high;
+ };
+
+struct pseudo_desc Gdtr = { sizeof Gdt - 1, RUN, RUN };
+struct pseudo_desc Idtr_prot = { sizeof Idt - 1, RUN, RUN };
+struct pseudo_desc Idtr_real = { 0x400 - 1, 0x0, 0x0 };
diff --git a/sys/i386/boot/boot.c b/sys/i386/boot/boot.c
new file mode 100644
index 0000000..50f39df
--- /dev/null
+++ b/sys/i386/boot/boot.c
@@ -0,0 +1,310 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, [92/04/03 16:51:14 rvb]
+ * $Id: boot.c,v 1.10 1994/04/20 22:06:24 phk Exp $
+ */
+
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#include <sys/param.h>
+#include "boot.h"
+#include <a.out.h>
+#include <sys/reboot.h>
+
+struct exec head;
+int argv[10], esym;
+char *name;
+char *names[] = {
+ "/386bsd", "/o386bsd", "/386bsd.old",
+ "/vmunix", "/ovmunix", "/vmunix.old"
+};
+#define NUMNAMES (sizeof(names)/sizeof(char *))
+
+extern int end;
+boot(drive)
+int drive;
+{
+ int loadflags, currname = 0;
+ char *t;
+
+ printf("\n>> FreeBSD BOOT @ 0x%x: %d/%d k of memory [%s]\n",
+ ouraddr,
+ argv[7] = memsize(0),
+ argv[8] = memsize(1),
+ "$Revision: 1.10 $");
+ printf("use hd(1,a)/386bsd to boot sd0 when wd0 is also installed\n");
+ gateA20();
+loadstart:
+ /***************************************************************\
+ * As a default set it to the first partition of the first *
+ * floppy or hard drive *
+ \***************************************************************/
+ part = unit = 0;
+ maj = (drive&0x80 ? 0 : 2); /* a good first bet */
+ name = names[currname++];
+
+ loadflags = 0;
+ if (currname == NUMNAMES)
+ currname = 0;
+ getbootdev(&loadflags);
+ if (openrd()) {
+ printf("Can't find %s\n", name);
+ goto loadstart;
+ }
+/* if (inode.i_mode&IEXEC)
+ loadflags |= RB_KDB;
+*/
+ loadprog(loadflags);
+ goto loadstart;
+}
+
+loadprog(howto)
+ int howto;
+{
+ long int startaddr;
+ long int addr; /* physical address.. not directly useable */
+ long int addr0;
+ int i;
+ static int (*x_entry)() = 0;
+ unsigned char tmpbuf[4096]; /* we need to load the first 4k here */
+
+ argv[3] = 0;
+ argv[4] = 0;
+ read(&head, sizeof(head));
+ if ( N_BADMAG(head)) {
+ printf("Invalid format!\n");
+ return;
+ }
+
+ poff = N_TXTOFF(head);
+ /*if(poff==0)
+ poff = 32;*/
+
+ startaddr = (int)head.a_entry;
+ addr = (startaddr & 0x00ffffff); /* some MEG boundary */
+ addr0 = addr;
+ printf("Booting %s(%d,%c)%s @ 0x%x\n"
+ , devs[maj]
+ , unit
+ , 'a'+part
+ , name
+ , addr);
+ if(addr < ouraddr)
+ {
+ if((addr + head.a_text + head.a_data) > ouraddr)
+ {
+ printf("kernel will not fit below loader\n");
+ return;
+ }
+ if((addr + head.a_text + head.a_data + head.a_bss) > 0xa0000)
+ {
+ printf("kernel too big, won't fit in 640K with bss\n");
+ printf("Only hope is to link the kernel for > 1MB\n");
+ return;
+ }
+ }
+ printf("text=0x%x ", head.a_text);
+ /********************************************************/
+ /* LOAD THE TEXT SEGMENT */
+ /* don't clobber the first 4k yet (BIOS NEEDS IT) */
+ /********************************************************/
+ read(tmpbuf,4096);
+ addr += 4096;
+ xread(addr, head.a_text - 4096);
+ addr += head.a_text - 4096;
+
+ /********************************************************/
+ /* Load the Initialised data after the text */
+ /********************************************************/
+ while (addr & CLOFSET)
+ *(char *)addr++ = 0;
+
+ printf("data=0x%x ", head.a_data);
+ xread(addr, head.a_data);
+ addr += head.a_data;
+
+ /********************************************************/
+ /* Skip over the uninitialised data */
+ /* (but clear it) */
+ /********************************************************/
+ printf("bss=0x%x ", head.a_bss);
+ if( (addr < ouraddr) && ((addr + head.a_bss) > ouraddr))
+ {
+ pbzero(addr,ouraddr - (int)addr);
+ }
+ else
+ {
+ pbzero(addr,head.a_bss);
+ }
+ argv[3] = (addr += head.a_bss);
+
+#ifdef LOADSYMS /* not yet, haven't worked this out yet */
+ if (addr > 0x100000)
+ {
+ /********************************************************/
+ /*copy in the symbol header */
+ /********************************************************/
+ pcpy(&head.a_syms, addr, sizeof(head.a_syms));
+ addr += sizeof(head.a_syms);
+
+ /********************************************************/
+ /* READ in the symbol table */
+ /********************************************************/
+ printf("symbols=[+0x%x", head.a_syms);
+ xread(addr, head.a_syms);
+ addr += head.a_syms;
+
+ /********************************************************/
+ /* Followed by the next integer (another header) */
+ /* more debug symbols? */
+ /********************************************************/
+ read(&i, sizeof(int));
+ pcpy(&i, addr, sizeof(int));
+ i -= sizeof(int);
+ addr += sizeof(int);
+
+
+ /********************************************************/
+ /* and that many bytes of (debug symbols?) */
+ /********************************************************/
+ printf("+0x%x] ", i);
+ xread(addr, i);
+ addr += i;
+ }
+#endif LOADSYMS
+ /********************************************************/
+ /* and note the end address of all this */
+ /********************************************************/
+
+ argv[4] = ((addr+sizeof(int)-1))&~(sizeof(int)-1);
+ printf("total=0x%x ",argv[4]);
+
+
+ /*
+ * We now pass the various bootstrap parameters to the loaded
+ * image via the argument list
+ * (THIS IS A BIT OF HISTORY FROM MACH.. LEAVE FOR NOW)
+ * arg1 = boot flags
+ * arg2 = boot device
+ * arg3 = start of symbol table (0 if not loaded)
+ * arg4 = end of symbol table (0 if not loaded)
+ * arg5 = transfer address from image
+ * arg6 = transfer address for next image pointer
+ */
+ switch(maj)
+ {
+ case 2:
+ printf("\n\nInsert file system floppy in drive A or B\n");
+ printf("Press 'A', 'B' or any other key for the default ");
+ printf("%c: ", unit+'A');
+ i = getchar();
+ if (i=='0' || i=='A' || i=='a')
+ unit = 0;
+ if (i=='1' || i=='B' || i=='b')
+ unit = 1;
+ printf("\n");
+ break;
+ case 4:
+ break;
+ }
+ argv[1] = howto;
+ argv[2] = (MAKEBOOTDEV(maj, 0, 0, unit, part)) ;
+ argv[5] = (head.a_entry &= 0xfffffff);
+ argv[6] = (int) &x_entry;
+ argv[0] = 8;
+ /****************************************************************/
+ /* copy that first page and overwrite any BIOS variables */
+ /****************************************************************/
+ printf("entry point=0x%x\n" ,((int)startaddr) & 0xffffff);
+ /* Under no circumstances overwrite precious BIOS variables! */
+ pcpy(tmpbuf, addr0, 0x400);
+ pcpy(tmpbuf + 0x500, addr0 + 0x500, 4096 - 0x500);
+ startprog(((int)startaddr & 0xffffff),argv);
+}
+
+char namebuf[100];
+getbootdev(howto)
+ int *howto;
+{
+ char c, *ptr = namebuf;
+ printf("Boot: [[[%s(%d,%c)]%s][-s][-a][-d]] :- "
+ , devs[maj]
+ , unit
+ , 'a'+part
+ , name);
+ if (gets(namebuf)) {
+ while (c=*ptr) {
+ while (c==' ')
+ c = *++ptr;
+ if (!c)
+ return;
+ if (c=='-')
+ while ((c = *++ptr) && c!=' ')
+ switch (c) {
+ case 'r':
+ *howto |= RB_DFLTROOT; continue;
+ case 'a':
+ *howto |= RB_ASKNAME; continue;
+ case 's':
+ *howto |= RB_SINGLE; continue;
+ case 'd':
+ *howto |= RB_KDB; continue;
+ case 'b':
+ *howto |= RB_HALT; continue;
+ }
+ else {
+ name = ptr;
+ while ((c = *++ptr) && c!=' ');
+ if (c)
+ *ptr++ = 0;
+ }
+ }
+ } else
+ printf("\n");
+}
+
diff --git a/sys/i386/boot/boot.h b/sys/i386/boot/boot.h
new file mode 100644
index 0000000..f77f882
--- /dev/null
+++ b/sys/i386/boot/boot.h
@@ -0,0 +1,40 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:35:03 rpd
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <ufs/quota.h>
+#include <ufs/fs.h>
+#include <ufs/inode.h>
+
+extern char *devs[], *name, *iodest;
+extern struct fs *fs;
+extern struct inode inode;
+extern int dosdev, unit, part, maj, boff, poff, bnum, cnt;
+extern long int ouraddr;
diff --git a/sys/i386/boot/boot.sed b/sys/i386/boot/boot.sed
new file mode 100644
index 0000000..c6b38ea
--- /dev/null
+++ b/sys/i386/boot/boot.sed
@@ -0,0 +1,3 @@
+/^[ ]*.data/c\
+ .text
+/^[ ]*.ident/d
diff --git a/sys/i386/boot/boot2.S b/sys/i386/boot/boot2.S
new file mode 100644
index 0000000..b3c96da
--- /dev/null
+++ b/sys/i386/boot/boot2.S
@@ -0,0 +1,169 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:35:26 rpd
+ * $Id: boot2.S,v 1.2 1993/10/16 19:11:33 rgrimes Exp $
+ */
+
+#include "asm.h"
+
+/* Conventional GDT indexes. */
+#define BOOT_CS_INDEX 3
+#define BOOT_CS16_INDEX 5
+#define BOOT_DS_INDEX 4
+#define DB_CS_INDEX 14
+#define DB_CS16_INDEX 15
+#define DB_DS_INDEX 16
+#define GDT_INDEX 17
+
+/* Vector numbers. */
+#define BREAKPOINT_VECTOR 3
+#define DEBUG_VECTOR 1
+
+/*
+ * boot2() -- second stage boot
+ */
+
+.globl EXT(ouraddr)
+
+ENTRY(boot2)
+ data32
+ subl %eax, %eax
+ mov %cs, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ data32
+ shll $4, %eax
+ addr32
+ data32
+ movl %eax, EXT(ouraddr)
+
+ /* fix up GDT entries for bootstrap */
+#define FIXUP(gdt_index) \
+ addr32; \
+ movl %eax, EXT(Gdt)+(8*gdt_index)+2; /* actually movw %ax */ \
+ addr32; \
+ movb %bl, EXT(Gdt)+(8*gdt_index)+4
+
+ data32
+ shld $16, %eax, %ebx
+ FIXUP(BOOT_CS_INDEX)
+ FIXUP(BOOT_CS16_INDEX)
+ FIXUP(BOOT_DS_INDEX)
+
+ /* fix up GDT entry for GDT, and GDT and IDT pointers */
+ data32
+ movl %eax, %ecx
+ data32
+ addl $ EXT(Gdt), %eax
+ data32
+ shld $16, %eax, %ebx
+ FIXUP(GDT_INDEX)
+ addr32
+ data32
+ movl %eax, EXT(Gdtr)+2
+ data32
+ addl $ EXT(Idt), %ecx
+ addr32
+ data32
+ movl %ecx, EXT(Idtr_prot)+2
+
+ /* %es = vector table segment for a while */
+ push %es
+ data32
+ subl %eax, %eax
+ mov %ax, %es
+
+ /* fix up GDT entries for bdb */
+ data32
+ movl $4*DEBUG_VECTOR, %esi
+ addr32
+ movl %es: 2(%esi), %eax /* actually movw to %ax */
+ data32
+ shll $4, %eax
+ data32
+ shld $16, %eax, %ebx
+ FIXUP(DB_CS_INDEX)
+ FIXUP(DB_CS16_INDEX)
+ FIXUP(DB_DS_INDEX)
+
+ /* Fetch entry points of bdb's protected mode trap handlers. These
+ * are stored at 2 before the corresponding entry points for real mode.
+ */
+ data32
+ subl %ebx, %ebx
+ addr32
+ movl %es: (%esi), %ebx /* actually movw to %bx */
+ data32
+ subl %ecx, %ecx
+ addr32
+ movl %es: 4*(BREAKPOINT_VECTOR-DEBUG_VECTOR)(%esi), %ecx
+ /* actually movw to %cx */
+
+ /* %es = bdb segment for a while */
+ data32
+ shrl $4, %eax
+ mov %ax, %es
+
+ /* fix up IDT entries for bdb */
+ subl $2, %ebx
+ movl %es: (%ebx), %eax /* actually movw to %ax */
+ addr32
+ movl %eax, EXT(Idt)+8*DEBUG_VECTOR /* actually movw %ax */
+ subl $2, %ecx
+ movl %es: (%ecx), %eax /* actually movw to %ax */
+ addr32
+ movl %eax, EXT(Idt)+8*BREAKPOINT_VECTOR /* actually movw %ax */
+
+ /* finished with groping in real mode segments */
+ pop %es
+
+ /* change to protected mode */
+ data32
+ call EXT(real_to_prot)
+
+ /* clear the bss */
+ movl $ EXT(edata), %edi /* no EXT(_edata) - krufty ld */
+ movl $ EXT(end), %ecx /* or EXT(_end) */
+ subl %edi, %ecx
+ subb %al, %al
+ rep
+ stosb
+
+ movzbl %dl, %edx /* discard head (%dh) and random high bits */
+ pushl %edx
+ call EXT(boot)
+oops:
+ hlt
+ jmp oops
+
+ .data
+ .align 2
+#if 0 /* XXX this would give losing "_ouraddr :". Better declared in C */
+EXT(ouraddr):
+#else
+_ouraddr:
+#endif
+ .long 0
diff --git a/sys/i386/boot/boot2.s b/sys/i386/boot/boot2.s
new file mode 100644
index 0000000..d319edf
--- /dev/null
+++ b/sys/i386/boot/boot2.s
@@ -0,0 +1,73 @@
+/*
+ * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/*
+ * HISTORY
+ * $Log: boot2.s,v $
+ * Revision 2.2 92/04/04 11:35:26 rpd
+ * From 2.5
+ * [92/03/30 rvb]
+ *
+ * Revision 2.2 91/04/02 14:39:21 mbj
+ * Put into rcs tree
+ * [90/02/09 rvb]
+ *
+ */
+
+#include "asm.h"
+#define LOADMSG 1
+/*
+ * boot2() -- second stage boot
+ */
+
+.globl _ouraddr
+
+ENTRY(boot2)
+ movl %cs, %ax
+ movl %ax, %ds
+ movl %ax, %es
+ data32
+ sall $4, %eax
+ data32
+ movl %eax, _ouraddr
+ /* save the drive type and ID */
+ data32
+ pushl %edx
+ /* change to protected mode */
+ data32
+ call _real_to_prot
+
+ call _boot
+ ret
+
+ .data
+ .align 2
+_ouraddr:
+ .long 0
+
+
diff --git a/sys/i386/boot/disk.c b/sys/i386/boot/disk.c
new file mode 100644
index 0000000..a63ca5a
--- /dev/null
+++ b/sys/i386/boot/disk.c
@@ -0,0 +1,281 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:35:49 rpd
+ * $Id: disk.c,v 1.4 1994/02/22 22:59:40 rgrimes Exp $
+ */
+
+/*
+ * 93/10/08 bde
+ * If there is no 386BSD partition, initialize the label sector with
+ * LABELSECTOR instead of with garbage.
+ *
+ * 93/08/22 bde
+ * Fixed reading of bad sector table. It is at the end of the 'c'
+ * partition, which is not always at the end of the disk.
+ */
+
+#include "boot.h"
+#ifdef DO_BAD144
+#include <sys/dkbad.h>
+#endif DO_BAD144
+#include <sys/disklabel.h>
+
+#define BIOS_DEV_FLOPPY 0x0
+#define BIOS_DEV_WIN 0x80
+
+#define BPS 512
+#define SPT(di) ((di)&0xff)
+#define HEADS(di) ((((di)>>8)&0xff)+1)
+
+char *devs[] = {"wd", "hd", "fd", "wt", "sd", 0};
+
+#ifdef DO_BAD144
+struct dkbad dkb;
+int do_bad144;
+int bsize;
+#endif DO_BAD144
+
+int spt, spc;
+
+char *iodest;
+struct fs *fs;
+struct inode inode;
+int dosdev, unit, part, maj, boff, poff, bnum, cnt;
+
+/*#define EMBEDDED_DISKLABEL 1*/
+extern struct disklabel disklabel;
+/*struct disklabel disklabel;*/
+
+devopen()
+{
+ struct dos_partition *dptr;
+ struct disklabel *dl;
+ int dosdev = inode.i_dev;
+ int i, sector, di;
+
+ di = get_diskinfo(dosdev);
+ spc = (spt = SPT(di)) * HEADS(di);
+ if (dosdev == 2)
+ {
+ boff = 0;
+ part = (spt == 15 ? 3 : 1);
+ }
+ else
+ {
+#ifdef EMBEDDED_DISKLABEL
+ dl = &disklabel;
+#else EMBEDDED_DISKLABEL
+ Bread(dosdev, 0);
+ dptr = (struct dos_partition *)(((char *)0)+DOSPARTOFF);
+ sector = LABELSECTOR;
+ for (i = 0; i < NDOSPART; i++, dptr++)
+ if (dptr->dp_typ == DOSPTYP_386BSD) {
+ sector = dptr->dp_start + LABELSECTOR;
+ break;
+ }
+ Bread(dosdev, sector++);
+ dl=((struct disklabel *)0);
+ disklabel = *dl; /* structure copy (maybe useful later)*/
+#endif EMBEDDED_DISKLABEL
+ if (dl->d_magic != DISKMAGIC) {
+ printf("bad disklabel");
+ return 1;
+ }
+ if( (maj == 4) || (maj == 0) || (maj == 1))
+ {
+ if (dl->d_type == DTYPE_SCSI)
+ {
+ maj = 4; /* use scsi as boot dev */
+ }
+ else
+ {
+ maj = 0; /* must be ESDI/IDE */
+ }
+ }
+ boff = dl->d_partitions[part].p_offset;
+#ifdef DO_BAD144
+ bsize = dl->d_partitions[part].p_size;
+ do_bad144 = 0;
+ if (dl->d_flags & D_BADSECT) {
+ /* this disk uses bad144 */
+ int i;
+ int dkbbnum;
+ struct dkbad *dkbptr;
+
+ /* find the first readable bad sector table */
+ /* some of this code is copied from ufs/ufs_disksubr.c */
+ /* including the bugs :-( */
+ /* read a bad sector table */
+
+#define BAD144_PART 2 /* XXX scattered magic numbers */
+#define BSD_PART 0 /* XXX should be 2 but bad144.c uses 0 */
+ if (dl->d_partitions[BSD_PART].p_offset != 0)
+ dkbbnum = dl->d_partitions[BAD144_PART].p_offset
+ + dl->d_partitions[BAD144_PART].p_size;
+ else
+ dkbbnum = dl->d_secperunit;
+ dkbbnum -= dl->d_nsectors;
+
+ if (dl->d_secsize > DEV_BSIZE)
+ dkbbnum *= dl->d_secsize / DEV_BSIZE;
+ else
+ dkbbnum /= DEV_BSIZE / dl->d_secsize;
+ i = 0;
+ do_bad144 = 0;
+ do {
+ /* XXX: what if the "DOS sector" < 512 bytes ??? */
+ Bread(dosdev, dkbbnum + i);
+ dkbptr = (struct dkbad *) 0;
+/* XXX why is this not in <sys/dkbad.h> ??? */
+#define DKBAD_MAGIC 0x4321
+ if (dkbptr->bt_mbz == 0 &&
+ dkbptr->bt_flag == DKBAD_MAGIC) {
+ dkb = *dkbptr; /* structure copy */
+ do_bad144 = 1;
+ break;
+ }
+ i += 2;
+ } while (i < 10 && i < dl->d_nsectors);
+ if (!do_bad144)
+ printf("Bad bad sector table\n");
+ else
+ printf("Using bad sector table at %d\n", dkbbnum+i);
+ }
+#endif DO_BAD144
+ }
+ return 0;
+}
+
+devread()
+{
+ int offset, sector = bnum;
+ int dosdev = inode.i_dev;
+ for (offset = 0; offset < cnt; offset += BPS)
+ {
+ Bread(dosdev, badsect(dosdev, sector++));
+ bcopy(0, iodest+offset, BPS);
+ }
+}
+
+#define I_ADDR ((void *) 0) /* XXX where all reads go */
+
+/* Read ahead buffer large enough for one track on a 1440K floppy. For
+ * reading from floppies, the bootstrap has to be loaded on a 64K boundary
+ * to ensure that this buffer doesn't cross a 64K DMA boundary.
+ */
+#define RA_SECTORS 18
+static char ra_buf[RA_SECTORS * BPS];
+static int ra_dev;
+static int ra_end;
+static int ra_first;
+
+Bread(dosdev,sector)
+ int dosdev,sector;
+{
+ if (dosdev != ra_dev || sector < ra_first || sector >= ra_end)
+ {
+ int cyl, head, sec, nsec;
+
+ cyl = sector/spc;
+ head = (sector % spc) / spt;
+ sec = sector % spt;
+ nsec = spt - sec;
+ if (nsec > RA_SECTORS)
+ nsec = RA_SECTORS;
+ twiddle();
+ if (biosread(dosdev, cyl, head, sec, nsec, ra_buf) != 0)
+ {
+ nsec = 1;
+ twiddle();
+ while (biosread(dosdev, cyl, head, sec, nsec, ra_buf) != 0) {
+ printf("Error: C:%d H:%d S:%d\n", cyl, head, sec);
+ twiddle();
+ }
+ }
+ ra_dev = dosdev;
+ ra_first = sector;
+ ra_end = sector + nsec;
+ }
+ bcopy(ra_buf + (sector - ra_first) * BPS, I_ADDR, BPS);
+}
+
+badsect(dosdev, sector)
+ int dosdev, sector;
+{
+ int i;
+#ifdef DO_BAD144
+ if (do_bad144) {
+ u_short cyl;
+ u_short head;
+ u_short sec;
+ int newsec;
+ struct disklabel *dl = &disklabel;
+
+ /* XXX */
+ /* from wd.c */
+ /* bt_cyl = cylinder number in sorted order */
+ /* bt_trksec is actually (head << 8) + sec */
+
+ /* only remap sectors in the partition */
+ if (sector < boff || sector >= boff + bsize) {
+ goto no_remap;
+ }
+
+ cyl = sector / dl->d_secpercyl;
+ head = (sector % dl->d_secpercyl) / dl->d_nsectors;
+ sec = sector % dl->d_nsectors;
+ sec = (head<<8) + sec;
+
+ /* now, look in the table for a possible bad sector */
+ for (i=0; i<126; i++) {
+ if (dkb.bt_bad[i].bt_cyl == cyl) {
+ /* found same cylinder */
+ if (dkb.bt_bad[i].bt_trksec == sec) {
+ /* FOUND! */
+ break;
+ }
+ } else if (dkb.bt_bad[i].bt_cyl > cyl) {
+ i = 126;
+ break;
+ }
+ }
+ if (i == 126) {
+ /* didn't find bad sector */
+ goto no_remap;
+ }
+ /* otherwise find replacement sector */
+ if (dl->d_partitions[BSD_PART].p_offset != 0)
+ newsec = dl->d_partitions[BAD144_PART].p_offset
+ + dl->d_partitions[BAD144_PART].p_size;
+ else
+ newsec = dl->d_secperunit;
+ newsec -= dl->d_nsectors + i + 1;
+ return newsec;
+ }
+#endif DO_BAD144
+ no_remap:
+ return sector;
+}
diff --git a/sys/i386/boot/io.c b/sys/i386/boot/io.c
new file mode 100644
index 0000000..6a5a58a
--- /dev/null
+++ b/sys/i386/boot/io.c
@@ -0,0 +1,202 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:35:57 rpd
+ * $Id$
+ */
+
+#include <i386/include/pio.h>
+
+#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */
+#define K_STATUS 0x64 /* keyboard status */
+#define K_CMD 0x64 /* keybd ctlr command (write-only) */
+
+#define K_OBUF_FUL 0x01 /* output buffer full */
+#define K_IBUF_FUL 0x02 /* input buffer full */
+
+#define KC_CMD_WIN 0xd0 /* read output port */
+#define KC_CMD_WOUT 0xd1 /* write output port */
+#define KB_A20 0x9f /* enable A20,
+ enable output buffer full interrupt
+ enable data line
+ disable clock line */
+
+/*
+ * Gate A20 for high memory
+ */
+unsigned char x_20 = KB_A20;
+gateA20()
+{
+#ifdef IBM_L40
+ outb(0x92, 0x2);
+#else IBM_L40
+ while (inb(K_STATUS) & K_IBUF_FUL);
+ while (inb(K_STATUS) & K_OBUF_FUL)
+ (void)inb(K_RDWR);
+
+ outb(K_CMD, KC_CMD_WOUT);
+ while (inb(K_STATUS) & K_IBUF_FUL);
+ outb(K_RDWR, x_20);
+ while (inb(K_STATUS) & K_IBUF_FUL);
+#endif IBM_L40
+}
+
+/* printf - only handles %d as decimal, %c as char, %s as string */
+
+printf(format,data)
+ char *format;
+ int data;
+{
+ int *dataptr = &data;
+ char c;
+
+ reset_twiddle();
+ while (c = *format++)
+ if (c != '%')
+ putchar(c);
+ else
+ switch (c = *format++) {
+ case 'd': {
+ int num = *dataptr++;
+ char buf[10], *ptr = buf;
+ if (num<0) {
+ num = -num;
+ putchar('-');
+ }
+ do
+ *ptr++ = '0'+num%10;
+ while (num /= 10);
+ do
+ putchar(*--ptr);
+ while (ptr != buf);
+ break;
+ }
+ case 'x': {
+ int num = *dataptr++, dig;
+ char buf[8], *ptr = buf;
+ do
+ *ptr++ = (dig=(num&0xf)) > 9?
+ 'a' + dig - 10 :
+ '0' + dig;
+ while (num >>= 4);
+ do
+ putchar(*--ptr);
+ while (ptr != buf);
+ break;
+ }
+ case 'c': putchar((*dataptr++)&0xff); break;
+ case 's': {
+ char *ptr = (char *)*dataptr++;
+ while (c = *ptr++)
+ putchar(c);
+ break;
+ }
+ }
+}
+
+putchar(c)
+{
+ if (c == '\n')
+ putc('\r');
+ putc(c);
+}
+
+getchar()
+{
+ int c;
+
+ if ((c=getc()) == '\r')
+ c = '\n';
+ if (c == '\b') {
+ putchar('\b');
+ putchar(' ');
+ }
+ putchar(c);
+ return(c);
+}
+
+gets(buf)
+char *buf;
+{
+ int i;
+ char *ptr=buf;
+
+ for (i = 240000; i>0; i--)
+ if (ischar())
+ for (;;)
+ switch(*ptr = getchar() & 0xff) {
+ case '\n':
+ case '\r':
+ *ptr = '\0';
+ return 1;
+ case '\b':
+ if (ptr > buf) ptr--;
+ continue;
+ default:
+ ptr++;
+ }
+ return 0;
+}
+
+strcmp(s1, s2)
+char *s1, *s2;
+{
+ while (*s1 == *s2) {
+ if (!*s1++)
+ return 0;
+ s2++;
+ }
+ return 1;
+}
+
+bcopy(from, to, len)
+char *from, *to;
+int len;
+{
+ while (len-- > 0)
+ *to++ = *from++;
+}
+
+static int tw_on;
+static int tw_pos;
+static char tw_chars[] = "|/-\\";
+
+reset_twiddle()
+{
+ if (tw_on)
+ putchar('\b');
+ tw_on = 0;
+ tw_pos = 0;
+}
+
+twiddle()
+{
+ if (tw_on)
+ putchar('\b');
+ else
+ tw_on = 1;
+ putchar(tw_chars[tw_pos++]);
+ tw_pos %= (sizeof(tw_chars) - 1);
+}
diff --git a/sys/i386/boot/rmaouthdr b/sys/i386/boot/rmaouthdr
new file mode 100644
index 0000000..4bb9c84
--- /dev/null
+++ b/sys/i386/boot/rmaouthdr
@@ -0,0 +1,6 @@
+#!/bin/csh -f
+#
+# from: Mach, Revision 2.2 92/04/04 11:36:01 rpd
+# $Id$
+#
+dd if=$1 of=$2 ibs=32 skip=1 obs=1024b
diff --git a/sys/i386/boot/start.S b/sys/i386/boot/start.S
new file mode 100644
index 0000000..62b93ac
--- /dev/null
+++ b/sys/i386/boot/start.S
@@ -0,0 +1,291 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:36:29 rpd
+ * $Id$
+ */
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+#include "asm.h"
+
+ .file "start.s"
+
+BOOTSEG = 0x9000 # boot will be loaded here (below 640K)
+BOOTSTACK = 0xe000 # boot stack
+SIGNATURE = 0xaa55
+LOADSZ = 15 # size of unix boot
+PARTSTART = 0x1be # starting address of partition table
+NUMPART = 4 # number of partitions in partition table
+PARTSZ = 16 # each partition table entry is 16 bytes
+BSDPART = 0xA5 # value of boot_ind, means bootable partition
+BOOTABLE = 0x80 # value of boot_ind, means bootable partition
+
+ .text
+
+ENTRY(boot1)
+ # start (aka boot1) is loaded at 0x0:0x7c00 but we want 0x7c0:0
+ # ljmp to the next instruction to adjust %cs
+ data32
+ ljmp $0x7c0, $start
+
+start:
+ # set up %ds
+ mov %cs, %ax
+ mov %ax, %ds
+
+ # set up %ss and %esp
+ data32
+ mov $BOOTSEG, %eax
+ mov %ax, %ss
+ data32
+ mov $BOOTSTACK, %esp
+
+ /*** set up %es, (where we will load boot2 to) ***/
+ mov %ax, %es
+
+#ifdef DEBUG
+ data32
+ mov $one, %esi
+ data32
+ call message
+#endif
+
+ # bootstrap passes us drive number in %dl
+ cmpb $0x80, %dl
+ data32
+ jae hd
+
+fd:
+# reset the disk system
+#ifdef DEBUG
+ data32
+ mov $two, %esi
+ data32
+ call message
+#endif
+ movb $0x0, %ah
+ int $0x13
+ data32
+ mov $0x0001, %ecx # cyl 0, sector 1
+ movb $0, %dh # head
+#ifdef DEBUG
+ data32
+ mov $three, %esi
+ data32
+ call message
+#endif
+ data32
+ jmp load
+
+hd: /**** load sector 0 into the BOOTSEG ****/
+#ifdef DEBUG
+ data32
+ mov $four, %esi
+ data32
+ call message
+#endif
+ data32
+ mov $0x0201, %eax
+ xor %ebx, %ebx # %bx = 0
+ data32
+ mov $0x0001, %ecx
+#ifdef DEBUG
+ data32
+ mov $five, %esi
+ data32
+ call message
+#endif
+ data32
+ andl $0xff, %edx
+ /*mov $0x0080, %edx*/
+ int $0x13
+ data32
+ jb read_error
+
+ /***# find the first 386BSD partition *****/
+ data32
+ mov $PARTSTART, %ebx
+ data32
+ mov $NUMPART, %ecx
+again:
+ addr32
+ movb %es:4(%ebx), %al
+ cmpb $BSDPART, %al
+ data32
+ je found
+ data32
+ add $PARTSZ, %ebx
+ data32
+ loop again
+ data32
+ mov $enoboot, %esi
+ data32
+ jmp err_stop
+
+
+/*
+# BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
+# Call with %ah = 0x2
+# %al = number of sectors
+# %ch = cylinder
+# %cl = sector
+# %dh = head
+# %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
+# %es:%bx = segment:offset of buffer
+# Return:
+# %al = 0x0 on success; err code on failure
+*/
+
+found:
+ addr32
+ movb %es:1(%ebx), %dh /* head */
+ addr32
+ movl %es:2(%ebx), %ecx /*sect, cyl (+ 2 bytes junk in top word) */
+
+load:
+ movb $0x2, %ah /* function 2 */
+ movb $LOADSZ, %al /* number of blocks */
+ xor %ebx, %ebx /* %bx = 0, put it at 0 in the BOOTSEG */
+ int $0x13
+ data32
+ jb read_error
+
+ # ljmp to the second stage boot loader (boot2).
+ # After ljmp, %cs is BOOTSEG and boot1 (512 bytes) will be used
+ # as an internal buffer "intbuf".
+
+#ifdef DEBUG
+ data32
+ mov $six, %esi
+ data32
+ call message
+#endif
+ data32
+ ljmp $BOOTSEG, $ EXT(boot2)
+
+#
+# read_error
+#
+
+read_error:
+ data32
+ mov $eread, %esi
+err_stop:
+ data32
+ call message
+ data32
+ jmp stop
+
+#
+# message: write the error message in %ds:%esi to console
+#
+
+message:
+/*
+ # Use BIOS "int 10H Function 0Eh" to write character in teletype mode
+ # %ah = 0xe %al = character
+ # %bh = page %bl = foreground color (graphics modes)
+*/
+
+ data32
+ push %eax
+ data32
+ push %ebx
+ data32
+ mov $0x0001, %ebx
+ cld
+
+nextb:
+ lodsb # load a byte into %al
+ cmpb $0x0, %al
+ data32
+ je done
+ movb $0xe, %ah
+ int $0x10 # display a byte
+ data32
+ jmp nextb
+done:
+ data32
+ pop %ebx
+ data32
+ pop %eax
+ data32
+ ret
+
+stop: hlt
+ data32
+ jmp stop # halt doesnt actually halt forever
+
+/* error messages */
+
+#ifdef DEBUG
+one: String "1\r\n\0"
+two: String "2\r\n\0"
+three: String "3\r\n\0"
+four: String "4\r\n\0"
+five: String "5\r\n\0"
+six: String "6\r\n\0"
+seven: String "7\r\n\0"
+#endif DEBUG
+eread: String "Read error\r\n\0"
+enoboot: String "No bootable partition\r\n\0"
+endofcode:
+/* throw in a partition in case we are block0 as well */
+/* flag, head, sec, cyl, typ, ehead, esect, ecyl, start, len */
+ . = EXT(boot1) + PARTSTART
+ .byte 0x0,0,0,0,0,0,0,0
+ .long 0,0
+ .byte 0x0,0,0,0,0,0,0,0
+ .long 0,0
+ .byte 0x0,0,0,0,0,0,0,0
+ .long 0,0
+ .byte BOOTABLE,0,1,0,BSDPART,255,255,255
+ .long 0,50000
+/* the last 2 bytes in the sector 0 contain the signature */
+ . = EXT(boot1) + 0x1fe
+ .value SIGNATURE
+ENTRY(disklabel)
+ . = EXT(boot1) + 0x400
diff --git a/sys/i386/boot/start.s b/sys/i386/boot/start.s
new file mode 100644
index 0000000..f6f4bf0
--- /dev/null
+++ b/sys/i386/boot/start.s
@@ -0,0 +1,323 @@
+/*
+ * Ported to boot 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/*
+ * HISTORY
+ * $Log: start.s,v $
+ * Revision 2.2 92/04/04 11:36:29 rpd
+ * Fix Intel Copyright as per B. Davies authorization.
+ * [92/04/03 rvb]
+ * Need to zero dh on hd path; at least for an adaptec card.
+ * [92/01/14 rvb]
+ *
+ * From 2.5 boot:
+ * Flush digit printing.
+ * Fuse floppy and hd boot by using Int 21 to tell
+ * boot type (slightly dubious since Int 21 is DOS
+ * not BIOS)
+ * [92/03/30 mg32]
+ *
+ * Revision 2.2 91/04/02 14:42:04 mbj
+ * Fix the BIG boot bug. We had missed a necessary data
+ * before a xor that was clearing a register used later
+ * as an index register.
+ * [91/03/01 rvb]
+ * Remember floppy type for swapgeneric
+ * Add Intel copyright
+ * [90/02/09 rvb]
+ *
+ */
+
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+#include "asm.h"
+
+ .file "start.s"
+
+BOOTSEG = 0x9000 # boot will be loaded at 640k-64k
+BOOTSTACK = 0xe000 # boot stack
+SIGNATURE = 0xaa55
+LOADSZ = 14 # size of unix boot
+PARTSTART = 0x1be # starting address of partition table
+NUMPART = 4 # number of partitions in partition table
+PARTSZ = 16 # each partition table entry is 16 bytes
+BSDPART = 0xA5 # value of boot_ind, means bootable partition
+BOOTABLE = 0x80 # value of boot_ind, means bootable partition
+
+ .text
+
+ENTRY(boot1)
+
+ # boot1 is loaded at 0x0:0x7c00
+ # ljmp to the next instruction to set up %cs
+ data32
+ ljmp $0x7c0, $start
+
+start:
+ # set up %ds
+ mov %cs, %ax
+ mov %ax, %ds
+
+
+ # set up %ss and %esp
+ data32
+ mov $BOOTSEG, %eax
+ mov %ax, %ss
+ data32
+ mov $BOOTSTACK, %esp
+
+ /*** set up %es, (where we will load boot2 to) ***/
+ mov %ax, %es
+
+#ifdef DEBUG
+ data32
+ mov $one, %esi
+ data32
+ call message
+#endif
+ # get the boot drive id
+ movb $0x33, %ah
+ movb $0x05, %al
+ int $0x21
+
+ cmpb $0x80, %dl
+ data32
+ jge hd
+
+fd:
+# reset the disk system
+#ifdef DEBUG
+ data32
+ mov $two, %esi
+ data32
+ call message
+#endif
+ movb $0x0, %ah
+ int $0x13
+ data32
+ mov $0x0001, %ecx # cyl 0, sector 1
+ data32
+#ifdef DEBUG
+ data32
+ mov $three, %esi
+ data32
+ call message
+#endif
+ jmp load
+
+hd: /**** load sector 0 into the BOOTSEG ****/
+#ifdef DEBUG
+ data32
+ mov $four, %esi
+ data32
+ call message
+#endif
+ data32
+ mov $0x0201, %eax
+ xor %ebx, %ebx # %bx = 0
+ data32
+ mov $0x0001, %ecx
+#ifdef DEBUG
+ data32
+ mov $five, %esi
+ data32
+ call message
+#endif
+ data32
+ andl $0xff, %edx
+ /*mov $0x0080, %edx*/
+ int $0x13
+ data32
+ jb read_error
+
+ /***# find the bootable partition *****/
+ data32
+ mov $PARTSTART, %ebx
+ data32
+ mov $NUMPART, %ecx
+again:
+ addr16
+ movb %es:4(%ebx), %al
+ cmpb $BSDPART, %al
+ data32
+ je found
+ data32
+ add $PARTSZ, %ebx
+ data32
+ loop again
+ data32
+ mov $enoboot, %esi
+ data32
+ jmp err_stop
+
+
+/*
+# BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory
+# Call with %ah = 0x2
+# %al = number of sectors
+# %ch = cylinder
+# %cl = sector
+# %dh = head
+# %dl = drive (0x80 for hard disk, 0x0 for floppy disk)
+# %es:%bx = segment:offset of buffer
+# Return:
+# %al = 0x0 on success; err code on failure
+*/
+
+found:
+ addr16
+ movb %es:1(%ebx), %dh /* head */
+ addr16
+ xor %ecx, %ecx
+ addr16
+ movw %es:2(%ebx), %ecx /*sect,cyl (+ 2 bytes junk in top word )*/
+
+load:
+ movb $0x2, %ah /* function 2 */
+ movb $LOADSZ, %al /* number of blocks */
+ xor %ebx, %ebx /* %bx = 0, put it at 0 in the BOOTSEG */
+ int $0x13
+ data32
+ jb read_error
+
+ # ljmp to the second stage boot loader (boot2).
+ # After ljmp, %cs is BOOTSEG and boot1 (512 bytes) will be used
+ # as an internal buffer "intbuf".
+
+#ifdef DEBUG
+ data32
+ mov $six, %esi
+ data32
+ call message
+#endif
+ data32
+ ljmp $BOOTSEG, $EXT(boot2)
+
+#
+# read_error
+#
+
+read_error:
+
+ data32
+ mov $eread, %esi
+err_stop:
+ data32
+ call message
+ data32
+ jmp stop
+
+#
+# message: write the error message in %ds:%esi to console
+#
+
+message:
+ # Use BIOS "int 10H Function 0Eh" to write character in teletype mode
+ # %ah = 0xe %al = character
+ # %bh = page %bl = foreground color (graphics modes)
+
+ data32
+ push %eax
+ data32
+ push %ebx
+ data32
+ mov $0x0001, %ebx
+ cld
+
+nextb:
+ lodsb # load a byte into %al
+ cmpb $0x0, %al
+ data32
+ je done
+ movb $0xe, %ah
+ int $0x10 # display a byte
+ data32
+ jmp nextb
+done:
+ data32
+ pop %ebx
+ data32
+ pop %eax
+ data32
+ ret
+
+stop: hlt
+ data32
+ jmp stop # halt doesnt actually halt forever
+
+/* error messages */
+
+#ifdef DEBUG
+one: String "1\r\n\0"
+two: String "2\r\n\0"
+three: String "3\r\n\0"
+four: String "4\r\n\0"
+five: String "5\r\n\0"
+six: String "6\r\n\0"
+seven: String "7\r\n\0"
+#endif DEBUG
+eread: String "Read error\r\n\0"
+enoboot: String "No bootable partition\r\n\0"
+endofcode:
+/* throw in a partition in case we are block0 as well */
+/* flag,head,sec,cyl,typ,ehead,esect,ecyl,start,len */
+ . = EXT(boot1) + PARTSTART
+ .byte 0x0,0,0,0,0,0,0,0
+ .long 0,0
+ .byte 0x0,0,0,0,0,0,0,0
+ .long 0,0
+ .byte 0x0,0,0,0,0,0,0,0
+ .long 0,0
+ .byte BOOTABLE,0,1,0,BSDPART,255,255,255
+ .long 0,50000
+/* the last 2 bytes in the sector 0 contain the signature */
+ . = EXT(boot1) + 0x1fe
+ .value SIGNATURE
+ENTRY(disklabel)
+ . = EXT(boot1) + 0x400
diff --git a/sys/i386/boot/sys.c b/sys/i386/boot/sys.c
new file mode 100644
index 0000000..4ffe171
--- /dev/null
+++ b/sys/i386/boot/sys.c
@@ -0,0 +1,232 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:36:34 rpd
+ * $Id$
+ */
+
+#include "boot.h"
+#include <sys/dir.h>
+#include <sys/reboot.h>
+
+/* #define BUFSIZE 4096 */
+#define BUFSIZE MAXBSIZE
+
+char buf[BUFSIZE], fsbuf[SBSIZE], iobuf[MAXBSIZE];
+
+int xread(addr, size)
+ char * addr;
+ int size;
+{
+ int count = BUFSIZE;
+ while (size > 0) {
+ if (BUFSIZE > size)
+ count = size;
+ read(buf, count);
+ pcpy(buf, addr, count);
+ size -= count;
+ addr += count;
+ }
+}
+
+read(buffer, count)
+ int count;
+ char *buffer;
+{
+ int logno, off, size;
+ int cnt2, bnum2;
+
+ while (count) {
+ off = blkoff(fs, poff);
+ logno = lblkno(fs, poff);
+ cnt2 = size = blksize(fs, &inode, logno);
+ bnum2 = fsbtodb(fs, block_map(logno)) + boff;
+ cnt = cnt2;
+ bnum = bnum2;
+ if ( (!off) && (size <= count))
+ {
+ iodest = buffer;
+ devread();
+ }
+ else
+ {
+ iodest = iobuf;
+ size -= off;
+ if (size > count)
+ size = count;
+ devread();
+ bcopy(iodest+off,buffer,size);
+ }
+ buffer += size;
+ count -= size;
+ poff += size;
+ }
+}
+
+find(path)
+ char *path;
+{
+ char *rest, ch;
+ int block, off, loc, ino = ROOTINO;
+ struct direct *dp;
+loop: iodest = iobuf;
+ cnt = fs->fs_bsize;
+ bnum = fsbtodb(fs,itod(fs,ino)) + boff;
+ devread();
+ bcopy(&((struct dinode *)iodest)[ino % fs->fs_inopb],
+ &inode.i_din,
+ sizeof (struct dinode));
+ if (!*path)
+ return 1;
+ while (*path == '/')
+ path++;
+ if (!inode.i_size || ((inode.i_mode&IFMT) != IFDIR))
+ return 0;
+ for (rest = path; (ch = *rest) && ch != '/'; rest++) ;
+ *rest = 0;
+ loc = 0;
+ do {
+ if (loc >= inode.i_size)
+ return 0;
+ if (!(off = blkoff(fs, loc))) {
+ block = lblkno(fs, loc);
+ cnt = blksize(fs, &inode, block);
+ bnum = fsbtodb(fs, block_map(block)) + boff;
+ iodest = iobuf;
+ devread();
+ }
+ dp = (struct direct *)(iodest + off);
+ loc += dp->d_reclen;
+ } while (!dp->d_ino || strcmp(path, dp->d_name));
+ ino = dp->d_ino;
+ *(path = rest) = ch;
+ goto loop;
+}
+
+char mapbuf[MAXBSIZE];
+int mapblock = 0;
+
+block_map(file_block)
+ int file_block;
+{
+ if (file_block < NDADDR)
+ return(inode.i_db[file_block]);
+ if ((bnum=fsbtodb(fs, inode.i_ib[0])+boff) != mapblock) {
+ iodest = mapbuf;
+ cnt = fs->fs_bsize;
+ devread();
+ mapblock = bnum;
+ }
+ return (((int *)mapbuf)[(file_block - NDADDR) % NINDIR(fs)]);
+}
+
+openrd()
+{
+ char **devp, *cp = name;
+ /*******************************************************\
+ * If bracket given look for preceding device name *
+ \*******************************************************/
+ while (*cp && *cp!='(')
+ cp++;
+ if (!*cp)
+ {
+ cp = name;
+ }
+ else
+ {
+ if (cp++ != name)
+ {
+ for (devp = devs; *devp; devp++)
+ if (name[0] == (*devp)[0] &&
+ name[1] == (*devp)[1])
+ break;
+ if (!*devp)
+ {
+ printf("Unknown device\n");
+ return 1;
+ }
+ maj = devp-devs;
+ }
+ /*******************************************************\
+ * Look inside brackets for unit number, and partition *
+ \*******************************************************/
+ if (*cp >= '0' && *cp <= '9')
+ if ((unit = *cp++ - '0') > 1)
+ {
+ printf("Bad unit\n");
+ return 1;
+ }
+ if (!*cp || (*cp == ',' && !*++cp))
+ return 1;
+ if (*cp >= 'a' && *cp <= 'p')
+ part = *cp++ - 'a';
+ while (*cp && *cp++!=')') ;
+ if (!*cp)
+ return 1;
+ }
+ switch(maj)
+ {
+ case 1:
+ dosdev = unit | 0x80;
+ unit = 0;
+ break;
+ case 0:
+ case 4:
+ dosdev = unit | 0x80;
+ break;
+ case 2:
+ dosdev = unit;
+ break;
+ case 3:
+ printf("Wangtek unsupported\n");
+ return 1;
+ break;
+ }
+ inode.i_dev = dosdev;
+ /***********************************************\
+ * Now we know the disk unit and part, *
+ * Load disk info, (open the device) *
+ \***********************************************/
+ if (devopen())
+ return 1;
+
+ /***********************************************\
+ * Load Filesystem info (mount the device) *
+ \***********************************************/
+ iodest = (char *)(fs = (struct fs *)fsbuf);
+ cnt = SBSIZE;
+ bnum = SBLOCK + boff;
+ devread();
+ /***********************************************\
+ * Find the actual FILE on the mounted device *
+ \***********************************************/
+ if (!find(cp))
+ {
+ return 1;
+ }
+ poff = 0;
+ name = cp;
+ return 0;
+}
diff --git a/sys/i386/boot/table.c b/sys/i386/boot/table.c
new file mode 100644
index 0000000..c53173d
--- /dev/null
+++ b/sys/i386/boot/table.c
@@ -0,0 +1,125 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:36:43 rpd
+ * $Id$
+ */
+
+/*
+ Copyright 1988, 1989, 1990, 1991, 1992
+ by Intel Corporation, Santa Clara, California.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appears in all
+copies and that both the copyright notice and this permission notice
+appear in supporting documentation, and that the name of Intel
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+
+INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/* Segment Descriptor
+ *
+ * 31 24 19 16 7 0
+ * ------------------------------------------------------------
+ * | | |B| |A| | | |1|0|E|W|A| |
+ * | BASE 31..24 |G|/|0|V| LIMIT |P|DPL| TYPE | BASE 23:16 |
+ * | | |D| |L| 19..16| | |1|1|C|R|A| |
+ * ------------------------------------------------------------
+ * | | |
+ * | BASE 15..0 | LIMIT 15..0 |
+ * | | |
+ * ------------------------------------------------------------
+ */
+
+struct seg_desc {
+ unsigned short limit_15_0;
+ unsigned short base_15_0;
+ unsigned char base_23_16;
+ unsigned char p_dpl_type;
+ unsigned char g_b_a_limit;
+ unsigned char base_31_24;
+ };
+
+#define RUN 0 /* not really 0, but filled in at boot time */
+
+struct seg_desc Gdt[] = {
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* 0x0 : null */
+ {0xFFFF, 0x0, 0x0, 0x9F, 0xCF, 0x0}, /* 0x08 : kernel code */
+ /* 0x9E? */
+ {0xFFFF, 0x0, 0x0, 0x93, 0xCF, 0x0}, /* 0x10 : kernel data */
+ /* 0x92? */
+ {0xFFFF, RUN, RUN, 0x9E, 0x40, 0x0}, /* 0x18 : boot code */
+ {0xFFFF, RUN, RUN, 0x92, 0x40, 0x0}, /* 0x20 : boot data */
+ {0xFFFF, RUN, RUN, 0x9E, 0x0, 0x0}, /* 0x28 : boot code, 16 bits */
+ /* More for bdb. */
+ {}, /* BIOS_CS_INDEX = 6 : null */
+ {}, /* BIOS_TMP_INDEX = 7 : null */
+ {}, /* TSS_INDEX = 8 : null */
+ {0xFFFF, 0x0, 0x0, 0xB2, 0x40, 0x0}, /* DS_286_INDEX = 9 */
+ {0xFFFF, 0x0, 0x0, 0xB2, 0x40, 0x0}, /* ES_286_INDEX = 10 */
+ {}, /* Unused = 11 : null */
+ {0x7FFF, 0x8000, 0xB, 0xB2, 0x40, 0x0}, /* COLOR_INDEX = 12 */
+ {0x7FFF, 0x0, 0xB, 0xB2, 0x40, 0x0}, /* MONO_INDEX = 13 */
+ {0xFFFF, RUN, RUN, 0x9A, 0x40, 0x0}, /* DB_CS_INDEX = 14 */
+ {0xFFFF, RUN, RUN, 0x9A, 0x0, 0x0}, /* DB_CS16_INDEX = 15 */
+ {0xFFFF, RUN, RUN, 0x92, 0x40, 0x0}, /* DB_DS_INDEX = 16 */
+ {8*18-1, RUN, RUN, 0x92, 0x40, 0x0}, /* GDT_INDEX = 17 */
+};
+
+struct idt_desc {
+ unsigned short entry_15_0;
+ unsigned short selector;
+ unsigned char padding;
+ unsigned char p_dpl_type;
+ unsigned short entry_31_16;
+};
+
+struct idt_desc Idt[] = {
+ {}, /* Null (int 0) */
+ {RUN, 0x70, 0, 0x8E, 0}, /* DEBUG_VECTOR = 1 */
+ {}, /* Null (int 2) */
+ {RUN, 0x70, 0, 0xEE, 0}, /* BREAKPOINT_VECTOR = 3 */
+};
+
+struct pseudo_desc {
+ unsigned short limit;
+ unsigned short base_low;
+ unsigned short base_high;
+ };
+
+struct pseudo_desc Gdtr = { sizeof Gdt - 1, RUN, RUN };
+struct pseudo_desc Idtr_prot = { sizeof Idt - 1, RUN, RUN };
+struct pseudo_desc Idtr_real = { 0x400 - 1, 0x0, 0x0 };
diff --git a/sys/i386/conf/GENERICAH b/sys/i386/conf/GENERICAH
new file mode 100644
index 0000000..c1a00df
--- /dev/null
+++ b/sys/i386/conf/GENERICAH
@@ -0,0 +1,90 @@
+#
+# GENERICAH -- Generic machine with WD/AHx family disks
+#
+# $Id: GENERICAH,v 1.32 1994/05/19 10:55:32 jkh Exp $
+#
+
+machine "i386"
+cpu "I386_CPU"
+cpu "I486_CPU"
+ident GENERICAH
+timezone 8 dst
+maxusers 10
+maxfdescs 2048 #Max file descriptors per process
+options MATH_EMULATE #Support for x87 emulation
+options INET #InterNETworking
+options ISOFS #ISO File System
+options NFS #Network File System
+options PCFS #MSDOS File System
+options "COMPAT_43" #Compatible with BSD 4.3
+options "TCP_COMPAT_42" #TCP/IP compatible with 4.2
+options XSERVER #Xserver
+options UCONSOLE #X Console support
+options "FAT_CURSOR" #block cursor in syscons or pccons
+#options GATEWAY #Host is a Gateway (forwards packets)
+options "SCSI_DELAY=15" #Be pessimistic about Joe SCSI device
+options "NCONS=4" #4 virtual consoles
+options "STAR_SAVER" #syscons "stars" screen saver
+
+config "386bsd" root on wd0 swap on wd0 and wd1 and sd0 and sd1 dumps on wd0
+
+controller isa0
+
+controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
+disk fd0 at fdc0 drive 0
+disk fd1 at fdc0 drive 1
+#tape ft0 at fdc0 drive 2
+
+controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr
+disk wd0 at wdc0 drive 0
+disk wd1 at wdc0 drive 1
+
+controller wdc1 at isa? port "IO_WD2" bio irq 15 vector wdintr
+disk wd2 at wdc1 drive 0
+disk wd3 at wdc1 drive 1
+
+controller ahb0 at isa? bio irq 11 vector ahbintr
+controller aha0 at isa? port "IO_AHA0" bio irq 11 drq 5 vector ahaintr
+controller scbus0
+
+device sd0
+device sd1
+device sd2
+device sd3
+
+device st0
+device st1
+
+device cd0 #Only need one of these, the code dynamically grows
+
+device wt0 at isa? port 0x300 bio irq 5 drq 1 vector wtintr
+device mcd0 at isa? port 0x300 bio irq 10 vector mcdintr
+device mcd1 at isa? port 0x340 bio irq 11 vector mcdintr
+
+device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr
+device npx0 at isa? port "IO_NPX" irq 13 vector npxintr
+
+device sio0 at isa? port "IO_COM1" tty irq 4 vector siointr
+device sio1 at isa? port "IO_COM2" tty irq 3 vector siointr
+device sio2 at isa? port "IO_COM3" tty irq 5 vector siointr
+device sio3 at isa? port "IO_COM4" tty irq 9 vector siointr
+
+device lpt0 at isa? port? tty irq 7 vector lptintr
+device lpt1 at isa? port? tty
+device lpt2 at isa? port? tty
+
+device ed0 at isa? port 0x280 net irq 5 iomem 0xd8000 vector edintr
+device ed1 at isa? port 0x300 net irq 5 iomem 0xd8000 vector edintr
+device ie0 at isa? port 0x360 net irq 7 iomem 0xd0000 vector ieintr
+device is0 at isa? port 0x280 net irq 10 drq 7 vector isintr
+
+pseudo-device loop
+pseudo-device ether
+pseudo-device log
+pseudo-device sl 2
+pseudo-device pty 16
+pseudo-device speaker
+
+pseudo-device swappager
+pseudo-device vnodepager
+pseudo-device devpager
diff --git a/sys/i386/conf/GENERICBT b/sys/i386/conf/GENERICBT
new file mode 100644
index 0000000..85f80de
--- /dev/null
+++ b/sys/i386/conf/GENERICBT
@@ -0,0 +1,90 @@
+#
+# GENERICBT -- Generic machine with WD/BTx family disks
+#
+# $Id: GENERICBT,v 1.32 1994/05/19 10:55:34 jkh Exp $
+#
+
+machine "i386"
+cpu "I386_CPU"
+cpu "I486_CPU"
+ident GENERICBT
+timezone 8 dst
+maxusers 10
+maxfdescs 2048 #Max file descriptors per process
+options MATH_EMULATE #Support for x87 emulation
+options INET #InterNETworking
+options ISOFS #ISO File System
+options NFS #Network File System
+options PCFS #MSDOS File System
+options "COMPAT_43" #Compatible with BSD 4.3
+options "TCP_COMPAT_42" #TCP/IP compatible with 4.2
+options XSERVER #Xserver
+options UCONSOLE #X Console support
+options "FAT_CURSOR" #block cursor in syscons or pccons
+#options GATEWAY #Host is a Gateway (forwards packets)
+options "NCONS=4" #4 virtual consoles
+options "STAR_SAVER" #syscons "stars" screen saver
+options "SCSI_DELAY=15" #Be pessimistic about Joe SCSI device
+
+config "386bsd" root on wd0 swap on wd0 and wd1 and sd0 and sd1 dumps on wd0
+
+controller isa0
+
+controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
+disk fd0 at fdc0 drive 0
+disk fd1 at fdc0 drive 1
+#tape ft0 at fdc0 drive 2
+
+controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr
+disk wd0 at wdc0 drive 0
+disk wd1 at wdc0 drive 1
+
+controller wdc1 at isa? port "IO_WD2" bio irq 15 vector wdintr
+disk wd2 at wdc1 drive 0
+disk wd3 at wdc1 drive 1
+
+controller bt0 at isa? port "IO_BT0" bio irq 12 vector btintr
+controller uha0 at isa? port "IO_UHA0" bio irq 14 drq 5 vector uhaintr
+controller scbus0
+
+device sd0
+device sd1
+device sd2
+device sd3
+
+device st0
+device st1
+
+device cd0 #Only need one of these, the code dynamically grows
+
+device wt0 at isa? port 0x300 bio irq 5 drq 1 vector wtintr
+device mcd0 at isa? port 0x300 bio irq 10 vector mcdintr
+device mcd1 at isa? port 0x340 bio irq 11 vector mcdintr
+
+device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr
+device npx0 at isa? port "IO_NPX" irq 13 vector npxintr
+
+device sio0 at isa? port "IO_COM1" tty irq 4 vector siointr
+device sio1 at isa? port "IO_COM2" tty irq 3 vector siointr
+device sio2 at isa? port "IO_COM3" tty irq 5 vector siointr
+device sio3 at isa? port "IO_COM4" tty irq 9 vector siointr
+
+device lpt0 at isa? port? tty irq 7 vector lptintr
+device lpt1 at isa? port? tty
+device lpt2 at isa? port? tty
+
+device ed0 at isa? port 0x280 net irq 5 iomem 0xd8000 vector edintr
+device ed1 at isa? port 0x300 net irq 5 iomem 0xd8000 vector edintr
+device ie0 at isa? port 0x360 net irq 7 iomem 0xd0000 vector ieintr
+device is0 at isa? port 0x280 net irq 10 drq 7 vector isintr
+
+pseudo-device loop
+pseudo-device ether
+pseudo-device log
+pseudo-device sl 2
+pseudo-device pty 16
+pseudo-device speaker
+
+pseudo-device swappager
+pseudo-device vnodepager
+pseudo-device devpager
diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT
new file mode 100644
index 0000000..90c79b8
--- /dev/null
+++ b/sys/i386/conf/LINT
@@ -0,0 +1,197 @@
+#
+# LINT -- config file for checking all the sources, tries to pull in
+# as much of the source tree as it can.
+#
+# This kernel is NOT MEANT to be runnable!
+#
+# $Id: LINT,v 1.70 1994/05/17 23:20:32 jkh Exp $
+#
+
+machine "i386"
+cpu "I386_CPU"
+cpu "I486_CPU"
+ident LINT
+timezone 8 dst
+maxusers 10
+maxfdescs 2048 #Max file descriptors per process
+options MATH_EMULATE #Support for x87 emulation
+
+# Do not use in binary distributions
+#options GPL_MATH_EMULATE #Support for x87 emualtion via
+ #new math emulator
+
+config "386bsd" root on wd0 swap on wd0 and sd0 dumps on wd0
+
+#
+# options that appear as inline #ifdef's
+#
+options "COM_BIDIR" #Bidirectional support in sys/isa/sio.c
+options "COM_MULTIPORT" #Multiport support in sys/isa/sio.c
+options "FIFO_TRIGGER=FIFO_TRIGGER_1" #Use this fifo value in sio.c
+
+options "COMPAT_43" #compatible with BSD 4.3
+options "SYMTAB_SPACE=113498" #This kernel needs LOTS of symtable
+options GATEWAY #internetwork gateway
+options KTRACE #kernel tracing
+
+options "NCONS=8" #number of syscons virtual consoles
+options "FAT_CURSOR" #block cursor in syscons or pccons
+options "STAR_SAVER" #syscons "stars" screen saver
+options "FADE_SAVER" #syscons "fade" screen saver
+options "SNAKE_SAVER" #syscons "snake" screen saver
+options "BLANK_SAVER" #syscons "blank" screen saver
+
+#options ALLOW_CONFLICT_IOADDR #no IO addr conflict checks (PS/2 mice)
+#options ALLOW_CONFLICT_IRQ #no IRQ conflict checks (mport serial)
+
+options "TCP_COMPAT_42" #tcp/ip compatible with 4.2
+ # ^^^ NOT RECOMMENDED FOR NORMAL USE
+options UCONSOLE #x console support
+options XSERVER #xserver
+options DECBIT #here because clnp.h wanted it here
+ #support for CLNP ``congestion
+ #experienced'' bit in ISO-TP
+options TROLL #CLNP network error simulator
+options ICMPPRINTFS #ICMP packet dump by printf()
+options NSERRPRINTFS #ditto for XNS Error protocol
+ #^^above three NOT RECOMMENTED
+options FASTLINKS #support for fast symbolic links
+options MACHVMCOMPAT #support for Mach-style vm calls
+options IPBROADCASTECHO=1 #send reply to broadcast pings
+options IPMASKAGENT=1 #send reply to icmp mask requests
+options TPCONS #support X.25 network-layer service
+options USER_LDT #allow user-level control of i386 ldt
+
+# See /sys/i386/doc/sound.doc for information about EXCLUDE options for
+# the sound drivers.
+
+# Multicast support.
+options MULTICAST # Multicast code
+options MROUTING # Multicast routing
+
+#
+# options that are in sys/conf/files
+#
+pseudo-device bpfilter 4 #berkeley packet filter
+options CCITT
+device cd0 #Only need one of these, the code dynamically grows
+device ch0
+pseudo-device ddb
+pseudo-device devpager
+options EON
+pseudo-device ether
+options FIFO
+#pseudo-device imp
+options INET #Internet communications protocols
+options ISO
+options ISOFS #ISO 9660 File System
+pseudo-device loop
+options MFS #Memory File System
+options NFS #Network File System
+options NS #Xerox NS communications protocols
+options NSIP #XNS over IP
+options PCFS #PC (MSDOS) File System
+pseudo-device ppp 2
+pseudo-device pty 4
+options QUOTA #enable disk quotas
+options RMP #HP remote maint protocol
+controller scbus0
+device sd0
+device sd1
+device sd2
+device sd3
+pseudo-device sl 2
+device st0
+device st1
+pseudo-device swappager
+options SYSVSHM
+options "SHMMAXPGS=64" # 256Kb of sharable memory
+options SYSVSEM
+options SYSVMSG
+#pseudo-device tb #tablet line discipline.
+options TPIP # ISO TP class 4 over IP
+#pseudo-device tun
+device uk0 #unknown scsi devices
+pseudo-device vnodepager
+
+#
+# options that are in sys/i386/conf/files.i386
+#
+#This is needed here so the isa? below will work
+controller isa0
+
+# driver for the Adaptec 154x SCSI cards.
+controller aha0 at isa? port "IO_AHA0" bio irq 11 drq 5 vector ahaintr
+# driver for the Adaptec 174x SCSI cards.
+controller ahb0 at isa? bio irq 11 vector ahbintr
+# driver for the Bustek 742.
+controller bt0 at isa? port "IO_BT0" bio irq 12 vector btintr
+# driver for the Seagate ST01/ST02 card, not yet finished.
+#controller sg0 at isa? bio irq 5 iomem 0xc8000 iosiz 0x2000 vector sgintr
+controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
+disk fd0 at fdc0 drive 0
+disk fd1 at fdc0 drive 1
+tape ft0 at fdc0 drive 2
+
+# driver for the Western Digital and SMCC WD80xx cards, for the Novell
+# NE1000/2000 card and the 3COM 3C503 card.
+device ed0 at isa? port 0x280 net irq 5 iomem 0xd8000 vector edintr
+# driver for the AT&T Starlan card.
+device ie0 at isa? port 0x360 net irq 7 iomem 0xd0000 vector ieintr
+#driver for the Isolan AT 4114-0 and the Isolink 4110 ethernet card.
+device is0 at isa? port 0x280 net irq 10 drq 7 vector isintr
+#device ix0 at isa? port 0x320 net irq 10 iomem 0xd0000 iosiz 32768 vector ixintr
+# driver for the Etherlink III ( 3C509 ) card, beta version.
+device ep0 at isa? port 0x300 net irq 10 vector epintr
+#driver for the 3c501
+device el0 at isa? port 0x300 net irq 9 vector elintr
+
+#special cased above:
+#controller isa0
+# interruptless parallel printer port driver
+device lpa0 at isa? port "IO_LPT1" tty
+device lpa1 at isa? port "IO_LPT2" tty
+# interrupt driven parallel printer port driver
+device lpt0 at isa? port "IO_LPT3" tty irq 7 vector lptintr
+# Driver for Mitsumi CD-ROM players
+device mcd0 at isa? port 0x300 bio irq 10 vector mcdintr
+# Driver for Logitech and ATI inport bus mice
+device mse0 at isa? port 0x23c tty irq 5 vector mseintr
+device npx0 at isa? port "IO_NPX" irq 13 vector npxintr
+device pc0 at isa? port "IO_KBD" tty irq 1 vector pcrint
+#only one of pc0 or sc0 allowed
+#device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr
+device sio0 at isa? port "IO_COM1" tty irq 4 vector siointr
+device sio1 at isa? port "IO_COM2" tty irq 3 vector siointr
+device sio2 at isa? port "IO_COM3" tty irq 5 vector siointr
+device sio3 at isa? port "IO_COM4" tty irq 9 vector siointr
+#PS/2 mouse driver (must follow pc0 or sc0 if enabled). Also enable
+#ALLOW_CONFLICT_IOADDR option (see above) if you want to use this.
+#device psm0 at isa? port "IO_KBD" tty irq 12 vector psmintr
+
+pseudo-device speaker
+#tw device-driver
+controller uha0 at isa? port "IO_UHA0" bio irq 14 drq 5 vector uhaintr
+controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr
+disk wd0 at wdc0 drive 0
+disk wd1 at wdc0 drive 1
+controller wdc1 at isa? port "IO_WD2" bio irq 15 vector wdintr
+disk wd2 at wdc1 drive 0
+disk wd3 at wdc1 drive 1
+device wt0 at isa? port 0x300 bio irq 5 drq 1 vector wtintr
+
+# Various sound card drivers.
+# See /sys/doc/sound.doc for more information.
+device snd5 at isa? port 0x330 irq 6 vector mpuintr
+device snd4 at isa? port 0x220 irq 15 drq 6 vector gusintr
+device snd3 at isa? port 0x388 irq 10 drq 6 vector pasintr
+device snd2 at isa? port 0x220 irq 7 drq 1 vector sbintr
+device snd6 at isa? port 0x220 irq 7 drq 5 vector sbintr
+device snd7 at isa? port 0x300
+device snd1 at isa? port 0x388
+
+# The digital speaker driver (/dev/pcaudio).
+device pca0 at isa? tty
+
+# options that have not been resolved yet
+pseudo-device log
diff --git a/sys/i386/conf/Makefile.i386 b/sys/i386/conf/Makefile.i386
new file mode 100644
index 0000000..db28a34
--- /dev/null
+++ b/sys/i386/conf/Makefile.i386
@@ -0,0 +1,179 @@
+# Copyright 1990 W. Jolitz
+# from: @(#)Makefile.i386 7.1 5/10/91
+# $Id: Makefile.i386,v 1.23 1994/03/21 20:48:47 ats Exp $
+#
+# Makefile for FreeBSD
+#
+# This makefile is constructed from a machine description:
+# config machineid
+# Most changes should be made in the machine description
+# /sys/i386/conf/``machineid''
+# after which you should do
+# config machineid
+# Generic makefile changes should be made in
+# /sys/i386/conf/Makefile.i386
+# after which config should be rerun for all machines.
+#
+# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE INVISIBLE TO MAKEFILE
+# IF YOU CHANGE THE DEFINITION OF ANY OF THESE RECOMPILE EVERYTHING
+#
+# -DTRACE compile in kernel tracing hooks
+# -DQUOTA compile in file system quotas
+#
+TOUCH= touch -f -c
+LD= /usr/bin/ld
+CC= cc
+CPP= cpp
+STRIP= strip
+DBSYM= /usr/sbin/dbsym
+
+S= ../..
+I386= ../../i386
+
+CWARNFLAGS=-W -Wreturn-type -Wcomment
+#
+# The following flags are next up for working on:
+# -Wredundant-decls -Wnested-externs
+#
+# When working on removing warnings from code, the `-Werror' flag should be
+# of material assistance.
+#
+COPTFLAGS=-O
+COPTFLAGS+=-D__FreeBSD__
+INCLUDES= -I. -I$S -I$S/sys
+COPTS= ${INCLUDES} ${IDENT} -DKERNEL -Di386 -DNPX
+ASFLAGS=
+CFLAGS= ${COPTFLAGS} ${CWARNFLAGS} ${DEBUG} ${COPTS}
+LOAD_ADDRESS?= F0100000
+
+NORMAL_C= ${CC} -c ${CFLAGS} ${PROF} $<
+NORMAL_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $<
+NORMAL_S= ${CPP} -I. -DLOCORE ${COPTS} $< | ${AS} ${ASFLAGS} -o $*.o
+DRIVER_C= ${CC} -c ${CFLAGS} ${PROF} $<
+DRIVER_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $<
+SYSTEM_OBJS=locore.o exception.o swtch.o support.o ${OBJS} param.o \
+ ioconf.o conf.o machdep.o
+SYSTEM_DEP=Makefile symbols.sort ${SYSTEM_OBJS}
+SYSTEM_LD_HEAD= @echo loading $@; rm -f $@
+SYSTEM_LD= @${LD} -Bstatic -Z -T ${LOAD_ADDRESS} -o $@ -X ${SYSTEM_OBJS} vers.o
+SYSTEM_LD_TAIL= @echo rearranging symbols; symorder symbols.sort $@; \
+ ${DBSYM} -fT ${LOAD_ADDRESS} $@; ${STRIP} -x $@; size $@; chmod 755 $@
+
+# (XXX) ok, this is weird. but we've got a working ed, and a broken ex, and
+# the script is identical for either... -- cgd
+#
+GPROF.EX= /usr/src/lib/csu.i386/gprof.ex
+PROFILE_C= ${CC} -S -c ${CFLAGS} $< ; \
+ ed - $*.s < ${GPROF.EX} ; \
+ ${AS} -o $@ $*.s ; \
+ rm -f $*.s
+
+%OBJS
+
+%CFILES
+
+%LOAD
+
+clean:
+ rm -f eddep *386bsd tags *.o locore.i [a-uw-z]*.s \
+ errs linterrs makelinks genassym ,assym.s stamp-assym
+
+#lint: /tmp param.c
+# @lint -hbxn -I. -DGENERIC -Dvolatile= ${COPTS} ${PARAM} \
+# ${I386}/i386/Locore.c ${CFILES} ioconf.c param.c | \
+# grep -v 'struct/union .* never defined' | \
+# grep -v 'possible pointer alignment problem'
+
+symbols.sort: ${I386}/i386/symbols.raw
+ grep -v '^#' ${I386}/i386/symbols.raw \
+ | sed 's/^ //' | sort -u > symbols.sort
+
+locore.o: assym.s ${I386}/i386/locore.s machine/trap.h machine/psl.h \
+ machine/pte.h ${I386}/isa/vector.s ${I386}/isa/icu.s \
+ $S/sys/errno.h machine/specialreg.h \
+ ${I386}/isa/icu.h ${I386}/isa/isa.h vector.h $S/net/netisr.h \
+ machine/asmacros.h
+ ${CPP} -I. -DLOCORE ${COPTS} ${I386}/i386/locore.s | \
+ ${AS} ${ASFLAGS} -o locore.o
+
+exception.o: assym.s ${I386}/i386/exception.s machine/trap.h \
+ ${I386}/isa/vector.s ${I386}/isa/icu.s \
+ $S/sys/errno.h ${I386}/isa/icu.h ${I386}/isa/isa.h vector.h \
+ $S/net/netisr.h machine/asmacros.h
+ ${CPP} -I. -DLOCORE ${COPTS} ${I386}/i386/exception.s | \
+ ${AS} ${ASFLAGS} -o exception.o
+
+swtch.o: assym.s ${I386}/i386/swtch.s \
+ $S/sys/errno.h machine/asmacros.h
+ ${CPP} -I. ${COPTS} ${I386}/i386/swtch.s | \
+ ${AS} ${ASFLAGS} -o swtch.o
+
+support.o: assym.s ${I386}/i386/support.s \
+ $S/sys/errno.h machine/asmacros.h
+ ${CPP} -I. ${COPTS} ${I386}/i386/support.s | \
+ ${AS} ${ASFLAGS} -o support.o
+
+machdep.o: ${I386}/i386/machdep.c Makefile
+ ${CC} -c ${CFLAGS} -DLOAD_ADDRESS=0x${LOAD_ADDRESS} ${PROF} $<
+
+# the following is necessary because autoconf.o depends on #if GENERIC
+autoconf.o: Makefile
+
+# depend on network configuration
+af.o uipc_proto.o locore.o: Makefile
+
+# depends on KDB (cons.o also depends on GENERIC)
+trap.o cons.o: Makefile
+
+assym.s: genassym
+ ./genassym >,assym.s
+ if cmp -s assym.s ,assym.s; then \
+ rm -f ,assym.s; \
+ else \
+ rm -f assym.s; \
+ mv ,assym.s assym.s; \
+ fi
+
+# Some of the defines that genassym outputs may well depend on the
+# value of kernel options.
+genassym: Makefile
+ ${CC} ${INCLUDES} -DKERNEL ${IDENT} ${PARAM} \
+ ${I386}/i386/genassym.c -static -o genassym
+
+depend: assym.s param.c
+ sh /usr/bin/mkdep -DLOAD_ADDRESS=0x${LOAD_ADDRESS} ${COPTS} ${CFILES} ioconf.c param.c ${I386}/i386/conf.c
+ sh /usr/bin/mkdep -a -p ${INCLUDES} ${IDENT} ${PARAM} ${I386}/i386/genassym.c
+
+links:
+ egrep '#if' ${CFILES} | sed -f $S/conf/defines | \
+ sed -e 's/:.*//' -e 's/\.c/.o/' | sort -u > dontlink
+ echo ${CFILES} | tr -s ' ' '\12' | sed 's/\.c/.o/' | \
+ sort -u | comm -23 - dontlink | \
+ sed 's,../.*/\(.*.o\),rm -f \1;ln -s ../GENERIC/\1 \1,' > makelinks
+ sh makelinks && rm -f dontlink
+
+tags:
+ @echo "see $S/kern/Makefile for tags"
+
+ioconf.o: ioconf.c $S/sys/param.h machine/pte.h $S/sys/buf.h \
+ ${I386}/isa/isa_device.h ${I386}/isa/isa.h ${I386}/isa/icu.h
+ ${CC} -c ${CFLAGS} ioconf.c
+
+conf.o: ${I386}/i386/conf.c $S/sys/conf.h
+ ${CC} -c ${CFLAGS} ${I386}/i386/conf.c
+
+param.c: $S/conf/param.c
+ -rm -f param.c
+ cp $S/conf/param.c .
+
+param.o: param.c Makefile
+ ${CC} -c ${CFLAGS} ${PARAM} param.c
+
+vers.o: ${SYSTEM_DEP} ${SYSTEM_SWAP_DEP}
+ sh $S/conf/newvers.sh ${KERN_IDENT} ${IDENT}
+ ${CC} ${CFLAGS} -c vers.c
+
+%RULES
+
+# DO NOT DELETE THIS LINE -- make depend uses it
+
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
new file mode 100644
index 0000000..90c79b8
--- /dev/null
+++ b/sys/i386/conf/NOTES
@@ -0,0 +1,197 @@
+#
+# LINT -- config file for checking all the sources, tries to pull in
+# as much of the source tree as it can.
+#
+# This kernel is NOT MEANT to be runnable!
+#
+# $Id: LINT,v 1.70 1994/05/17 23:20:32 jkh Exp $
+#
+
+machine "i386"
+cpu "I386_CPU"
+cpu "I486_CPU"
+ident LINT
+timezone 8 dst
+maxusers 10
+maxfdescs 2048 #Max file descriptors per process
+options MATH_EMULATE #Support for x87 emulation
+
+# Do not use in binary distributions
+#options GPL_MATH_EMULATE #Support for x87 emualtion via
+ #new math emulator
+
+config "386bsd" root on wd0 swap on wd0 and sd0 dumps on wd0
+
+#
+# options that appear as inline #ifdef's
+#
+options "COM_BIDIR" #Bidirectional support in sys/isa/sio.c
+options "COM_MULTIPORT" #Multiport support in sys/isa/sio.c
+options "FIFO_TRIGGER=FIFO_TRIGGER_1" #Use this fifo value in sio.c
+
+options "COMPAT_43" #compatible with BSD 4.3
+options "SYMTAB_SPACE=113498" #This kernel needs LOTS of symtable
+options GATEWAY #internetwork gateway
+options KTRACE #kernel tracing
+
+options "NCONS=8" #number of syscons virtual consoles
+options "FAT_CURSOR" #block cursor in syscons or pccons
+options "STAR_SAVER" #syscons "stars" screen saver
+options "FADE_SAVER" #syscons "fade" screen saver
+options "SNAKE_SAVER" #syscons "snake" screen saver
+options "BLANK_SAVER" #syscons "blank" screen saver
+
+#options ALLOW_CONFLICT_IOADDR #no IO addr conflict checks (PS/2 mice)
+#options ALLOW_CONFLICT_IRQ #no IRQ conflict checks (mport serial)
+
+options "TCP_COMPAT_42" #tcp/ip compatible with 4.2
+ # ^^^ NOT RECOMMENDED FOR NORMAL USE
+options UCONSOLE #x console support
+options XSERVER #xserver
+options DECBIT #here because clnp.h wanted it here
+ #support for CLNP ``congestion
+ #experienced'' bit in ISO-TP
+options TROLL #CLNP network error simulator
+options ICMPPRINTFS #ICMP packet dump by printf()
+options NSERRPRINTFS #ditto for XNS Error protocol
+ #^^above three NOT RECOMMENTED
+options FASTLINKS #support for fast symbolic links
+options MACHVMCOMPAT #support for Mach-style vm calls
+options IPBROADCASTECHO=1 #send reply to broadcast pings
+options IPMASKAGENT=1 #send reply to icmp mask requests
+options TPCONS #support X.25 network-layer service
+options USER_LDT #allow user-level control of i386 ldt
+
+# See /sys/i386/doc/sound.doc for information about EXCLUDE options for
+# the sound drivers.
+
+# Multicast support.
+options MULTICAST # Multicast code
+options MROUTING # Multicast routing
+
+#
+# options that are in sys/conf/files
+#
+pseudo-device bpfilter 4 #berkeley packet filter
+options CCITT
+device cd0 #Only need one of these, the code dynamically grows
+device ch0
+pseudo-device ddb
+pseudo-device devpager
+options EON
+pseudo-device ether
+options FIFO
+#pseudo-device imp
+options INET #Internet communications protocols
+options ISO
+options ISOFS #ISO 9660 File System
+pseudo-device loop
+options MFS #Memory File System
+options NFS #Network File System
+options NS #Xerox NS communications protocols
+options NSIP #XNS over IP
+options PCFS #PC (MSDOS) File System
+pseudo-device ppp 2
+pseudo-device pty 4
+options QUOTA #enable disk quotas
+options RMP #HP remote maint protocol
+controller scbus0
+device sd0
+device sd1
+device sd2
+device sd3
+pseudo-device sl 2
+device st0
+device st1
+pseudo-device swappager
+options SYSVSHM
+options "SHMMAXPGS=64" # 256Kb of sharable memory
+options SYSVSEM
+options SYSVMSG
+#pseudo-device tb #tablet line discipline.
+options TPIP # ISO TP class 4 over IP
+#pseudo-device tun
+device uk0 #unknown scsi devices
+pseudo-device vnodepager
+
+#
+# options that are in sys/i386/conf/files.i386
+#
+#This is needed here so the isa? below will work
+controller isa0
+
+# driver for the Adaptec 154x SCSI cards.
+controller aha0 at isa? port "IO_AHA0" bio irq 11 drq 5 vector ahaintr
+# driver for the Adaptec 174x SCSI cards.
+controller ahb0 at isa? bio irq 11 vector ahbintr
+# driver for the Bustek 742.
+controller bt0 at isa? port "IO_BT0" bio irq 12 vector btintr
+# driver for the Seagate ST01/ST02 card, not yet finished.
+#controller sg0 at isa? bio irq 5 iomem 0xc8000 iosiz 0x2000 vector sgintr
+controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
+disk fd0 at fdc0 drive 0
+disk fd1 at fdc0 drive 1
+tape ft0 at fdc0 drive 2
+
+# driver for the Western Digital and SMCC WD80xx cards, for the Novell
+# NE1000/2000 card and the 3COM 3C503 card.
+device ed0 at isa? port 0x280 net irq 5 iomem 0xd8000 vector edintr
+# driver for the AT&T Starlan card.
+device ie0 at isa? port 0x360 net irq 7 iomem 0xd0000 vector ieintr
+#driver for the Isolan AT 4114-0 and the Isolink 4110 ethernet card.
+device is0 at isa? port 0x280 net irq 10 drq 7 vector isintr
+#device ix0 at isa? port 0x320 net irq 10 iomem 0xd0000 iosiz 32768 vector ixintr
+# driver for the Etherlink III ( 3C509 ) card, beta version.
+device ep0 at isa? port 0x300 net irq 10 vector epintr
+#driver for the 3c501
+device el0 at isa? port 0x300 net irq 9 vector elintr
+
+#special cased above:
+#controller isa0
+# interruptless parallel printer port driver
+device lpa0 at isa? port "IO_LPT1" tty
+device lpa1 at isa? port "IO_LPT2" tty
+# interrupt driven parallel printer port driver
+device lpt0 at isa? port "IO_LPT3" tty irq 7 vector lptintr
+# Driver for Mitsumi CD-ROM players
+device mcd0 at isa? port 0x300 bio irq 10 vector mcdintr
+# Driver for Logitech and ATI inport bus mice
+device mse0 at isa? port 0x23c tty irq 5 vector mseintr
+device npx0 at isa? port "IO_NPX" irq 13 vector npxintr
+device pc0 at isa? port "IO_KBD" tty irq 1 vector pcrint
+#only one of pc0 or sc0 allowed
+#device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr
+device sio0 at isa? port "IO_COM1" tty irq 4 vector siointr
+device sio1 at isa? port "IO_COM2" tty irq 3 vector siointr
+device sio2 at isa? port "IO_COM3" tty irq 5 vector siointr
+device sio3 at isa? port "IO_COM4" tty irq 9 vector siointr
+#PS/2 mouse driver (must follow pc0 or sc0 if enabled). Also enable
+#ALLOW_CONFLICT_IOADDR option (see above) if you want to use this.
+#device psm0 at isa? port "IO_KBD" tty irq 12 vector psmintr
+
+pseudo-device speaker
+#tw device-driver
+controller uha0 at isa? port "IO_UHA0" bio irq 14 drq 5 vector uhaintr
+controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr
+disk wd0 at wdc0 drive 0
+disk wd1 at wdc0 drive 1
+controller wdc1 at isa? port "IO_WD2" bio irq 15 vector wdintr
+disk wd2 at wdc1 drive 0
+disk wd3 at wdc1 drive 1
+device wt0 at isa? port 0x300 bio irq 5 drq 1 vector wtintr
+
+# Various sound card drivers.
+# See /sys/doc/sound.doc for more information.
+device snd5 at isa? port 0x330 irq 6 vector mpuintr
+device snd4 at isa? port 0x220 irq 15 drq 6 vector gusintr
+device snd3 at isa? port 0x388 irq 10 drq 6 vector pasintr
+device snd2 at isa? port 0x220 irq 7 drq 1 vector sbintr
+device snd6 at isa? port 0x220 irq 7 drq 5 vector sbintr
+device snd7 at isa? port 0x300
+device snd1 at isa? port 0x388
+
+# The digital speaker driver (/dev/pcaudio).
+device pca0 at isa? tty
+
+# options that have not been resolved yet
+pseudo-device log
diff --git a/sys/i386/conf/SYSCONS b/sys/i386/conf/SYSCONS
new file mode 100644
index 0000000..5c1fb04
--- /dev/null
+++ b/sys/i386/conf/SYSCONS
@@ -0,0 +1,87 @@
+#
+# SYSCONS -- Generic machine with WD/AHx family disks and syscons
+#
+# $Id: SYSCONS,v 1.20 1994/03/01 01:27:03 alm Exp $
+#
+
+machine "i386"
+cpu "I386_CPU"
+cpu "I486_CPU"
+ident SYSCONS
+timezone 8 dst
+maxusers 10
+maxfdescs 2048 #Max file descriptors per process
+options MATH_EMULATE #Support for x87 emulation
+options INET #InterNETworking
+options ISOFS #ISO File System
+options NFS #Network File System
+options PCFS #MSDOS File System
+options "COMPAT_43" #Compatible with BSD 4.3
+options "TCP_COMPAT_42" #TCP/IP compatible with 4.2
+options XSERVER #Xserver
+options UCONSOLE #X Console support
+options "NCONS=8" #8 virtual consoles
+options "FAT_CURSOR" #block cursor in syscons
+options "STAR_SAVER" #syscons "stars" screen saver
+#options GATEWAY #Host is a Gateway (forwards packets)
+
+config "386bsd" root on wd0 swap on wd0 and sd0 dumps on wd0
+
+controller isa0
+
+controller fdc0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
+disk fd0 at fdc0 drive 0
+disk fd1 at fdc0 drive 1
+#tape ft0 at fdc0 drive 2
+
+controller wdc0 at isa? port "IO_WD1" bio irq 14 vector wdintr
+disk wd0 at wdc0 drive 0
+disk wd1 at wdc0 drive 1
+
+controller wdc1 at isa? port "IO_WD2" bio irq 15 vector wdintr
+disk wd2 at wdc1 drive 0
+disk wd3 at wdc1 drive 1
+
+controller ahb0 at isa? bio irq 11 vector ahbintr
+controller aha0 at isa? port "IO_AHA0" bio irq 11 drq 5 vector ahaintr
+controller scbus0
+
+device sd0
+device sd1
+device sd2
+device sd3
+
+device st0
+device st1
+
+device cd0 #Only need one of these, the code dynamically grows
+
+device sc0 at isa? port "IO_KBD" tty irq 1 vector scintr
+device npx0 at isa? port "IO_NPX" irq 13 vector npxintr
+
+device sio0 at isa? port "IO_COM1" tty irq 4 vector siointr
+device sio1 at isa? port "IO_COM2" tty irq 3 vector siointr
+device sio2 at isa? port "IO_COM3" tty irq 5 vector siointr
+device sio3 at isa? port "IO_COM4" tty irq 9 vector siointr
+
+device lpt0 at isa? port "IO_LPT3" tty irq 7 vector lptintr
+device lpa0 at isa? port "IO_LPT1" tty
+device lpa1 at isa? port "IO_LPT2" tty
+
+device ed0 at isa? port 0x280 net irq 5 iomem 0xd8000 vector edintr
+device ed1 at isa? port 0x300 net irq 5 iomem 0xd8000 vector edintr
+device ie0 at isa? port 0x360 net irq 7 iomem 0xd0000 vector ieintr
+device is0 at isa? port 0x280 net irq 10 drq 7 vector isintr
+
+device wt0 at isa? port 0x300 bio irq 5 drq 1 vector wtintr
+
+pseudo-device loop
+pseudo-device ether
+pseudo-device log
+pseudo-device sl 2
+pseudo-device pty 16
+pseudo-device speaker
+
+pseudo-device swappager
+pseudo-device vnodepager
+pseudo-device devpager
diff --git a/sys/i386/conf/devices.i386 b/sys/i386/conf/devices.i386
new file mode 100644
index 0000000..2b3061a
--- /dev/null
+++ b/sys/i386/conf/devices.i386
@@ -0,0 +1,13 @@
+# This file tells what major numbers the various possible swap devices have.
+#
+# $Id: devices.i386,v 1.5 1994/01/04 20:09:28 nate Exp $
+#
+wd 0
+dk 1
+fd 2
+wt 3
+sd 4
+st 5
+cd 6
+mcd 7
+scd 8
diff --git a/sys/i386/conf/files.i386 b/sys/i386/conf/files.i386
new file mode 100644
index 0000000..7aec440
--- /dev/null
+++ b/sys/i386/conf/files.i386
@@ -0,0 +1,116 @@
+# This file tells config what files go into building a kernel,
+# files marked standard are always included.
+#
+# $Id: files.i386,v 1.32 1994/04/29 21:49:02 gclarkii Exp $
+#
+i386/i386/autoconf.c standard device-driver
+i386/i386/cons.c standard
+i386/i386/db_disasm.c optional ddb
+i386/i386/db_interface.c optional ddb
+i386/i386/db_trace.c optional ddb
+i386/i386/in_cksum.c optional inet
+i386/i386/math_emulate.c optional math_emulate
+i386/i386/mem.c standard
+i386/i386/microtime.s standard
+i386/i386/ns_cksum.c optional ns
+i386/i386/pmap.c standard
+i386/i386/sys_machdep.c standard
+i386/i386/trap.c standard
+i386/i386/vm_machdep.c standard
+i386/isa/aha1542.c optional aha device-driver
+i386/isa/aha1742.c optional ahb device-driver
+i386/isa/bt742a.c optional bt device-driver
+i386/isa/clock.c standard
+i386/isa/com.c optional com device-driver
+i386/isa/fd.c optional fd device-driver
+i386/isa/ft.c optional ft device-driver
+i386/isa/if_ed.c optional ed device-driver
+i386/isa/if_el.c optional el device-driver
+i386/isa/if_ep.c optional ep device-driver
+i386/isa/if_ie.c optional ie device-driver
+i386/isa/if_is.c optional is device-driver
+i386/isa/if_ix.c optional ix device-driver
+i386/isa/isa.c optional isa device-driver
+i386/isa/lpa.c optional lpa device-driver
+i386/isa/lpt.c optional lpt device-driver
+i386/isa/mcd.c optional mcd device-driver
+i386/isa/mse.c optional mse device-driver
+i386/isa/npx.c optional npx device-driver
+i386/isa/syscons.c optional sc device-driver
+i386/isa/pccons.c optional pc device-driver
+i386/isa/pcaudio.c optional pca device-driver
+i386/isa/psm.c optional psm device-driver
+i386/isa/sb.c optional sb device-driver
+i386/isa/scd.c optional scd device-driver
+i386/isa/sg.c optional sg device-driver
+i386/isa/sio.c optional sio device-driver
+i386/isa/sound/adlib_card.c optional snd device-driver
+i386/isa/sound/audio.c optional snd device-driver
+i386/isa/sound/dev_table.c optional snd device-driver
+i386/isa/sound/dmabuf.c optional snd device-driver
+i386/isa/sound/gus_card.c optional snd device-driver
+i386/isa/sound/gus_midi.c optional snd device-driver
+i386/isa/sound/gus_vol.c optional snd device-driver
+i386/isa/sound/gus_wave.c optional snd device-driver
+i386/isa/sound/ics2101.c optional snd device-driver
+i386/isa/sound/midi.c optional snd device-driver
+i386/isa/sound/midibuf.c optional snd device-driver
+i386/isa/sound/mpu401.c optional snd device-driver
+i386/isa/sound/opl3.c optional snd device-driver
+i386/isa/sound/pas2_card.c optional snd device-driver
+i386/isa/sound/pas2_midi.c optional snd device-driver
+i386/isa/sound/pas2_mixer.c optional snd device-driver
+i386/isa/sound/pas2_pcm.c optional snd device-driver
+i386/isa/sound/patmgr.c optional snd device-driver
+i386/isa/sound/pro_midi.c optional snd device-driver
+i386/isa/sound/sb16_dsp.c optional snd device-driver
+i386/isa/sound/sb16_midi.c optional snd device-driver
+i386/isa/sound/sb_card.c optional snd device-driver
+i386/isa/sound/sb_dsp.c optional snd device-driver
+i386/isa/sound/sb_midi.c optional snd device-driver
+i386/isa/sound/sb_mixer.c optional snd device-driver
+i386/isa/sound/sequencer.c optional snd device-driver
+i386/isa/sound/sound_switch.c optional snd device-driver
+i386/isa/sound/soundcard.c optional snd device-driver
+i386/isa/spkr.c optional speaker
+i386/isa/tw.c optional tw device-driver
+i386/isa/ultra14f.c optional uha device-driver
+i386/isa/wd.c optional wd device-driver
+i386/isa/wt.c optional wt device-driver
+i386/isa/pcvt/pcvt_drv.c optional vt device-driver
+i386/isa/pcvt/pcvt_sup.c optional vt device-driver
+i386/isa/pcvt/pcvt_out.c optional vt device-driver
+i386/isa/pcvt/pcvt_kbd.c optional vt device-driver
+i386/isa/pcvt/pcvt_vtf.c optional vt device-driver
+i386/isa/pcvt/pcvt_ext.c optional vt device-driver
+gnu/fpemul/div_small.s optional gpl_math_emulate
+gnu/fpemul/errors.c optional gpl_math_emulate
+gnu/fpemul/fpu_arith.c optional gpl_math_emulate
+gnu/fpemul/fpu_aux.c optional gpl_math_emulate
+gnu/fpemul/fpu_entry.c optional gpl_math_emulate
+gnu/fpemul/fpu_etc.c optional gpl_math_emulate
+gnu/fpemul/fpu_trig.c optional gpl_math_emulate
+gnu/fpemul/get_address.c optional gpl_math_emulate
+gnu/fpemul/load_store.c optional gpl_math_emulate
+gnu/fpemul/poly_2xm1.c optional gpl_math_emulate
+gnu/fpemul/poly_atan.c optional gpl_math_emulate
+gnu/fpemul/poly_div.s optional gpl_math_emulate
+gnu/fpemul/poly_l2.c optional gpl_math_emulate
+gnu/fpemul/poly_mul64.s optional gpl_math_emulate
+gnu/fpemul/poly_sin.c optional gpl_math_emulate
+gnu/fpemul/poly_tan.c optional gpl_math_emulate
+gnu/fpemul/polynomial.s optional gpl_math_emulate
+gnu/fpemul/reg_add_sub.c optional gpl_math_emulate
+gnu/fpemul/reg_compare.c optional gpl_math_emulate
+gnu/fpemul/reg_constant.c optional gpl_math_emulate
+gnu/fpemul/reg_div.s optional gpl_math_emulate
+gnu/fpemul/reg_ld_str.c optional gpl_math_emulate
+gnu/fpemul/reg_mul.c optional gpl_math_emulate
+gnu/fpemul/reg_norm.s optional gpl_math_emulate
+gnu/fpemul/reg_round.s optional gpl_math_emulate
+gnu/fpemul/reg_u_add.s optional gpl_math_emulate
+gnu/fpemul/reg_u_div.s optional gpl_math_emulate
+gnu/fpemul/reg_u_mul.s optional gpl_math_emulate
+gnu/fpemul/reg_u_sub.s optional gpl_math_emulate
+gnu/fpemul/wm_shrx.s optional gpl_math_emulate
+gnu/fpemul/wm_sqrt.s optional gpl_math_emulate
diff --git a/sys/i386/eisa/aha1742.c b/sys/i386/eisa/aha1742.c
new file mode 100644
index 0000000..95c0aed
--- /dev/null
+++ b/sys/i386/eisa/aha1742.c
@@ -0,0 +1,1244 @@
+/*
+ * Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems for use under the MACH(2.5) operating system.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ * commenced: Sun Sep 27 18:14:01 PDT 1992
+ *
+ * $Id: aha1742.c,v 1.14 1994/01/11 07:24:32 rgrimes Exp $
+ */
+
+#include <sys/types.h>
+
+#ifdef KERNEL /* don't laugh, it compiles as a program too.. look */
+#include <ahb.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <i386/include/pio.h>
+#include <i386/isa/isa_device.h>
+#endif /*KERNEL */
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+/* */
+
+#ifdef KERNEL
+# ifdef NetBSD
+# ifdef DDB
+int Debugger();
+# else /* DDB */
+#define Debugger() panic("should call debugger here (adaptec.c)")
+# endif /* DDB */
+# else
+#include "ddb.h"
+#endif /* netbsd */
+#else /* KERNEL */
+#define NAHB 1
+#endif /* kernel */
+
+#ifndef NetBSD
+typedef timeout_func_t timeout_t;
+#endif
+
+typedef unsigned long int physaddr;
+#include "kernel.h"
+
+#define KVTOPHYS(x) vtophys(x)
+
+#define AHB_ECB_MAX 32 /* store up to 32ECBs at any one time */
+ /* in aha1742 H/W ( Not MAX ? ) */
+#define ECB_HASH_SIZE 32 /* when we have a physical addr. for */
+ /* a ecb and need to find the ecb in */
+ /* space, look it up in the hash table */
+#define ECB_HASH_SHIFT 9 /* only hash on multiples of 512 */
+#define ECB_HASH(x) ((((long int)(x))>>ECB_HASH_SHIFT) % ECB_HASH_SIZE)
+
+#define AHB_NSEG 33 /* number of dma segments supported */
+
+/*
+ * AHA1740 standard EISA Host ID regs (Offset from slot base)
+ */
+#define HID0 0xC80 /* 0,1: msb of ID2, 3-7: ID1 */
+#define HID1 0xC81 /* 0-4: ID3, 4-7: LSB ID2 */
+#define HID2 0xC82 /* product, 0=174[20] 1 = 1744 */
+#define HID3 0xC83 /* firmware revision */
+
+#define CHAR1(B1,B2) (((B1>>2) & 0x1F) | '@')
+#define CHAR2(B1,B2) (((B1<<3) & 0x18) | ((B2>>5) & 0x7)|'@')
+#define CHAR3(B1,B2) ((B2 & 0x1F) | '@')
+
+/* AHA1740 EISA board control registers (Offset from slot base) */
+#define EBCTRL 0xC84
+#define CDEN 0x01
+/*
+ * AHA1740 EISA board mode registers (Offset from slot base)
+ */
+#define PORTADDR 0xCC0
+#define PORTADDR_ENHANCED 0x80
+#define BIOSADDR 0xCC1
+#define INTDEF 0xCC2
+#define SCSIDEF 0xCC3
+#define BUSDEF 0xCC4
+#define RESV0 0xCC5
+#define RESV1 0xCC6
+#define RESV2 0xCC7
+/**** bit definitions for INTDEF ****/
+#define INT9 0x00
+#define INT10 0x01
+#define INT11 0x02
+#define INT12 0x03
+#define INT14 0x05
+#define INT15 0x06
+#define INTHIGH 0x08 /* int high=ACTIVE (else edge) */
+#define INTEN 0x10
+/**** bit definitions for SCSIDEF ****/
+#define HSCSIID 0x0F /* our SCSI ID */
+#define RSTPWR 0x10 /* reset scsi bus on power up or reset */
+/**** bit definitions for BUSDEF ****/
+#define B0uS 0x00 /* give up bus immediatly */
+#define B4uS 0x01 /* delay 4uSec. */
+#define B8uS 0x02
+/*
+ * AHA1740 ENHANCED mode mailbox control regs (Offset from slot base)
+ */
+#define MBOXOUT0 0xCD0
+#define MBOXOUT1 0xCD1
+#define MBOXOUT2 0xCD2
+#define MBOXOUT3 0xCD3
+
+#define ATTN 0xCD4
+#define G2CNTRL 0xCD5
+#define G2INTST 0xCD6
+#define G2STAT 0xCD7
+
+#define MBOXIN0 0xCD8
+#define MBOXIN1 0xCD9
+#define MBOXIN2 0xCDA
+#define MBOXIN3 0xCDB
+
+#define G2STAT2 0xCDC
+
+/*
+ * Bit definitions for the 5 control/status registers
+ */
+#define ATTN_TARGET 0x0F
+#define ATTN_OPCODE 0xF0
+#define OP_IMMED 0x10
+#define AHB_TARG_RESET 0x80
+#define OP_START_ECB 0x40
+#define OP_ABORT_ECB 0x50
+
+#define G2CNTRL_SET_HOST_READY 0x20
+#define G2CNTRL_CLEAR_EISA_INT 0x40
+#define G2CNTRL_HARD_RESET 0x80
+
+#define G2INTST_TARGET 0x0F
+#define G2INTST_INT_STAT 0xF0
+#define AHB_ECB_OK 0x10
+#define AHB_ECB_RECOVERED 0x50
+#define AHB_HW_ERR 0x70
+#define AHB_IMMED_OK 0xA0
+#define AHB_ECB_ERR 0xC0
+#define AHB_ASN 0xD0 /* for target mode */
+#define AHB_IMMED_ERR 0xE0
+
+#define G2STAT_BUSY 0x01
+#define G2STAT_INT_PEND 0x02
+#define G2STAT_MBOX_EMPTY 0x04
+
+#define G2STAT2_HOST_READY 0x01
+
+struct ahb_dma_seg {
+ physaddr addr;
+ long len;
+};
+
+struct ahb_ecb_status {
+ u_short status;
+#define ST_DON 0x0001
+#define ST_DU 0x0002
+#define ST_QF 0x0008
+#define ST_SC 0x0010
+#define ST_DO 0x0020
+#define ST_CH 0x0040
+#define ST_INT 0x0080
+#define ST_ASA 0x0100
+#define ST_SNS 0x0200
+#define ST_INI 0x0800
+#define ST_ME 0x1000
+#define ST_ECA 0x4000
+ u_char ha_status;
+#define HS_OK 0x00
+#define HS_CMD_ABORTED_HOST 0x04
+#define HS_CMD_ABORTED_ADAPTER 0x05
+#define HS_TIMED_OUT 0x11
+#define HS_HARDWARE_ERR 0x20
+#define HS_SCSI_RESET_ADAPTER 0x22
+#define HS_SCSI_RESET_INCOMING 0x23
+ u_char targ_status;
+#define TS_OK 0x00
+#define TS_CHECK_CONDITION 0x02
+#define TS_BUSY 0x08
+ u_long resid_count;
+ u_long resid_addr;
+ u_short addit_status;
+ u_char sense_len;
+ u_char unused[9];
+ u_char cdb[6];
+};
+
+
+struct ecb {
+ u_char opcode;
+#define ECB_SCSI_OP 0x01
+ u_char:4;
+ u_char options:3;
+ u_char:1;
+ short opt1;
+#define ECB_CNE 0x0001
+#define ECB_DI 0x0080
+#define ECB_SES 0x0400
+#define ECB_S_G 0x1000
+#define ECB_DSB 0x4000
+#define ECB_ARS 0x8000
+ short opt2;
+#define ECB_LUN 0x0007
+#define ECB_TAG 0x0008
+#define ECB_TT 0x0030
+#define ECB_ND 0x0040
+#define ECB_DAT 0x0100
+#define ECB_DIR 0x0200
+#define ECB_ST 0x0400
+#define ECB_CHK 0x0800
+#define ECB_REC 0x4000
+#define ECB_NRB 0x8000
+ u_short unused1;
+ physaddr data;
+ u_long datalen;
+ physaddr status;
+ physaddr chain;
+ short unused2;
+ short unused3;
+ physaddr sense;
+ u_char senselen;
+ u_char cdblen;
+ short cksum;
+ u_char cdb[12];
+ /*-----------------end of hardware supported fields----------------*/
+ struct ecb *next; /* in free list */
+ struct scsi_xfer *xs; /* the scsi_xfer for this cmd */
+ int flags;
+#define ECB_FREE 0
+#define ECB_ACTIVE 1
+#define ECB_ABORTED 2
+#define ECB_IMMED 4
+#define ECB_IMMED_FAIL 8
+ struct ahb_dma_seg ahb_dma[AHB_NSEG];
+ struct ahb_ecb_status ecb_status;
+ struct scsi_sense_data ecb_sense;
+ struct ecb *nexthash;
+ physaddr hashkey; /* physaddr of this struct */
+};
+
+struct ahb_data {
+ int flags;
+#define AHB_INIT 0x01;
+ int baseport;
+ struct ecb *ecbhash[ECB_HASH_SIZE];
+ struct ecb *free_ecb;
+ int our_id; /* our scsi id */
+ int vect;
+ struct ecb *immed_ecb; /* an outstanding immediete command */
+ struct scsi_link sc_link;
+ int numecbs;
+} *ahbdata[NAHB];
+
+int ahbprobe();
+int ahbprobe1 __P((struct isa_device *dev));
+int ahb_attach();
+int ahb_init __P((int unit));
+int ahbintr();
+int32 ahb_scsi_cmd();
+void ahb_timeout(caddr_t, int);
+void ahb_done();
+struct ecb *cheat;
+void ahb_free_ecb();
+void ahbminphys();
+struct ecb *ahb_ecb_phys_kv();
+u_int32 ahb_adapter_info();
+
+#define MAX_SLOTS 8 /* XXX should this be 16?? Need EISA spec */
+static ahb_slot = 0; /* slot last board was found in */
+static ahb_unit = 0;
+int ahb_debug = 0;
+#define AHB_SHOWECBS 0x01
+#define AHB_SHOWINTS 0x02
+#define AHB_SHOWCMDS 0x04
+#define AHB_SHOWMISC 0x08
+#define FAIL 1
+#define SUCCESS 0
+#define PAGESIZ 4096
+
+#ifdef KERNEL
+struct isa_driver ahbdriver =
+{
+ ahbprobe,
+ ahb_attach,
+ "ahb"
+};
+
+struct scsi_adapter ahb_switch =
+{
+ ahb_scsi_cmd,
+ ahbminphys,
+ 0,
+ 0,
+ ahb_adapter_info,
+ "ahb",
+ { 0, 0 }
+};
+
+/* the below structure is so we have a default dev struct for our link struct */
+struct scsi_device ahb_dev =
+{
+ NULL, /* Use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+ "ahb",
+ 0,
+ { 0, 0 }
+};
+
+#endif /*KERNEL */
+
+#ifndef KERNEL
+main()
+{
+ printf("ahb_data size is %d\n", sizeof(struct ahb_data));
+ printf("ecb size is %d\n", sizeof(struct ecb));
+}
+
+#else /*KERNEL */
+
+/*
+ * Function to send a command out through a mailbox
+ */
+void
+ahb_send_mbox(int unit, int opcode, int target, struct ecb *ecb)
+{
+ int port = ahbdata[unit]->baseport;
+ int wait = 300; /* 3ms should be enough */
+ int stport = port + G2STAT;
+ int s = splbio();
+
+ while (--wait) {
+ if ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY))
+ == (G2STAT_MBOX_EMPTY))
+ break;
+ DELAY(10);
+ }
+ if (wait == 0) {
+ printf("ahb%d: board not responding\n", unit);
+ Debugger("aha1742");
+ }
+ outl(port + MBOXOUT0, KVTOPHYS(ecb)); /* don't know this will work */
+ outb(port + ATTN, opcode | target);
+
+ splx(s);
+}
+
+/*
+ * Function to poll for command completion when in poll mode
+ */
+int
+ahb_poll(int unit, int wait)
+{ /* in msec */
+ struct ahb_data *ahb = ahbdata[unit];
+ int port = ahb->baseport;
+ int stport = port + G2STAT;
+
+ retry:
+ while (--wait) {
+ if (inb(stport) & G2STAT_INT_PEND)
+ break;
+ DELAY(1000);
+ } if (wait == 0) {
+ printf("ahb%d: board not responding\n", unit);
+ return (EIO);
+ }
+ if (cheat != ahb_ecb_phys_kv(ahb, inl(port + MBOXIN0))) {
+ printf("discarding %x ", inl(port + MBOXIN0));
+ outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT);
+ DELAY(50000);
+ goto retry;
+ }
+ /* don't know this will work */
+ ahbintr(unit);
+ return (0);
+}
+
+/*
+ * Function to send an immediate type command to the adapter
+ */
+void
+ahb_send_immed(int unit, int target, u_long cmd)
+{
+ int port = ahbdata[unit]->baseport;
+ int s = splbio();
+ int stport = port + G2STAT;
+ int wait = 100; /* 1 ms enough? */
+
+ while (--wait) {
+ if ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY))
+ == (G2STAT_MBOX_EMPTY))
+ break;
+ DELAY(10);
+ } if (wait == 0) {
+ printf("ahb%d: board not responding\n", unit);
+ Debugger("aha1742");
+ }
+ outl(port + MBOXOUT0, cmd); /* don't know this will work */
+ outb(port + G2CNTRL, G2CNTRL_SET_HOST_READY);
+ outb(port + ATTN, OP_IMMED | target);
+ splx(s);
+}
+
+/*
+ * Check the slots looking for a board we recognise
+ * If we find one, note it's address (slot) and call
+ * the actual probe routine to check it out.
+ */
+int
+ahbprobe(dev)
+ struct isa_device *dev;
+{
+ int port;
+ u_char byte1, byte2, byte3;
+
+ ahb_slot++;
+ while (ahb_slot <= MAX_SLOTS) {
+ port = 0x1000 * ahb_slot;
+ byte1 = inb(port + HID0);
+ byte2 = inb(port + HID1);
+ byte3 = inb(port + HID2);
+ if (byte1 == 0xff) {
+ ahb_slot++;
+ continue;
+ }
+ if ((CHAR1(byte1, byte2) == 'A')
+ && (CHAR2(byte1, byte2) == 'D')
+ && (CHAR3(byte1, byte2) == 'P')
+ && ((byte3 == 0) || (byte3 == 1))) {
+ dev->id_iobase = port;
+ return ahbprobe1(dev);
+ }
+ ahb_slot++;
+ }
+ return 0;
+}
+
+/*
+ * Check if the device can be found at the port given
+ * and if so, set it up ready for further work
+ * as an argument, takes the isa_device structure from
+ * autoconf.c.
+ */
+int
+ahbprobe1(dev)
+ struct isa_device *dev;
+{
+ /*
+ * find unit and check we have that many defined
+ */
+ int unit = ahb_unit;
+ struct ahb_data *ahb;
+
+ if (unit >= NAHB) {
+ printf("ahb: unit number (%d) too high\n", unit);
+ return 0;
+ }
+ dev->id_unit = unit;
+
+ /*
+ * Allocate a storage area for us
+ */
+ if (ahbdata[unit]) {
+ printf("ahb%d: memory already allocated\n", unit);
+ return 0;
+ }
+ ahb = malloc(sizeof(struct ahb_data), M_TEMP, M_NOWAIT);
+ if (!ahb) {
+ printf("ahb%d: cannot malloc!\n", unit);
+ return 0;
+ }
+ bzero(ahb, sizeof(struct ahb_data));
+ ahbdata[unit] = ahb;
+ ahb->baseport = dev->id_iobase;
+ /*
+ * Try initialise a unit at this location
+ * sets up dma and bus speed, loads ahb->vect
+ */
+ if (ahb_init(unit) != 0) {
+ ahbdata[unit] = NULL;
+ free(ahb, M_TEMP);
+ return (0);
+ }
+ /*
+ * If it's there, put in it's interrupt vectors
+ */
+ dev->id_irq = (1 << ahb->vect);
+ dev->id_drq = -1; /* use EISA dma */
+
+ ahb_unit++;
+ return 0x1000;
+}
+
+/*
+ * Attach all the sub-devices we can find
+ */
+int
+ahb_attach(dev)
+ struct isa_device *dev;
+{
+#ifdef NetBSD
+ int unit = dev->id_masunit;
+#else
+ int unit = dev->id_unit;
+#endif
+ struct ahb_data *ahb = ahbdata[unit];
+
+ /*
+ * fill in the prototype scsi_link.
+ */
+ ahb->sc_link.adapter_unit = unit;
+ ahb->sc_link.adapter_targ = ahb->our_id;
+ ahb->sc_link.adapter = &ahb_switch;
+ ahb->sc_link.device = &ahb_dev;
+
+ /*
+ * ask the adapter what subunits are present
+ */
+ scsi_attachdevs(&(ahb->sc_link));
+
+ return 1;
+}
+
+/*
+ * Return some information to the caller about
+ * the adapter and it's capabilities
+ */
+u_int32
+ahb_adapter_info(unit)
+ int unit;
+{
+ return (2); /* 2 outstanding requests at a time per device */
+}
+
+/*
+ * Catch an interrupt from the adaptor
+ */
+int
+ahbintr(unit)
+ int unit;
+{
+ struct ecb *ecb;
+ unsigned char stat;
+ u_char ahbstat;
+ int target;
+ long int mboxval;
+ struct ahb_data *ahb = ahbdata[unit];
+
+ int port = ahb->baseport;
+
+#ifdef AHBDEBUG
+ printf("ahbintr ");
+#endif /*AHBDEBUG */
+
+ while (inb(port + G2STAT) & G2STAT_INT_PEND) {
+ /*
+ * First get all the information and then
+ * acknowlege the interrupt
+ */
+ ahbstat = inb(port + G2INTST);
+ target = ahbstat & G2INTST_TARGET;
+ stat = ahbstat & G2INTST_INT_STAT;
+ mboxval = inl(port + MBOXIN0); /* don't know this will work */
+ outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT);
+#ifdef AHBDEBUG
+ printf("status = 0x%x ", stat);
+#endif /*AHBDEBUG */
+ /*
+ * Process the completed operation
+ */
+
+ if (stat == AHB_ECB_OK) { /* common case is fast */
+ ecb = ahb_ecb_phys_kv(ahb, mboxval);
+ } else {
+ switch (stat) {
+ case AHB_IMMED_OK:
+ ecb = ahb->immed_ecb;
+ ahb->immed_ecb = 0;
+ break;
+ case AHB_IMMED_ERR:
+ ecb = ahb->immed_ecb;
+ ecb->flags |= ECB_IMMED_FAIL;
+ ahb->immed_ecb = 0;
+ break;
+ case AHB_ASN: /* for target mode */
+ printf("ahb%d: Unexpected ASN interrupt(%x)\n",
+ unit, mboxval);
+ ecb = 0;
+ break;
+ case AHB_HW_ERR:
+ printf("ahb%d: Hardware error interrupt(%x)\n",
+ unit, mboxval);
+ ecb = 0;
+ break;
+ case AHB_ECB_RECOVERED:
+ ecb = ahb_ecb_phys_kv(ahb, mboxval);
+ break;
+ case AHB_ECB_ERR:
+ ecb = ahb_ecb_phys_kv(ahb, mboxval);
+ break;
+ default:
+ printf(" Unknown return from ahb%d(%x)\n", unit, ahbstat);
+ ecb = 0;
+ }
+ } if (ecb) {
+#ifdef AHBDEBUG
+ if (ahb_debug & AHB_SHOWCMDS) {
+ show_scsi_cmd(ecb->xs);
+ }
+ if ((ahb_debug & AHB_SHOWECBS) && ecb)
+ printf("<int ecb(%x)>", ecb);
+#endif /*AHBDEBUG */
+ untimeout((timeout_t)ahb_timeout, (caddr_t)ecb);
+ ahb_done(unit, ecb, ((stat == AHB_ECB_OK) ? SUCCESS : FAIL));
+ }
+ }
+ return 1;
+}
+
+/*
+ * We have a ecb which has been processed by the
+ * adaptor, now we look to see how the operation
+ * went.
+ */
+void
+ahb_done(unit, ecb, state)
+ int unit, state;
+ struct ecb *ecb;
+{
+ struct ahb_ecb_status *stat = &ecb->ecb_status;
+ struct scsi_sense_data *s1, *s2;
+ struct scsi_xfer *xs = ecb->xs;
+
+ SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahb_done\n"));
+ /*
+ * Otherwise, put the results of the operation
+ * into the xfer and call whoever started it
+ */
+ if (ecb->flags & ECB_IMMED) {
+ if (ecb->flags & ECB_IMMED_FAIL) {
+ xs->error = XS_DRIVER_STUFFUP;
+ }
+ goto done;
+ }
+ if ((state == SUCCESS) || (xs->flags & SCSI_ERR_OK)) { /* All went correctly OR errors expected */
+ xs->resid = 0;
+ xs->error = 0;
+ } else {
+
+ s1 = &(ecb->ecb_sense);
+ s2 = &(xs->sense);
+
+ if (stat->ha_status) {
+ switch (stat->ha_status) {
+ case HS_SCSI_RESET_ADAPTER:
+ break;
+ case HS_SCSI_RESET_INCOMING:
+ break;
+ case HS_CMD_ABORTED_HOST: /* No response */
+ case HS_CMD_ABORTED_ADAPTER: /* No response */
+ break;
+ case HS_TIMED_OUT: /* No response */
+#ifdef AHBDEBUG
+ if (ahb_debug & AHB_SHOWMISC) {
+ printf("timeout reported back\n");
+ }
+#endif /*AHBDEBUG */
+ xs->error = XS_TIMEOUT;
+ break;
+ default: /* Other scsi protocol messes */
+ xs->error = XS_DRIVER_STUFFUP;
+#ifdef AHBDEBUG
+ if (ahb_debug & AHB_SHOWMISC) {
+ printf("unexpected ha_status: %x\n",
+ stat->ha_status);
+ }
+#endif /*AHBDEBUG */
+ }
+ } else {
+ switch (stat->targ_status) {
+ case TS_CHECK_CONDITION:
+ /* structure copy!!!!! */
+ *s2 = *s1;
+ xs->error = XS_SENSE;
+ break;
+ case TS_BUSY:
+ xs->error = XS_BUSY;
+ break;
+ default:
+#ifdef AHBDEBUG
+ if (ahb_debug & AHB_SHOWMISC) {
+ printf("unexpected targ_status: %x\n",
+ stat->targ_status);
+ }
+#endif /*AHBDEBUG */
+ xs->error = XS_DRIVER_STUFFUP;
+ }
+ }
+ }
+done: xs->flags |= ITSDONE;
+ ahb_free_ecb(unit, ecb, xs->flags);
+ scsi_done(xs);
+}
+
+/*
+ * A ecb (and hence a mbx-out is put onto the
+ * free list.
+ */
+void
+ahb_free_ecb(unit, ecb, flags)
+ int unit, flags;
+ struct ecb *ecb;
+{
+ unsigned int opri = 0;
+ struct ahb_data *ahb = ahbdata[unit];
+
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+
+ ecb->next = ahb->free_ecb;
+ ahb->free_ecb = ecb;
+ ecb->flags = ECB_FREE;
+ /*
+ * If there were none, wake abybody waiting for
+ * one to come free, starting with queued entries
+ */
+ if (!ecb->next) {
+ wakeup((caddr_t)&ahb->free_ecb);
+ }
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+}
+
+/*
+ * Get a free ecb
+ * If there are none, see if we can allocate a
+ * new one. If so, put it in the hash table too
+ * otherwise either return an error or sleep
+ */
+struct ecb *
+ahb_get_ecb(unit, flags)
+ int unit, flags;
+{
+ struct ahb_data *ahb = ahbdata[unit];
+ unsigned opri = 0;
+ struct ecb *ecbp;
+ int hashnum;
+
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+ /*
+ * If we can and have to, sleep waiting for one to come free
+ * but only if we can't allocate a new one.
+ */
+ while (!(ecbp = ahb->free_ecb)) {
+ if (ahb->numecbs < AHB_ECB_MAX) {
+ ecbp = (struct ecb *) malloc(sizeof(struct ecb),
+ M_TEMP,
+ M_NOWAIT);
+ if (ecbp) {
+ bzero(ecbp, sizeof(struct ecb));
+ ahb->numecbs++;
+ ecbp->flags = ECB_ACTIVE;
+ /*
+ * put in the phystokv hash table
+ * Never gets taken out.
+ */
+ ecbp->hashkey = KVTOPHYS(ecbp);
+ hashnum = ECB_HASH(ecbp->hashkey);
+ ecbp->nexthash = ahb->ecbhash[hashnum];
+ ahb->ecbhash[hashnum] = ecbp;
+ } else {
+ printf("ahb%d: Can't malloc ECB\n", unit);
+ } goto gottit;
+ } else {
+ if (!(flags & SCSI_NOSLEEP)) {
+ tsleep((caddr_t)&ahb->free_ecb, PRIBIO,
+ "ahbecb", 0);
+ }
+ }
+ } if (ecbp) {
+ /* Get ECB from from free list */
+ ahb->free_ecb = ecbp->next;
+ ecbp->flags = ECB_ACTIVE;
+ }
+gottit: if (!(flags & SCSI_NOMASK))
+ splx(opri);
+
+ return (ecbp);
+}
+
+/*
+ * given a physical address, find the ecb that
+ * it corresponds to:
+ */
+struct ecb *
+ahb_ecb_phys_kv(ahb, ecb_phys)
+ struct ahb_data *ahb;
+ physaddr ecb_phys;
+{
+ int hashnum = ECB_HASH(ecb_phys);
+ struct ecb *ecbp = ahb->ecbhash[hashnum];
+
+ while (ecbp) {
+ if (ecbp->hashkey == ecb_phys)
+ break;
+ ecbp = ecbp->nexthash;
+ }
+ return ecbp;
+}
+
+/*
+ * Start the board, ready for normal operation
+ */
+int
+ahb_init(unit)
+ int unit;
+{
+ struct ahb_data *ahb = ahbdata[unit];
+ int port = ahb->baseport;
+ int intdef;
+ int wait = 1000; /* 1 sec enough? */
+ int i;
+ int stport = port + G2STAT;
+#define NO_NO 1
+#ifdef NO_NO
+ /*
+ * reset board, If it doesn't respond, assume
+ * that it's not there.. good for the probe
+ */
+ outb(port + EBCTRL, CDEN); /* enable full card */
+ outb(port + PORTADDR, PORTADDR_ENHANCED);
+
+ outb(port + G2CNTRL, G2CNTRL_HARD_RESET);
+ DELAY(1000);
+ outb(port + G2CNTRL, 0);
+ DELAY(10000);
+ while (--wait) {
+ if ((inb(stport) & G2STAT_BUSY) == 0)
+ break;
+ DELAY(1000);
+ } if (wait == 0) {
+#ifdef AHBDEBUG
+ if (ahb_debug & AHB_SHOWMISC)
+ printf("ahb_init: No answer from aha1742 board\n");
+#endif /*AHBDEBUG */
+ return (ENXIO);
+ }
+ i = inb(port + MBOXIN0) & 0xff;
+ if (i) {
+ printf("self test failed, val = 0x%x\n", i);
+ return (EIO);
+ }
+#endif
+ while (inb(stport) & G2STAT_INT_PEND) {
+ printf(".");
+ outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT);
+ DELAY(10000);
+ }
+ outb(port + EBCTRL, CDEN); /* enable full card */
+ outb(port + PORTADDR, PORTADDR_ENHANCED);
+ /*
+ * Assume we have a board at this stage
+ * setup dma channel from jumpers and save int
+ * level
+ */
+ printf("ahb%d: reading board settings, ", unit);
+
+ intdef = inb(port + INTDEF);
+ switch (intdef & 0x07) {
+ case INT9:
+ ahb->vect = 9;
+ break;
+ case INT10:
+ ahb->vect = 10;
+ break;
+ case INT11:
+ ahb->vect = 11;
+ break;
+ case INT12:
+ ahb->vect = 12;
+ break;
+ case INT14:
+ ahb->vect = 14;
+ break;
+ case INT15:
+ ahb->vect = 15;
+ break;
+ default:
+ printf("illegal int setting\n");
+ return (EIO);
+ }
+ printf("int=%d\n", ahb->vect);
+
+ outb(port + INTDEF, (intdef | INTEN)); /* make sure we can interrupt */
+
+ /* who are we on the scsi bus? */
+ ahb->our_id = (inb(port + SCSIDEF) & HSCSIID);
+
+ /*
+ * Note that we are going and return (to probe)
+ */
+ ahb->flags |= AHB_INIT;
+ return (0);
+}
+
+#ifndef min
+#define min(x,y) (x < y ? x : y)
+#endif /* min */
+
+void
+ahbminphys(bp)
+ struct buf *bp;
+{
+ if (bp->b_bcount > ((AHB_NSEG - 1) * PAGESIZ)) {
+ bp->b_bcount = ((AHB_NSEG - 1) * PAGESIZ);
+ }
+}
+
+/*
+ * start a scsi operation given the command and
+ * the data address. Also needs the unit, target
+ * and lu
+ */
+int32
+ahb_scsi_cmd(xs)
+ struct scsi_xfer *xs;
+{
+ struct ecb *ecb;
+ struct ahb_dma_seg *sg;
+ int seg; /* scatter gather seg being worked on */
+ int thiskv;
+ physaddr thisphys, nextphys;
+ int unit = xs->sc_link->adapter_unit;
+ int bytes_this_seg, bytes_this_page, datalen, flags;
+ struct ahb_data *ahb = ahbdata[unit];
+ int s;
+
+ SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahb_scsi_cmd\n"));
+ /*
+ * get a ecb (mbox-out) to use. If the transfer
+ * is from a buf (possibly from interrupt time)
+ * then we can't allow it to sleep
+ */
+ flags = xs->flags;
+ if (xs->bp)
+ flags |= (SCSI_NOSLEEP); /* just to be sure */
+ if (flags & ITSDONE) {
+ printf("ahb%d: Already done?", unit);
+ xs->flags &= ~ITSDONE;
+ }
+ if (!(flags & INUSE)) {
+ printf("ahb%d: Not in use?", unit);
+ xs->flags |= INUSE;
+ }
+ if (!(ecb = ahb_get_ecb(unit, flags))) {
+ xs->error = XS_DRIVER_STUFFUP;
+ return (TRY_AGAIN_LATER);
+ }
+ cheat = ecb;
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("start ecb(%x)\n", ecb));
+ ecb->xs = xs;
+ /*
+ * If it's a reset, we need to do an 'immediate'
+ * command, and store it's ecb for later
+ * if there is already an immediate waiting,
+ * then WE must wait
+ */
+ if (flags & SCSI_RESET) {
+ ecb->flags |= ECB_IMMED;
+ if (ahb->immed_ecb) {
+ return (TRY_AGAIN_LATER);
+ }
+ ahb->immed_ecb = ecb;
+ if (!(flags & SCSI_NOMASK)) {
+ s = splbio();
+ ahb_send_immed(unit, xs->sc_link->target, AHB_TARG_RESET);
+ timeout(ahb_timeout, (caddr_t)ecb, (xs->timeout * hz) / 1000);
+ splx(s);
+ return (SUCCESSFULLY_QUEUED);
+ } else {
+ ahb_send_immed(unit, xs->sc_link->target, AHB_TARG_RESET);
+ /*
+ * If we can't use interrupts, poll on completion
+ */
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("wait\n"));
+ if (ahb_poll(unit, xs->timeout)) {
+ ahb_free_ecb(unit, ecb, flags);
+ xs->error = XS_TIMEOUT;
+ return (HAD_ERROR);
+ }
+ return (COMPLETE);
+ }
+ }
+ /*
+ * Put all the arguments for the xfer in the ecb
+ */
+ ecb->opcode = ECB_SCSI_OP;
+ ecb->opt1 = ECB_SES | ECB_DSB | ECB_ARS;
+ if (xs->datalen) {
+ ecb->opt1 |= ECB_S_G;
+ }
+ ecb->opt2 = xs->sc_link->lun | ECB_NRB;
+ ecb->cdblen = xs->cmdlen;
+ ecb->sense = KVTOPHYS(&(ecb->ecb_sense));
+ ecb->senselen = sizeof(ecb->ecb_sense);
+ ecb->status = KVTOPHYS(&(ecb->ecb_status));
+
+ if (xs->datalen) { /* should use S/G only if not zero length */
+ ecb->data = KVTOPHYS(ecb->ahb_dma);
+ sg = ecb->ahb_dma;
+ seg = 0;
+#ifdef TFS
+ if (flags & SCSI_DATA_UIO) {
+ iovp = ((struct uio *) xs->data)->uio_iov;
+ datalen = ((struct uio *) xs->data)->uio_iovcnt;
+ xs->datalen = 0;
+ while ((datalen) && (seg < AHB_NSEG)) {
+ sg->addr = (physaddr) iovp->iov_base;
+ xs->datalen += sg->len = iovp->iov_len;
+ SC_DEBUGN(xs->sc_link, SDEV_DB4,
+ ("(0x%x@0x%x)", iovp->iov_len
+ ,iovp->iov_base));
+ sg++;
+ iovp++;
+ seg++;
+ datalen--;
+ }
+ }
+ else
+#endif /*TFS */
+ {
+ /*
+ * Set up the scatter gather block
+ */
+
+ SC_DEBUG(xs->sc_link, SDEV_DB4,
+ ("%d @0x%x:- ", xs->datalen, xs->data));
+ datalen = xs->datalen;
+ thiskv = (int) xs->data;
+ thisphys = KVTOPHYS(thiskv);
+
+ while ((datalen) && (seg < AHB_NSEG)) {
+ bytes_this_seg = 0;
+
+ /* put in the base address */
+ sg->addr = thisphys;
+
+ SC_DEBUGN(xs->sc_link, SDEV_DB4, ("0x%x", thisphys));
+
+ /* do it at least once */
+ nextphys = thisphys;
+ while ((datalen) && (thisphys == nextphys)) {
+ /*
+ * This page is contiguous (physically) with
+ * the the last, just extend the length
+ */
+ /* how far to the end of the page */
+ nextphys = (thisphys & (~(PAGESIZ - 1)))
+ + PAGESIZ;
+ bytes_this_page = nextphys - thisphys;
+ /**** or the data ****/
+ bytes_this_page = min(bytes_this_page
+ ,datalen);
+ bytes_this_seg += bytes_this_page;
+ datalen -= bytes_this_page;
+
+ /* get more ready for the next page */
+ thiskv = (thiskv & (~(PAGESIZ - 1)))
+ + PAGESIZ;
+ if (datalen)
+ thisphys = KVTOPHYS(thiskv);
+ }
+ /*
+ * next page isn't contiguous, finish the seg
+ */
+ SC_DEBUGN(xs->sc_link, SDEV_DB4,
+ ("(0x%x)", bytes_this_seg));
+ sg->len = bytes_this_seg;
+ sg++;
+ seg++;
+ }
+ } /*end of iov/kv decision */
+ ecb->datalen = seg * sizeof(struct ahb_dma_seg);
+ SC_DEBUGN(xs->sc_link, SDEV_DB4, ("\n"));
+ if (datalen) { /* there's still data, must have run out of segs! */
+ printf("ahb_scsi_cmd%d: more than %d DMA segs\n",
+ unit, AHB_NSEG);
+ xs->error = XS_DRIVER_STUFFUP;
+ ahb_free_ecb(unit, ecb, flags);
+ return (HAD_ERROR);
+ }
+ } else { /* No data xfer, use non S/G values */
+ ecb->data = (physaddr) 0;
+ ecb->datalen = 0;
+ } ecb->chain = (physaddr) 0;
+ /*
+ * Put the scsi command in the ecb and start it
+ */
+ bcopy(xs->cmd, ecb->cdb, xs->cmdlen);
+ /*
+ * Usually return SUCCESSFULLY QUEUED
+ */
+ if (!(flags & SCSI_NOMASK)) {
+ s = splbio();
+ ahb_send_mbox(unit, OP_START_ECB, xs->sc_link->target, ecb);
+ timeout(ahb_timeout, (caddr_t)ecb, (xs->timeout * hz) / 1000);
+ splx(s);
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_sent\n"));
+ return (SUCCESSFULLY_QUEUED);
+ }
+ /*
+ * If we can't use interrupts, poll on completion
+ */
+ ahb_send_mbox(unit, OP_START_ECB, xs->sc_link->target, ecb);
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_wait\n"));
+ do {
+ if (ahb_poll(unit, xs->timeout)) {
+ if (!(xs->flags & SCSI_SILENT))
+ printf("cmd fail\n");
+ ahb_send_mbox(unit, OP_ABORT_ECB, xs->sc_link->target, ecb);
+ if (ahb_poll(unit, 2000)) {
+ printf("abort failed in wait\n");
+ ahb_free_ecb(unit, ecb, flags);
+ }
+ xs->error = XS_DRIVER_STUFFUP;
+ return (HAD_ERROR);
+ }
+ } while (!(xs->flags & ITSDONE)); /* something (?) else finished */
+ if (xs->error) {
+ return (HAD_ERROR);
+ }
+ return (COMPLETE);
+}
+
+void
+ahb_timeout(caddr_t arg1, int arg2)
+{
+ struct ecb * ecb = (struct ecb *)arg1;
+ int unit;
+ struct ahb_data *ahb;
+ int s = splbio();
+
+ unit = ecb->xs->sc_link->adapter_unit;
+ ahb = ahbdata[unit];
+ printf("ahb%d:%d:%d (%s%d) timed out ", unit
+ ,ecb->xs->sc_link->target
+ ,ecb->xs->sc_link->lun
+ ,ecb->xs->sc_link->device->name
+ ,ecb->xs->sc_link->dev_unit);
+
+#ifdef AHBDEBUG
+ if (ahb_debug & AHB_SHOWECBS)
+ ahb_print_active_ecb(unit);
+#endif /*AHBDEBUG */
+
+ /*
+ * If it's immediate, don't try abort it
+ */
+ if (ecb->flags & ECB_IMMED) {
+ ecb->xs->retries = 0; /* I MEAN IT ! */
+ ecb->flags |= ECB_IMMED_FAIL;
+ ahb_done(unit, ecb, FAIL);
+ splx(s);
+ return;
+ }
+ /*
+ * If it has been through before, then
+ * a previous abort has failed, don't
+ * try abort again
+ */
+ if (ecb->flags == ECB_ABORTED) {
+ /*
+ * abort timed out
+ */
+ printf("AGAIN");
+ ecb->xs->retries = 0; /* I MEAN IT ! */
+ ecb->ecb_status.ha_status = HS_CMD_ABORTED_HOST;
+ ahb_done(unit, ecb, FAIL);
+ } else { /* abort the operation that has timed out */
+ printf("\n");
+ ahb_send_mbox(unit, OP_ABORT_ECB, ecb->xs->sc_link->target, ecb);
+ /* 2 secs for the abort */
+ timeout(ahb_timeout, (caddr_t)ecb, 2 * hz);
+ ecb->flags = ECB_ABORTED;
+ }
+ splx(s);
+}
+
+#ifdef AHBDEBUG
+void
+ahb_print_ecb(ecb)
+ struct ecb *ecb;
+{
+ printf("ecb:%x op:%x cmdlen:%d senlen:%d\n"
+ ,ecb
+ ,ecb->opcode
+ ,ecb->cdblen
+ ,ecb->senselen);
+ printf(" datlen:%d hstat:%x tstat:%x flags:%x\n"
+ ,ecb->datalen
+ ,ecb->ecb_status.ha_status
+ ,ecb->ecb_status.targ_status
+ ,ecb->flags);
+ show_scsi_cmd(ecb->xs);
+}
+
+void
+ahb_print_active_ecb(int unit)
+{
+ struct ahb_data *ahb = ahbdata[unit];
+ struct ecb *ecb;
+ int i = 0;
+
+ while (i < ECB_HASH_SIZE) {
+ ecb = ahb->ecbhash[i];
+ while (ecb) {
+ if (ecb->flags != ECB_FREE) {
+ ahb_print_ecb(ecb);
+ }
+ ecb = ecb->nexthash;
+ } i++;
+ }
+}
+#endif /*AHBDEBUG */
+#endif /*KERNEL */
diff --git a/sys/i386/i386/autoconf.c b/sys/i386/i386/autoconf.c
new file mode 100644
index 0000000..3575d1c
--- /dev/null
+++ b/sys/i386/i386/autoconf.c
@@ -0,0 +1,209 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)autoconf.c 7.1 (Berkeley) 5/9/91
+ * $Id: autoconf.c,v 1.10 1994/03/21 14:53:08 ache Exp $
+ */
+
+/*
+ * Setup the system to run on the current machine.
+ *
+ * Configure() is called at boot time and initializes the vba
+ * device tables and the memory controller monitoring. Available
+ * devices are determined (from possibilities mentioned in ioconf.c),
+ * and the drivers are initialized.
+ */
+#include "param.h"
+#include "systm.h"
+#include "buf.h"
+#include "dkstat.h"
+#include "conf.h"
+#include "dmap.h"
+#include "reboot.h"
+#include "kernel.h"
+
+#include "machine/pte.h"
+
+static void swapconf(void);
+static void setroot(void);
+
+/*
+ * The following several variables are related to
+ * the configuration process, and are used in initializing
+ * the machine.
+ */
+int dkn; /* number of iostat dk numbers assigned so far */
+extern int cold; /* cold start flag initialized in locore.s */
+
+/*
+ * Determine i/o configuration for a machine.
+ */
+void
+configure()
+{
+
+#include "isa.h"
+#if NISA > 0
+ isa_configure();
+#endif
+
+#if GENERICxxx && !defined(DISKLESS)
+ if ((boothowto & RB_ASKNAME) == 0)
+ setroot();
+ setconf();
+#else
+#ifndef DISKLESS
+ setroot();
+#endif
+#endif
+ /*
+ * Configure swap area and related system
+ * parameter based on device(s) used.
+ */
+ swapconf();
+ cold = 0;
+}
+
+/*
+ * Configure swap space and related parameters.
+ */
+static void
+swapconf()
+{
+ register struct swdevt *swp;
+ register int nblks;
+ extern int Maxmem;
+
+ for (swp = swdevt; swp->sw_dev > 0; swp++)
+ {
+ unsigned d = major(swp->sw_dev);
+
+ if (d > nblkdev) break;
+ if (bdevsw[d].d_psize) {
+ nblks = (*bdevsw[d].d_psize)(swp->sw_dev);
+ if (nblks > 0 &&
+ (swp->sw_nblks == 0 || swp->sw_nblks > nblks))
+ swp->sw_nblks = nblks;
+ else
+ swp->sw_nblks = 0;
+ }
+ swp->sw_nblks = ctod(dtoc(swp->sw_nblks));
+ }
+ if (dumplo == 0 && bdevsw[major(dumpdev)].d_psize)
+ dumplo = (*bdevsw[major(dumpdev)].d_psize)(dumpdev) -
+ Maxmem*NBPG/512;
+ if (dumplo < 0)
+ dumplo = 0;
+}
+
+#define DOSWAP /* change swdevt and dumpdev */
+u_long bootdev = 0; /* should be dev_t, but not until 32 bits */
+
+static char devname[][2] = {
+ 'w','d', /* 0 = wd */
+ 's','w', /* 1 = sw */
+#define FDMAJOR 2
+ 'f','d', /* 2 = fd */
+ 'w','t', /* 3 = wt */
+ 's','d', /* 4 = sd -- new SCSI system */
+};
+
+#define PARTITIONMASK 0x7
+#define PARTITIONSHIFT 3
+#define FDUNITSHIFT 6
+
+/*
+ * Attempt to find the device from which we were booted.
+ * If we can do so, and not instructed not to do so,
+ * change rootdev to correspond to the load device.
+ */
+static void
+setroot()
+{
+ int majdev, mindev, unit, part, adaptor;
+ dev_t temp = 0, orootdev;
+ struct swdevt *swp;
+
+/*printf("howto %x bootdev %x ", boothowto, bootdev);*/
+ if (boothowto & RB_DFLTROOT ||
+ (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC)
+ return;
+ majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK;
+ if (majdev > sizeof(devname) / sizeof(devname[0]))
+ return;
+ adaptor = (bootdev >> B_ADAPTORSHIFT) & B_ADAPTORMASK;
+ unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK;
+ if (majdev == FDMAJOR) {
+ part = 3; /* raw */
+ mindev = unit << FDUNITSHIFT;
+ }
+ else {
+ part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK;
+ mindev = (unit << PARTITIONSHIFT) + part;
+ }
+ orootdev = rootdev;
+ rootdev = makedev(majdev, mindev);
+ /*
+ * If the original rootdev is the same as the one
+ * just calculated, don't need to adjust the swap configuration.
+ */
+ if (rootdev == orootdev)
+ return;
+ printf("changing root device to %c%c%d%c\n",
+ devname[majdev][0], devname[majdev][1],
+ mindev >> (majdev == FDMAJOR ? FDUNITSHIFT : PARTITIONSHIFT),
+ part + 'a');
+#ifdef DOSWAP
+ mindev &= ~PARTITIONMASK;
+ for (swp = swdevt; swp->sw_dev; swp++) {
+ if (majdev == major(swp->sw_dev) &&
+ mindev == (minor(swp->sw_dev) & ~PARTITIONMASK)) {
+
+ temp = swdevt[0].sw_dev;
+ swdevt[0].sw_dev = swp->sw_dev;
+ swp->sw_dev = temp;
+ break;
+ }
+ }
+ if (swp->sw_dev == 0)
+ return;
+ /*
+ * If dumpdev was the same as the old primary swap
+ * device, move it to the new primary swap device.
+ */
+ if (temp == dumpdev)
+ dumpdev = swdevt[0].sw_dev;
+#endif
+}
diff --git a/sys/i386/i386/conf.c b/sys/i386/i386/conf.c
new file mode 100644
index 0000000..a52f8cd
--- /dev/null
+++ b/sys/i386/i386/conf.c
@@ -0,0 +1,636 @@
+/*
+ * Copyright (c) UNIX System Laboratories, Inc. All or some portions
+ * of this file are derived from material licensed to the
+ * University of California by American Telephone and Telegraph Co.
+ * or UNIX System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ */
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)conf.c 5.8 (Berkeley) 5/12/91
+ * $Id: conf.c,v 1.24 1994/04/21 14:10:31 sos Exp $
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "buf.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "conf.h"
+
+int nullop(), enxio(), enodev();
+d_rdwr_t rawread, rawwrite;
+d_strategy_t swstrategy;
+
+#include "wd.h"
+#if (NWD > 0)
+d_open_t wdopen;
+d_close_t wdclose;
+d_strategy_t wdstrategy;
+d_ioctl_t wdioctl;
+d_dump_t wddump;
+d_psize_t wdsize;
+#else
+#define wdopen (d_open_t *)enxio
+#define wdclose (d_close_t *)enxio
+#define wdstrategy (d_strategy_t *)enxio
+#define wdioctl (d_ioctl_t *)enxio
+#define wddump (d_dump_t *)enxio
+#define wdsize (d_psize_t *)0
+#endif
+
+#include "sd.h"
+#if NSD > 0
+d_open_t sdopen;
+d_close_t sdclose;
+d_strategy_t sdstrategy;
+d_ioctl_t sdioctl;
+d_dump_t sddump;
+d_psize_t sdsize;
+#else
+#define sdopen (d_open_t *)enxio
+#define sdclose (d_close_t *)enxio
+#define sdstrategy (d_strategy_t *)enxio
+#define sdioctl (d_ioctl_t *)enxio
+#define sddump (d_dump_t *)enxio
+#define sdsize (d_psize_t *)0
+#endif
+
+#include "st.h"
+#if NST > 0
+d_open_t stopen;
+d_close_t stclose;
+d_strategy_t ststrategy;
+d_ioctl_t stioctl;
+/*int stdump(),stsize();*/
+#define stdump (d_dump_t *)enxio
+#define stsize (d_psize_t *)0
+#else
+#define stopen (d_open_t *)enxio
+#define stclose (d_close_t *)enxio
+#define ststrategy (d_strategy_t *)enxio
+#define stioctl (d_ioctl_t *)enxio
+#define stdump (d_dump_t *)enxio
+#define stsize (d_psize_t *)0
+#endif
+
+#include "cd.h"
+#if NCD > 0
+d_open_t cdopen;
+d_close_t cdclose;
+d_strategy_t cdstrategy;
+d_ioctl_t cdioctl;
+d_psize_t cdsize;
+#define cddump (d_dump_t *)enxio
+#else
+#define cdopen (d_open_t *)enxio
+#define cdclose (d_close_t *)enxio
+#define cdstrategy (d_strategy_t *)enxio
+#define cdioctl (d_ioctl_t *)enxio
+#define cddump (d_dump_t *)enxio
+#define cdsize (d_psize_t *)0
+#endif
+
+#include "mcd.h"
+#if NMCD > 0
+d_open_t mcdopen;
+d_close_t mcdclose;
+d_strategy_t mcdstrategy;
+d_ioctl_t mcdioctl;
+d_psize_t mcdsize;
+#define mcddump (d_dump_t *)enxio
+#else
+#define mcdopen (d_open_t *)enxio
+#define mcdclose (d_close_t *)enxio
+#define mcdstrategy (d_strategy_t *)enxio
+#define mcdioctl (d_ioctl_t *)enxio
+#define mcddump (d_dump_t *)enxio
+#define mcdsize (d_psize_t *)0
+#endif
+
+#include "ch.h"
+#if NCH > 0
+d_open_t chopen;
+d_close_t chclose;
+d_ioctl_t chioctl;
+#else
+#define chopen (d_open_t *)enxio
+#define chclose (d_close_t *)enxio
+#define chioctl (d_ioctl_t *)enxio
+#endif
+
+#include "wt.h"
+#if NWT > 0
+d_open_t wtopen;
+d_close_t wtclose;
+d_strategy_t wtstrategy;
+d_ioctl_t wtioctl;
+d_dump_t wtdump;
+d_psize_t wtsize;
+#else
+#define wtopen (d_open_t *)enxio
+#define wtclose (d_close_t *)enxio
+#define wtstrategy (d_strategy_t *)enxio
+#define wtioctl (d_ioctl_t *)enxio
+#define wtdump (d_dump_t *)enxio
+#define wtsize (d_psize_t *)0
+#endif
+
+#include "fd.h"
+#if NFD > 0
+d_open_t Fdopen;
+d_close_t fdclose;
+d_strategy_t fdstrategy;
+d_ioctl_t fdioctl;
+#define fddump (d_dump_t *)enxio
+#define fdsize (d_psize_t *)0
+#else
+#define Fdopen (d_open_t *)enxio
+#define fdclose (d_close_t *)enxio
+#define fdstrategy (d_strategy_t *)enxio
+#define fdioctl (d_ioctl_t *)enxio
+#define fddump (d_dump_t *)enxio
+#define fdsize (d_psize_t *)0
+#endif
+
+#define swopen (d_open_t *)enodev
+#define swclose (d_close_t *)enodev
+d_strategy_t swstrategy;
+#define swioctl (d_ioctl_t *)enodev
+#define swdump (d_dump_t *)enodev
+#define swsize (d_psize_t *)enodev
+
+d_rdwr_t swread, swwrite;
+
+struct bdevsw bdevsw[] =
+{
+ { wdopen, wdclose, wdstrategy, wdioctl, /*0*/
+ wddump, wdsize, 0 },
+ { swopen, swclose, swstrategy, swioctl, /*1*/
+ swdump, swsize, 0 },
+ { Fdopen, fdclose, fdstrategy, fdioctl, /*2*/
+ fddump, fdsize, 0 },
+ { wtopen, wtclose, wtstrategy, wtioctl, /*3*/
+ wtdump, wtsize, B_TAPE },
+ { sdopen, sdclose, sdstrategy, sdioctl, /*4*/
+ sddump, sdsize, 0 },
+ { stopen, stclose, ststrategy, stioctl, /*5*/
+ stdump, stsize, 0 },
+ { cdopen, cdclose, cdstrategy, cdioctl, /*6*/
+ cddump, cdsize, 0 },
+ { mcdopen, mcdclose, mcdstrategy, mcdioctl, /*7*/
+ mcddump, mcdsize, 0 },
+ { 0, } /* block major 8 is reserved for local use */
+/*
+ * If you need a bdev major number, please contact the FreeBSD team
+ * by sending mail to "FreeBSD-hackers@freefall.cdrom.com".
+ * If you assign one yourself it may conflict with someone else.
+ */
+};
+int nblkdev = sizeof (bdevsw) / sizeof (bdevsw[0]);
+
+/* console */
+#include "machine/cons.h"
+
+d_open_t cnopen;
+d_close_t cnclose;
+d_rdwr_t cnread, cnwrite;
+d_ioctl_t cnioctl;
+d_select_t cnselect;
+
+/* more console */
+d_open_t pcopen;
+d_close_t pcclose;
+d_rdwr_t pcread, pcwrite;
+d_ioctl_t pcioctl;
+d_mmap_t pcmmap;
+extern struct tty *pccons;
+
+/* controlling TTY */
+d_open_t cttyopen;
+d_rdwr_t cttyread, cttywrite;
+d_ioctl_t cttyioctl;
+d_select_t cttyselect;
+
+/* /dev/mem */
+d_open_t mmopen;
+d_close_t mmclose;
+d_rdwr_t mmrw;
+d_mmap_t memmmap;
+#define mmselect seltrue
+
+#include "pty.h"
+#if NPTY > 0
+d_open_t ptsopen;
+d_close_t ptsclose;
+d_rdwr_t ptsread, ptswrite;
+d_stop_t ptsstop;
+d_open_t ptcopen;
+d_close_t ptcclose;
+d_rdwr_t ptcread, ptcwrite;
+d_select_t ptcselect;
+d_ioctl_t ptyioctl;
+extern struct tty *pt_tty[];
+#else
+#define ptsopen (d_open_t *)enxio
+#define ptsclose (d_close_t *)enxio
+#define ptsread (d_rdwr_t *)enxio
+#define ptswrite (d_rdwr_t *)enxio
+#define ptcopen (d_open_t *)enxio
+#define ptcclose (d_close_t *)enxio
+#define ptcread (d_rdwr_t *)enxio
+#define ptcwrite (d_rdwr_t *)enxio
+#define ptyioctl (d_ioctl_t *)enxio
+#define pt_tty NULL
+#define ptcselect (d_select_t *)enxio
+#define ptsstop (d_stop_t *)nullop
+#endif
+
+#include "com.h"
+#if NCOM > 0
+d_open_t comopen;
+d_close_t comclose;
+d_rdwr_t comread;
+d_rdwr_t comwrite;
+d_ioctl_t comioctl;
+d_select_t comselect;
+#define comreset (d_reset_t *)enxio
+extern struct tty *com_tty[];
+#else
+#define comopen (d_open_t *)enxio
+#define comclose (d_close_t *)enxio
+#define comread (d_rdwr_t *)enxio
+#define comwrite (d_rdwr_t *)enxio
+#define comioctl (d_ioctl_t *)enxio
+#define comreset (d_reset_t *)enxio
+#define comselect (d_select_t *)enxio
+#define com_tty NULL
+#endif
+
+/* /dev/klog */
+d_open_t logopen;
+d_close_t logclose;
+d_rdwr_t logread;
+d_ioctl_t logioctl;
+d_select_t logselect;
+
+d_select_t ttselect, seltrue;
+
+#include "lpt.h"
+#if NLPT > 0
+d_open_t lptopen;
+d_close_t lptclose;
+d_rdwr_t lptwrite;
+d_ioctl_t lptioctl;
+#else
+#define lptopen (d_open_t *)enxio
+#define lptclose (d_close_t *)enxio
+#define lptwrite (d_rdwr_t *)enxio
+#define lptioctl (d_ioctl_t *)enxio
+#endif
+
+#include "tw.h"
+#if NTW > 0
+d_open_t twopen;
+d_close_t twclose;
+d_rdwr_t twread, twwrite;
+d_select_t twselect;
+#else
+#define twopen (d_open_t *)enxio
+#define twclose (d_close_t *)enxio
+#define twread (d_rdwr_t *)enxio
+#define twwrite (d_rdwr_t *)enxio
+#define twselect (d_select_t *)enxio
+#endif
+
+#include "sb.h" /* Sound Blaster */
+#if NSB > 0
+d_open_t sbopen;
+d_close_t sbclose;
+d_ioctl_t sbioctl;
+d_rdwr_t sbread, sbwrite;
+d_select_t sbselect;
+#else
+#define sbopen (d_open_t *)enxio
+#define sbclose (d_close_t *)enxio
+#define sbioctl (d_ioctl_t *)enxio
+#define sbread (d_rdwr_t *)enxio
+#define sbwrite (d_rdwr_t *)enxio
+#define sbselect seltrue
+#endif
+
+#include "psm.h"
+#if NPSM > 0
+d_open_t psmopen;
+d_close_t psmclose;
+d_rdwr_t psmread;
+d_select_t psmselect;
+d_ioctl_t psmioctl;
+#else
+#define psmopen (d_open_t *)enxio
+#define psmclose (d_close_t *)enxio
+#define psmread (d_rdwr_t *)enxio
+#define psmselect (d_select_t *)enxio
+#define psmioctl (d_ioctl_t *)enxio
+#endif
+
+#include "snd.h" /* General Sound Driver */
+#if NSND > 0
+d_open_t sndopen;
+d_close_t sndclose;
+d_ioctl_t sndioctl;
+d_rdwr_t sndread, sndwrite;
+d_select_t sndselect;
+#else
+#define sndopen (d_open_t *)enxio
+#define sndclose (d_close_t *)enxio
+#define sndioctl (d_ioctl_t *)enxio
+#define sndread (d_rdwr_t *)enxio
+#define sndwrite (d_rdwr_t *)enxio
+#define sndselect seltrue
+#endif
+
+/* /dev/fd/NNN */
+d_open_t fdopen;
+
+#include "bpfilter.h"
+#if NBPFILTER > 0
+d_open_t bpfopen;
+d_close_t bpfclose;
+d_rdwr_t bpfread, bpfwrite;
+d_select_t bpfselect;
+d_ioctl_t bpfioctl;
+#else
+#define bpfopen (d_open_t *)enxio
+#define bpfclose (d_close_t *)enxio
+#define bpfread (d_rdwr_t *)enxio
+#define bpfwrite (d_rdwr_t *)enxio
+#define bpfselect (d_select_t *)enxio
+#define bpfioctl (d_ioctl_t *)enxio
+#endif
+
+#include "lpa.h"
+#if NLPA > 0
+d_open_t lpaopen;
+d_close_t lpaclose;
+d_rdwr_t lpawrite;
+d_ioctl_t lpaioctl;
+#else
+#define lpaopen (d_open_t *)enxio
+#define lpaclose (d_close_t *)enxio
+#define lpawrite (d_rdwr_t *)enxio
+#define lpaioctl (d_ioctl_t *)enxio
+#endif
+
+#include "speaker.h"
+#if NSPEAKER > 0
+d_open_t spkropen;
+d_close_t spkrclose;
+d_rdwr_t spkrwrite;
+d_ioctl_t spkrioctl;
+#else
+#define spkropen (d_open_t *)enxio
+#define spkrclose (d_close_t *)enxio
+#define spkrwrite (d_rdwr_t *)enxio
+#define spkrioctl (d_ioctl_t *)enxio
+#endif
+
+#include "pca.h"
+#if NPCA > 0
+d_open_t pcaopen;
+d_close_t pcaclose;
+d_rdwr_t pcawrite;
+d_ioctl_t pcaioctl;
+#else
+#define pcaopen (d_open_t *)enxio
+#define pcaclose (d_close_t *)enxio
+#define pcawrite (d_rdwr_t *)enxio
+#define pcaioctl (d_ioctl_t *)enxio
+#endif
+
+#include "mse.h"
+#if NMSE > 0
+d_open_t mseopen;
+d_close_t mseclose;
+d_rdwr_t mseread;
+d_select_t mseselect;
+#else
+#define mseopen (d_open_t *)enxio
+#define mseclose (d_close_t *)enxio
+#define mseread (d_rdwr_t *)enxio
+#define mseselect (d_select_t *)enxio
+#endif
+
+#include "sio.h"
+#if NSIO > 0
+d_open_t sioopen;
+d_close_t sioclose;
+d_rdwr_t sioread, siowrite;
+d_ioctl_t sioioctl;
+d_select_t sioselect;
+d_stop_t siostop;
+#define sioreset (d_reset_t *)enxio
+extern struct tty *sio_tty[];
+#else
+#define sioopen (d_open_t *)enxio
+#define sioclose (d_close_t *)enxio
+#define sioread (d_rdwr_t *)enxio
+#define siowrite (d_rdwr_t *)enxio
+#define sioioctl (d_ioctl_t *)enxio
+#define siostop (d_stop_t *)enxio
+#define sioreset (d_reset_t *)enxio
+#define sioselect (d_select_t *)enxio
+#define sio_tty NULL
+#endif
+
+#include "su.h"
+#if NSU > 0
+d_open_t suopen;
+d_close_t suclose;
+d_ioctl_t suioctl;
+#else
+#define suopen (d_open_t *)enxio
+#define suclose (d_close_t *)enxio
+#define suioctl (d_ioctl_t *)enxio
+#endif
+
+#include "uk.h"
+#if NUK > 0
+d_open_t ukopen;
+d_close_t ukclose;
+d_ioctl_t ukioctl;
+#else
+#define ukopen (d_open_t *)enxio
+#define ukclose (d_close_t *)enxio
+#define ukioctl (d_ioctl_t *)enxio
+#endif
+
+#define noopen (d_open_t *)enodev
+#define noclose (d_close_t *)enodev
+#define noread (d_rdwr_t *)enodev
+#define nowrite noread
+#define noioc (d_ioctl_t *)enodev
+#define nostop (d_stop_t *)enodev
+#define noreset (d_reset_t *)enodev
+#define noselect (d_select_t *)enodev
+#define nommap (d_mmap_t *)enodev
+#define nostrat (d_strategy_t *)enodev
+
+#define nullopen (d_open_t *)nullop
+#define nullclose (d_close_t *)nullop
+#define nullstop (d_stop_t *)nullop
+#define nullreset (d_reset_t *)nullop
+
+/* open, close, read, write, ioctl, stop, reset, ttys, select, mmap, strat */
+struct cdevsw cdevsw[] =
+{
+ { cnopen, cnclose, cnread, cnwrite, /*0*/
+ cnioctl, nullstop, nullreset, NULL, /* console */
+ cnselect, nommap, NULL },
+ { cttyopen, nullclose, cttyread, cttywrite, /*1*/
+ cttyioctl, nullstop, nullreset, NULL, /* tty */
+ cttyselect, nommap, NULL },
+ { mmopen, mmclose, mmrw, mmrw, /*2*/
+ noioc, nullstop, nullreset, NULL, /* memory */
+ mmselect, memmmap, NULL },
+ { wdopen, wdclose, rawread, rawwrite, /*3*/
+ wdioctl, nostop, nullreset, NULL, /* wd */
+ seltrue, nommap, wdstrategy },
+ { nullopen, nullclose, rawread, rawwrite, /*4*/
+ noioc, nostop, noreset, NULL, /* swap */
+ noselect, nommap, swstrategy },
+ { ptsopen, ptsclose, ptsread, ptswrite, /*5*/
+ ptyioctl, ptsstop, nullreset, pt_tty, /* ttyp */
+ ttselect, nommap, NULL },
+ { ptcopen, ptcclose, ptcread, ptcwrite, /*6*/
+ ptyioctl, nullstop, nullreset, pt_tty, /* ptyp */
+ ptcselect, nommap, NULL },
+ { logopen, logclose, logread, nowrite, /*7*/
+ logioctl, nostop, nullreset, NULL, /* klog */
+ logselect, nommap, NULL },
+ { comopen, comclose, comread, comwrite, /*8*/
+ comioctl, nostop, comreset, com_tty, /* com */
+ comselect, nommap, NULL },
+ { Fdopen, fdclose, rawread, rawwrite, /*9*/
+ fdioctl, nostop, nullreset, NULL, /* Fd (!=fd) */
+ seltrue, nommap, fdstrategy },
+ { wtopen, wtclose, rawread, rawwrite, /*10*/
+ wtioctl, nostop, nullreset, NULL, /* wt */
+ seltrue, nommap, wtstrategy },
+ { noopen, noclose, noread, nowrite, /*11*/
+ noioc, nostop, nullreset, NULL,
+ seltrue, nommap, nostrat },
+ { pcopen, pcclose, pcread, pcwrite, /*12*/
+ pcioctl, nullstop, nullreset, &pccons, /* pc */
+ ttselect, pcmmap, NULL },
+ { sdopen, sdclose, rawread, rawwrite, /*13*/
+ sdioctl, nostop, nullreset, NULL, /* sd */
+ seltrue, nommap, sdstrategy },
+ { stopen, stclose, rawread, rawwrite, /*14*/
+ stioctl, nostop, nullreset, NULL, /* st */
+ seltrue, nommap, ststrategy },
+ { cdopen, cdclose, rawread, nowrite, /*15*/
+ cdioctl, nostop, nullreset, NULL, /* cd */
+ seltrue, nommap, cdstrategy },
+ { lptopen, lptclose, noread, lptwrite, /*16*/
+ lptioctl, nullstop, nullreset, NULL, /* lpt */
+ seltrue, nommap, nostrat},
+ { chopen, chclose, noread, nowrite, /*17*/
+ chioctl, nostop, nullreset, NULL, /* ch */
+ noselect, nommap, nostrat },
+ { suopen, suclose, noread, nowrite, /*18*/
+ suioctl, nostop, nullreset, NULL, /* scsi 'generic' */
+ seltrue, nommap, nostrat },
+ { twopen, twclose, twread, twwrite, /*19*/
+ noioc, nullstop, nullreset, NULL, /* tw */
+ twselect, nommap, nostrat },
+ { sbopen, sbclose, sbread, sbwrite, /*20*/
+ sbioctl, nostop, nullreset, NULL, /* soundblaster*/
+ sbselect, nommap, NULL },
+ { psmopen, psmclose, psmread, nowrite, /*21*/
+ psmioctl, nostop, nullreset, NULL, /* psm mice */
+ psmselect, nommap, NULL },
+ { fdopen, noclose, noread, nowrite, /*22*/
+ noioc, nostop, nullreset, NULL, /* fd (!=Fd) */
+ noselect, nommap, nostrat },
+ { bpfopen, bpfclose, bpfread, bpfwrite, /*23*/
+ bpfioctl, nostop, nullreset, NULL, /* bpf */
+ bpfselect, nommap, NULL },
+ { pcaopen, pcaclose, noread, pcawrite, /*24*/
+ pcaioctl, nostop, nullreset, NULL, /* pcaudio */
+ seltrue, nommap, NULL },
+ { lpaopen, lpaclose, noread, lpawrite, /*25*/
+ lpaioctl, nullstop, nullreset, NULL, /* lpa */
+ seltrue, nommap, NULL },
+ { spkropen, spkrclose, noread, spkrwrite, /*26*/
+ spkrioctl, nostop, nullreset, NULL, /* spkr */
+ seltrue, nommap, NULL },
+ { mseopen, mseclose, mseread, nowrite, /*27*/
+ noioc, nostop, nullreset, NULL, /* mse */
+ mseselect, nommap, NULL },
+ { sioopen, sioclose, sioread, siowrite, /*28*/
+ sioioctl, siostop, sioreset, sio_tty, /* sio */
+ sioselect, nommap, NULL },
+ { mcdopen, mcdclose, rawread, nowrite, /*29*/
+ mcdioctl, nostop, nullreset, NULL, /* mitsumi cd */
+ seltrue, nommap, mcdstrategy },
+ { sndopen, sndclose, sndread, sndwrite, /*30*/
+ sndioctl, nostop, nullreset, NULL, /* sound driver */
+ sndselect, nommap, NULL },
+ { ukopen, ukclose, noread, nowrite, /*31*/
+ ukioctl, nostop, nullreset, NULL, /* unknown */
+ seltrue, nommap, NULL }, /* scsi */
+ { 0, } /* character device 32 is reserved for local use */
+/*
+ * If you need a cdev major number, please contact the FreeBSD team
+ * by sending mail to `freebsd-hackers@freefall.cdrom.com'.
+ * If you assign one yourself it may then conflict with someone else.
+ */
+};
+int nchrdev = sizeof (cdevsw) / sizeof (cdevsw[0]);
+
+int mem_no = 2; /* major device number of memory special file */
+
+/*
+ * Swapdev is a fake device implemented
+ * in sw.c used only internally to get to swstrategy.
+ * It cannot be provided to the users, because the
+ * swstrategy routine munches the b_dev and b_blkno entries
+ * before calling the appropriate driver. This would horribly
+ * confuse, e.g. the hashing routines. Instead, /dev/drum is
+ * provided as a character (raw) device.
+ */
+dev_t swapdev = makedev(1, 0);
diff --git a/sys/i386/i386/cons.c b/sys/i386/i386/cons.c
new file mode 100644
index 0000000..f5fc887
--- /dev/null
+++ b/sys/i386/i386/cons.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)cons.c 7.2 (Berkeley) 5/9/91
+ * $Id: cons.c,v 1.10 1994/01/23 19:17:17 davidg Exp $
+ */
+
+
+#include "sys/param.h"
+#include "sys/proc.h"
+#include "sys/user.h"
+#include "sys/systm.h"
+#include "sys/buf.h"
+#include "sys/ioctl.h"
+#include "sys/tty.h"
+#include "sys/file.h"
+#include "sys/conf.h"
+#include "sys/vnode.h"
+#include "machine/stdarg.h"
+
+#include "machine/cons.h"
+
+/* XXX - all this could be autoconfig()ed */
+int pccnprobe(), pccninit(), pccngetc(), pccnputc();
+
+#include "sio.h"
+#if NSIO > 0
+int siocnprobe(), siocninit(), siocngetc(), siocnputc();
+#endif
+
+#include "com.h"
+#if NCOM > 0
+int comcnprobe(), comcninit(), comcngetc(), comcnputc();
+#endif
+
+struct consdev constab[] = {
+ { pccnprobe, pccninit, pccngetc, pccnputc },
+#if NSIO > 0
+ { siocnprobe, siocninit, siocngetc, siocnputc },
+#endif
+#if NCOM > 0
+ { comcnprobe, comcninit, comcngetc, comcnputc },
+#endif
+ { 0 },
+};
+/* end XXX */
+
+struct tty *constty = 0; /* virtual console output device */
+struct consdev *cn_tab; /* physical console device info */
+struct tty *cn_tty; /* XXX: console tty struct for tprintf */
+
+void
+cninit()
+{
+ register struct consdev *cp;
+
+ /*
+ * Collect information about all possible consoles
+ * and find the one with highest priority
+ */
+ for (cp = constab; cp->cn_probe; cp++) {
+ (*cp->cn_probe)(cp);
+ if (cp->cn_pri > CN_DEAD &&
+ (cn_tab == NULL || cp->cn_pri > cn_tab->cn_pri))
+ cn_tab = cp;
+ }
+ /*
+ * No console, we can handle it
+ */
+ if ((cp = cn_tab) == NULL)
+ return;
+ /*
+ * Turn on console
+ */
+ cn_tty = cp->cn_tp;
+ (*cp->cn_init)(cp);
+}
+
+int
+cnopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ struct vnode *vp = 0;
+
+ if (cn_tab == NULL)
+ return (0);
+
+ dev = cn_tab->cn_dev;
+ if ((vfinddev(dev, VCHR, &vp) == 0) && vcount(vp))
+ return (0);
+
+ return ((*cdevsw[major(dev)].d_open)(dev, flag, mode, p));
+}
+
+int
+cnclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ struct vnode *vp = 0;
+
+ if (cn_tab == NULL)
+ return (0);
+
+ dev = cn_tab->cn_dev;
+ if ((vfinddev(dev, VCHR, &vp) == 0) && vcount(vp))
+ return (0);
+
+ return ((*cdevsw[major(dev)].d_close)(dev, flag, mode, p));
+}
+
+int
+cnread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ if (cn_tab == NULL)
+ return (0);
+ dev = cn_tab->cn_dev;
+ return ((*cdevsw[major(dev)].d_read)(dev, uio, flag));
+}
+
+int
+cnwrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ if (cn_tab == NULL)
+ return (0);
+ if (constty)
+ dev = constty->t_dev;
+ else
+ dev = cn_tab->cn_dev;
+ return ((*cdevsw[major(dev)].d_write)(dev, uio, flag));
+}
+
+int
+cnioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ int error;
+
+ if (cn_tab == NULL)
+ return (0);
+ /*
+ * Superuser can always use this to wrest control of console
+ * output from the "virtual" console.
+ */
+ if (cmd == TIOCCONS && constty) {
+ error = suser(p->p_ucred, (u_short *) NULL);
+ if (error)
+ return (error);
+ constty = NULL;
+ return (0);
+ }
+ dev = cn_tab->cn_dev;
+ return ((*cdevsw[major(dev)].d_ioctl)(dev, cmd, data, flag, p));
+}
+
+/*ARGSUSED*/
+int
+cnselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ if (cn_tab == NULL)
+ return (1);
+ return (ttselect(cn_tab->cn_dev, rw, p));
+}
+
+int
+cngetc()
+{
+ if (cn_tab == NULL)
+ return (0);
+ return ((*cn_tab->cn_getc)(cn_tab->cn_dev));
+}
+
+void
+cnputc(c)
+ register int c;
+{
+ if (cn_tab == NULL)
+ return;
+ if (c) {
+ (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
+ if (c == '\n')
+ (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
+ }
+}
+
+int
+pg(const char *p, ...) {
+ va_list args;
+ va_start(args, p);
+ printf("%r\n>", p, args);
+ return(cngetc());
+}
+
+
diff --git a/sys/i386/i386/cons.h b/sys/i386/i386/cons.h
new file mode 100644
index 0000000..5e0f30d
--- /dev/null
+++ b/sys/i386/i386/cons.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)cons.h 7.2 (Berkeley) 5/9/91
+ * $Id: cons.h,v 1.3 1993/11/07 17:41:33 wollman Exp $
+ */
+
+#ifndef _MACHINE_CONS_H_
+#define _MACHINE_CONS_H_ 1
+
+struct consdev {
+ int (*cn_probe)(); /* probe hardware and fill in consdev info */
+ int (*cn_init)(); /* turn on as console */
+ int (*cn_getc)(); /* kernel getchar interface */
+ int (*cn_putc)(); /* kernel putchar interface */
+ struct tty *cn_tp; /* tty structure for console device */
+ dev_t cn_dev; /* major/minor of device */
+ short cn_pri; /* pecking order; the higher the better */
+};
+
+/* values for cn_pri - reflect our policy for console selection */
+#define CN_DEAD 0 /* device doesn't exist */
+#define CN_NORMAL 1 /* device exists but is nothing special */
+#define CN_INTERNAL 2 /* "internal" bit-mapped display */
+#define CN_REMOTE 3 /* serial interface with remote bit set */
+
+/* XXX */
+#define CONSMAJOR 0
+
+#ifdef KERNEL
+extern struct consdev constab[];
+extern struct consdev *cn_tab;
+extern struct tty *cn_tty;
+
+struct proc; struct uio;
+
+/* cdevsw[] entries */
+extern int cnopen(int /*dev_t*/, int, int, struct proc *);
+extern int cnclose(int /*dev_t*/, int, int, struct proc *);
+extern int cnread(int /*dev_t*/, struct uio *, int);
+extern int cnwrite(int /*dev_t*/, struct uio *, int);
+extern int cnioctl(int /*dev_t*/, int, caddr_t, int, struct proc *);
+extern int cnselect(int /*dev_t*/, int, struct proc *);
+
+/* other kernel entry points */
+extern void cninit(void);
+extern int cngetc(void);
+extern void cnputc(int /*char*/);
+extern int pg(const char *, ...);
+
+#endif /* KERNEL */
+#endif /* _MACHINE_CONS_H_ */
diff --git a/sys/i386/i386/db_disasm.c b/sys/i386/i386/db_disasm.c
new file mode 100644
index 0000000..98e251b
--- /dev/null
+++ b/sys/i386/i386/db_disasm.c
@@ -0,0 +1,1375 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_disasm.c,v 1.4 1993/11/25 01:30:51 wollman Exp $
+ */
+
+/*
+ * Instruction disassembler.
+ */
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "ddb/ddb.h"
+
+#include <ddb/db_access.h>
+#include <ddb/db_sym.h>
+
+/*
+ * Size attributes
+ */
+#define BYTE 0
+#define WORD 1
+#define LONG 2
+#define QUAD 3
+#define SNGL 4
+#define DBLR 5
+#define EXTR 6
+#define SDEP 7
+#define NONE 8
+
+/*
+ * Addressing modes
+ */
+#define E 1 /* general effective address */
+#define Eind 2 /* indirect address (jump, call) */
+#define Ew 3 /* address, word size */
+#define Eb 4 /* address, byte size */
+#define R 5 /* register, in 'reg' field */
+#define Rw 6 /* word register, in 'reg' field */
+#define Ri 7 /* register in instruction */
+#define S 8 /* segment reg, in 'reg' field */
+#define Si 9 /* segment reg, in instruction */
+#define A 10 /* accumulator */
+#define BX 11 /* (bx) */
+#define CL 12 /* cl, for shifts */
+#define DX 13 /* dx, for IO */
+#define SI 14 /* si */
+#define DI 15 /* di */
+#define CR 16 /* control register */
+#define DR 17 /* debug register */
+#define TR 18 /* test register */
+#define I 19 /* immediate, unsigned */
+#define Is 20 /* immediate, signed */
+#define Ib 21 /* byte immediate, unsigned */
+#define Ibs 22 /* byte immediate, signed */
+#define Iw 23 /* word immediate, unsigned */
+#define Il 24 /* long immediate */
+#define O 25 /* direct address */
+#define Db 26 /* byte displacement from EIP */
+#define Dl 27 /* long displacement from EIP */
+#define o1 28 /* constant 1 */
+#define o3 29 /* constant 3 */
+#define OS 30 /* immediate offset/segment */
+#define ST 31 /* FP stack top */
+#define STI 32 /* FP stack */
+#define X 33 /* extended FP op */
+#define XA 34 /* for 'fstcw %ax' */
+
+struct inst {
+ char * i_name; /* name */
+ short i_has_modrm; /* has regmodrm byte */
+ short i_size; /* operand size */
+ int i_mode; /* addressing modes */
+ char * i_extra; /* pointer to extra opcode table */
+};
+
+#define op1(x) (x)
+#define op2(x,y) ((x)|((y)<<8))
+#define op3(x,y,z) ((x)|((y)<<8)|((z)<<16))
+
+struct finst {
+ char * f_name; /* name for memory instruction */
+ int f_size; /* size for memory instruction */
+ int f_rrmode; /* mode for rr instruction */
+ char * f_rrname; /* name for rr instruction
+ (or pointer to table) */
+};
+
+char * db_Grp6[] = {
+ "sldt",
+ "str",
+ "lldt",
+ "ltr",
+ "verr",
+ "verw",
+ "",
+ ""
+};
+
+char * db_Grp7[] = {
+ "sgdt",
+ "sidt",
+ "lgdt",
+ "lidt",
+ "smsw",
+ "",
+ "lmsw",
+ "invlpg"
+};
+
+char * db_Grp8[] = {
+ "",
+ "",
+ "",
+ "",
+ "bt",
+ "bts",
+ "btr",
+ "btc"
+};
+
+struct inst db_inst_0f0x[] = {
+/*00*/ { "", TRUE, NONE, op1(Ew), (char *)db_Grp6 },
+/*01*/ { "", TRUE, NONE, op1(Ew), (char *)db_Grp7 },
+/*02*/ { "lar", TRUE, LONG, op2(E,R), 0 },
+/*03*/ { "lsl", TRUE, LONG, op2(E,R), 0 },
+/*04*/ { "", FALSE, NONE, 0, 0 },
+/*05*/ { "", FALSE, NONE, 0, 0 },
+/*06*/ { "clts", FALSE, NONE, 0, 0 },
+/*07*/ { "", FALSE, NONE, 0, 0 },
+
+/*08*/ { "invd", FALSE, NONE, 0, 0 },
+/*09*/ { "wbinvd",FALSE, NONE, 0, 0 },
+/*0a*/ { "", FALSE, NONE, 0, 0 },
+/*0b*/ { "", FALSE, NONE, 0, 0 },
+/*0c*/ { "", FALSE, NONE, 0, 0 },
+/*0d*/ { "", FALSE, NONE, 0, 0 },
+/*0e*/ { "", FALSE, NONE, 0, 0 },
+/*0f*/ { "", FALSE, NONE, 0, 0 },
+};
+
+struct inst db_inst_0f2x[] = {
+/*20*/ { "mov", TRUE, LONG, op2(CR,E), 0 }, /* use E for reg */
+/*21*/ { "mov", TRUE, LONG, op2(DR,E), 0 }, /* since mod == 11 */
+/*22*/ { "mov", TRUE, LONG, op2(E,CR), 0 },
+/*23*/ { "mov", TRUE, LONG, op2(E,DR), 0 },
+/*24*/ { "mov", TRUE, LONG, op2(TR,E), 0 },
+/*25*/ { "", FALSE, NONE, 0, 0 },
+/*26*/ { "mov", TRUE, LONG, op2(E,TR), 0 },
+/*27*/ { "", FALSE, NONE, 0, 0 },
+
+/*28*/ { "", FALSE, NONE, 0, 0 },
+/*29*/ { "", FALSE, NONE, 0, 0 },
+/*2a*/ { "", FALSE, NONE, 0, 0 },
+/*2b*/ { "", FALSE, NONE, 0, 0 },
+/*2c*/ { "", FALSE, NONE, 0, 0 },
+/*2d*/ { "", FALSE, NONE, 0, 0 },
+/*2e*/ { "", FALSE, NONE, 0, 0 },
+/*2f*/ { "", FALSE, NONE, 0, 0 },
+};
+
+struct inst db_inst_0f8x[] = {
+/*80*/ { "jo", FALSE, NONE, op1(Dl), 0 },
+/*81*/ { "jno", FALSE, NONE, op1(Dl), 0 },
+/*82*/ { "jb", FALSE, NONE, op1(Dl), 0 },
+/*83*/ { "jnb", FALSE, NONE, op1(Dl), 0 },
+/*84*/ { "jz", FALSE, NONE, op1(Dl), 0 },
+/*85*/ { "jnz", FALSE, NONE, op1(Dl), 0 },
+/*86*/ { "jbe", FALSE, NONE, op1(Dl), 0 },
+/*87*/ { "jnbe", FALSE, NONE, op1(Dl), 0 },
+
+/*88*/ { "js", FALSE, NONE, op1(Dl), 0 },
+/*89*/ { "jns", FALSE, NONE, op1(Dl), 0 },
+/*8a*/ { "jp", FALSE, NONE, op1(Dl), 0 },
+/*8b*/ { "jnp", FALSE, NONE, op1(Dl), 0 },
+/*8c*/ { "jl", FALSE, NONE, op1(Dl), 0 },
+/*8d*/ { "jnl", FALSE, NONE, op1(Dl), 0 },
+/*8e*/ { "jle", FALSE, NONE, op1(Dl), 0 },
+/*8f*/ { "jnle", FALSE, NONE, op1(Dl), 0 },
+};
+
+struct inst db_inst_0f9x[] = {
+/*90*/ { "seto", TRUE, NONE, op1(Eb), 0 },
+/*91*/ { "setno", TRUE, NONE, op1(Eb), 0 },
+/*92*/ { "setb", TRUE, NONE, op1(Eb), 0 },
+/*93*/ { "setnb", TRUE, NONE, op1(Eb), 0 },
+/*94*/ { "setz", TRUE, NONE, op1(Eb), 0 },
+/*95*/ { "setnz", TRUE, NONE, op1(Eb), 0 },
+/*96*/ { "setbe", TRUE, NONE, op1(Eb), 0 },
+/*97*/ { "setnbe",TRUE, NONE, op1(Eb), 0 },
+
+/*98*/ { "sets", TRUE, NONE, op1(Eb), 0 },
+/*99*/ { "setns", TRUE, NONE, op1(Eb), 0 },
+/*9a*/ { "setp", TRUE, NONE, op1(Eb), 0 },
+/*9b*/ { "setnp", TRUE, NONE, op1(Eb), 0 },
+/*9c*/ { "setl", TRUE, NONE, op1(Eb), 0 },
+/*9d*/ { "setnl", TRUE, NONE, op1(Eb), 0 },
+/*9e*/ { "setle", TRUE, NONE, op1(Eb), 0 },
+/*9f*/ { "setnle",TRUE, NONE, op1(Eb), 0 },
+};
+
+struct inst db_inst_0fax[] = {
+/*a0*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*a1*/ { "pop", FALSE, NONE, op1(Si), 0 },
+/*a2*/ { "", FALSE, NONE, 0, 0 },
+/*a3*/ { "bt", TRUE, LONG, op2(E,R), 0 },
+/*a4*/ { "shld", TRUE, LONG, op3(Ib,E,R), 0 },
+/*a5*/ { "shld", TRUE, LONG, op3(CL,E,R), 0 },
+/*a6*/ { "", FALSE, NONE, 0, 0 },
+/*a7*/ { "", FALSE, NONE, 0, 0 },
+
+/*a8*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*a9*/ { "pop", FALSE, NONE, op1(Si), 0 },
+/*aa*/ { "", FALSE, NONE, 0, 0 },
+/*ab*/ { "bts", TRUE, LONG, op2(E,R), 0 },
+/*ac*/ { "shrd", TRUE, LONG, op3(Ib,E,R), 0 },
+/*ad*/ { "shrd", TRUE, LONG, op3(CL,E,R), 0 },
+/*a6*/ { "", FALSE, NONE, 0, 0 },
+/*a7*/ { "imul", TRUE, LONG, op2(E,R), 0 },
+};
+
+struct inst db_inst_0fbx[] = {
+/*b0*/ { "", FALSE, NONE, 0, 0 },
+/*b1*/ { "", FALSE, NONE, 0, 0 },
+/*b2*/ { "lss", TRUE, LONG, op2(E, R), 0 },
+/*b3*/ { "bts", TRUE, LONG, op2(R, E), 0 },
+/*b4*/ { "lfs", TRUE, LONG, op2(E, R), 0 },
+/*b5*/ { "lgs", TRUE, LONG, op2(E, R), 0 },
+/*b6*/ { "movzb", TRUE, LONG, op2(E, R), 0 },
+/*b7*/ { "movzw", TRUE, LONG, op2(E, R), 0 },
+
+/*b8*/ { "", FALSE, NONE, 0, 0 },
+/*b9*/ { "", FALSE, NONE, 0, 0 },
+/*ba*/ { "", TRUE, LONG, op2(Is, E), (char *)db_Grp8 },
+/*bb*/ { "btc", TRUE, LONG, op2(R, E), 0 },
+/*bc*/ { "bsf", TRUE, LONG, op2(E, R), 0 },
+/*bd*/ { "bsr", TRUE, LONG, op2(E, R), 0 },
+/*be*/ { "movsb", TRUE, LONG, op2(E, R), 0 },
+/*bf*/ { "movsw", TRUE, LONG, op2(E, R), 0 },
+};
+
+struct inst db_inst_0fcx[] = {
+/*c0*/ { "xadd", TRUE, BYTE, op2(R, E), 0 },
+/*c1*/ { "xadd", TRUE, LONG, op2(R, E), 0 },
+/*c2*/ { "", FALSE, NONE, 0, 0 },
+/*c3*/ { "", FALSE, NONE, 0, 0 },
+/*c4*/ { "", FALSE, NONE, 0, 0 },
+/*c5*/ { "", FALSE, NONE, 0, 0 },
+/*c6*/ { "", FALSE, NONE, 0, 0 },
+/*c7*/ { "", FALSE, NONE, 0, 0 },
+/*c8*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*c9*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*ca*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*cb*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*cc*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*cd*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*ce*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+/*cf*/ { "bswap", FALSE, LONG, op1(Ri), 0 },
+};
+
+struct inst db_inst_0fdx[] = {
+/*c0*/ { "cmpxchg",TRUE, BYTE, op2(R, E), 0 },
+/*c1*/ { "cmpxchg",TRUE, LONG, op2(R, E), 0 },
+/*c2*/ { "", FALSE, NONE, 0, 0 },
+/*c3*/ { "", FALSE, NONE, 0, 0 },
+/*c4*/ { "", FALSE, NONE, 0, 0 },
+/*c5*/ { "", FALSE, NONE, 0, 0 },
+/*c6*/ { "", FALSE, NONE, 0, 0 },
+/*c7*/ { "", FALSE, NONE, 0, 0 },
+/*c8*/ { "", FALSE, NONE, 0, 0 },
+/*c9*/ { "", FALSE, NONE, 0, 0 },
+/*ca*/ { "", FALSE, NONE, 0, 0 },
+/*cb*/ { "", FALSE, NONE, 0, 0 },
+/*cc*/ { "", FALSE, NONE, 0, 0 },
+/*cd*/ { "", FALSE, NONE, 0, 0 },
+/*ce*/ { "", FALSE, NONE, 0, 0 },
+/*cf*/ { "", FALSE, NONE, 0, 0 },
+};
+
+struct inst *db_inst_0f[] = {
+ db_inst_0f0x,
+ 0,
+ db_inst_0f2x,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ db_inst_0f8x,
+ db_inst_0f9x,
+ db_inst_0fax,
+ db_inst_0fbx,
+ db_inst_0fcx,
+ db_inst_0fdx,
+ 0,
+ 0
+};
+
+char * db_Esc92[] = {
+ "fnop", "", "", "", "", "", "", ""
+};
+char * db_Esc93[] = {
+ "", "", "", "", "", "", "", ""
+};
+char * db_Esc94[] = {
+ "fchs", "fabs", "", "", "ftst", "fxam", "", ""
+};
+char * db_Esc95[] = {
+ "fld1", "fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz",""
+};
+char * db_Esc96[] = {
+ "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp",
+ "fincstp"
+};
+char * db_Esc97[] = {
+ "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos"
+};
+
+char * db_Esca4[] = {
+ "", "fucompp","", "", "", "", "", ""
+};
+
+char * db_Escb4[] = {
+ "", "", "fnclex","fninit","", "", "", ""
+};
+
+char * db_Esce3[] = {
+ "", "fcompp","", "", "", "", "", ""
+};
+
+char * db_Escf4[] = {
+ "fnstsw","", "", "", "", "", "", ""
+};
+
+struct finst db_Esc8[] = {
+/*0*/ { "fadd", SNGL, op2(STI,ST), 0 },
+/*1*/ { "fmul", SNGL, op2(STI,ST), 0 },
+/*2*/ { "fcom", SNGL, op2(STI,ST), 0 },
+/*3*/ { "fcomp", SNGL, op2(STI,ST), 0 },
+/*4*/ { "fsub", SNGL, op2(STI,ST), 0 },
+/*5*/ { "fsubr", SNGL, op2(STI,ST), 0 },
+/*6*/ { "fdiv", SNGL, op2(STI,ST), 0 },
+/*7*/ { "fdivr", SNGL, op2(STI,ST), 0 },
+};
+
+struct finst db_Esc9[] = {
+/*0*/ { "fld", SNGL, op1(STI), 0 },
+/*1*/ { "", NONE, op1(STI), "fxch" },
+/*2*/ { "fst", SNGL, op1(X), (char *)db_Esc92 },
+/*3*/ { "fstp", SNGL, op1(X), (char *)db_Esc93 },
+/*4*/ { "fldenv", NONE, op1(X), (char *)db_Esc94 },
+/*5*/ { "fldcw", NONE, op1(X), (char *)db_Esc95 },
+/*6*/ { "fnstenv",NONE, op1(X), (char *)db_Esc96 },
+/*7*/ { "fnstcw", NONE, op1(X), (char *)db_Esc97 },
+};
+
+struct finst db_Esca[] = {
+/*0*/ { "fiadd", WORD, 0, 0 },
+/*1*/ { "fimul", WORD, 0, 0 },
+/*2*/ { "ficom", WORD, 0, 0 },
+/*3*/ { "ficomp", WORD, 0, 0 },
+/*4*/ { "fisub", WORD, op1(X), (char *)db_Esca4 },
+/*5*/ { "fisubr", WORD, 0, 0 },
+/*6*/ { "fidiv", WORD, 0, 0 },
+/*7*/ { "fidivr", WORD, 0, 0 }
+};
+
+struct finst db_Escb[] = {
+/*0*/ { "fild", WORD, 0, 0 },
+/*1*/ { "", NONE, 0, 0 },
+/*2*/ { "fist", WORD, 0, 0 },
+/*3*/ { "fistp", WORD, 0, 0 },
+/*4*/ { "", WORD, op1(X), (char *)db_Escb4 },
+/*5*/ { "fld", EXTR, 0, 0 },
+/*6*/ { "", WORD, 0, 0 },
+/*7*/ { "fstp", EXTR, 0, 0 },
+};
+
+struct finst db_Escc[] = {
+/*0*/ { "fadd", DBLR, op2(ST,STI), 0 },
+/*1*/ { "fmul", DBLR, op2(ST,STI), 0 },
+/*2*/ { "fcom", DBLR, op2(ST,STI), 0 },
+/*3*/ { "fcomp", DBLR, op2(ST,STI), 0 },
+/*4*/ { "fsub", DBLR, op2(ST,STI), "fsubr" },
+/*5*/ { "fsubr", DBLR, op2(ST,STI), "fsub" },
+/*6*/ { "fdiv", DBLR, op2(ST,STI), "fdivr" },
+/*7*/ { "fdivr", DBLR, op2(ST,STI), "fdiv" },
+};
+
+struct finst db_Escd[] = {
+/*0*/ { "fld", DBLR, op1(STI), "ffree" },
+/*1*/ { "", NONE, 0, 0 },
+/*2*/ { "fst", DBLR, op1(STI), 0 },
+/*3*/ { "fstp", DBLR, op1(STI), 0 },
+/*4*/ { "frstor", NONE, op1(STI), "fucom" },
+/*5*/ { "", NONE, op1(STI), "fucomp" },
+/*6*/ { "fnsave", NONE, 0, 0 },
+/*7*/ { "fnstsw", NONE, 0, 0 },
+};
+
+struct finst db_Esce[] = {
+/*0*/ { "fiadd", LONG, op2(ST,STI), "faddp" },
+/*1*/ { "fimul", LONG, op2(ST,STI), "fmulp" },
+/*2*/ { "ficom", LONG, 0, 0 },
+/*3*/ { "ficomp", LONG, op1(X), (char *)db_Esce3 },
+/*4*/ { "fisub", LONG, op2(ST,STI), "fsubrp" },
+/*5*/ { "fisubr", LONG, op2(ST,STI), "fsubp" },
+/*6*/ { "fidiv", LONG, op2(ST,STI), "fdivrp" },
+/*7*/ { "fidivr", LONG, op2(ST,STI), "fdivp" },
+};
+
+struct finst db_Escf[] = {
+/*0*/ { "fild", LONG, 0, 0 },
+/*1*/ { "", LONG, 0, 0 },
+/*2*/ { "fist", LONG, 0, 0 },
+/*3*/ { "fistp", LONG, 0, 0 },
+/*4*/ { "fbld", NONE, op1(XA), (char *)db_Escf4 },
+/*5*/ { "fld", QUAD, 0, 0 },
+/*6*/ { "fbstp", NONE, 0, 0 },
+/*7*/ { "fstp", QUAD, 0, 0 },
+};
+
+struct finst *db_Esc_inst[] = {
+ db_Esc8, db_Esc9, db_Esca, db_Escb,
+ db_Escc, db_Escd, db_Esce, db_Escf
+};
+
+char * db_Grp1[] = {
+ "add",
+ "or",
+ "adc",
+ "sbb",
+ "and",
+ "sub",
+ "xor",
+ "cmp"
+};
+
+char * db_Grp2[] = {
+ "rol",
+ "ror",
+ "rcl",
+ "rcr",
+ "shl",
+ "shr",
+ "shl",
+ "sar"
+};
+
+struct inst db_Grp3[] = {
+ { "test", TRUE, NONE, op2(I,E), 0 },
+ { "test", TRUE, NONE, op2(I,E), 0 },
+ { "not", TRUE, NONE, op1(E), 0 },
+ { "neg", TRUE, NONE, op1(E), 0 },
+ { "mul", TRUE, NONE, op2(E,A), 0 },
+ { "imul", TRUE, NONE, op2(E,A), 0 },
+ { "div", TRUE, NONE, op2(E,A), 0 },
+ { "idiv", TRUE, NONE, op2(E,A), 0 },
+};
+
+struct inst db_Grp4[] = {
+ { "inc", TRUE, BYTE, op1(E), 0 },
+ { "dec", TRUE, BYTE, op1(E), 0 },
+ { "", TRUE, NONE, 0, 0 },
+ { "", TRUE, NONE, 0, 0 },
+ { "", TRUE, NONE, 0, 0 },
+ { "", TRUE, NONE, 0, 0 },
+ { "", TRUE, NONE, 0, 0 },
+ { "", TRUE, NONE, 0, 0 }
+};
+
+struct inst db_Grp5[] = {
+ { "inc", TRUE, LONG, op1(E), 0 },
+ { "dec", TRUE, LONG, op1(E), 0 },
+ { "call", TRUE, NONE, op1(Eind),0 },
+ { "lcall", TRUE, NONE, op1(Eind),0 },
+ { "jmp", TRUE, NONE, op1(Eind),0 },
+ { "ljmp", TRUE, NONE, op1(Eind),0 },
+ { "push", TRUE, LONG, op1(E), 0 },
+ { "", TRUE, NONE, 0, 0 }
+};
+
+struct inst db_inst_table[256] = {
+/*00*/ { "add", TRUE, BYTE, op2(R, E), 0 },
+/*01*/ { "add", TRUE, LONG, op2(R, E), 0 },
+/*02*/ { "add", TRUE, BYTE, op2(E, R), 0 },
+/*03*/ { "add", TRUE, LONG, op2(E, R), 0 },
+/*04*/ { "add", FALSE, BYTE, op2(Is, A), 0 },
+/*05*/ { "add", FALSE, LONG, op2(Is, A), 0 },
+/*06*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*07*/ { "pop", FALSE, NONE, op1(Si), 0 },
+
+/*08*/ { "or", TRUE, BYTE, op2(R, E), 0 },
+/*09*/ { "or", TRUE, LONG, op2(R, E), 0 },
+/*0a*/ { "or", TRUE, BYTE, op2(E, R), 0 },
+/*0b*/ { "or", TRUE, LONG, op2(E, R), 0 },
+/*0c*/ { "or", FALSE, BYTE, op2(I, A), 0 },
+/*0d*/ { "or", FALSE, LONG, op2(I, A), 0 },
+/*0e*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*0f*/ { "", FALSE, NONE, 0, 0 },
+
+/*10*/ { "adc", TRUE, BYTE, op2(R, E), 0 },
+/*11*/ { "adc", TRUE, LONG, op2(R, E), 0 },
+/*12*/ { "adc", TRUE, BYTE, op2(E, R), 0 },
+/*13*/ { "adc", TRUE, LONG, op2(E, R), 0 },
+/*14*/ { "adc", FALSE, BYTE, op2(Is, A), 0 },
+/*15*/ { "adc", FALSE, LONG, op2(Is, A), 0 },
+/*16*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*17*/ { "pop", FALSE, NONE, op1(Si), 0 },
+
+/*18*/ { "sbb", TRUE, BYTE, op2(R, E), 0 },
+/*19*/ { "sbb", TRUE, LONG, op2(R, E), 0 },
+/*1a*/ { "sbb", TRUE, BYTE, op2(E, R), 0 },
+/*1b*/ { "sbb", TRUE, LONG, op2(E, R), 0 },
+/*1c*/ { "sbb", FALSE, BYTE, op2(Is, A), 0 },
+/*1d*/ { "sbb", FALSE, LONG, op2(Is, A), 0 },
+/*1e*/ { "push", FALSE, NONE, op1(Si), 0 },
+/*1f*/ { "pop", FALSE, NONE, op1(Si), 0 },
+
+/*20*/ { "and", TRUE, BYTE, op2(R, E), 0 },
+/*21*/ { "and", TRUE, LONG, op2(R, E), 0 },
+/*22*/ { "and", TRUE, BYTE, op2(E, R), 0 },
+/*23*/ { "and", TRUE, LONG, op2(E, R), 0 },
+/*24*/ { "and", FALSE, BYTE, op2(I, A), 0 },
+/*25*/ { "and", FALSE, LONG, op2(I, A), 0 },
+/*26*/ { "", FALSE, NONE, 0, 0 },
+/*27*/ { "aaa", FALSE, NONE, 0, 0 },
+
+/*28*/ { "sub", TRUE, BYTE, op2(R, E), 0 },
+/*29*/ { "sub", TRUE, LONG, op2(R, E), 0 },
+/*2a*/ { "sub", TRUE, BYTE, op2(E, R), 0 },
+/*2b*/ { "sub", TRUE, LONG, op2(E, R), 0 },
+/*2c*/ { "sub", FALSE, BYTE, op2(Is, A), 0 },
+/*2d*/ { "sub", FALSE, LONG, op2(Is, A), 0 },
+/*2e*/ { "", FALSE, NONE, 0, 0 },
+/*2f*/ { "das", FALSE, NONE, 0, 0 },
+
+/*30*/ { "xor", TRUE, BYTE, op2(R, E), 0 },
+/*31*/ { "xor", TRUE, LONG, op2(R, E), 0 },
+/*32*/ { "xor", TRUE, BYTE, op2(E, R), 0 },
+/*33*/ { "xor", TRUE, LONG, op2(E, R), 0 },
+/*34*/ { "xor", FALSE, BYTE, op2(I, A), 0 },
+/*35*/ { "xor", FALSE, LONG, op2(I, A), 0 },
+/*36*/ { "", FALSE, NONE, 0, 0 },
+/*37*/ { "daa", FALSE, NONE, 0, 0 },
+
+/*38*/ { "cmp", TRUE, BYTE, op2(R, E), 0 },
+/*39*/ { "cmp", TRUE, LONG, op2(R, E), 0 },
+/*3a*/ { "cmp", TRUE, BYTE, op2(E, R), 0 },
+/*3b*/ { "cmp", TRUE, LONG, op2(E, R), 0 },
+/*3c*/ { "cmp", FALSE, BYTE, op2(Is, A), 0 },
+/*3d*/ { "cmp", FALSE, LONG, op2(Is, A), 0 },
+/*3e*/ { "", FALSE, NONE, 0, 0 },
+/*3f*/ { "aas", FALSE, NONE, 0, 0 },
+
+/*40*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*41*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*42*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*43*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*44*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*45*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*46*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+/*47*/ { "inc", FALSE, LONG, op1(Ri), 0 },
+
+/*48*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*49*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4a*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4b*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4c*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4d*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4e*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+/*4f*/ { "dec", FALSE, LONG, op1(Ri), 0 },
+
+/*50*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*51*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*52*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*53*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*54*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*55*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*56*/ { "push", FALSE, LONG, op1(Ri), 0 },
+/*57*/ { "push", FALSE, LONG, op1(Ri), 0 },
+
+/*58*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*59*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5a*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5b*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5c*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5d*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5e*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+/*5f*/ { "pop", FALSE, LONG, op1(Ri), 0 },
+
+/*60*/ { "pusha", FALSE, LONG, 0, 0 },
+/*61*/ { "popa", FALSE, LONG, 0, 0 },
+/*62*/ { "bound", TRUE, LONG, op2(E, R), 0 },
+/*63*/ { "arpl", TRUE, NONE, op2(Ew,Rw), 0 },
+
+/*64*/ { "", FALSE, NONE, 0, 0 },
+/*65*/ { "", FALSE, NONE, 0, 0 },
+/*66*/ { "", FALSE, NONE, 0, 0 },
+/*67*/ { "", FALSE, NONE, 0, 0 },
+
+/*68*/ { "push", FALSE, LONG, op1(I), 0 },
+/*69*/ { "imul", TRUE, LONG, op3(I,E,R), 0 },
+/*6a*/ { "push", FALSE, LONG, op1(Ib), 0 },
+/*6b*/ { "imul", TRUE, LONG, op3(Ibs,E,R),0 },
+/*6c*/ { "ins", FALSE, BYTE, op2(DX, DI), 0 },
+/*6d*/ { "ins", FALSE, LONG, op2(DX, DI), 0 },
+/*6e*/ { "outs", FALSE, BYTE, op2(SI, DX), 0 },
+/*6f*/ { "outs", FALSE, LONG, op2(SI, DX), 0 },
+
+/*70*/ { "jo", FALSE, NONE, op1(Db), 0 },
+/*71*/ { "jno", FALSE, NONE, op1(Db), 0 },
+/*72*/ { "jb", FALSE, NONE, op1(Db), 0 },
+/*73*/ { "jnb", FALSE, NONE, op1(Db), 0 },
+/*74*/ { "jz", FALSE, NONE, op1(Db), 0 },
+/*75*/ { "jnz", FALSE, NONE, op1(Db), 0 },
+/*76*/ { "jbe", FALSE, NONE, op1(Db), 0 },
+/*77*/ { "jnbe", FALSE, NONE, op1(Db), 0 },
+
+/*78*/ { "js", FALSE, NONE, op1(Db), 0 },
+/*79*/ { "jns", FALSE, NONE, op1(Db), 0 },
+/*7a*/ { "jp", FALSE, NONE, op1(Db), 0 },
+/*7b*/ { "jnp", FALSE, NONE, op1(Db), 0 },
+/*7c*/ { "jl", FALSE, NONE, op1(Db), 0 },
+/*7d*/ { "jnl", FALSE, NONE, op1(Db), 0 },
+/*7e*/ { "jle", FALSE, NONE, op1(Db), 0 },
+/*7f*/ { "jnle", FALSE, NONE, op1(Db), 0 },
+
+/*80*/ { "", TRUE, BYTE, op2(I, E), (char *)db_Grp1 },
+/*81*/ { "", TRUE, LONG, op2(I, E), (char *)db_Grp1 },
+/*82*/ { "", TRUE, BYTE, op2(Is,E), (char *)db_Grp1 },
+/*83*/ { "", TRUE, LONG, op2(Ibs,E), (char *)db_Grp1 },
+/*84*/ { "test", TRUE, BYTE, op2(R, E), 0 },
+/*85*/ { "test", TRUE, LONG, op2(R, E), 0 },
+/*86*/ { "xchg", TRUE, BYTE, op2(R, E), 0 },
+/*87*/ { "xchg", TRUE, LONG, op2(R, E), 0 },
+
+/*88*/ { "mov", TRUE, BYTE, op2(R, E), 0 },
+/*89*/ { "mov", TRUE, LONG, op2(R, E), 0 },
+/*8a*/ { "mov", TRUE, BYTE, op2(E, R), 0 },
+/*8b*/ { "mov", TRUE, LONG, op2(E, R), 0 },
+/*8c*/ { "mov", TRUE, NONE, op2(S, Ew), 0 },
+/*8d*/ { "lea", TRUE, LONG, op2(E, R), 0 },
+/*8e*/ { "mov", TRUE, NONE, op2(Ew, S), 0 },
+/*8f*/ { "pop", TRUE, LONG, op1(E), 0 },
+
+/*90*/ { "nop", FALSE, NONE, 0, 0 },
+/*91*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*92*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*93*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*94*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*95*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*96*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+/*97*/ { "xchg", FALSE, LONG, op2(A, Ri), 0 },
+
+/*98*/ { "cbw", FALSE, SDEP, 0, "cwde" }, /* cbw/cwde */
+/*99*/ { "cwd", FALSE, SDEP, 0, "cdq" }, /* cwd/cdq */
+/*9a*/ { "lcall", FALSE, NONE, op1(OS), 0 },
+/*9b*/ { "wait", FALSE, NONE, 0, 0 },
+/*9c*/ { "pushf", FALSE, LONG, 0, 0 },
+/*9d*/ { "popf", FALSE, LONG, 0, 0 },
+/*9e*/ { "sahf", FALSE, NONE, 0, 0 },
+/*9f*/ { "lahf", FALSE, NONE, 0, 0 },
+
+/*a0*/ { "mov", FALSE, BYTE, op2(O, A), 0 },
+/*a1*/ { "mov", FALSE, LONG, op2(O, A), 0 },
+/*a2*/ { "mov", FALSE, BYTE, op2(A, O), 0 },
+/*a3*/ { "mov", FALSE, LONG, op2(A, O), 0 },
+/*a4*/ { "movs", FALSE, BYTE, op2(SI,DI), 0 },
+/*a5*/ { "movs", FALSE, LONG, op2(SI,DI), 0 },
+/*a6*/ { "cmps", FALSE, BYTE, op2(SI,DI), 0 },
+/*a7*/ { "cmps", FALSE, LONG, op2(SI,DI), 0 },
+
+/*a8*/ { "test", FALSE, BYTE, op2(I, A), 0 },
+/*a9*/ { "test", FALSE, LONG, op2(I, A), 0 },
+/*aa*/ { "stos", FALSE, BYTE, op1(DI), 0 },
+/*ab*/ { "stos", FALSE, LONG, op1(DI), 0 },
+/*ac*/ { "lods", FALSE, BYTE, op1(SI), 0 },
+/*ad*/ { "lods", FALSE, LONG, op1(SI), 0 },
+/*ae*/ { "scas", FALSE, BYTE, op1(SI), 0 },
+/*af*/ { "scas", FALSE, LONG, op1(SI), 0 },
+
+/*b0*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b1*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b2*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b3*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b4*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b5*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b6*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+/*b7*/ { "mov", FALSE, BYTE, op2(I, Ri), 0 },
+
+/*b8*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*b9*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*ba*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*bb*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*bc*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*bd*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*be*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+/*bf*/ { "mov", FALSE, LONG, op2(I, Ri), 0 },
+
+/*c0*/ { "", TRUE, BYTE, op2(Ib, E), (char *)db_Grp2 },
+/*c1*/ { "", TRUE, LONG, op2(Ib, E), (char *)db_Grp2 },
+/*c2*/ { "ret", FALSE, NONE, op1(Iw), 0 },
+/*c3*/ { "ret", FALSE, NONE, 0, 0 },
+/*c4*/ { "les", TRUE, LONG, op2(E, R), 0 },
+/*c5*/ { "lds", TRUE, LONG, op2(E, R), 0 },
+/*c6*/ { "mov", TRUE, BYTE, op2(I, E), 0 },
+/*c7*/ { "mov", TRUE, LONG, op2(I, E), 0 },
+
+/*c8*/ { "enter", FALSE, NONE, op2(Ib, Iw), 0 },
+/*c9*/ { "leave", FALSE, NONE, 0, 0 },
+/*ca*/ { "lret", FALSE, NONE, op1(Iw), 0 },
+/*cb*/ { "lret", FALSE, NONE, 0, 0 },
+/*cc*/ { "int", FALSE, NONE, op1(o3), 0 },
+/*cd*/ { "int", FALSE, NONE, op1(Ib), 0 },
+/*ce*/ { "into", FALSE, NONE, 0, 0 },
+/*cf*/ { "iret", FALSE, NONE, 0, 0 },
+
+/*d0*/ { "", TRUE, BYTE, op2(o1, E), (char *)db_Grp2 },
+/*d1*/ { "", TRUE, LONG, op2(o1, E), (char *)db_Grp2 },
+/*d2*/ { "", TRUE, BYTE, op2(CL, E), (char *)db_Grp2 },
+/*d3*/ { "", TRUE, LONG, op2(CL, E), (char *)db_Grp2 },
+/*d4*/ { "aam", TRUE, NONE, 0, 0 },
+/*d5*/ { "aad", TRUE, NONE, 0, 0 },
+/*d6*/ { "", FALSE, NONE, 0, 0 },
+/*d7*/ { "xlat", FALSE, BYTE, op1(BX), 0 },
+
+/*d8*/ { "", TRUE, NONE, 0, (char *)db_Esc8 },
+/*d9*/ { "", TRUE, NONE, 0, (char *)db_Esc9 },
+/*da*/ { "", TRUE, NONE, 0, (char *)db_Esca },
+/*db*/ { "", TRUE, NONE, 0, (char *)db_Escb },
+/*dc*/ { "", TRUE, NONE, 0, (char *)db_Escc },
+/*dd*/ { "", TRUE, NONE, 0, (char *)db_Escd },
+/*de*/ { "", TRUE, NONE, 0, (char *)db_Esce },
+/*df*/ { "", TRUE, NONE, 0, (char *)db_Escf },
+
+/*e0*/ { "loopne",FALSE, NONE, op1(Db), 0 },
+/*e1*/ { "loope", FALSE, NONE, op1(Db), 0 },
+/*e2*/ { "loop", FALSE, NONE, op1(Db), 0 },
+/*e3*/ { "jcxz", FALSE, SDEP, op1(Db), "jecxz" },
+/*e4*/ { "in", FALSE, BYTE, op2(Ib, A), 0 },
+/*e5*/ { "in", FALSE, LONG, op2(Ib, A) , 0 },
+/*e6*/ { "out", FALSE, BYTE, op2(A, Ib), 0 },
+/*e7*/ { "out", FALSE, LONG, op2(A, Ib) , 0 },
+
+/*e8*/ { "call", FALSE, NONE, op1(Dl), 0 },
+/*e9*/ { "jmp", FALSE, NONE, op1(Dl), 0 },
+/*ea*/ { "ljmp", FALSE, NONE, op1(OS), 0 },
+/*eb*/ { "jmp", FALSE, NONE, op1(Db), 0 },
+/*ec*/ { "in", FALSE, BYTE, op2(DX, A), 0 },
+/*ed*/ { "in", FALSE, LONG, op2(DX, A) , 0 },
+/*ee*/ { "out", FALSE, BYTE, op2(A, DX), 0 },
+/*ef*/ { "out", FALSE, LONG, op2(A, DX) , 0 },
+
+/*f0*/ { "", FALSE, NONE, 0, 0 },
+/*f1*/ { "", FALSE, NONE, 0, 0 },
+/*f2*/ { "", FALSE, NONE, 0, 0 },
+/*f3*/ { "", FALSE, NONE, 0, 0 },
+/*f4*/ { "hlt", FALSE, NONE, 0, 0 },
+/*f5*/ { "cmc", FALSE, NONE, 0, 0 },
+/*f6*/ { "", TRUE, BYTE, 0, (char *)db_Grp3 },
+/*f7*/ { "", TRUE, LONG, 0, (char *)db_Grp3 },
+
+/*f8*/ { "clc", FALSE, NONE, 0, 0 },
+/*f9*/ { "stc", FALSE, NONE, 0, 0 },
+/*fa*/ { "cli", FALSE, NONE, 0, 0 },
+/*fb*/ { "sti", FALSE, NONE, 0, 0 },
+/*fc*/ { "cld", FALSE, NONE, 0, 0 },
+/*fd*/ { "std", FALSE, NONE, 0, 0 },
+/*fe*/ { "", TRUE, NONE, 0, (char *)db_Grp4 },
+/*ff*/ { "", TRUE, NONE, 0, (char *)db_Grp5 },
+};
+
+struct inst db_bad_inst =
+ { "???", FALSE, NONE, 0, 0 }
+;
+
+#define f_mod(byte) ((byte)>>6)
+#define f_reg(byte) (((byte)>>3)&0x7)
+#define f_rm(byte) ((byte)&0x7)
+
+#define sib_ss(byte) ((byte)>>6)
+#define sib_index(byte) (((byte)>>3)&0x7)
+#define sib_base(byte) ((byte)&0x7)
+
+struct i_addr {
+ int is_reg; /* if reg, reg number is in 'disp' */
+ int disp;
+ char * base;
+ char * index;
+ int ss;
+};
+
+char * db_index_reg_16[8] = {
+ "%bx,%si",
+ "%bx,%di",
+ "%bp,%si",
+ "%bp,%di",
+ "%si",
+ "%di",
+ "%bp",
+ "%bx"
+};
+
+char * db_reg[3][8] = {
+ "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh",
+ "%ax", "%cx", "%dx", "%bx", "%sp", "%bp", "%si", "%di",
+ "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi"
+};
+
+char * db_seg_reg[8] = {
+ "%es", "%cs", "%ss", "%ds", "%fs", "%gs", "", ""
+};
+
+/*
+ * lengths for size attributes
+ */
+int db_lengths[] = {
+ 1, /* BYTE */
+ 2, /* WORD */
+ 4, /* LONG */
+ 8, /* QUAD */
+ 4, /* SNGL */
+ 8, /* DBLR */
+ 10, /* EXTR */
+};
+
+#define get_value_inc(result, loc, size, is_signed) \
+ result = db_get_value((loc), (size), (is_signed)); \
+ (loc) += (size);
+
+/*
+ * Read address at location and return updated location.
+ */
+db_addr_t
+db_read_address(loc, short_addr, regmodrm, addrp)
+ db_addr_t loc;
+ int short_addr;
+ int regmodrm;
+ struct i_addr *addrp; /* out */
+{
+ int mod, rm, sib, index, ss, disp;
+
+ mod = f_mod(regmodrm);
+ rm = f_rm(regmodrm);
+
+ if (mod == 3) {
+ addrp->is_reg = TRUE;
+ addrp->disp = rm;
+ return (loc);
+ }
+ addrp->is_reg = FALSE;
+ addrp->index = 0;
+
+ if (short_addr) {
+ addrp->index = 0;
+ addrp->ss = 0;
+ switch (mod) {
+ case 0:
+ if (rm == 6) {
+ get_value_inc(disp, loc, 2, TRUE);
+ addrp->disp = disp;
+ addrp->base = 0;
+ }
+ else {
+ addrp->disp = 0;
+ addrp->base = db_index_reg_16[rm];
+ }
+ break;
+ case 1:
+ get_value_inc(disp, loc, 1, TRUE);
+ addrp->disp = disp;
+ addrp->base = db_index_reg_16[rm];
+ break;
+ case 2:
+ get_value_inc(disp, loc, 2, TRUE);
+ addrp->disp = disp;
+ addrp->base = db_index_reg_16[rm];
+ break;
+ }
+ }
+ else {
+ if (mod != 3 && rm == 4) {
+ get_value_inc(sib, loc, 1, FALSE);
+ rm = sib_base(sib);
+ index = sib_index(sib);
+ if (index != 4)
+ addrp->index = db_reg[LONG][index];
+ addrp->ss = sib_ss(sib);
+ }
+
+ switch (mod) {
+ case 0:
+ if (rm == 5) {
+ get_value_inc(addrp->disp, loc, 4, FALSE);
+ addrp->base = 0;
+ }
+ else {
+ addrp->disp = 0;
+ addrp->base = db_reg[LONG][rm];
+ }
+ break;
+
+ case 1:
+ get_value_inc(disp, loc, 1, TRUE);
+ addrp->disp = disp;
+ addrp->base = db_reg[LONG][rm];
+ break;
+
+ case 2:
+ get_value_inc(disp, loc, 4, FALSE);
+ addrp->disp = disp;
+ addrp->base = db_reg[LONG][rm];
+ break;
+ }
+ }
+ return (loc);
+}
+
+void
+db_print_address(seg, size, addrp)
+ char * seg;
+ int size;
+ struct i_addr *addrp;
+{
+ if (addrp->is_reg) {
+ db_printf("%s", db_reg[size][addrp->disp]);
+ return;
+ }
+
+ if (seg) {
+ db_printf("%s:", seg);
+ }
+
+ db_printsym((db_addr_t)addrp->disp, DB_STGY_ANY);
+ if (addrp->base != 0 || addrp->index != 0) {
+ db_printf("(");
+ if (addrp->base)
+ db_printf("%s", addrp->base);
+ if (addrp->index)
+ db_printf(",%s,%d", addrp->index, 1<<addrp->ss);
+ db_printf(")");
+ }
+}
+
+/*
+ * Disassemble floating-point ("escape") instruction
+ * and return updated location.
+ */
+db_addr_t
+db_disasm_esc(loc, inst, short_addr, size, seg)
+ db_addr_t loc;
+ int inst;
+ int short_addr;
+ int size;
+ char * seg;
+{
+ int regmodrm;
+ struct finst *fp;
+ int mod;
+ struct i_addr address;
+ char * name;
+
+ get_value_inc(regmodrm, loc, 1, FALSE);
+ fp = &db_Esc_inst[inst - 0xd8][f_reg(regmodrm)];
+ mod = f_mod(regmodrm);
+ if (mod != 3) {
+ /*
+ * Normal address modes.
+ */
+ loc = db_read_address(loc, short_addr, regmodrm, &address);
+ db_printf(fp->f_name);
+ switch(fp->f_size) {
+ case SNGL:
+ db_printf("s");
+ break;
+ case DBLR:
+ db_printf("l");
+ break;
+ case EXTR:
+ db_printf("t");
+ break;
+ case WORD:
+ db_printf("s");
+ break;
+ case LONG:
+ db_printf("l");
+ break;
+ case QUAD:
+ db_printf("q");
+ break;
+ default:
+ break;
+ }
+ db_printf("\t");
+ db_print_address(seg, BYTE, &address);
+ }
+ else {
+ /*
+ * 'reg-reg' - special formats
+ */
+ switch (fp->f_rrmode) {
+ case op2(ST,STI):
+ name = (fp->f_rrname) ? fp->f_rrname : fp->f_name;
+ db_printf("%s\t%%st,%%st(%d)",name,f_rm(regmodrm));
+ break;
+ case op2(STI,ST):
+ name = (fp->f_rrname) ? fp->f_rrname : fp->f_name;
+ db_printf("%s\t%%st(%d),%%st",name, f_rm(regmodrm));
+ break;
+ case op1(STI):
+ name = (fp->f_rrname) ? fp->f_rrname : fp->f_name;
+ db_printf("%s\t%%st(%d)",name, f_rm(regmodrm));
+ break;
+ case op1(X):
+ db_printf("%s", ((char **)fp->f_rrname)[f_rm(regmodrm)]);
+ break;
+ case op1(XA):
+ db_printf("%s\t%%ax",
+ ((char **)fp->f_rrname)[f_rm(regmodrm)]);
+ break;
+ default:
+ db_printf("<bad instruction>");
+ break;
+ }
+ }
+
+ return (loc);
+}
+
+/*
+ * Disassemble instruction at 'loc'. 'altfmt' specifies an
+ * (optional) alternate format. Return address of start of
+ * next instruction.
+ */
+db_addr_t
+db_disasm(loc, altfmt)
+ db_addr_t loc;
+ boolean_t altfmt;
+{
+ int inst;
+ int size;
+ int short_addr;
+ char * seg;
+ struct inst * ip;
+ char * i_name;
+ int i_size;
+ int i_mode;
+ int regmodrm = 0;
+ boolean_t first;
+ int displ;
+ int prefix;
+ int imm;
+ int imm2;
+ int len;
+ struct i_addr address;
+
+ get_value_inc(inst, loc, 1, FALSE);
+ short_addr = FALSE;
+ size = LONG;
+ seg = 0;
+
+ /*
+ * Get prefixes
+ */
+ prefix = TRUE;
+ do {
+ switch (inst) {
+ case 0x66: /* data16 */
+ size = WORD;
+ break;
+ case 0x67:
+ short_addr = TRUE;
+ break;
+ case 0x26:
+ seg = "%es";
+ break;
+ case 0x36:
+ seg = "%ss";
+ break;
+ case 0x2e:
+ seg = "%cs";
+ break;
+ case 0x3e:
+ seg = "%ds";
+ break;
+ case 0x64:
+ seg = "%fs";
+ break;
+ case 0x65:
+ seg = "%gs";
+ break;
+ case 0xf0:
+ db_printf("lock ");
+ break;
+ case 0xf2:
+ db_printf("repne ");
+ break;
+ case 0xf3:
+ db_printf("repe "); /* XXX repe VS rep */
+ break;
+ default:
+ prefix = FALSE;
+ break;
+ }
+ if (prefix) {
+ get_value_inc(inst, loc, 1, FALSE);
+ }
+ } while (prefix);
+
+ if (inst >= 0xd8 && inst <= 0xdf) {
+ loc = db_disasm_esc(loc, inst, short_addr, size, seg);
+ db_printf("\n");
+ return (loc);
+ }
+
+ if (inst == 0x0f) {
+ get_value_inc(inst, loc, 1, FALSE);
+ ip = db_inst_0f[inst>>4];
+ if (ip == 0) {
+ ip = &db_bad_inst;
+ }
+ else {
+ ip = &ip[inst&0xf];
+ }
+ }
+ else
+ ip = &db_inst_table[inst];
+
+ if (ip->i_has_modrm) {
+ get_value_inc(regmodrm, loc, 1, FALSE);
+ loc = db_read_address(loc, short_addr, regmodrm, &address);
+ }
+
+ i_name = ip->i_name;
+ i_size = ip->i_size;
+ i_mode = ip->i_mode;
+
+ if (ip->i_extra == (char *)db_Grp1 ||
+ ip->i_extra == (char *)db_Grp2 ||
+ ip->i_extra == (char *)db_Grp6 ||
+ ip->i_extra == (char *)db_Grp7 ||
+ ip->i_extra == (char *)db_Grp8) {
+ i_name = ((char **)ip->i_extra)[f_reg(regmodrm)];
+ }
+ else if (ip->i_extra == (char *)db_Grp3) {
+ ip = (struct inst *)ip->i_extra;
+ ip = &ip[f_reg(regmodrm)];
+ i_name = ip->i_name;
+ i_mode = ip->i_mode;
+ }
+ else if (ip->i_extra == (char *)db_Grp4 ||
+ ip->i_extra == (char *)db_Grp5) {
+ ip = (struct inst *)ip->i_extra;
+ ip = &ip[f_reg(regmodrm)];
+ i_name = ip->i_name;
+ i_mode = ip->i_mode;
+ i_size = ip->i_size;
+ }
+
+ if (i_size == SDEP) {
+ if (size == WORD)
+ db_printf(i_name);
+ else
+ db_printf(ip->i_extra);
+ }
+ else {
+ db_printf(i_name);
+ if (i_size != NONE) {
+ if (i_size == BYTE) {
+ db_printf("b");
+ size = BYTE;
+ }
+ else if (i_size == WORD) {
+ db_printf("w");
+ size = WORD;
+ }
+ else if (size == WORD)
+ db_printf("w");
+ else
+ db_printf("l");
+ }
+ }
+ db_printf("\t");
+ for (first = TRUE;
+ i_mode != 0;
+ i_mode >>= 8, first = FALSE)
+ {
+ if (!first)
+ db_printf(",");
+
+ switch (i_mode & 0xFF) {
+
+ case E:
+ db_print_address(seg, size, &address);
+ break;
+
+ case Eind:
+ db_printf("*");
+ db_print_address(seg, size, &address);
+ break;
+
+ case Ew:
+ db_print_address(seg, WORD, &address);
+ break;
+
+ case Eb:
+ db_print_address(seg, BYTE, &address);
+ break;
+
+ case R:
+ db_printf("%s", db_reg[size][f_reg(regmodrm)]);
+ break;
+
+ case Rw:
+ db_printf("%s", db_reg[WORD][f_reg(regmodrm)]);
+ break;
+
+ case Ri:
+ db_printf("%s", db_reg[size][f_rm(inst)]);
+ break;
+
+ case S:
+ db_printf("%s", db_seg_reg[f_reg(regmodrm)]);
+ break;
+
+ case Si:
+ db_printf("%s", db_seg_reg[f_reg(inst)]);
+ break;
+
+ case A:
+ db_printf("%s", db_reg[size][0]); /* acc */
+ break;
+
+ case BX:
+ if (seg)
+ db_printf("%s:", seg);
+ db_printf("(%s)", short_addr ? "%bx" : "%ebx");
+ break;
+
+ case CL:
+ db_printf("%%cl");
+ break;
+
+ case DX:
+ db_printf("%%dx");
+ break;
+
+ case SI:
+ if (seg)
+ db_printf("%s:", seg);
+ db_printf("(%s)", short_addr ? "%si" : "%esi");
+ break;
+
+ case DI:
+ db_printf("%%es:(%s)", short_addr ? "%di" : "%edi");
+ break;
+
+ case CR:
+ db_printf("%%cr%d", f_reg(regmodrm));
+ break;
+
+ case DR:
+ db_printf("%%dr%d", f_reg(regmodrm));
+ break;
+
+ case TR:
+ db_printf("%%tr%d", f_reg(regmodrm));
+ break;
+
+ case I:
+ len = db_lengths[size];
+ get_value_inc(imm, loc, len, FALSE);/* unsigned */
+ db_printf("$%#n", imm);
+ break;
+
+ case Is:
+ len = db_lengths[size];
+ get_value_inc(imm, loc, len, TRUE); /* signed */
+ db_printf("$%#r", imm);
+ break;
+
+ case Ib:
+ get_value_inc(imm, loc, 1, FALSE); /* unsigned */
+ db_printf("$%#n", imm);
+ break;
+
+ case Ibs:
+ get_value_inc(imm, loc, 1, TRUE); /* signed */
+ db_printf("$%#r", imm);
+ break;
+
+ case Iw:
+ get_value_inc(imm, loc, 2, FALSE); /* unsigned */
+ db_printf("$%#n", imm);
+ break;
+
+ case Il:
+ get_value_inc(imm, loc, 4, FALSE);
+ db_printf("$%#n", imm);
+ break;
+
+ case O:
+ if (short_addr) {
+ get_value_inc(displ, loc, 2, TRUE);
+ }
+ else {
+ get_value_inc(displ, loc, 4, TRUE);
+ }
+ if (seg)
+ db_printf("%s:%#r",seg, displ);
+ else
+ db_printsym((db_addr_t)displ, DB_STGY_ANY);
+ break;
+
+ case Db:
+ get_value_inc(displ, loc, 1, TRUE);
+ db_printsym((db_addr_t)(displ + loc), DB_STGY_XTRN);
+ break;
+
+ case Dl:
+ get_value_inc(displ, loc, 4, TRUE);
+ db_printsym((db_addr_t)(displ + loc), DB_STGY_XTRN);
+ break;
+
+ case o1:
+ db_printf("$1");
+ break;
+
+ case o3:
+ db_printf("$3");
+ break;
+
+ case OS:
+ get_value_inc(imm, loc, 4, FALSE); /* offset */
+ get_value_inc(imm2, loc, 2, FALSE); /* segment */
+ db_printf("$%#n,%#n", imm2, imm);
+ break;
+ }
+ }
+
+ if (altfmt == 0) {
+ if (inst == 0xe9 || inst == 0xeb) {
+ /*
+ * GAS pads to longword boundary after unconditional jumps.
+ */
+ loc = (loc + (4-1)) & ~(4-1);
+ }
+ }
+ db_printf("\n");
+ return (loc);
+}
+
diff --git a/sys/i386/i386/db_interface.c b/sys/i386/i386/db_interface.c
new file mode 100644
index 0000000..5f7c9d5
--- /dev/null
+++ b/sys/i386/i386/db_interface.c
@@ -0,0 +1,240 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_interface.c,v 1.5 1993/12/19 00:50:00 wollman Exp $
+ */
+
+/*
+ * Interface to new debugger.
+ */
+#include "param.h"
+#include "systm.h"
+#include "kernel.h"
+#include "proc.h"
+#include "ddb/ddb.h"
+
+#include <sys/reboot.h>
+#include <vm/vm_statistics.h>
+#include <vm/pmap.h>
+
+#include <setjmp.h>
+
+int db_active = 0;
+
+db_regs_t ddb_regs;
+
+/*
+ * Received keyboard interrupt sequence.
+ */
+void
+kdb_kbd_trap(regs)
+ struct i386_saved_state *regs;
+{
+ if (db_active == 0 && (boothowto & RB_KDB)) {
+ printf("\n\nkernel: keyboard interrupt\n");
+ kdb_trap(-1, 0, regs);
+ }
+}
+
+/*
+ * kdb_trap - field a TRACE or BPT trap
+ */
+
+static jmp_buf *db_nofault = 0;
+
+int
+kdb_trap(type, code, regs)
+ int type, code;
+ register struct i386_saved_state *regs;
+{
+#if 0
+ if ((boothowto&RB_KDB) == 0)
+ return(0);
+#endif
+
+ switch (type) {
+ case T_BPTFLT /* T_INT3 */: /* breakpoint */
+ case T_KDBTRAP /* T_WATCHPOINT */: /* watchpoint */
+ case T_PRIVINFLT /* T_DEBUG */: /* single_step */
+
+ case -1: /* keyboard interrupt */
+ break;
+
+ default:
+ kdbprinttrap(type, code);
+
+ if (db_nofault) {
+ jmp_buf *no_fault = db_nofault;
+ db_nofault = 0;
+ longjmp(*no_fault, 1);
+ }
+ }
+
+ /* Should switch to kdb`s own stack here. */
+
+ ddb_regs = *regs;
+
+ if ((regs->tf_cs & 0x3) == 0) {
+ /*
+ * Kernel mode - esp and ss not saved
+ */
+ ddb_regs.tf_esp = (int)&regs->tf_esp; /* kernel stack pointer */
+#if 0
+ ddb_regs.ss = KERNEL_DS;
+#endif
+ asm(" movw %%ss,%%ax; movl %%eax,%0 "
+ : "=g" (ddb_regs.tf_ss)
+ :
+ : "ax");
+ }
+
+ db_active++;
+ cnpollc(TRUE);
+ db_trap(type, code);
+ cnpollc(FALSE);
+ db_active--;
+
+ regs->tf_eip = ddb_regs.tf_eip;
+ regs->tf_eflags = ddb_regs.tf_eflags;
+ regs->tf_eax = ddb_regs.tf_eax;
+ regs->tf_ecx = ddb_regs.tf_ecx;
+ regs->tf_edx = ddb_regs.tf_edx;
+ regs->tf_ebx = ddb_regs.tf_ebx;
+ if (regs->tf_cs & 0x3) {
+ /*
+ * user mode - saved esp and ss valid
+ */
+ regs->tf_esp = ddb_regs.tf_esp; /* user stack pointer */
+ regs->tf_ss = ddb_regs.tf_ss & 0xffff; /* user stack segment */
+ }
+ regs->tf_ebp = ddb_regs.tf_ebp;
+ regs->tf_esi = ddb_regs.tf_esi;
+ regs->tf_edi = ddb_regs.tf_edi;
+ regs->tf_es = ddb_regs.tf_es & 0xffff;
+ regs->tf_cs = ddb_regs.tf_cs & 0xffff;
+ regs->tf_ds = ddb_regs.tf_ds & 0xffff;
+#if 0
+ regs->tf_fs = ddb_regs.tf_fs & 0xffff;
+ regs->tf_gs = ddb_regs.tf_gs & 0xffff;
+#endif
+
+ return (1);
+}
+
+/*
+ * Print trap reason.
+ */
+void
+kdbprinttrap(type, code)
+ int type, code;
+{
+ printf("kernel: ");
+ printf("type %d", type);
+ printf(" trap, code=%x\n", code);
+}
+
+/*
+ * Read bytes from kernel address space for debugger.
+ */
+
+extern jmp_buf db_jmpbuf;
+
+void
+db_read_bytes(addr, size, data)
+ vm_offset_t addr;
+ register int size;
+ register char *data;
+{
+ register char *src;
+
+ db_nofault = &db_jmpbuf;
+
+ src = (char *)addr;
+ while (--size >= 0)
+ *data++ = *src++;
+
+ db_nofault = 0;
+}
+
+/*
+ * Write bytes to kernel address space for debugger.
+ */
+void
+db_write_bytes(addr, size, data)
+ vm_offset_t addr;
+ register int size;
+ register char *data;
+{
+ register char *dst;
+
+ register pt_entry_t *ptep0 = 0;
+ pt_entry_t oldmap0 = { 0 };
+ vm_offset_t addr1;
+ register pt_entry_t *ptep1 = 0;
+ pt_entry_t oldmap1 = { 0 };
+ extern char etext;
+
+ db_nofault = &db_jmpbuf;
+
+ if (addr >= VM_MIN_KERNEL_ADDRESS &&
+ addr <= (vm_offset_t)&etext)
+ {
+ ptep0 = pmap_pte(kernel_pmap, addr);
+ oldmap0 = *ptep0;
+ *(int *)ptep0 |= /* INTEL_PTE_WRITE */ PG_RW;
+
+ addr1 = i386_trunc_page(addr + size - 1);
+ if (i386_trunc_page(addr) != addr1) {
+ /* data crosses a page boundary */
+
+ ptep1 = pmap_pte(kernel_pmap, addr1);
+ oldmap1 = *ptep1;
+ *(int *)ptep1 |= /* INTEL_PTE_WRITE */ PG_RW;
+ }
+ tlbflush();
+ }
+
+ dst = (char *)addr;
+
+ while (--size >= 0)
+ *dst++ = *data++;
+
+ db_nofault = 0;
+
+ if (ptep0) {
+ *ptep0 = oldmap0;
+ if (ptep1) {
+ *ptep1 = oldmap1;
+ }
+ tlbflush();
+ }
+}
+
+void
+Debugger (msg)
+ const char *msg;
+{
+ asm ("int $3");
+}
diff --git a/sys/i386/i386/db_trace.c b/sys/i386/i386/db_trace.c
new file mode 100644
index 0000000..c7c2cd8
--- /dev/null
+++ b/sys/i386/i386/db_trace.c
@@ -0,0 +1,339 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * $Id: db_trace.c,v 1.4 1994/01/03 07:55:19 davidg Exp $
+ */
+
+#include "param.h"
+
+#include <vm/vm_param.h>
+#include <vm/lock.h>
+#include <vm/vm_statistics.h>
+#include <machine/pmap.h>
+#include "systm.h"
+#include "proc.h"
+#include "ddb/ddb.h"
+
+#include <ddb/db_access.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_variables.h>
+
+/*
+ * Machine register set.
+ */
+struct db_variable db_regs[] = {
+ "cs", (int *)&ddb_regs.tf_cs, FCN_NULL,
+ "ds", (int *)&ddb_regs.tf_ds, FCN_NULL,
+ "es", (int *)&ddb_regs.tf_es, FCN_NULL,
+#if 0
+ "fs", (int *)&ddb_regs.tf_fs, FCN_NULL,
+ "gs", (int *)&ddb_regs.tf_gs, FCN_NULL,
+#endif
+ "ss", (int *)&ddb_regs.tf_ss, FCN_NULL,
+ "eax", (int *)&ddb_regs.tf_eax, FCN_NULL,
+ "ecx", (int *)&ddb_regs.tf_ecx, FCN_NULL,
+ "edx", (int *)&ddb_regs.tf_edx, FCN_NULL,
+ "ebx", (int *)&ddb_regs.tf_ebx, FCN_NULL,
+ "esp", (int *)&ddb_regs.tf_esp,FCN_NULL,
+ "ebp", (int *)&ddb_regs.tf_ebp, FCN_NULL,
+ "esi", (int *)&ddb_regs.tf_esi, FCN_NULL,
+ "edi", (int *)&ddb_regs.tf_edi, FCN_NULL,
+ "eip", (int *)&ddb_regs.tf_eip, FCN_NULL,
+ "efl", (int *)&ddb_regs.tf_eflags, FCN_NULL,
+};
+struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
+
+/*
+ * Stack trace.
+ */
+#define INKERNEL(va) (((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
+
+struct i386_frame {
+ struct i386_frame *f_frame;
+ int f_retaddr;
+ int f_arg0;
+};
+
+#define TRAP 1
+#define INTERRUPT 2
+#define SYSCALL 3
+
+db_addr_t db_trap_symbol_value = 0;
+db_addr_t db_syscall_symbol_value = 0;
+db_addr_t db_kdintr_symbol_value = 0;
+boolean_t db_trace_symbols_found = FALSE;
+
+void
+db_find_trace_symbols()
+{
+ db_expr_t value;
+ if (db_value_of_name("_trap", &value))
+ db_trap_symbol_value = (db_addr_t) value;
+ if (db_value_of_name("_kdintr", &value))
+ db_kdintr_symbol_value = (db_addr_t) value;
+ if (db_value_of_name("_syscall", &value))
+ db_syscall_symbol_value = (db_addr_t) value;
+ db_trace_symbols_found = TRUE;
+}
+
+/*
+ * Figure out how many arguments were passed into the frame at "fp".
+ */
+int
+db_numargs(fp)
+ struct i386_frame *fp;
+{
+ int *argp;
+ int inst;
+ int args;
+ extern char etext[];
+
+ argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE);
+ if (argp < (int *)VM_MIN_KERNEL_ADDRESS || argp > (int *)etext)
+ args = 5;
+ else {
+ inst = db_get_value((int)argp, 4, FALSE);
+ if ((inst & 0xff) == 0x59) /* popl %ecx */
+ args = 1;
+ else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */
+ args = ((inst >> 16) & 0xff) / 4;
+ else
+ args = 5;
+ }
+ return (args);
+}
+
+/*
+ * Figure out the next frame up in the call stack.
+ * For trap(), we print the address of the faulting instruction and
+ * proceed with the calling frame. We return the ip that faulted.
+ * If the trap was caused by jumping through a bogus pointer, then
+ * the next line in the backtrace will list some random function as
+ * being called. It should get the argument list correct, though.
+ * It might be possible to dig out from the next frame up the name
+ * of the function that faulted, but that could get hairy.
+ */
+void
+db_nextframe(fp, ip, argp, is_trap)
+ struct i386_frame **fp; /* in/out */
+ db_addr_t *ip; /* out */
+ int *argp; /* in */
+ int is_trap; /* in */
+{
+ struct i386_saved_state *saved_regs;
+
+ switch (is_trap) {
+ case 0:
+ *ip = (db_addr_t)
+ db_get_value((int) &(*fp)->f_retaddr, 4, FALSE);
+ *fp = (struct i386_frame *)
+ db_get_value((int) &(*fp)->f_frame, 4, FALSE);
+ break;
+ case TRAP:
+ default:
+ /*
+ * We know that trap() has 1 argument and we know that
+ * it is an (int *).
+ */
+#if 0
+ saved_regs = (struct i386_saved_state *)
+ db_get_value((int)argp, 4, FALSE);
+#endif
+ saved_regs = (struct i386_saved_state *)argp;
+ db_printf("--- trap (number %d) ---\n",
+ saved_regs->tf_trapno & 0xffff);
+ db_printsym(saved_regs->tf_eip, DB_STGY_XTRN);
+ db_printf(":\n");
+ *fp = (struct i386_frame *)saved_regs->tf_ebp;
+ *ip = (db_addr_t)saved_regs->tf_eip;
+ break;
+
+ case SYSCALL: {
+ struct trapframe *saved_regs = (struct trapframe *)argp;
+
+ db_printf("--- syscall (number %d) ---\n", saved_regs->tf_eax);
+ db_printsym(saved_regs->tf_eip, DB_STGY_XTRN);
+ db_printf(":\n");
+ *fp = (struct i386_frame *)saved_regs->tf_ebp;
+ *ip = (db_addr_t)saved_regs->tf_eip;
+ }
+ break;
+ }
+}
+
+void
+db_stack_trace_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ boolean_t have_addr;
+ db_expr_t count;
+ char *modif;
+{
+ struct i386_frame *frame, *lastframe;
+ int *argp;
+ db_addr_t callpc;
+ int is_trap;
+ boolean_t kernel_only = TRUE;
+ boolean_t trace_thread = FALSE;
+
+#if 0
+ if (!db_trace_symbols_found)
+ db_find_trace_symbols();
+#endif
+
+ {
+ register char *cp = modif;
+ register char c;
+
+ while ((c = *cp++) != 0) {
+ if (c == 't')
+ trace_thread = TRUE;
+ if (c == 'u')
+ kernel_only = FALSE;
+ }
+ }
+
+ if (count == -1)
+ count = 65535;
+
+ if (!have_addr) {
+ frame = (struct i386_frame *)ddb_regs.tf_ebp;
+ callpc = (db_addr_t)ddb_regs.tf_eip;
+ }
+ else if (trace_thread) {
+ printf ("db_trace.c: can't trace thread\n");
+ }
+ else {
+ frame = (struct i386_frame *)addr;
+ callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE);
+ }
+
+ lastframe = 0;
+ while (count-- && frame != 0) {
+ int narg;
+ char * name;
+ db_expr_t offset;
+ db_sym_t sym;
+#define MAXNARG 16
+ char *argnames[MAXNARG], **argnp = NULL;
+
+ sym = db_search_symbol(callpc, DB_STGY_ANY, &offset);
+ db_symbol_values(sym, &name, NULL);
+
+ if (lastframe == 0 && sym == NULL) {
+ /* Symbol not found, peek at code */
+ int instr = db_get_value(callpc, 4, FALSE);
+
+ offset = 1;
+ if ((instr & 0x00ffffff) == 0x00e58955 ||
+ /* enter: pushl %ebp, movl %esp, %ebp */
+ (instr & 0x0000ffff) == 0x0000e589
+ /* enter+1: movl %esp, %ebp */ ) {
+ offset = 0;
+ }
+ }
+#define STRCMP(s1,s2) ((s1) && (s2) && strcmp((s1), (s2)) == 0)
+ if (INKERNEL((int)frame) && STRCMP(name, "_trap")) {
+ narg = 1;
+ is_trap = TRAP;
+ }
+ else
+ if (INKERNEL((int)frame) && STRCMP(name, "_kdintr")) {
+ is_trap = INTERRUPT;
+ narg = 0;
+ }
+ else
+ if (INKERNEL((int)frame) && STRCMP(name, "_syscall")) {
+ is_trap = SYSCALL;
+ narg = 0;
+ }
+#undef STRCMP
+ else {
+ is_trap = 0;
+ narg = MAXNARG;
+ if (db_sym_numargs(sym, &narg, argnames)) {
+ argnp = argnames;
+ } else {
+ narg = db_numargs(frame);
+ }
+ }
+
+ db_printf("%s(", name);
+
+ if (lastframe == 0 && offset == 0 && !have_addr) {
+ /*
+ * We have a breakpoint before the frame is set up
+ * Use %esp instead
+ */
+ argp = &((struct i386_frame *)(ddb_regs.tf_esp-4))->f_arg0;
+ } else
+ argp = &frame->f_arg0;
+
+ while (narg) {
+ if (argnp)
+ db_printf("%s=", *argnp++);
+ db_printf("%x", db_get_value((int)argp, 4, FALSE));
+ argp++;
+ if (--narg != 0)
+ db_printf(",");
+ }
+ db_printf(") at ");
+ db_printsym(callpc, DB_STGY_PROC);
+ db_printf("\n");
+
+ if (lastframe == 0 && offset == 0 && !have_addr) {
+ /* Frame really belongs to next callpc */
+ lastframe = (struct i386_frame *)(ddb_regs.tf_esp-4);
+ callpc = (db_addr_t)db_get_value((int)&lastframe->f_retaddr, 4, FALSE);
+ continue;
+ }
+
+ lastframe = frame;
+ db_nextframe(&frame, &callpc, &frame->f_arg0, is_trap);
+
+ if (frame == 0) {
+ /* end of chain */
+ break;
+ }
+ if (INKERNEL((int)frame)) {
+ /* staying in kernel */
+ if (frame <= lastframe) {
+ db_printf("Bad frame pointer: 0x%x\n", frame);
+ break;
+ }
+ }
+ else if (INKERNEL((int)lastframe)) {
+ /* switch from user to kernel */
+ if (kernel_only)
+ break; /* kernel stack only */
+ }
+ else {
+ /* in user */
+ if (frame <= lastframe) {
+ db_printf("Bad user frame pointer: 0x%x\n", frame);
+ break;
+ }
+ }
+ }
+}
diff --git a/sys/i386/i386/dkbad.c b/sys/i386/i386/dkbad.c
new file mode 100644
index 0000000..2ebf05c
--- /dev/null
+++ b/sys/i386/i386/dkbad.c
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)dkbad.c 5.4 (Berkeley) 1/19/91
+ * $Id: dkbad.c,v 1.2 1993/10/16 14:14:59 rgrimes Exp $
+ */
+
+
+#ifndef NOBADSECT
+#include "sys/param.h"
+#include "systm.h"
+#include "sys/buf.h"
+#include "sys/dkbad.h"
+
+/*
+ * Search the bad sector table looking for
+ * the specified sector. Return index if found.
+ * Return -1 if not found.
+ */
+
+isbad(bt, cyl, trk, sec)
+ register struct dkbad *bt;
+{
+ register int i;
+ register long blk, bblk;
+
+ blk = ((long)cyl << 16) + (trk << 8) + sec;
+ for (i = 0; i < 126; i++) {
+ bblk = ((long)bt->bt_bad[i].bt_cyl << 16) + bt->bt_bad[i].bt_trksec;
+ if (blk == bblk)
+ return (i);
+ if (blk < bblk || bblk < 0)
+ break;
+ }
+ return (-1);
+}
+#endif
diff --git a/sys/i386/i386/exception.s b/sys/i386/i386/exception.s
new file mode 100644
index 0000000..30bc164
--- /dev/null
+++ b/sys/i386/i386/exception.s
@@ -0,0 +1,275 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: exception.s,v 1.2 1994/01/03 07:55:20 davidg Exp $
+ */
+
+#include "npx.h" /* NNPX */
+
+#include "assym.s" /* system defines */
+
+#include "errno.h" /* error return codes */
+
+#include "machine/spl.h" /* SWI_AST_MASK ... */
+
+#include "machine/psl.h" /* PSL_I */
+
+#include "machine/trap.h" /* trap codes */
+#include "syscall.h" /* syscall numbers */
+
+#include "machine/asmacros.h" /* miscellaneous macros */
+
+#define KDSEL 0x10 /* kernel data selector */
+#define SEL_RPL_MASK 0x0003
+#define TRAPF_CS_OFF (13 * 4)
+
+ .text
+
+/*****************************************************************************/
+/* Trap handling */
+/*****************************************************************************/
+/*
+ * Trap and fault vector routines
+ */
+#define IDTVEC(name) ALIGN_TEXT ; .globl _X/**/name ; _X/**/name:
+#define TRAP(a) pushl $(a) ; jmp _alltraps
+
+/*
+ * XXX - debugger traps are now interrupt gates so at least bdb doesn't lose
+ * control. The sti's give the standard losing behaviour for ddb and kgdb.
+ */
+#ifdef BDE_DEBUGGER
+#define BDBTRAP(name) \
+ ss ; \
+ cmpb $0,_bdb_exists ; \
+ je 1f ; \
+ testb $SEL_RPL_MASK,4(%esp) ; \
+ jne 1f ; \
+ ss ; \
+ .globl bdb_/**/name/**/_ljmp ; \
+bdb_/**/name/**/_ljmp: ; \
+ ljmp $0,$0 ; \
+1:
+#else
+#define BDBTRAP(name)
+#endif
+
+#ifdef KGDB
+# define BPTTRAP(a) testl $PSL_I,4+8(%esp) ; je 1f ; sti ; 1: ; \
+ pushl $(a) ; jmp _bpttraps
+#else
+# define BPTTRAP(a) testl $PSL_I,4+8(%esp) ; je 1f ; sti ; 1: ; TRAP(a)
+#endif
+
+MCOUNT_LABEL(user)
+MCOUNT_LABEL(btrap)
+
+IDTVEC(div)
+ pushl $0; TRAP(T_DIVIDE)
+IDTVEC(dbg)
+ BDBTRAP(dbg)
+ pushl $0; BPTTRAP(T_TRCTRAP)
+IDTVEC(nmi)
+ pushl $0; TRAP(T_NMI)
+IDTVEC(bpt)
+ BDBTRAP(bpt)
+ pushl $0; BPTTRAP(T_BPTFLT)
+IDTVEC(ofl)
+ pushl $0; TRAP(T_OFLOW)
+IDTVEC(bnd)
+ pushl $0; TRAP(T_BOUND)
+IDTVEC(ill)
+ pushl $0; TRAP(T_PRIVINFLT)
+IDTVEC(dna)
+ pushl $0; TRAP(T_DNA)
+IDTVEC(dble)
+ TRAP(T_DOUBLEFLT)
+IDTVEC(fpusegm)
+ pushl $0; TRAP(T_FPOPFLT)
+IDTVEC(tss)
+ TRAP(T_TSSFLT)
+IDTVEC(missing)
+ TRAP(T_SEGNPFLT)
+IDTVEC(stk)
+ TRAP(T_STKFLT)
+IDTVEC(prot)
+ TRAP(T_PROTFLT)
+IDTVEC(page)
+ TRAP(T_PAGEFLT)
+IDTVEC(rsvd)
+ pushl $0; TRAP(T_RESERVED)
+IDTVEC(fpu)
+#if NNPX > 0
+ /*
+ * Handle like an interrupt so that we can call npxintr to clear the
+ * error. It would be better to handle npx interrupts as traps but
+ * this is difficult for nested interrupts.
+ */
+ pushl $0 /* dumby error code */
+ pushl $0 /* dumby trap type */
+ pushal
+ pushl %ds
+ pushl %es /* now the stack frame is a trap frame */
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+ FAKE_MCOUNT(12*4(%esp))
+ movl _cpl,%eax
+ pushl %eax
+ pushl $0 /* dummy unit to finish building intr frame */
+ incl _cnt+V_TRAP
+ orl $SWI_AST_MASK,%eax
+ movl %eax,_cpl
+ call _npxintr
+ MEXITCOUNT
+ jmp _doreti
+#else /* NNPX > 0 */
+ pushl $0; TRAP(T_ARITHTRAP)
+#endif /* NNPX > 0 */
+ /* 17 - 31 reserved for future exp */
+IDTVEC(rsvd0)
+ pushl $0; TRAP(17)
+IDTVEC(rsvd1)
+ pushl $0; TRAP(18)
+IDTVEC(rsvd2)
+ pushl $0; TRAP(19)
+IDTVEC(rsvd3)
+ pushl $0; TRAP(20)
+IDTVEC(rsvd4)
+ pushl $0; TRAP(21)
+IDTVEC(rsvd5)
+ pushl $0; TRAP(22)
+IDTVEC(rsvd6)
+ pushl $0; TRAP(23)
+IDTVEC(rsvd7)
+ pushl $0; TRAP(24)
+IDTVEC(rsvd8)
+ pushl $0; TRAP(25)
+IDTVEC(rsvd9)
+ pushl $0; TRAP(26)
+IDTVEC(rsvd10)
+ pushl $0; TRAP(27)
+IDTVEC(rsvd11)
+ pushl $0; TRAP(28)
+IDTVEC(rsvd12)
+ pushl $0; TRAP(29)
+IDTVEC(rsvd13)
+ pushl $0; TRAP(30)
+IDTVEC(rsvd14)
+ pushl $0; TRAP(31)
+
+ SUPERALIGN_TEXT
+_alltraps:
+ pushal
+ pushl %ds
+ pushl %es
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+ FAKE_MCOUNT(12*4(%esp))
+calltrap:
+ FAKE_MCOUNT(_btrap) /* init "from" _btrap -> calltrap */
+ incl _cnt+V_TRAP
+ orl $SWI_AST_MASK,_cpl
+ call _trap
+ /*
+ * There was no place to save the cpl so we have to recover it
+ * indirectly. For traps from user mode it was 0, and for traps
+ * from kernel mode Oring SWI_AST_MASK into it didn't change it.
+ */
+ subl %eax,%eax
+ testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp)
+ jne 1f
+ movl _cpl,%eax
+1:
+ /*
+ * Return via _doreti to handle ASTs. Have to change trap frame
+ * to interrupt frame.
+ */
+ pushl %eax
+ subl $4,%esp
+ MEXITCOUNT
+ jmp _doreti
+
+#ifdef KGDB
+/*
+ * This code checks for a kgdb trap, then falls through
+ * to the regular trap code.
+ */
+ SUPERALIGN_TEXT
+_bpttraps:
+ pushal
+ pushl %ds
+ pushl %es
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+ FAKE_MCOUNT(12*4(%esp))
+ testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp) /* non-kernel mode? */
+ jne calltrap /* yes */
+ call _kgdb_trap_glue
+ MEXITCOUNT
+ jmp calltrap
+#endif
+
+/*
+ * Call gate entry for syscall
+ */
+ SUPERALIGN_TEXT
+IDTVEC(syscall)
+ pushfl /* Room for tf_err */
+ pushfl /* Room for tf_trapno */
+ pushal
+ pushl %ds
+ pushl %es
+ movl $KDSEL,%eax /* switch to kernel segments */
+ movl %ax,%ds
+ movl %ax,%es
+ movl TF_ERR(%esp),%eax /* copy eflags from tf_err to fs_eflags */
+ movl %eax,TF_EFLAGS(%esp)
+ FAKE_MCOUNT(12*4(%esp))
+ incl _cnt+V_SYSCALL
+ movl $SWI_AST_MASK,_cpl
+ call _syscall
+ /*
+ * Return via _doreti to handle ASTs.
+ */
+ pushl $0 /* cpl to restore */
+ subl $4,%esp
+ MEXITCOUNT
+ jmp _doreti
+
+/*
+ * include generated interrupt vectors and ISA intr code
+ */
+#include "i386/isa/vector.s"
+#include "i386/isa/icu.s"
diff --git a/sys/i386/i386/genassym.c b/sys/i386/i386/genassym.c
new file mode 100644
index 0000000..b7847e8
--- /dev/null
+++ b/sys/i386/i386/genassym.c
@@ -0,0 +1,194 @@
+/*-
+ * Copyright (c) 1982, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)genassym.c 5.11 (Berkeley) 5/10/91
+ * $Id: genassym.c,v 1.6 1993/11/13 02:24:59 davidg Exp $
+ */
+
+#include "sys/param.h"
+#include "sys/buf.h"
+#include "sys/vmmeter.h"
+#include "sys/proc.h"
+#include "sys/user.h"
+#include "sys/mbuf.h"
+#include "sys/msgbuf.h"
+#include "sys/resourcevar.h"
+#include "machine/cpu.h"
+#include "machine/trap.h"
+#include "machine/psl.h"
+#include "sys/syscall.h"
+#include "vm/vm_param.h"
+#include "vm/vm_map.h"
+#include "machine/pmap.h"
+
+main()
+{
+ struct proc *p = (struct proc *)0;
+ struct vmmeter *vm = (struct vmmeter *)0;
+ struct user *up = (struct user *)0;
+ struct rusage *rup = (struct rusage *)0;
+ struct uprof *uprof = (struct uprof *)0;
+ struct vmspace *vms = (struct vmspace *)0;
+ vm_map_t map = (vm_map_t)0;
+ pmap_t pmap = (pmap_t)0;
+ struct pcb *pcb = (struct pcb *)0;
+ struct trapframe *tf = (struct trapframe *)0;
+ struct sigframe *sigf = (struct sigframe *)0;
+ register unsigned i;
+
+ printf("#define\tI386_CR3PAT %d\n", I386_CR3PAT);
+ printf("#define\tUDOT_SZ %d\n", sizeof(struct user));
+ printf("#define\tP_LINK %d\n", &p->p_link);
+ printf("#define\tP_RLINK %d\n", &p->p_rlink);
+ printf("#define\tP_VMSPACE %d\n", &p->p_vmspace);
+ printf("#define\tVM_PMAP %d\n", &vms->vm_pmap);
+ printf("#define\tP_ADDR %d\n", &p->p_addr);
+ printf("#define\tP_PRI %d\n", &p->p_pri);
+ printf("#define\tP_STAT %d\n", &p->p_stat);
+ printf("#define\tP_WCHAN %d\n", &p->p_wchan);
+ printf("#define\tP_FLAG %d\n", &p->p_flag);
+ printf("#define\tP_PID %d\n", &p->p_pid);
+ printf("#define\tSSLEEP %d\n", SSLEEP);
+ printf("#define\tSRUN %d\n", SRUN);
+ printf("#define\tV_SWTCH %d\n", &vm->v_swtch);
+ printf("#define\tV_TRAP %d\n", &vm->v_trap);
+ printf("#define\tV_SYSCALL %d\n", &vm->v_syscall);
+ printf("#define\tV_INTR %d\n", &vm->v_intr);
+ printf("#define\tV_SOFT %d\n", &vm->v_soft);
+ printf("#define\tV_PDMA %d\n", &vm->v_pdma);
+ printf("#define\tV_FAULTS %d\n", &vm->v_faults);
+ printf("#define\tV_PGREC %d\n", &vm->v_pgrec);
+ printf("#define\tV_FASTPGREC %d\n", &vm->v_fastpgrec);
+ printf("#define\tUPAGES %d\n", UPAGES);
+ printf("#define\tHIGHPAGES %d\n", HIGHPAGES);
+ printf("#define\tCLSIZE %d\n", CLSIZE);
+ printf("#define\tNBPG %d\n", NBPG);
+ printf("#define\tNPTEPG %d\n", NPTEPG);
+ printf("#define\tPDESIZE %d\n", PDESIZE);
+ printf("#define\tPTESIZE %d\n", PTESIZE);
+ printf("#define\tNKPDE %d\n", NKPDE);
+ printf("#define\tNKPT %d\n", NKPT);
+ printf("#define\tKPTDI 0x%x\n", KPTDI);
+ printf("#define\tKSTKPTDI 0x%x\n", KSTKPTDI);
+ printf("#define\tKSTKPTEOFF 0x%x\n", KSTKPTEOFF);
+ printf("#define\tPTDPTDI 0x%x\n", PTDPTDI);
+ printf("#define\tAPTDPTDI 0x%x\n", APTDPTDI);
+ printf("#define\tPGSHIFT %d\n", PGSHIFT);
+ printf("#define\tPDRSHIFT %d\n", PDRSHIFT);
+ printf("#define\tSYSPTSIZE %d\n", SYSPTSIZE);
+ printf("#define\tUSRPTSIZE %d\n", USRPTSIZE);
+ printf("#define\tUSRIOSIZE %d\n", USRIOSIZE);
+#ifdef SYSVSHM
+ printf("#define\tSHMMAXPGS %d\n", SHMMAXPGS);
+#endif
+ printf("#define\tUSRSTACK 0x%x\n", USRSTACK);
+ printf("#define\tVM_MAXUSER_ADDRESS 0x%x\n", VM_MAXUSER_ADDRESS);
+ printf("#define\tKERNBASE 0x%x\n", KERNBASE);
+ printf("#define\tMSGBUFPTECNT %d\n", btoc(sizeof (struct msgbuf)));
+ printf("#define\tNMBCLUSTERS %d\n", NMBCLUSTERS);
+ printf("#define\tMCLBYTES %d\n", MCLBYTES);
+ printf("#define\tPCB_LINK %d\n", &pcb->pcb_tss.tss_link);
+ printf("#define\tPCB_ESP0 %d\n", &pcb->pcb_tss.tss_esp0);
+ printf("#define\tPCB_SS0 %d\n", &pcb->pcb_tss.tss_ss0);
+ printf("#define\tPCB_ESP1 %d\n", &pcb->pcb_tss.tss_esp1);
+ printf("#define\tPCB_SS1 %d\n", &pcb->pcb_tss.tss_ss1);
+ printf("#define\tPCB_ESP2 %d\n", &pcb->pcb_tss.tss_esp2);
+ printf("#define\tPCB_SS2 %d\n", &pcb->pcb_tss.tss_ss2);
+ printf("#define\tPCB_CR3 %d\n", &pcb->pcb_tss.tss_cr3);
+ printf("#define\tPCB_EIP %d\n", &pcb->pcb_tss.tss_eip);
+ printf("#define\tPCB_EFLAGS %d\n", &pcb->pcb_tss.tss_eflags);
+ printf("#define\tPCB_EAX %d\n", &pcb->pcb_tss.tss_eax);
+ printf("#define\tPCB_ECX %d\n", &pcb->pcb_tss.tss_ecx);
+ printf("#define\tPCB_EDX %d\n", &pcb->pcb_tss.tss_edx);
+ printf("#define\tPCB_EBX %d\n", &pcb->pcb_tss.tss_ebx);
+ printf("#define\tPCB_ESP %d\n", &pcb->pcb_tss.tss_esp);
+ printf("#define\tPCB_EBP %d\n", &pcb->pcb_tss.tss_ebp);
+ printf("#define\tPCB_ESI %d\n", &pcb->pcb_tss.tss_esi);
+ printf("#define\tPCB_EDI %d\n", &pcb->pcb_tss.tss_edi);
+ printf("#define\tPCB_ES %d\n", &pcb->pcb_tss.tss_es);
+ printf("#define\tPCB_CS %d\n", &pcb->pcb_tss.tss_cs);
+ printf("#define\tPCB_SS %d\n", &pcb->pcb_tss.tss_ss);
+ printf("#define\tPCB_DS %d\n", &pcb->pcb_tss.tss_ds);
+ printf("#define\tPCB_FS %d\n", &pcb->pcb_tss.tss_fs);
+ printf("#define\tPCB_GS %d\n", &pcb->pcb_tss.tss_gs);
+ printf("#define\tPCB_LDT %d\n", &pcb->pcb_tss.tss_ldt);
+ printf("#define\tPCB_USERLDT %d\n", &pcb->pcb_ldt);
+ printf("#define\tPCB_IOOPT %d\n", &pcb->pcb_tss.tss_ioopt);
+ printf("#define\tU_PROF %d\n", &up->u_stats.p_prof);
+ printf("#define\tU_PROFSCALE %d\n", &up->u_stats.p_prof.pr_scale);
+ printf("#define\tPR_BASE %d\n", &uprof->pr_base);
+ printf("#define\tPR_SIZE %d\n", &uprof->pr_size);
+ printf("#define\tPR_OFF %d\n", &uprof->pr_off);
+ printf("#define\tPR_SCALE %d\n", &uprof->pr_scale);
+ printf("#define\tRU_MINFLT %d\n", &rup->ru_minflt);
+ printf("#define\tPCB_FLAGS %d\n", &pcb->pcb_flags);
+ printf("#define\tPCB_SAVEFPU %d\n", &pcb->pcb_savefpu);
+ printf("#define\tFP_USESEMC %d\n", FP_USESEMC);
+ printf("#define\tPCB_SAVEEMC %d\n", &pcb->pcb_saveemc);
+ printf("#define\tPCB_CMAP2 %d\n", &pcb->pcb_cmap2);
+ printf("#define\tPCB_IML %d\n", &pcb->pcb_iml);
+ printf("#define\tPCB_ONFAULT %d\n", &pcb->pcb_onfault);
+
+ printf("#define\tTF_ES %d\n", &tf->tf_es);
+ printf("#define\tTF_DS %d\n", &tf->tf_ds);
+ printf("#define\tTF_EDI %d\n", &tf->tf_edi);
+ printf("#define\tTF_ESI %d\n", &tf->tf_esi);
+ printf("#define\tTF_EBP %d\n", &tf->tf_ebp);
+ printf("#define\tTF_ISP %d\n", &tf->tf_isp);
+ printf("#define\tTF_EBX %d\n", &tf->tf_ebx);
+ printf("#define\tTF_EDX %d\n", &tf->tf_edx);
+ printf("#define\tTF_ECX %d\n", &tf->tf_ecx);
+ printf("#define\tTF_EAX %d\n", &tf->tf_eax);
+ printf("#define\tTF_TRAPNO %d\n", &tf->tf_trapno);
+ printf("#define\tTF_ERR %d\n", &tf->tf_err);
+ printf("#define\tTF_EIP %d\n", &tf->tf_eip);
+ printf("#define\tTF_CS %d\n", &tf->tf_cs);
+ printf("#define\tTF_EFLAGS %d\n", &tf->tf_eflags);
+ printf("#define\tTF_ESP %d\n", &tf->tf_esp);
+ printf("#define\tTF_SS %d\n", &tf->tf_ss);
+
+ printf("#define\tSIGF_SIGNUM %d\n", &sigf->sf_signum);
+ printf("#define\tSIGF_CODE %d\n", &sigf->sf_code);
+ printf("#define\tSIGF_SCP %d\n", &sigf->sf_scp);
+ printf("#define\tSIGF_HANDLER %d\n", &sigf->sf_handler);
+ printf("#define\tSIGF_SC %d\n", &sigf->sf_sc);
+
+ printf("#define\tB_READ %d\n", B_READ);
+ printf("#define\tENOENT %d\n", ENOENT);
+ printf("#define\tEFAULT %d\n", EFAULT);
+ printf("#define\tENAMETOOLONG %d\n", ENAMETOOLONG);
+ exit(0);
+}
+
diff --git a/sys/i386/i386/in_cksum.c b/sys/i386/i386/in_cksum.c
new file mode 100644
index 0000000..b11f0ff
--- /dev/null
+++ b/sys/i386/i386/in_cksum.c
@@ -0,0 +1,237 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from tahoe: in_cksum.c 1.2 86/01/05
+ * from: @(#)in_cksum.c 1.3 (Berkeley) 1/19/91
+ * $Id: in_cksum.c,v 1.4 1993/12/19 00:50:02 wollman Exp $
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "sys/mbuf.h"
+
+/*
+ * Checksum routine for Internet Protocol family headers.
+ *
+ * This routine is very heavily used in the network
+ * code and should be modified for each CPU to be as fast as possible.
+ *
+ * This implementation is 386 version.
+ */
+
+#undef ADDCARRY
+#define ADDCARRY(x) if ((x) > 0xffff) (x) -= 0xffff
+#define REDUCE {sum = (sum & 0xffff) + (sum >> 16); ADDCARRY(sum);}
+
+/*
+ * Thanks to gcc we don't have to guess
+ * which registers contain sum & w.
+ */
+#define ADD(n) asm("addl " #n "(%2), %0" : "=r" (sum) : "0" (sum), "r" (w))
+#define ADDC(n) asm("adcl " #n "(%2), %0" : "=r" (sum) : "0" (sum), "r" (w))
+#define LOAD(n) asm volatile("movb " #n "(%1), %0" : "=r" (junk) : "r" (w))
+#define MOP asm("adcl $0, %0" : "=r" (sum) : "0" (sum))
+
+int
+in_cksum(m, len)
+ register struct mbuf *m;
+ register int len;
+{
+ register u_short *w;
+ register unsigned sum = 0;
+ register int mlen = 0;
+ int byte_swapped = 0;
+ union { char c[2]; u_short s; } su;
+
+ for (;m && len; m = m->m_next) {
+ if (m->m_len == 0)
+ continue;
+ w = mtod(m, u_short *);
+ if (mlen == -1) {
+ /*
+ * The first byte of this mbuf is the continuation
+ * of a word spanning between this mbuf and the
+ * last mbuf.
+ */
+
+ /* su.c[0] is already saved when scanning previous
+ * mbuf. sum was REDUCEd when we found mlen == -1
+ */
+ su.c[1] = *(u_char *)w;
+ sum += su.s;
+ w = (u_short *)((char *)w + 1);
+ mlen = m->m_len - 1;
+ len--;
+ } else
+ mlen = m->m_len;
+ if (len < mlen)
+ mlen = len;
+ len -= mlen;
+ /*
+ * Force to long boundary so we do longword aligned
+ * memory operations
+ */
+ if (3 & (int) w) {
+ REDUCE;
+ if ((1 & (int) w) && (mlen > 0)) {
+ sum <<= 8;
+ su.c[0] = *(char *)w;
+ w = (u_short *)((char *)w + 1);
+ mlen--;
+ byte_swapped = 1;
+ }
+ if ((2 & (int) w) && (mlen >= 2)) {
+ sum += *w++;
+ mlen -= 2;
+ }
+ }
+ /*
+ * Advance to a 486 cache line boundary.
+ */
+ if (4 & (int) w && mlen >= 4) {
+ ADD(0);
+ MOP;
+ w += 2;
+ mlen -= 4;
+ }
+ if (8 & (int) w && mlen >= 8) {
+ ADD(0);
+ ADDC(4);
+ MOP;
+ w += 4;
+ mlen -= 8;
+ }
+ /*
+ * Do as much of the checksum as possible 32 bits at at time.
+ * In fact, this loop is unrolled to make overhead from
+ * branches &c small.
+ */
+ mlen -= 1;
+ while ((mlen -= 32) >= 0) {
+ u_char junk;
+ /*
+ * Add with carry 16 words and fold in the last
+ * carry by adding a 0 with carry.
+ *
+ * The early ADD(16) and the LOAD(32) are to load
+ * the next 2 cache lines in advance on 486's. The
+ * 486 has a penalty of 2 clock cycles for loading
+ * a cache line, plus whatever time the external
+ * memory takes to load the first word(s) addressed.
+ * These penalties are unavoidable. Subsequent
+ * accesses to a cache line being loaded (and to
+ * other external memory?) are delayed until the
+ * whole load finishes. These penalties are mostly
+ * avoided by not accessing external memory for
+ * 8 cycles after the ADD(16) and 12 cycles after
+ * the LOAD(32). The loop terminates when mlen
+ * is initially 33 (not 32) to guaranteed that
+ * the LOAD(32) is within bounds.
+ */
+ ADD(16);
+ ADDC(0);
+ ADDC(4);
+ ADDC(8);
+ ADDC(12);
+ LOAD(32);
+ ADDC(20);
+ ADDC(24);
+ ADDC(28);
+ MOP;
+ w += 16;
+ }
+ mlen += 32 + 1;
+ if (mlen >= 32) {
+ ADD(16);
+ ADDC(0);
+ ADDC(4);
+ ADDC(8);
+ ADDC(12);
+ ADDC(20);
+ ADDC(24);
+ ADDC(28);
+ MOP;
+ w += 16;
+ mlen -= 32;
+ }
+ if (mlen >= 16) {
+ ADD(0);
+ ADDC(4);
+ ADDC(8);
+ ADDC(12);
+ MOP;
+ w += 8;
+ mlen -= 16;
+ }
+ if (mlen >= 8) {
+ ADD(0);
+ ADDC(4);
+ MOP;
+ w += 4;
+ mlen -= 8;
+ }
+ if (mlen == 0 && byte_swapped == 0)
+ continue; /* worth 1% maybe ?? */
+ REDUCE;
+ while ((mlen -= 2) >= 0) {
+ sum += *w++;
+ }
+ if (byte_swapped) {
+ sum <<= 8;
+ byte_swapped = 0;
+ if (mlen == -1) {
+ su.c[1] = *(char *)w;
+ sum += su.s;
+ mlen = 0;
+ } else
+ mlen = -1;
+ } else if (mlen == -1)
+ /*
+ * This mbuf has odd number of bytes.
+ * There could be a word split betwen
+ * this mbuf and the next mbuf.
+ * Save the last byte (to prepend to next mbuf).
+ */
+ su.c[0] = *(char *)w;
+ }
+
+ if (len)
+ printf("cksum: out of data\n");
+ if (mlen == -1) {
+ /* The last mbuf has odd # of bytes. Follow the
+ standard (the odd byte is shifted left by 8 bits) */
+ su.c[1] = 0;
+ sum += su.s;
+ }
+ REDUCE;
+ return (~sum & 0xffff);
+}
diff --git a/sys/i386/i386/locore.s b/sys/i386/i386/locore.s
new file mode 100644
index 0000000..8da8438
--- /dev/null
+++ b/sys/i386/i386/locore.s
@@ -0,0 +1,552 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)locore.s 7.3 (Berkeley) 5/13/91
+ * $Id: locore.s,v 1.15 1994/02/01 04:08:54 davidg Exp $
+ */
+
+/*
+ * locore.s: FreeBSD machine support for the Intel 386
+ * originally from: locore.s, by William F. Jolitz
+ *
+ * Substantially rewritten by David Greenman, Rod Grimes,
+ * Bruce Evans, Wolfgang Solfrank, and many others.
+ */
+
+#include "npx.h" /* for NNPX */
+#include "assym.s" /* system definitions */
+#include "machine/psl.h" /* processor status longword defs */
+#include "machine/pte.h" /* page table entry definitions */
+#include "errno.h" /* error return codes */
+#include "machine/specialreg.h" /* x86 special registers */
+#include "machine/cputypes.h" /* x86 cpu type definitions */
+#include "syscall.h" /* system call numbers */
+#include "machine/asmacros.h" /* miscellaneous asm macros */
+
+/*
+ * XXX
+ *
+ * Note: This version greatly munged to avoid various assembler errors
+ * that may be fixed in newer versions of gas. Perhaps newer versions
+ * will have more pleasant appearance.
+ */
+
+/*
+ * PTmap is recursive pagemap at top of virtual address space.
+ * Within PTmap, the page directory can be found (third indirection).
+ */
+ .globl _PTmap,_PTD,_PTDpde,_Sysmap
+ .set _PTmap,PTDPTDI << PDRSHIFT
+ .set _PTD,_PTmap + (PTDPTDI * NBPG)
+ .set _PTDpde,_PTD + (PTDPTDI * PDESIZE)
+
+/* Sysmap is the base address of the kernel page tables */
+ .set _Sysmap,_PTmap + (KPTDI * NBPG)
+
+/*
+ * APTmap, APTD is the alternate recursive pagemap.
+ * It's used when modifying another process's page tables.
+ */
+ .globl _APTmap,_APTD,_APTDpde
+ .set _APTmap,APTDPTDI << PDRSHIFT
+ .set _APTD,_APTmap + (APTDPTDI * NBPG)
+ .set _APTDpde,_PTD + (APTDPTDI * PDESIZE)
+
+/*
+ * Access to each processes kernel stack is via a region of
+ * per-process address space (at the beginning), immediatly above
+ * the user process stack.
+ */
+ .set _kstack,USRSTACK
+ .globl _kstack
+
+/*
+ * Globals
+ */
+ .data
+ .globl _esym
+_esym: .long 0 /* ptr to end of syms */
+
+ .globl _boothowto,_bootdev,_curpcb
+
+ .globl _cpu,_cold,_atdevbase
+_cpu: .long 0 /* are we 386, 386sx, or 486 */
+_cold: .long 1 /* cold till we are not */
+_atdevbase: .long 0 /* location of start of iomem in virtual */
+_atdevphys: .long 0 /* location of device mapping ptes (phys) */
+
+ .globl _KERNend
+_KERNend: .long 0 /* phys addr end of kernel (just after bss) */
+
+ .globl _IdlePTD,_KPTphys
+_IdlePTD: .long 0 /* phys addr of kernel PTD */
+_KPTphys: .long 0 /* phys addr of kernel page tables */
+
+ .globl _cyloffset
+_cyloffset: .long 0 /* cylinder offset from boot blocks */
+
+ .globl _proc0paddr
+_proc0paddr: .long 0 /* address of proc 0 address space */
+
+#ifdef BDE_DEBUGGER
+ .globl _bdb_exists /* flag to indicate BDE debugger is available */
+_bdb_exists: .long 0
+#endif
+
+ .globl tmpstk
+ .space 0x1000
+tmpstk:
+
+
+/*
+ * System Initialization
+ */
+ .text
+
+/*
+ * btext: beginning of text section.
+ * Also the entry point (jumped to directly from the boot blocks).
+ */
+NON_GPROF_ENTRY(btext)
+ movw $0x1234,0x472 /* warm boot */
+ jmp 1f
+ .org 0x500 /* space for BIOS variables */
+
+ /*
+ * pass parameters on stack (howto, bootdev, unit, cyloffset, esym)
+ * note: (%esp) is return address of boot
+ * ( if we want to hold onto /boot, it's physical %esp up to _end)
+ */
+
+ 1: movl 4(%esp),%eax
+ movl %eax,_boothowto-KERNBASE
+ movl 8(%esp),%eax
+ movl %eax,_bootdev-KERNBASE
+ movl 12(%esp),%eax
+ movl %eax,_cyloffset-KERNBASE
+ movl 16(%esp),%eax
+ addl $KERNBASE,%eax
+ movl %eax,_esym-KERNBASE
+#ifdef DISKLESS /* Copy diskless structure */
+ movl _nfs_diskless_size-KERNBASE,%ecx
+ movl 20(%esp),%esi
+ movl $(_nfs_diskless-KERNBASE),%edi
+ rep
+ movsb
+#endif
+
+ /* find out our CPU type. */
+ pushfl
+ popl %eax
+ movl %eax,%ecx
+ xorl $0x40000,%eax
+ pushl %eax
+ popfl
+ pushfl
+ popl %eax
+ xorl %ecx,%eax
+ shrl $18,%eax
+ andl $1,%eax
+ push %ecx
+ popfl
+
+ cmpl $0,%eax
+ jne 1f
+ movl $CPU_386,_cpu-KERNBASE
+ jmp 2f
+1: movl $CPU_486,_cpu-KERNBASE
+2:
+
+ /*
+ * Finished with old stack; load new %esp now instead of later so
+ * we can trace this code without having to worry about the trace
+ * trap clobbering the memory test or the zeroing of the bss+bootstrap
+ * page tables.
+ *
+ * XXX - wdboot clears the bss after testing that this is safe.
+ * This is too wasteful - memory below 640K is scarce. The boot
+ * program should check:
+ * text+data <= &stack_variable - more_space_for_stack
+ * text+data+bss+pad+space_for_page_tables <= end_of_memory
+ * Oops, the gdt is in the carcass of the boot program so clearing
+ * the rest of memory is still not possible.
+ */
+ movl $tmpstk-KERNBASE,%esp /* bootstrap stack end location */
+
+/*
+ * Virtual address space of kernel:
+ *
+ * text | data | bss | [syms] | page dir | proc0 kernel stack | usr stk map | Sysmap
+ * pages: 1 UPAGES (2) 1 NKPT (7)
+ */
+
+/* find end of kernel image */
+ movl $_end-KERNBASE,%ecx
+ addl $NBPG-1,%ecx /* page align up */
+ andl $~(NBPG-1),%ecx
+ movl %ecx,%esi /* esi = start of free memory */
+ movl %ecx,_KERNend-KERNBASE /* save end of kernel */
+
+/* clear bss */
+ movl $_edata-KERNBASE,%edi
+ subl %edi,%ecx /* get amount to clear */
+ xorl %eax,%eax /* specify zero fill */
+ cld
+ rep
+ stosb
+
+/*
+ * The value in esi is both the end of the kernel bss and a pointer to
+ * the kernel page directory, and is used by the rest of locore to build
+ * the tables.
+ * esi + 1(page dir) + 2(UPAGES) + 1(p0stack) + NKPT(number of kernel
+ * page table pages) is then passed on the stack to init386(first) as
+ * the value first. esi should ALWAYS be page aligned!!
+ */
+ movl %esi,%ecx /* Get current first availiable address */
+
+/* clear pagetables, page directory, stack, etc... */
+ movl %esi,%edi /* base (page directory) */
+ movl $((1+UPAGES+1+NKPT)*NBPG),%ecx /* amount to clear */
+ xorl %eax,%eax /* specify zero fill */
+ cld
+ rep
+ stosb
+
+/* physical address of Idle proc/kernel page directory */
+ movl %esi,_IdlePTD-KERNBASE
+
+/*
+ * fillkpt
+ * eax = (page frame address | control | status) == pte
+ * ebx = address of page table
+ * ecx = how many pages to map
+ */
+#define fillkpt \
+1: movl %eax,(%ebx) ; \
+ addl $NBPG,%eax ; /* increment physical address */ \
+ addl $4,%ebx ; /* next pte */ \
+ loop 1b ;
+
+/*
+ * Map Kernel
+ *
+ * First step - build page tables
+ */
+#if defined (KGDB) || defined (BDE_DEBUGGER)
+ movl _KERNend-KERNBASE,%ecx /* this much memory, */
+ shrl $PGSHIFT,%ecx /* for this many PTEs */
+#ifdef BDE_DEBUGGER
+ cmpl $0xa0,%ecx /* XXX - cover debugger pages */
+ jae 1f
+ movl $0xa0,%ecx
+1:
+#endif /* BDE_DEBUGGER */
+ movl $PG_V|PG_KW,%eax /* having these bits set, */
+ lea ((1+UPAGES+1)*NBPG)(%esi),%ebx /* phys addr of kernel PT base */
+ movl %ebx,_KPTphys-KERNBASE /* save in global */
+ fillkpt
+
+#else /* !KGDB && !BDE_DEBUGGER */
+ /* write protect kernel text (doesn't do a thing for 386's - only 486's) */
+ movl $_etext-KERNBASE,%ecx /* get size of text */
+ shrl $PGSHIFT,%ecx /* for this many PTEs */
+ movl $PG_V|PG_KR,%eax /* specify read only */
+ lea ((1+UPAGES+1)*NBPG)(%esi),%ebx /* phys addr of kernel PT base */
+ movl %ebx,_KPTphys-KERNBASE /* save in global */
+ fillkpt
+
+ /* data and bss are r/w */
+ andl $PG_FRAME,%eax /* strip to just addr of bss */
+ movl _KERNend-KERNBASE,%ecx /* calculate size */
+ subl %eax,%ecx
+ shrl $PGSHIFT,%ecx
+ orl $PG_V|PG_KW,%eax /* valid, kernel read/write */
+ fillkpt
+#endif /* KGDB || BDE_DEBUGGER */
+
+/* now initialize the page dir, upages, p0stack PT, and page tables */
+
+ movl $(1+UPAGES+1+NKPT),%ecx /* number of PTEs */
+ movl %esi,%eax /* phys address of PTD */
+ andl $PG_FRAME,%eax /* convert to PFN, should be a NOP */
+ orl $PG_V|PG_KW,%eax /* valid, kernel read/write */
+ movl %esi,%ebx /* calculate pte offset to ptd */
+ shrl $PGSHIFT-2,%ebx
+ addl %esi,%ebx /* address of page directory */
+ addl $((1+UPAGES+1)*NBPG),%ebx /* offset to kernel page tables */
+ fillkpt
+
+/* map I/O memory map */
+
+ movl _KPTphys-KERNBASE,%ebx /* base of kernel page tables */
+ lea (0xa0 * PTESIZE)(%ebx),%ebx /* hardwire ISA hole at KERNBASE + 0xa0000 */
+ movl $0x100-0xa0,%ecx /* for this many pte s, */
+ movl $(0xa0000|PG_V|PG_KW|PG_N),%eax /* valid, kernel read/write, non-cacheable */
+ movl %ebx,_atdevphys-KERNBASE /* save phys addr of ptes */
+ fillkpt
+
+ /* map proc 0's kernel stack into user page table page */
+
+ movl $UPAGES,%ecx /* for this many pte s, */
+ lea (1*NBPG)(%esi),%eax /* physical address in proc 0 */
+ lea (KERNBASE)(%eax),%edx /* change into virtual addr */
+ movl %edx,_proc0paddr-KERNBASE /* save VA for proc 0 init */
+ orl $PG_V|PG_KW,%eax /* valid, kernel read/write */
+ lea ((1+UPAGES)*NBPG)(%esi),%ebx /* addr of stack page table in proc 0 */
+ addl $(KSTKPTEOFF * PTESIZE),%ebx /* offset to kernel stack PTE */
+ fillkpt
+
+/*
+ * Initialize kernel page table directory
+ */
+ /* install a pde for temporary double map of bottom of VA */
+ movl _KPTphys-KERNBASE,%eax
+ orl $PG_V|PG_KW,%eax /* valid, kernel read/write */
+ movl %eax,(%esi) /* which is where temp maps! */
+
+ /* initialize kernel pde's */
+ movl $(NKPT),%ecx /* for this many PDEs */
+ lea (KPTDI*PDESIZE)(%esi),%ebx /* offset of pde for kernel */
+ fillkpt
+
+ /* install a pde recursively mapping page directory as a page table! */
+ movl %esi,%eax /* phys address of ptd in proc 0 */
+ orl $PG_V|PG_KW,%eax /* pde entry is valid */
+ movl %eax,PTDPTDI*PDESIZE(%esi) /* which is where PTmap maps! */
+
+ /* install a pde to map kernel stack for proc 0 */
+ lea ((1+UPAGES)*NBPG)(%esi),%eax /* physical address of pt in proc 0 */
+ orl $PG_V|PG_KW,%eax /* pde entry is valid */
+ movl %eax,KSTKPTDI*PDESIZE(%esi) /* which is where kernel stack maps! */
+
+#ifdef BDE_DEBUGGER
+ /* copy and convert stuff from old gdt and idt for debugger */
+
+ cmpl $0x0375c339,0x96104 /* XXX - debugger signature */
+ jne 1f
+ movb $1,_bdb_exists-KERNBASE
+1:
+ pushal
+ subl $2*6,%esp
+
+ sgdt (%esp)
+ movl 2(%esp),%esi /* base address of current gdt */
+ movl $_gdt-KERNBASE,%edi
+ movl %edi,2(%esp)
+ movl $8*18/4,%ecx
+ rep /* copy gdt */
+ movsl
+ movl $_gdt-KERNBASE,-8+2(%edi) /* adjust gdt self-ptr */
+ movb $0x92,-8+5(%edi)
+
+ sidt 6(%esp)
+ movl 6+2(%esp),%esi /* base address of current idt */
+ movl 8+4(%esi),%eax /* convert dbg descriptor to ... */
+ movw 8(%esi),%ax
+ movl %eax,bdb_dbg_ljmp+1-KERNBASE /* ... immediate offset ... */
+ movl 8+2(%esi),%eax
+ movw %ax,bdb_dbg_ljmp+5-KERNBASE /* ... and selector for ljmp */
+ movl 24+4(%esi),%eax /* same for bpt descriptor */
+ movw 24(%esi),%ax
+ movl %eax,bdb_bpt_ljmp+1-KERNBASE
+ movl 24+2(%esi),%eax
+ movw %ax,bdb_bpt_ljmp+5-KERNBASE
+
+ movl $_idt-KERNBASE,%edi
+ movl %edi,6+2(%esp)
+ movl $8*4/4,%ecx
+ rep /* copy idt */
+ movsl
+
+ lgdt (%esp)
+ lidt 6(%esp)
+
+ addl $2*6,%esp
+ popal
+#endif /* BDE_DEBUGGER */
+
+ /* load base of page directory and enable mapping */
+ movl %esi,%eax /* phys address of ptd in proc 0 */
+ orl $I386_CR3PAT,%eax
+ movl %eax,%cr3 /* load ptd addr into mmu */
+ movl %cr0,%eax /* get control word */
+ orl $CR0_PE|CR0_PG,%eax /* enable paging */
+ movl %eax,%cr0 /* and let's page NOW! */
+
+ pushl $begin /* jump to high mem */
+ ret
+
+begin: /* now running relocated at KERNBASE where the system is linked to run */
+
+ .globl _Crtat /* XXX - locore should not know about */
+ movl _Crtat,%eax /* variables of device drivers (pccons)! */
+ subl $(KERNBASE+0xA0000),%eax
+ movl _atdevphys,%edx /* get pte PA */
+ subl _KPTphys,%edx /* remove base of ptes, now have phys offset */
+ shll $PGSHIFT-2,%edx /* corresponding to virt offset */
+ addl $KERNBASE,%edx /* add virtual base */
+ movl %edx,_atdevbase
+ addl %eax,%edx
+ movl %edx,_Crtat
+
+ /* set up bootstrap stack - 48 bytes */
+ movl $_kstack+UPAGES*NBPG-4*12,%esp /* bootstrap stack end location */
+ xorl %eax,%eax /* mark end of frames */
+ movl %eax,%ebp
+ movl _proc0paddr,%eax
+ movl %esi,PCB_CR3(%eax)
+
+#ifdef BDE_DEBUGGER
+ /* relocate debugger gdt entries */
+
+ movl $_gdt+8*9,%eax /* adjust slots 9-17 */
+ movl $9,%ecx
+reloc_gdt:
+ movb $KERNBASE>>24,7(%eax) /* top byte of base addresses, was 0, */
+ addl $8,%eax /* now KERNBASE>>24 */
+ loop reloc_gdt
+
+ cmpl $0,_bdb_exists
+ je 1f
+ int $3
+1:
+#endif /* BDE_DEBUGGER */
+
+ /*
+ * Skip over the page tables and the kernel stack
+ */
+ lea ((1+UPAGES+1+NKPT)*NBPG)(%esi),%esi
+
+ pushl %esi /* value of first for init386(first) */
+ call _init386 /* wire 386 chip for unix operation */
+
+ movl $0,_PTD
+ call _main /* autoconfiguration, mountroot etc */
+ popl %esi
+
+ /*
+ * now we've run main() and determined what cpu-type we are, we can
+ * enable WP mode on i486 cpus and above.
+ */
+#if defined(I486_CPU) || defined(I586_CPU)
+ cmpl $CPUCLASS_386,_cpu_class
+ je 1f
+ movl %cr0,%eax /* get control word */
+ orl $CR0_WP,%eax /* enable write protect for all modes */
+ movl %eax,%cr0 /* and do it */
+#endif
+ /*
+ * on return from main(), we are process 1
+ * set up address space and stack so that we can 'return' to user mode
+ */
+1:
+ .globl __ucodesel,__udatasel
+ movl __ucodesel,%eax
+ movl __udatasel,%ecx
+ /* build outer stack frame */
+ pushl %ecx /* user ss */
+ pushl $USRSTACK /* user esp */
+ pushl %eax /* user cs */
+ pushl $0 /* user ip */
+ movl %cx,%ds
+ movl %cx,%es
+ movl %ax,%fs /* double map cs to fs */
+ movl %cx,%gs /* and ds to gs */
+ lret /* goto user! */
+
+ pushl $lretmsg1 /* "should never get here!" */
+ call _panic
+lretmsg1:
+ .asciz "lret: toinit\n"
+
+
+#define LCALL(x,y) .byte 0x9a ; .long y ; .word x
+/*
+ * Icode is copied out to process 1 and executed in user mode:
+ * execve("/sbin/init", argv, envp); exit(0);
+ * If the execve fails, process 1 exits and the system panics.
+ */
+NON_GPROF_ENTRY(icode)
+ pushl $0 /* envp for execve() */
+
+# pushl $argv-_icode /* can't do this 'cos gas 1.38 is broken */
+ movl $argv,%eax
+ subl $_icode,%eax
+ pushl %eax /* argp for execve() */
+
+# pushl $init-_icode
+ movl $init,%eax
+ subl $_icode,%eax
+ pushl %eax /* fname for execve() */
+
+ pushl %eax /* dummy return address */
+
+ movl $SYS_execve,%eax
+ LCALL(0x7,0x0)
+
+ /* exit if something botches up in the above execve() */
+ pushl %eax /* execve failed, the errno will do for an */
+ /* exit code because errnos are < 128 */
+ pushl %eax /* dummy return address */
+ movl $SYS_exit,%eax
+ LCALL(0x7,0x0)
+
+init:
+ .asciz "/sbin/init"
+ ALIGN_DATA
+argv:
+ .long init+6-_icode /* argv[0] = "init" ("/sbin/init" + 6) */
+ .long eicode-_icode /* argv[1] follows icode after copyout */
+ .long 0
+eicode:
+
+ .globl _szicode
+_szicode:
+ .long _szicode-_icode
+
+NON_GPROF_ENTRY(sigcode)
+ call SIGF_HANDLER(%esp)
+ lea SIGF_SC(%esp),%eax /* scp (the call may have clobbered the */
+ /* copy at 8(%esp)) */
+ pushl %eax
+ pushl %eax /* junk to fake return address */
+ movl $103,%eax /* XXX sigreturn() */
+ LCALL(0x7,0) /* enter kernel with args on stack */
+ hlt /* never gets here */
+
+ .globl _szsigcode
+_szsigcode:
+ .long _szsigcode-_sigcode
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
new file mode 100644
index 0000000..eab1075
--- /dev/null
+++ b/sys/i386/i386/machdep.c
@@ -0,0 +1,1449 @@
+/*-
+ * Copyright (c) 1992 Terrence R. Lambert.
+ * Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91
+ * $Id: machdep.c,v 1.41 1994/03/30 02:31:11 davidg Exp $
+ */
+
+#include "npx.h"
+#include "isa.h"
+
+#include <stddef.h>
+#include "param.h"
+#include "systm.h"
+#include "signalvar.h"
+#include "kernel.h"
+#include "map.h"
+#include "proc.h"
+#include "user.h"
+#include "exec.h" /* for PS_STRINGS */
+#include "buf.h"
+#include "reboot.h"
+#include "conf.h"
+#include "file.h"
+#include "callout.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "msgbuf.h"
+
+#ifdef SYSVSHM
+#include "sys/shm.h"
+#endif
+
+#ifdef SYSVMSG
+#include "msg.h"
+#endif
+
+#ifdef SYSVSEM
+#include "sem.h"
+#endif
+
+#include "vm/vm.h"
+#include "vm/vm_kern.h"
+#include "vm/vm_page.h"
+
+#include "sys/exec.h"
+#include "sys/vnode.h"
+
+extern vm_offset_t avail_start, avail_end;
+
+#include "machine/cpu.h"
+#include "machine/reg.h"
+#include "machine/psl.h"
+#include "machine/specialreg.h"
+#include "machine/sysarch.h"
+#include "machine/cons.h"
+
+#include "i386/isa/isa.h"
+#include "i386/isa/rtc.h"
+
+static void identifycpu(void);
+static void initcpu(void);
+static int test_page(int *, int);
+
+extern int grow(struct proc *,int);
+const char machine[] = "PC-Class";
+const char *cpu_model;
+
+#ifndef PANIC_REBOOT_WAIT_TIME
+#define PANIC_REBOOT_WAIT_TIME 15 /* default to 15 seconds */
+#endif
+
+/*
+ * Declare these as initialized data so we can patch them.
+ */
+int nswbuf = 0;
+#ifdef NBUF
+int nbuf = NBUF;
+#else
+int nbuf = 0;
+#endif
+#ifdef BUFPAGES
+int bufpages = BUFPAGES;
+#else
+int bufpages = 0;
+#endif
+#ifdef BOUNCEPAGES
+int bouncepages = BOUNCEPAGES;
+#else
+int bouncepages = 0;
+#endif
+extern int freebufspace;
+extern char *bouncememory;
+
+int _udatasel, _ucodesel;
+
+/*
+ * Machine-dependent startup code
+ */
+int boothowto = 0, Maxmem = 0, badpages = 0, physmem = 0;
+long dumplo;
+extern int bootdev;
+int biosmem;
+
+vm_offset_t phys_avail[6];
+
+extern cyloffset;
+
+int cpu_class;
+
+void dumpsys __P((void));
+
+void
+cpu_startup()
+{
+ register int unixsize;
+ register unsigned i;
+ register struct pte *pte;
+ int mapaddr, j;
+ register caddr_t v;
+ int maxbufs, base, residual;
+ extern long Usrptsize;
+ vm_offset_t minaddr, maxaddr;
+ vm_size_t size = 0;
+ int firstaddr;
+
+ /*
+ * Initialize error message buffer (at end of core).
+ */
+
+ /* avail_end was pre-decremented in init_386() to compensate */
+ for (i = 0; i < btoc(sizeof (struct msgbuf)); i++)
+ pmap_enter(pmap_kernel(), (vm_offset_t)msgbufp,
+ avail_end + i * NBPG,
+ VM_PROT_ALL, TRUE);
+ msgbufmapped = 1;
+
+ /*
+ * Good {morning,afternoon,evening,night}.
+ */
+ printf(version);
+ identifycpu();
+ printf("real memory = %d (%d pages)\n", ptoa(physmem), physmem);
+ if (badpages)
+ printf("bad memory = %d (%d pages)\n", ptoa(badpages), badpages);
+
+ /*
+ * Allocate space for system data structures.
+ * The first available kernel virtual address is in "v".
+ * As pages of kernel virtual memory are allocated, "v" is incremented.
+ * As pages of memory are allocated and cleared,
+ * "firstaddr" is incremented.
+ * An index into the kernel page table corresponding to the
+ * virtual memory address maintained in "v" is kept in "mapaddr".
+ */
+
+ /*
+ * Make two passes. The first pass calculates how much memory is
+ * needed and allocates it. The second pass assigns virtual
+ * addresses to the various data structures.
+ */
+ firstaddr = 0;
+again:
+ v = (caddr_t)firstaddr;
+
+#define valloc(name, type, num) \
+ (name) = (type *)v; v = (caddr_t)((name)+(num))
+#define valloclim(name, type, num, lim) \
+ (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num)))
+ valloc(callout, struct callout, ncallout);
+#ifdef SYSVSHM
+ valloc(shmsegs, struct shmid_ds, shminfo.shmmni);
+#endif
+#ifdef SYSVSEM
+ valloc(sema, struct semid_ds, seminfo.semmni);
+ valloc(sem, struct sem, seminfo.semmns);
+ /* This is pretty disgusting! */
+ valloc(semu, int, (seminfo.semmnu * seminfo.semusz) / sizeof(int));
+#endif
+#ifdef SYSVMSG
+ valloc(msgpool, char, msginfo.msgmax);
+ valloc(msgmaps, struct msgmap, msginfo.msgseg);
+ valloc(msghdrs, struct msg, msginfo.msgtql);
+ valloc(msqids, struct msqid_ds, msginfo.msgmni);
+#endif
+ /*
+ * Determine how many buffers to allocate.
+ * Use 20% of memory of memory beyond the first 2MB
+ * Insure a minimum of 16 fs buffers.
+ * We allocate 1/2 as many swap buffer headers as file i/o buffers.
+ */
+ if (bufpages == 0)
+ bufpages = ((physmem << PGSHIFT) - 2048*1024) / NBPG / 5;
+ if (bufpages < 64)
+ bufpages = 64;
+
+ /*
+ * We must still limit the maximum number of buffers to be no
+ * more than 2/5's of the size of the kernal malloc region, this
+ * will only take effect for machines with lots of memory
+ */
+ bufpages = min(bufpages, (VM_KMEM_SIZE / NBPG) * 2 / 5);
+ if (nbuf == 0) {
+ nbuf = bufpages / 2;
+ if (nbuf < 32)
+ nbuf = 32;
+ }
+ freebufspace = bufpages * NBPG;
+ if (nswbuf == 0) {
+ nswbuf = (nbuf / 2) &~ 1; /* force even */
+ if (nswbuf > 256)
+ nswbuf = 256; /* sanity */
+ }
+ valloc(swbuf, struct buf, nswbuf);
+ valloc(buf, struct buf, nbuf);
+
+#ifndef NOBOUNCE
+ /*
+ * If there is more than 16MB of memory, allocate some bounce buffers
+ */
+ if (Maxmem > 4096) {
+ if (bouncepages == 0)
+ bouncepages = 96; /* largest physio size + extra */
+ v = (caddr_t)((vm_offset_t)((vm_offset_t)v + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1));
+ valloc(bouncememory, char, bouncepages * PAGE_SIZE);
+ }
+#endif
+
+ /*
+ * End of first pass, size has been calculated so allocate memory
+ */
+ if (firstaddr == 0) {
+ size = (vm_size_t)(v - firstaddr);
+ firstaddr = (int)kmem_alloc(kernel_map, round_page(size));
+ if (firstaddr == 0)
+ panic("startup: no room for tables");
+ goto again;
+ }
+
+ /*
+ * End of second pass, addresses have been assigned
+ */
+ if ((vm_size_t)(v - firstaddr) != size)
+ panic("startup: table size inconsistency");
+
+ /*
+ * Allocate a submap for buffer space allocations.
+ * XXX we are NOT using buffer_map, but due to
+ * the references to it we will just allocate 1 page of
+ * vm (not real memory) to make things happy...
+ */
+ buffer_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr,
+ /* bufpages * */NBPG, TRUE);
+ /*
+ * Allocate a submap for physio
+ */
+ phys_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr,
+ VM_PHYS_SIZE, TRUE);
+
+ /*
+ * Finally, allocate mbuf pool. Since mclrefcnt is an off-size
+ * we use the more space efficient malloc in place of kmem_alloc.
+ */
+ mclrefcnt = (char *)malloc(NMBCLUSTERS+CLBYTES/MCLBYTES,
+ M_MBUF, M_NOWAIT);
+ bzero(mclrefcnt, NMBCLUSTERS+CLBYTES/MCLBYTES);
+ mb_map = kmem_suballoc(kmem_map, (vm_offset_t)&mbutl, &maxaddr,
+ VM_MBUF_SIZE, FALSE);
+ /*
+ * Initialize callouts
+ */
+ callfree = callout;
+ for (i = 1; i < ncallout; i++)
+ callout[i-1].c_next = &callout[i];
+
+ printf("avail memory = %d (%d pages)\n", ptoa(vm_page_free_count), vm_page_free_count);
+ printf("using %d buffers containing %d bytes of memory\n",
+ nbuf, bufpages * CLBYTES);
+
+#ifndef NOBOUNCE
+ /*
+ * init bounce buffers
+ */
+ vm_bounce_init();
+#endif
+
+ /*
+ * Set up CPU-specific registers, cache, etc.
+ */
+ initcpu();
+
+ /*
+ * Set up buffers, so they can be used to read disk labels.
+ */
+ bufinit();
+
+ /*
+ * Configure the system.
+ */
+ configure();
+}
+
+
+struct cpu_nameclass i386_cpus[] = {
+ { "Intel 80286", CPUCLASS_286 }, /* CPU_286 */
+ { "i386SX", CPUCLASS_386 }, /* CPU_386SX */
+ { "i386DX", CPUCLASS_386 }, /* CPU_386 */
+ { "i486SX", CPUCLASS_486 }, /* CPU_486SX */
+ { "i486DX", CPUCLASS_486 }, /* CPU_486 */
+ { "i586", CPUCLASS_586 }, /* CPU_586 */
+};
+
+static void
+identifycpu()
+{
+ printf("CPU: ");
+ if (cpu >= 0 && cpu < (sizeof i386_cpus/sizeof(struct cpu_nameclass))) {
+ printf("%s", i386_cpus[cpu].cpu_name);
+ cpu_class = i386_cpus[cpu].cpu_class;
+ cpu_model = i386_cpus[cpu].cpu_name;
+ } else {
+ printf("unknown cpu type %d\n", cpu);
+ panic("startup: bad cpu id");
+ }
+ printf(" (");
+ switch(cpu_class) {
+ case CPUCLASS_286:
+ printf("286");
+ break;
+ case CPUCLASS_386:
+ printf("386");
+ break;
+ case CPUCLASS_486:
+ printf("486");
+ break;
+ case CPUCLASS_586:
+ printf("586");
+ break;
+ default:
+ printf("unknown"); /* will panic below... */
+ }
+ printf("-class CPU)");
+ printf("\n"); /* cpu speed would be nice, but how? */
+
+ /*
+ * Now that we have told the user what they have,
+ * let them know if that machine type isn't configured.
+ */
+ switch (cpu_class) {
+ case CPUCLASS_286: /* a 286 should not make it this far, anyway */
+#if !defined(I386_CPU) && !defined(I486_CPU) && !defined(I586_CPU)
+#error This kernel is not configured for one of the supported CPUs
+#endif
+#if !defined(I386_CPU)
+ case CPUCLASS_386:
+#endif
+#if !defined(I486_CPU)
+ case CPUCLASS_486:
+#endif
+#if !defined(I586_CPU)
+ case CPUCLASS_586:
+#endif
+ panic("CPU class not configured");
+ default:
+ break;
+ }
+}
+
+#ifdef PGINPROF
+/*
+ * Return the difference (in microseconds)
+ * between the current time and a previous
+ * time as represented by the arguments.
+ * If there is a pending clock interrupt
+ * which has not been serviced due to high
+ * ipl, return error code.
+ */
+/*ARGSUSED*/
+vmtime(otime, olbolt, oicr)
+ register int otime, olbolt, oicr;
+{
+
+ return (((time.tv_sec-otime)*60 + lbolt-olbolt)*16667);
+}
+#endif
+
+extern int kstack[];
+
+/*
+ * Send an interrupt to process.
+ *
+ * Stack is set up to allow sigcode stored
+ * in u. to call routine, followed by kcall
+ * to sigreturn routine below. After sigreturn
+ * resets the signal mask, the stack, and the
+ * frame pointer, it returns to the user
+ * specified pc, psl.
+ */
+void
+sendsig(catcher, sig, mask, code)
+ sig_t catcher;
+ int sig, mask;
+ unsigned code;
+{
+ register struct proc *p = curproc;
+ register int *regs;
+ register struct sigframe *fp;
+ struct sigacts *ps = p->p_sigacts;
+ int oonstack, frmtrap;
+
+ regs = p->p_regs;
+ oonstack = ps->ps_onstack;
+ /*
+ * Allocate and validate space for the signal handler
+ * context. Note that if the stack is in P0 space, the
+ * call to grow() is a nop, and the useracc() check
+ * will fail if the process has not already allocated
+ * the space with a `brk'.
+ */
+ if (!ps->ps_onstack && (ps->ps_sigonstack & sigmask(sig))) {
+ fp = (struct sigframe *)(ps->ps_sigsp
+ - sizeof(struct sigframe));
+ ps->ps_onstack = 1;
+ } else {
+ fp = (struct sigframe *)(regs[tESP]
+ - sizeof(struct sigframe));
+ }
+
+ /*
+ * grow() will return FALSE if the fp will not fit inside the stack
+ * and the stack can not be grown. useracc will return FALSE
+ * if access is denied.
+ */
+ if ((grow(p, (int)fp) == FALSE) ||
+ (useracc((caddr_t)fp, sizeof (struct sigframe), B_WRITE) == FALSE)) {
+ /*
+ * Process has trashed its stack; give it an illegal
+ * instruction to halt it in its tracks.
+ */
+ SIGACTION(p, SIGILL) = SIG_DFL;
+ sig = sigmask(SIGILL);
+ p->p_sigignore &= ~sig;
+ p->p_sigcatch &= ~sig;
+ p->p_sigmask &= ~sig;
+ psignal(p, SIGILL);
+ return;
+ }
+
+ /*
+ * Build the argument list for the signal handler.
+ */
+ fp->sf_signum = sig;
+ fp->sf_code = code;
+ fp->sf_scp = &fp->sf_sc;
+ fp->sf_addr = (char *) regs[tERR];
+ fp->sf_handler = catcher;
+
+ /* save scratch registers */
+ fp->sf_sc.sc_eax = regs[tEAX];
+ fp->sf_sc.sc_ebx = regs[tEBX];
+ fp->sf_sc.sc_ecx = regs[tECX];
+ fp->sf_sc.sc_edx = regs[tEDX];
+ fp->sf_sc.sc_esi = regs[tESI];
+ fp->sf_sc.sc_edi = regs[tEDI];
+ fp->sf_sc.sc_cs = regs[tCS];
+ fp->sf_sc.sc_ds = regs[tDS];
+ fp->sf_sc.sc_ss = regs[tSS];
+ fp->sf_sc.sc_es = regs[tES];
+ fp->sf_sc.sc_isp = regs[tISP];
+
+ /*
+ * Build the signal context to be used by sigreturn.
+ */
+ fp->sf_sc.sc_onstack = oonstack;
+ fp->sf_sc.sc_mask = mask;
+ fp->sf_sc.sc_sp = regs[tESP];
+ fp->sf_sc.sc_fp = regs[tEBP];
+ fp->sf_sc.sc_pc = regs[tEIP];
+ fp->sf_sc.sc_ps = regs[tEFLAGS];
+ regs[tESP] = (int)fp;
+ regs[tEIP] = (int)((struct pcb *)kstack)->pcb_sigc;
+ regs[tEFLAGS] &= ~PSL_VM;
+ regs[tCS] = _ucodesel;
+ regs[tDS] = _udatasel;
+ regs[tES] = _udatasel;
+ regs[tSS] = _udatasel;
+}
+
+/*
+ * System call to cleanup state after a signal
+ * has been taken. Reset signal mask and
+ * stack state from context left by sendsig (above).
+ * Return to previous pc and psl as specified by
+ * context left by sendsig. Check carefully to
+ * make sure that the user has not modified the
+ * psl to gain improper privileges or to cause
+ * a machine fault.
+ */
+struct sigreturn_args {
+ struct sigcontext *sigcntxp;
+};
+
+int
+sigreturn(p, uap, retval)
+ struct proc *p;
+ struct sigreturn_args *uap;
+ int *retval;
+{
+ register struct sigcontext *scp;
+ register struct sigframe *fp;
+ register int *regs = p->p_regs;
+ int eflags;
+
+ /*
+ * (XXX old comment) regs[tESP] points to the return address.
+ * The user scp pointer is above that.
+ * The return address is faked in the signal trampoline code
+ * for consistency.
+ */
+ scp = uap->sigcntxp;
+ fp = (struct sigframe *)
+ ((caddr_t)scp - offsetof(struct sigframe, sf_sc));
+
+ if (useracc((caddr_t)fp, sizeof (*fp), 0) == 0)
+ return(EINVAL);
+
+ eflags = scp->sc_ps;
+ if ((eflags & PSL_USERCLR) != 0 ||
+ (eflags & PSL_USERSET) != PSL_USERSET ||
+ (eflags & PSL_IOPL) < (regs[tEFLAGS] & PSL_IOPL)) {
+#ifdef DEBUG
+ printf("sigreturn: eflags=0x%x\n", eflags);
+#endif
+ return(EINVAL);
+ }
+
+ /*
+ * Sanity check the user's selectors and error if they
+ * are suspect.
+ */
+#define max_ldt_sel(pcb) \
+ ((pcb)->pcb_ldt ? (pcb)->pcb_ldt_len : (sizeof(ldt) / sizeof(ldt[0])))
+
+#define valid_ldt_sel(sel) \
+ (ISLDT(sel) && ISPL(sel) == SEL_UPL && \
+ IDXSEL(sel) < max_ldt_sel(&p->p_addr->u_pcb))
+
+#define null_sel(sel) \
+ (!ISLDT(sel) && IDXSEL(sel) == 0)
+
+ if ((scp->sc_cs&0xffff != _ucodesel && !valid_ldt_sel(scp->sc_cs)) ||
+ (scp->sc_ss&0xffff != _udatasel && !valid_ldt_sel(scp->sc_ss)) ||
+ (scp->sc_ds&0xffff != _udatasel && !valid_ldt_sel(scp->sc_ds) &&
+ !null_sel(scp->sc_ds)) ||
+ (scp->sc_es&0xffff != _udatasel && !valid_ldt_sel(scp->sc_es) &&
+ !null_sel(scp->sc_es))) {
+#ifdef DEBUG
+ printf("sigreturn: cs=0x%x ss=0x%x ds=0x%x es=0x%x\n",
+ scp->sc_cs, scp->sc_ss, scp->sc_ds, scp->sc_es);
+#endif
+ trapsignal(p, SIGBUS, T_PROTFLT);
+ return(EINVAL);
+ }
+
+#undef max_ldt_sel
+#undef valid_ldt_sel
+#undef null_sel
+
+ /* restore scratch registers */
+ regs[tEAX] = scp->sc_eax;
+ regs[tEBX] = scp->sc_ebx;
+ regs[tECX] = scp->sc_ecx;
+ regs[tEDX] = scp->sc_edx;
+ regs[tESI] = scp->sc_esi;
+ regs[tEDI] = scp->sc_edi;
+ regs[tCS] = scp->sc_cs;
+ regs[tDS] = scp->sc_ds;
+ regs[tES] = scp->sc_es;
+ regs[tSS] = scp->sc_ss;
+ regs[tISP] = scp->sc_isp;
+
+ if (useracc((caddr_t)scp, sizeof (*scp), 0) == 0)
+ return(EINVAL);
+
+ p->p_sigacts->ps_onstack = scp->sc_onstack & 01;
+ p->p_sigmask = scp->sc_mask &~
+ (sigmask(SIGKILL)|sigmask(SIGCONT)|sigmask(SIGSTOP));
+ regs[tEBP] = scp->sc_fp;
+ regs[tESP] = scp->sc_sp;
+ regs[tEIP] = scp->sc_pc;
+ regs[tEFLAGS] = eflags;
+ return(EJUSTRETURN);
+}
+
+/*
+ * a simple function to make the system panic (and dump a vmcore)
+ * in a predictable fashion
+ */
+void diediedie()
+{
+ panic("because you said to!");
+}
+
+int waittime = -1;
+struct pcb dumppcb;
+
+void
+boot(arghowto)
+ int arghowto;
+{
+ register long dummy; /* r12 is reserved */
+ register int howto; /* r11 == how to boot */
+ register int devtype; /* r10 == major of root dev */
+ extern int cold;
+ int nomsg = 1;
+
+ if (cold) {
+ printf("hit reset please");
+ for(;;);
+ }
+ howto = arghowto;
+ if ((howto&RB_NOSYNC) == 0 && waittime < 0 && bfreelist[0].b_forw) {
+ register struct buf *bp;
+ int iter, nbusy;
+
+ waittime = 0;
+ (void) splnet();
+ printf("syncing disks... ");
+ /*
+ * Release inodes held by texts before update.
+ */
+ if (panicstr == 0)
+ vnode_pager_umount(NULL);
+ sync(curproc, NULL, NULL);
+ /*
+ * Unmount filesystems
+ */
+#if 0
+ if (panicstr == 0)
+ vfs_unmountall();
+#endif
+
+ for (iter = 0; iter < 20; iter++) {
+ nbusy = 0;
+ for (bp = &buf[nbuf]; --bp >= buf; )
+ if ((bp->b_flags & (B_BUSY|B_INVAL)) == B_BUSY)
+ nbusy++;
+ if (nbusy == 0)
+ break;
+ if (nomsg) {
+ printf("updating disks before rebooting... ");
+ nomsg = 0;
+ }
+ printf("%d ", nbusy);
+ DELAY(40000 * iter);
+ }
+ if (nbusy)
+ printf("giving up\n");
+ else
+ printf("done\n");
+ DELAY(10000); /* wait for printf to finish */
+ }
+ splhigh();
+ devtype = major(rootdev);
+ if (howto&RB_HALT) {
+ printf("\n");
+ printf("The operating system has halted.\n");
+ printf("Please press any key to reboot.\n\n");
+ cngetc();
+ } else {
+ if (howto & RB_DUMP) {
+ savectx(&dumppcb, 0);
+ dumppcb.pcb_ptd = rcr3();
+ dumpsys();
+
+ if (PANIC_REBOOT_WAIT_TIME != 0) {
+ if (PANIC_REBOOT_WAIT_TIME != -1) {
+ int loop;
+ printf("Automatic reboot in %d seconds - press a key on the console to abort\n",
+ PANIC_REBOOT_WAIT_TIME);
+ for (loop = PANIC_REBOOT_WAIT_TIME; loop > 0; --loop) {
+ DELAY(1000 * 1000); /* one second */
+ if (sgetc(1)) /* Did user type a key? */
+ break;
+ }
+ if (!loop)
+ goto die;
+ }
+ } else { /* zero time specified - reboot NOW */
+ goto die;
+ }
+ printf("--> Press a key on the console to reboot <--\n");
+ cngetc();
+ }
+ }
+#ifdef lint
+ dummy = 0; dummy = dummy;
+ printf("howto %d, devtype %d\n", arghowto, devtype);
+#endif
+die:
+ printf("Rebooting...\n");
+ DELAY(1000000); /* wait 1 sec for printf's to complete and be read */
+ cpu_reset();
+ for(;;) ;
+ /* NOTREACHED */
+}
+
+unsigned long dumpmag = 0x8fca0101UL; /* magic number for savecore */
+int dumpsize = 0; /* also for savecore */
+/*
+ * Doadump comes here after turning off memory management and
+ * getting on the dump stack, either when called above, or by
+ * the auto-restart code.
+ */
+void
+dumpsys()
+{
+
+ if (dumpdev == NODEV)
+ return;
+ if ((minor(dumpdev)&07) != 1)
+ return;
+ dumpsize = Maxmem;
+ printf("\ndumping to dev %x, offset %d\n", dumpdev, dumplo);
+ printf("dump ");
+ switch ((*bdevsw[major(dumpdev)].d_dump)(dumpdev)) {
+
+ case ENXIO:
+ printf("device bad\n");
+ break;
+
+ case EFAULT:
+ printf("device not ready\n");
+ break;
+
+ case EINVAL:
+ printf("area improper\n");
+ break;
+
+ case EIO:
+ printf("i/o error\n");
+ break;
+
+ case EINTR:
+ printf("aborted from console\n");
+ break;
+
+ default:
+ printf("succeeded\n");
+ break;
+ }
+}
+
+#ifdef HZ
+/*
+ * If HZ is defined we use this code, otherwise the code in
+ * /sys/i386/i386/microtime.s is used. The othercode only works
+ * for HZ=100.
+ */
+microtime(tvp)
+ register struct timeval *tvp;
+{
+ int s = splhigh();
+
+ *tvp = time;
+ tvp->tv_usec += tick;
+ while (tvp->tv_usec > 1000000) {
+ tvp->tv_sec++;
+ tvp->tv_usec -= 1000000;
+ }
+ splx(s);
+}
+#endif /* HZ */
+
+static void
+initcpu()
+{
+}
+
+/*
+ * Clear registers on exec
+ */
+void
+setregs(p, entry, stack)
+ struct proc *p;
+ u_long entry;
+ u_long stack;
+{
+ p->p_regs[tEBP] = 0; /* bottom of the fp chain */
+ p->p_regs[tEIP] = entry;
+ p->p_regs[tESP] = stack;
+ p->p_regs[tSS] = _udatasel;
+ p->p_regs[tDS] = _udatasel;
+ p->p_regs[tES] = _udatasel;
+ p->p_regs[tCS] = _ucodesel;
+
+ p->p_addr->u_pcb.pcb_flags = 0; /* no fp at all */
+ load_cr0(rcr0() | CR0_TS); /* start emulating */
+#if NNPX > 0
+ npxinit(__INITIAL_NPXCW__);
+#endif /* NNPX > 0 */
+}
+
+/*
+ * Initialize 386 and configure to run kernel
+ */
+
+/*
+ * Initialize segments & interrupt table
+ */
+
+union descriptor gdt[NGDT];
+union descriptor ldt[NLDT]; /* local descriptor table */
+struct gate_descriptor idt[NIDT]; /* interrupt descriptor table */
+
+int _default_ldt, currentldt;
+
+struct i386tss tss, panic_tss;
+
+extern struct user *proc0paddr;
+
+/* software prototypes -- in more palatable form */
+struct soft_segment_descriptor gdt_segs[] = {
+ /* Null Descriptor */
+{ 0x0, /* segment base address */
+ 0x0, /* length */
+ 0, /* segment type */
+ 0, /* segment descriptor priority level */
+ 0, /* segment descriptor present */
+ 0, 0,
+ 0, /* default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Code Descriptor for kernel */
+{ 0x0, /* segment base address */
+ 0xfffff, /* length - all address space */
+ SDT_MEMERA, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0, 0,
+ 1, /* default 32 vs 16 bit size */
+ 1 /* limit granularity (byte/page units)*/ },
+ /* Data Descriptor for kernel */
+{ 0x0, /* segment base address */
+ 0xfffff, /* length - all address space */
+ SDT_MEMRWA, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0, 0,
+ 1, /* default 32 vs 16 bit size */
+ 1 /* limit granularity (byte/page units)*/ },
+ /* LDT Descriptor */
+{ (int) ldt, /* segment base address */
+ sizeof(ldt)-1, /* length - all address space */
+ SDT_SYSLDT, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0, 0,
+ 0, /* unused - default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Null Descriptor - Placeholder */
+{ 0x0, /* segment base address */
+ 0x0, /* length - all address space */
+ 0, /* segment type */
+ 0, /* segment descriptor priority level */
+ 0, /* segment descriptor present */
+ 0, 0,
+ 0, /* default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Panic Tss Descriptor */
+{ (int) &panic_tss, /* segment base address */
+ sizeof(tss)-1, /* length - all address space */
+ SDT_SYS386TSS, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0, 0,
+ 0, /* unused - default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Proc 0 Tss Descriptor */
+{ (int) kstack, /* segment base address */
+ sizeof(tss)-1, /* length - all address space */
+ SDT_SYS386TSS, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0, 0,
+ 0, /* unused - default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* User LDT Descriptor per process */
+{ (int) ldt, /* segment base address */
+ (512 * sizeof(union descriptor)-1), /* length */
+ SDT_SYSLDT, /* segment type */
+ 0, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0, 0,
+ 0, /* unused - default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+};
+
+struct soft_segment_descriptor ldt_segs[] = {
+ /* Null Descriptor - overwritten by call gate */
+{ 0x0, /* segment base address */
+ 0x0, /* length - all address space */
+ 0, /* segment type */
+ 0, /* segment descriptor priority level */
+ 0, /* segment descriptor present */
+ 0, 0,
+ 0, /* default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Null Descriptor - overwritten by call gate */
+{ 0x0, /* segment base address */
+ 0x0, /* length - all address space */
+ 0, /* segment type */
+ 0, /* segment descriptor priority level */
+ 0, /* segment descriptor present */
+ 0, 0,
+ 0, /* default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Null Descriptor - overwritten by call gate */
+{ 0x0, /* segment base address */
+ 0x0, /* length - all address space */
+ 0, /* segment type */
+ 0, /* segment descriptor priority level */
+ 0, /* segment descriptor present */
+ 0, 0,
+ 0, /* default 32 vs 16 bit size */
+ 0 /* limit granularity (byte/page units)*/ },
+ /* Code Descriptor for user */
+{ 0x0, /* segment base address */
+ 0xfffff, /* length - all address space */
+ SDT_MEMERA, /* segment type */
+ SEL_UPL, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0, 0,
+ 1, /* default 32 vs 16 bit size */
+ 1 /* limit granularity (byte/page units)*/ },
+ /* Data Descriptor for user */
+{ 0x0, /* segment base address */
+ 0xfffff, /* length - all address space */
+ SDT_MEMRWA, /* segment type */
+ SEL_UPL, /* segment descriptor priority level */
+ 1, /* segment descriptor present */
+ 0, 0,
+ 1, /* default 32 vs 16 bit size */
+ 1 /* limit granularity (byte/page units)*/ } };
+
+void
+setidt(idx, func, typ, dpl)
+ int idx;
+ void (*func)();
+ int typ;
+ int dpl;
+{
+ struct gate_descriptor *ip = idt + idx;
+
+ ip->gd_looffset = (int)func;
+ ip->gd_selector = 8;
+ ip->gd_stkcpy = 0;
+ ip->gd_xx = 0;
+ ip->gd_type = typ;
+ ip->gd_dpl = dpl;
+ ip->gd_p = 1;
+ ip->gd_hioffset = ((int)func)>>16 ;
+}
+
+#define IDTVEC(name) __CONCAT(X,name)
+typedef void idtvec_t();
+
+extern idtvec_t
+ IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl),
+ IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(dble), IDTVEC(fpusegm),
+ IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot),
+ IDTVEC(page), IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(rsvd0),
+ IDTVEC(rsvd1), IDTVEC(rsvd2), IDTVEC(rsvd3), IDTVEC(rsvd4),
+ IDTVEC(rsvd5), IDTVEC(rsvd6), IDTVEC(rsvd7), IDTVEC(rsvd8),
+ IDTVEC(rsvd9), IDTVEC(rsvd10), IDTVEC(rsvd11), IDTVEC(rsvd12),
+ IDTVEC(rsvd13), IDTVEC(rsvd14), IDTVEC(rsvd14), IDTVEC(syscall);
+
+int _gsel_tss;
+
+void
+init386(first)
+ int first;
+{
+ extern ssdtosd(), lgdt(), lidt(), lldt(), etext;
+ int x, *pi;
+ unsigned biosbasemem, biosextmem;
+ struct gate_descriptor *gdp;
+ extern int sigcode,szsigcode;
+ /* table descriptors - used to load tables by microp */
+ struct region_descriptor r_gdt, r_idt;
+ int pagesinbase, pagesinext;
+ int target_page;
+
+ proc0.p_addr = proc0paddr;
+
+ /*
+ * Initialize the console before we print anything out.
+ */
+
+ cninit ();
+
+ /*
+ * make gdt memory segments, the code segment goes up to end of the
+ * page with etext in it, the data segment goes to the end of
+ * the address space
+ */
+ gdt_segs[GCODE_SEL].ssd_limit = i386_btop(i386_round_page(&etext)) - 1;
+ gdt_segs[GDATA_SEL].ssd_limit = i386_btop(0) - 1;
+ for (x=0; x < NGDT; x++) ssdtosd(gdt_segs+x, gdt+x);
+
+ /* make ldt memory segments */
+ /*
+ * The data segment limit must not cover the user area because we
+ * don't want the user area to be writable in copyout() etc. (page
+ * level protection is lost in kernel mode on 386's). Also, we
+ * don't want the user area to be writable directly (page level
+ * protection of the user area is not available on 486's with
+ * CR0_WP set, because there is no user-read/kernel-write mode).
+ *
+ * XXX - VM_MAXUSER_ADDRESS is an end address, not a max. And it
+ * should be spelled ...MAX_USER...
+ */
+#define VM_END_USER_RW_ADDRESS VM_MAXUSER_ADDRESS
+ /*
+ * The code segment limit has to cover the user area until we move
+ * the signal trampoline out of the user area. This is safe because
+ * the code segment cannot be written to directly.
+ */
+#define VM_END_USER_R_ADDRESS (VM_END_USER_RW_ADDRESS + UPAGES * NBPG)
+ ldt_segs[LUCODE_SEL].ssd_limit = i386_btop(VM_END_USER_R_ADDRESS) - 1;
+ ldt_segs[LUDATA_SEL].ssd_limit = i386_btop(VM_END_USER_RW_ADDRESS) - 1;
+ /* Note. eventually want private ldts per process */
+ for (x=0; x < 5; x++) ssdtosd(ldt_segs+x, ldt+x);
+
+ /* exceptions */
+ setidt(0, &IDTVEC(div), SDT_SYS386TGT, SEL_KPL);
+ setidt(1, &IDTVEC(dbg), SDT_SYS386TGT, SEL_KPL);
+ setidt(2, &IDTVEC(nmi), SDT_SYS386TGT, SEL_KPL);
+ setidt(3, &IDTVEC(bpt), SDT_SYS386TGT, SEL_UPL);
+ setidt(4, &IDTVEC(ofl), SDT_SYS386TGT, SEL_UPL);
+ setidt(5, &IDTVEC(bnd), SDT_SYS386TGT, SEL_KPL);
+ setidt(6, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL);
+ setidt(7, &IDTVEC(dna), SDT_SYS386TGT, SEL_KPL);
+ setidt(8, &IDTVEC(dble), SDT_SYS386TGT, SEL_KPL);
+ setidt(9, &IDTVEC(fpusegm), SDT_SYS386TGT, SEL_KPL);
+ setidt(10, &IDTVEC(tss), SDT_SYS386TGT, SEL_KPL);
+ setidt(11, &IDTVEC(missing), SDT_SYS386TGT, SEL_KPL);
+ setidt(12, &IDTVEC(stk), SDT_SYS386TGT, SEL_KPL);
+ setidt(13, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL);
+ setidt(14, &IDTVEC(page), SDT_SYS386TGT, SEL_KPL);
+ setidt(15, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL);
+ setidt(16, &IDTVEC(fpu), SDT_SYS386TGT, SEL_KPL);
+ setidt(17, &IDTVEC(rsvd0), SDT_SYS386TGT, SEL_KPL);
+ setidt(18, &IDTVEC(rsvd1), SDT_SYS386TGT, SEL_KPL);
+ setidt(19, &IDTVEC(rsvd2), SDT_SYS386TGT, SEL_KPL);
+ setidt(20, &IDTVEC(rsvd3), SDT_SYS386TGT, SEL_KPL);
+ setidt(21, &IDTVEC(rsvd4), SDT_SYS386TGT, SEL_KPL);
+ setidt(22, &IDTVEC(rsvd5), SDT_SYS386TGT, SEL_KPL);
+ setidt(23, &IDTVEC(rsvd6), SDT_SYS386TGT, SEL_KPL);
+ setidt(24, &IDTVEC(rsvd7), SDT_SYS386TGT, SEL_KPL);
+ setidt(25, &IDTVEC(rsvd8), SDT_SYS386TGT, SEL_KPL);
+ setidt(26, &IDTVEC(rsvd9), SDT_SYS386TGT, SEL_KPL);
+ setidt(27, &IDTVEC(rsvd10), SDT_SYS386TGT, SEL_KPL);
+ setidt(28, &IDTVEC(rsvd11), SDT_SYS386TGT, SEL_KPL);
+ setidt(29, &IDTVEC(rsvd12), SDT_SYS386TGT, SEL_KPL);
+ setidt(30, &IDTVEC(rsvd13), SDT_SYS386TGT, SEL_KPL);
+ setidt(31, &IDTVEC(rsvd14), SDT_SYS386TGT, SEL_KPL);
+
+#include "isa.h"
+#if NISA >0
+ isa_defaultirq();
+#endif
+
+ r_gdt.rd_limit = sizeof(gdt) - 1;
+ r_gdt.rd_base = (int) gdt;
+ lgdt(&r_gdt);
+ r_idt.rd_limit = sizeof(idt) - 1;
+ r_idt.rd_base = (int) idt;
+ lidt(&r_idt);
+ _default_ldt = GSEL(GLDT_SEL, SEL_KPL);
+ lldt(_default_ldt);
+ currentldt = _default_ldt;
+
+#include "ddb.h"
+#if NDDB > 0
+ kdb_init();
+ if (boothowto & RB_KDB)
+ Debugger("Boot flags requested debugger");
+#endif
+
+ /* Use BIOS values stored in RTC CMOS RAM, since probing
+ * breaks certain 386 AT relics.
+ */
+ biosbasemem = rtcin(RTC_BASELO)+ (rtcin(RTC_BASEHI)<<8);
+ biosextmem = rtcin(RTC_EXTLO)+ (rtcin(RTC_EXTHI)<<8);
+
+ /*
+ * If BIOS tells us that it has more than 640k in the basemem,
+ * don't believe it - set it to 640k.
+ */
+ if (biosbasemem > 640)
+ biosbasemem = 640;
+
+ /*
+ * Some 386 machines might give us a bogus number for extended
+ * mem. If this happens, stop now.
+ */
+#ifndef LARGEMEM
+ if (biosextmem > 65536) {
+ panic("extended memory beyond limit of 64MB");
+ /* NOTREACHED */
+ }
+#endif
+
+ pagesinbase = biosbasemem * 1024 / NBPG;
+ pagesinext = biosextmem * 1024 / NBPG;
+
+ /*
+ * Special hack for chipsets that still remap the 384k hole when
+ * there's 16MB of memory - this really confuses people that
+ * are trying to use bus mastering ISA controllers with the
+ * "16MB limit"; they only have 16MB, but the remapping puts
+ * them beyond the limit.
+ * XXX - this should be removed when bounce buffers are
+ * implemented.
+ */
+ /*
+ * If extended memory is between 15-16MB (16-17MB phys address range),
+ * chop it to 15MB.
+ */
+ if ((pagesinext > 3840) && (pagesinext < 4096))
+ pagesinext = 3840;
+
+ /*
+ * Maxmem isn't the "maximum memory", it's the highest page of
+ * of the physical address space. It should be "Maxphyspage".
+ */
+ Maxmem = pagesinext + 0x100000/PAGE_SIZE;
+
+#ifdef MAXMEM
+ if (MAXMEM/4 < Maxmem)
+ Maxmem = MAXMEM/4;
+#endif
+ /*
+ * Calculate number of physical pages, but account for Maxmem
+ * limitation above.
+ */
+ physmem = pagesinbase +
+ (min(pagesinext + 0x100000/PAGE_SIZE, Maxmem) - 0x100000/PAGE_SIZE);
+
+ /* call pmap initialization to make new kernel address space */
+ pmap_bootstrap (first, 0);
+
+ /*
+ * Do simple memory test over range of extended memory that BIOS
+ * indicates exists. Adjust Maxmem to the highest page of
+ * good memory.
+ */
+ printf("Testing memory (%dMB)...", ptoa(Maxmem)/1024/1024);
+
+ for (target_page = Maxmem - 1; target_page >= atop(first); target_page--) {
+ extern struct pte *CMAP1;
+ extern caddr_t CADDR1;
+
+ /*
+ * map page into kernel: valid, read/write, non-cacheable
+ */
+ *(int *)CMAP1 = PG_V | PG_KW | PG_N | ptoa(target_page);
+ tlbflush();
+
+ /*
+ * Test for alternating 1's and 0's
+ */
+ filli(0xaaaaaaaa, CADDR1, PAGE_SIZE/sizeof(int));
+ if (test_page((int *)CADDR1, 0xaaaaaaaa)) {
+ Maxmem = target_page;
+ badpages++;
+ continue;
+ }
+ /*
+ * Test for alternating 0's and 1's
+ */
+ filli(0x55555555, CADDR1, PAGE_SIZE/sizeof(int));
+ if (test_page((int *)CADDR1, 0x55555555)) {
+ Maxmem = target_page;
+ badpages++;
+ continue;
+ }
+ /*
+ * Test for all 1's
+ */
+ filli(0xffffffff, CADDR1, PAGE_SIZE/sizeof(int));
+ if (test_page((int *)CADDR1, 0xffffffff)) {
+ Maxmem = target_page;
+ badpages++;
+ continue;
+ }
+ /*
+ * Test zeroing of page
+ */
+ bzero(CADDR1, PAGE_SIZE);
+ if (test_page((int *)CADDR1, 0)) {
+ /*
+ * test of page failed
+ */
+ Maxmem = target_page;
+ badpages++;
+ continue;
+ }
+ }
+ printf("done.\n");
+
+ avail_end = (Maxmem << PAGE_SHIFT)
+ - i386_round_page(sizeof(struct msgbuf));
+
+ /*
+ * Initialize pointers to the two chunks of memory; for use
+ * later in vm_page_startup.
+ */
+ /* avail_start is initialized in pmap_bootstrap */
+ x = 0;
+ if (pagesinbase > 1) {
+ phys_avail[x++] = NBPG; /* skip first page of memory */
+ phys_avail[x++] = pagesinbase * NBPG; /* memory up to the ISA hole */
+ }
+ phys_avail[x++] = avail_start; /* memory up to the end */
+ phys_avail[x++] = avail_end;
+ phys_avail[x++] = 0; /* no more chunks */
+ phys_avail[x++] = 0;
+
+ /* now running on new page tables, configured,and u/iom is accessible */
+
+ /* make a initial tss so microp can get interrupt stack on syscall! */
+ proc0.p_addr->u_pcb.pcb_tss.tss_esp0 = (int) kstack + UPAGES*NBPG;
+ proc0.p_addr->u_pcb.pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ;
+ _gsel_tss = GSEL(GPROC0_SEL, SEL_KPL);
+
+ ((struct i386tss *)gdt_segs[GPROC0_SEL].ssd_base)->tss_ioopt =
+ (sizeof(tss))<<16;
+
+ ltr(_gsel_tss);
+
+ /* make a call gate to reenter kernel with */
+ gdp = &ldt[LSYS5CALLS_SEL].gd;
+
+ x = (int) &IDTVEC(syscall);
+ gdp->gd_looffset = x++;
+ gdp->gd_selector = GSEL(GCODE_SEL,SEL_KPL);
+ gdp->gd_stkcpy = 1;
+ gdp->gd_type = SDT_SYS386CGT;
+ gdp->gd_dpl = SEL_UPL;
+ gdp->gd_p = 1;
+ gdp->gd_hioffset = ((int) &IDTVEC(syscall)) >>16;
+
+ /* transfer to user mode */
+
+ _ucodesel = LSEL(LUCODE_SEL, SEL_UPL);
+ _udatasel = LSEL(LUDATA_SEL, SEL_UPL);
+
+ /* setup proc 0's pcb */
+ bcopy(&sigcode, proc0.p_addr->u_pcb.pcb_sigc, szsigcode);
+ proc0.p_addr->u_pcb.pcb_flags = 0;
+ proc0.p_addr->u_pcb.pcb_ptd = IdlePTD;
+}
+
+int
+test_page(address, pattern)
+ int *address;
+ int pattern;
+{
+ int *x;
+
+ for (x = address; x < (int *)((char *)address + PAGE_SIZE); x++) {
+ if (*x != pattern)
+ return (1);
+ }
+ return(0);
+}
+
+/*
+ * insert an element into a queue
+ */
+#undef insque
+void /* XXX replace with inline FIXME! */
+_insque(element, head)
+ register struct prochd *element, *head;
+{
+ element->ph_link = head->ph_link;
+ head->ph_link = (struct proc *)element;
+ element->ph_rlink = (struct proc *)head;
+ ((struct prochd *)(element->ph_link))->ph_rlink=(struct proc *)element;
+}
+
+/*
+ * remove an element from a queue
+ */
+#undef remque
+void /* XXX replace with inline FIXME! */
+_remque(element)
+ register struct prochd *element;
+{
+ ((struct prochd *)(element->ph_link))->ph_rlink = element->ph_rlink;
+ ((struct prochd *)(element->ph_rlink))->ph_link = element->ph_link;
+ element->ph_rlink = (struct proc *)0;
+}
+
+/*
+ * The registers are in the frame; the frame is in the user area of
+ * the process in question; when the process is active, the registers
+ * are in "the kernel stack"; when it's not, they're still there, but
+ * things get flipped around. So, since p->p_regs is the whole address
+ * of the register set, take its offset from the kernel stack, and
+ * index into the user block. Don't you just *love* virtual memory?
+ * (I'm starting to think seymour is right...)
+ */
+
+int
+ptrace_set_pc (struct proc *p, unsigned int addr) {
+ void *regs = (char*)p->p_addr +
+ ((char*) p->p_regs - (char*) kstack);
+
+ ((struct trapframe *)regs)->tf_eip = addr;
+ return 0;
+}
+
+int
+ptrace_single_step (struct proc *p) {
+ void *regs = (char*)p->p_addr +
+ ((char*) p->p_regs - (char*) kstack);
+
+ ((struct trapframe *)regs)->tf_eflags |= PSL_T;
+ return 0;
+}
+
+/*
+ * Copy the registers to user-space.
+ */
+
+int
+ptrace_getregs (struct proc *p, unsigned int *addr) {
+ int error;
+ struct regs regs = {0};
+
+ if (error = fill_regs (p, &regs))
+ return error;
+
+ return copyout (&regs, addr, sizeof (regs));
+}
+
+int
+ptrace_setregs (struct proc *p, unsigned int *addr) {
+ int error;
+ struct regs regs = {0};
+
+ if (error = copyin (addr, &regs, sizeof(regs)))
+ return error;
+
+ return set_regs (p, &regs);
+}
+
+int
+fill_regs(struct proc *p, struct regs *regs) {
+ int error;
+ struct trapframe *tp;
+ void *ptr = (char*)p->p_addr +
+ ((char*) p->p_regs - (char*) kstack);
+
+ tp = ptr;
+ regs->r_es = tp->tf_es;
+ regs->r_ds = tp->tf_ds;
+ regs->r_edi = tp->tf_edi;
+ regs->r_esi = tp->tf_esi;
+ regs->r_ebp = tp->tf_ebp;
+ regs->r_ebx = tp->tf_ebx;
+ regs->r_edx = tp->tf_edx;
+ regs->r_ecx = tp->tf_ecx;
+ regs->r_eax = tp->tf_eax;
+ regs->r_eip = tp->tf_eip;
+ regs->r_cs = tp->tf_cs;
+ regs->r_eflags = tp->tf_eflags;
+ regs->r_esp = tp->tf_esp;
+ regs->r_ss = tp->tf_ss;
+ return 0;
+}
+
+int
+set_regs (struct proc *p, struct regs *regs) {
+ int error;
+ struct trapframe *tp;
+ void *ptr = (char*)p->p_addr +
+ ((char*) p->p_regs - (char*) kstack);
+
+ tp = ptr;
+ tp->tf_es = regs->r_es;
+ tp->tf_ds = regs->r_ds;
+ tp->tf_edi = regs->r_edi;
+ tp->tf_esi = regs->r_esi;
+ tp->tf_ebp = regs->r_ebp;
+ tp->tf_ebx = regs->r_ebx;
+ tp->tf_edx = regs->r_edx;
+ tp->tf_ecx = regs->r_ecx;
+ tp->tf_eax = regs->r_eax;
+ tp->tf_eip = regs->r_eip;
+ tp->tf_cs = regs->r_cs;
+ tp->tf_eflags = regs->r_eflags;
+ tp->tf_esp = regs->r_esp;
+ tp->tf_ss = regs->r_ss;
+ return 0;
+}
+
+#include "ddb.h"
+#if NDDB <= 0
+void
+Debugger(const char *msg)
+{
+ printf("Debugger(\"%s\") called.", msg);
+}
+#endif /* no DDB */
diff --git a/sys/i386/i386/math_emu.h b/sys/i386/i386/math_emu.h
new file mode 100644
index 0000000..453a903
--- /dev/null
+++ b/sys/i386/i386/math_emu.h
@@ -0,0 +1,156 @@
+/*
+ * linux/include/linux/math_emu.h
+ *
+ * (C) 1991 Linus Torvalds
+ *
+ * $Id$
+ */
+#ifndef _LINUX_MATH_EMU_H
+#define _LINUX_MATH_EMU_H
+
+/*#define math_abort(x,y) \
+(((volatile void (*)(struct info *,unsigned int)) __math_abort)((x),(y)))*/
+
+/*
+ * Gcc forces this stupid alignment problem: I want to use only two longs
+ * for the temporary real 64-bit mantissa, but then gcc aligns out the
+ * structure to 12 bytes which breaks things in math_emulate.c. Shit. I
+ * want some kind of "no-alignt" pragma or something.
+ */
+
+typedef struct {
+ long a,b;
+ short exponent;
+} temp_real;
+
+typedef struct {
+ short m0,m1,m2,m3;
+ short exponent;
+} temp_real_unaligned;
+
+#define real_to_real(a,b) \
+((*(long long *) (b) = *(long long *) (a)),((b)->exponent = (a)->exponent))
+
+typedef struct {
+ long a,b;
+} long_real;
+
+typedef long short_real;
+
+typedef struct {
+ long a,b;
+ short sign;
+} temp_int;
+
+struct swd {
+ int ie:1;
+ int de:1;
+ int ze:1;
+ int oe:1;
+ int ue:1;
+ int pe:1;
+ int sf:1;
+ int ir:1;
+ int c0:1;
+ int c1:1;
+ int c2:1;
+ int top:3;
+ int c3:1;
+ int b:1;
+};
+struct i387_struct {
+ long cwd;
+ long swd;
+ long twd;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
+};
+
+#define I387 (*(struct i387_struct *)&(((struct pcb *)curproc->p_addr)->pcb_savefpu))
+#define SWD (*(struct swd *) &I387.swd)
+#define ROUNDING ((I387.cwd >> 10) & 3)
+#define PRECISION ((I387.cwd >> 8) & 3)
+
+#define BITS24 0
+#define BITS53 2
+#define BITS64 3
+
+#define ROUND_NEAREST 0
+#define ROUND_DOWN 1
+#define ROUND_UP 2
+#define ROUND_0 3
+
+#define CONSTZ (temp_real_unaligned) {0x0000,0x0000,0x0000,0x0000,0x0000}
+#define CONST1 (temp_real_unaligned) {0x0000,0x0000,0x0000,0x8000,0x3FFF}
+#define CONSTPI (temp_real_unaligned) {0xC235,0x2168,0xDAA2,0xC90F,0x4000}
+#define CONSTLN2 (temp_real_unaligned) {0x79AC,0xD1CF,0x17F7,0xB172,0x3FFE}
+#define CONSTLG2 (temp_real_unaligned) {0xF799,0xFBCF,0x9A84,0x9A20,0x3FFD}
+#define CONSTL2E (temp_real_unaligned) {0xF0BC,0x5C17,0x3B29,0xB8AA,0x3FFF}
+#define CONSTL2T (temp_real_unaligned) {0x8AFE,0xCD1B,0x784B,0xD49A,0x4000}
+
+#define set_IE() (I387.swd |= 1)
+#define set_DE() (I387.swd |= 2)
+#define set_ZE() (I387.swd |= 4)
+#define set_OE() (I387.swd |= 8)
+#define set_UE() (I387.swd |= 16)
+#define set_PE() (I387.swd |= 32)
+
+#define set_C0() (I387.swd |= 0x0100)
+#define set_C1() (I387.swd |= 0x0200)
+#define set_C2() (I387.swd |= 0x0400)
+#define set_C3() (I387.swd |= 0x4000)
+
+/* ea.c */
+
+char * ea(struct trapframe *, unsigned short);
+
+/* convert.c */
+
+void frndint(const temp_real * __a, temp_real * __b);
+void Fscale(const temp_real *, const temp_real *, temp_real *);
+void short_to_temp(const short_real * __a, temp_real * __b);
+void long_to_temp(const long_real * __a, temp_real * __b);
+void temp_to_short(const temp_real * __a, short_real * __b);
+void temp_to_long(const temp_real * __a, long_real * __b);
+void real_to_int(const temp_real * __a, temp_int * __b);
+void int_to_real(const temp_int * __a, temp_real * __b);
+
+/* get_put.c */
+
+void get_short_real(temp_real *, struct trapframe *, unsigned short);
+void get_long_real(temp_real *, struct trapframe *, unsigned short);
+void get_temp_real(temp_real *, struct trapframe *, unsigned short);
+void get_short_int(temp_real *, struct trapframe *, unsigned short);
+void get_long_int(temp_real *, struct trapframe *, unsigned short);
+void get_longlong_int(temp_real *, struct trapframe *, unsigned short);
+void get_BCD(temp_real *, struct trapframe *, unsigned short);
+void put_short_real(const temp_real *, struct trapframe *, unsigned short);
+void put_long_real(const temp_real *, struct trapframe *, unsigned short);
+void put_temp_real(const temp_real *, struct trapframe *, unsigned short);
+void put_short_int(const temp_real *, struct trapframe *, unsigned short);
+void put_long_int(const temp_real *, struct trapframe *, unsigned short);
+void put_longlong_int(const temp_real *, struct trapframe *, unsigned short);
+void put_BCD(const temp_real *, struct trapframe *, unsigned short);
+
+/* add.c */
+
+void fadd(const temp_real *, const temp_real *, temp_real *);
+
+/* mul.c */
+
+void fmul(const temp_real *, const temp_real *, temp_real *);
+
+/* div.c */
+
+void fdiv(const temp_real *, const temp_real *, temp_real *);
+
+/* compare.c */
+
+void fcom(const temp_real *, const temp_real *);
+void fucom(const temp_real *, const temp_real *);
+void ftst(const temp_real *);
+
+#endif
diff --git a/sys/i386/i386/math_emulate.c b/sys/i386/i386/math_emulate.c
new file mode 100644
index 0000000..1b15e61
--- /dev/null
+++ b/sys/i386/i386/math_emulate.c
@@ -0,0 +1,1475 @@
+/*
+ * linux/kernel/math/math_emulate.c
+ *
+ * (C) 1991 Linus Torvalds
+ *
+ * [expediant "port" of linux 8087 emulator to 386BSD, with apologies -wfj]
+ *
+ * from: 386BSD 0.1
+ * $Id: math_emulate.c,v 1.7 1994/01/29 22:07:16 nate Exp $
+ */
+
+/*
+ * Limited emulation 27.12.91 - mostly loads/stores, which gcc wants
+ * even for soft-float, unless you use bruce evans' patches. The patches
+ * are great, but they have to be re-applied for every version, and the
+ * library is different for soft-float and 80387. So emulation is more
+ * practical, even though it's slower.
+ *
+ * 28.12.91 - loads/stores work, even BCD. I'll have to start thinking
+ * about add/sub/mul/div. Urgel. I should find some good source, but I'll
+ * just fake up something.
+ *
+ * 30.12.91 - add/sub/mul/div/com seem to work mostly. I should really
+ * test every possible combination.
+ */
+
+/*
+ * This file is full of ugly macros etc: one problem was that gcc simply
+ * didn't want to make the structures as they should be: it has to try to
+ * align them. Sickening code, but at least I've hidden the ugly things
+ * in this one file: the other files don't need to know about these things.
+ *
+ * The other files also don't care about ST(x) etc - they just get addresses
+ * to 80-bit temporary reals, and do with them as they please. I wanted to
+ * hide most of the 387-specific things here.
+ */
+
+#include "machine/cpu.h"
+#include "machine/psl.h"
+#include "machine/reg.h"
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "user.h"
+#include "acct.h"
+#include "kernel.h"
+#include "signal.h"
+
+#define __ALIGNED_TEMP_REAL 1
+#include "i386/i386/math_emu.h"
+
+#define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x))
+#define ST(x) (*__st((x)))
+#define PST(x) ((const temp_real *) __st((x)))
+#define math_abort(tfp, signo) tfp->tf_eip = oldeip; return (signo);
+
+/*
+ * We don't want these inlined - it gets too messy in the machine-code.
+ */
+static void fpop(void);
+static void fpush(void);
+static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b);
+static temp_real_unaligned * __st(int i);
+
+unsigned char get_fs_byte(char *adr) { return(fubyte(adr)); }
+unsigned short get_fs_word(unsigned short *adr) { return(fuword(adr)); }
+unsigned long get_fs_long(unsigned long *adr) { return(fuword(adr)); }
+void put_fs_byte(unsigned char val, char *adr) { (void)subyte(adr,val); }
+void put_fs_word(unsigned short val, short *adr) { (void)susword(adr,val); }
+void put_fs_long(u_long val, unsigned long *adr) { (void)suword(adr,val); }
+
+int
+math_emulate(struct trapframe * info)
+{
+ unsigned short code;
+ temp_real tmp;
+ char * address;
+ u_long oldeip;
+
+ /* ever used fp? */
+ if ((((struct pcb *)curproc->p_addr)->pcb_flags & FP_SOFTFP) == 0) {
+ ((struct pcb *)curproc->p_addr)->pcb_flags |= FP_SOFTFP;
+ I387.cwd = 0x037f;
+ I387.swd = 0x0000;
+ I387.twd = 0x0000;
+ }
+
+ if (I387.cwd & I387.swd & 0x3f)
+ I387.swd |= 0x8000;
+ else
+ I387.swd &= 0x7fff;
+ oldeip = info->tf_eip;
+/* 0x001f means user code space */
+ if ((u_short)info->tf_cs != 0x001F) {
+ printf("math_emulate: %04x:%08x\n\r", (u_short)info->tf_cs,
+ oldeip);
+ panic("?Math emulation needed in kernel?");
+ }
+ code = get_fs_word((unsigned short *) oldeip);
+ bswapw(code);
+ code &= 0x7ff;
+ I387.fip = oldeip;
+ *(unsigned short *) &I387.fcs = (u_short) info->tf_cs;
+ *(1+(unsigned short *) &I387.fcs) = code;
+ info->tf_eip += 2;
+ switch (code) {
+ case 0x1d0: /* fnop */
+ return(0);
+ case 0x1d1: case 0x1d2: case 0x1d3:
+ case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7:
+ math_abort(info,SIGILL);
+ case 0x1e0: /* fchs */
+ ST(0).exponent ^= 0x8000;
+ return(0);
+ case 0x1e1: /* fabs */
+ ST(0).exponent &= 0x7fff;
+ return(0);
+ case 0x1e2: case 0x1e3:
+ math_abort(info,SIGILL);
+ case 0x1e4: /* fxtract */
+ ftst(PST(0)); /* ?????? */
+ return(0);
+ case 0x1e5: /* fxam */
+ printf("fxam not implemented\n\r");
+ math_abort(info,SIGILL);
+ case 0x1e6: case 0x1e7:
+ math_abort(info,SIGILL);
+ case 0x1e8: /* fld1 */
+ fpush();
+ ST(0) = CONST1;
+ return(0);
+ case 0x1e9: /* fld2t */
+ fpush();
+ ST(0) = CONSTL2T;
+ return(0);
+ case 0x1ea: /* fld2e */
+ fpush();
+ ST(0) = CONSTL2E;
+ return(0);
+ case 0x1eb: /* fldpi */
+ fpush();
+ ST(0) = CONSTPI;
+ return(0);
+ case 0x1ec: /* fldlg2 */
+ fpush();
+ ST(0) = CONSTLG2;
+ return(0);
+ case 0x1ed: /* fldln2 */
+ fpush();
+ ST(0) = CONSTLN2;
+ return(0);
+ case 0x1ee: /* fldz */
+ fpush();
+ ST(0) = CONSTZ;
+ return(0);
+ case 0x1ef:
+ math_abort(info,SIGILL);
+ case 0x1f0: case 0x1f1: case 0x1f2: case 0x1f3:
+ case 0x1f4: case 0x1f5: case 0x1f6: case 0x1f7:
+ case 0x1f8: case 0x1f9: case 0x1fa: case 0x1fb:
+ case 0x1fe: case 0x1ff:
+ uprintf(
+ "math_emulate: instruction %04x not implemented\n",
+ code + 0xd800);
+ math_abort(info,SIGILL);
+ case 0x1fc: /* frndint */
+ frndint(PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0x1fd: /* fscale */
+ /* incomplete and totally inadequate -wfj */
+ Fscale(PST(0), PST(1), &tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0); /* 19 Sep 92*/
+ case 0x2e9: /* ????? */
+/* if this should be a fucomp ST(0),ST(1) , it must be a 0x3e9 ATS */
+ fucom(PST(1),PST(0));
+ fpop(); fpop();
+ return(0);
+ case 0x3d0: case 0x3d1: /* fist ?? */
+ return(0);
+ case 0x3e2: /* fclex */
+ I387.swd &= 0x7f00;
+ return(0);
+ case 0x3e3: /* fninit */
+ I387.cwd = 0x037f;
+ I387.swd = 0x0000;
+ I387.twd = 0x0000;
+ return(0);
+ case 0x3e4:
+ return(0);
+ case 0x6d9: /* fcompp */
+ fcom(PST(1),PST(0));
+ fpop(); fpop();
+ return(0);
+ case 0x7e0: /* fstsw ax */
+ *(short *) &info->tf_eax = I387.swd;
+ return(0);
+ }
+ switch (code >> 3) {
+ case 0x18: /* fadd */
+ fadd(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0x19: /* fmul */
+ fmul(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0x1a: /* fcom */
+ fcom(PST(code & 7),PST(0));
+ return(0);
+ case 0x1b: /* fcomp */
+ fcom(PST(code & 7),PST(0));
+ fpop();
+ return(0);
+ case 0x1c: /* fsubr */
+ real_to_real(&ST(code & 7),&tmp);
+ tmp.exponent ^= 0x8000;
+ fadd(PST(0),&tmp,&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0x1d: /* fsub */
+ ST(0).exponent ^= 0x8000;
+ fadd(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0x1e: /* fdivr */
+ fdiv(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0x1f: /* fdiv */
+ fdiv(PST(code & 7),PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0x38: /* fld */
+ fpush();
+ ST(0) = ST((code & 7)+1); /* why plus 1 ????? ATS */
+ return(0);
+ case 0x39: /* fxch */
+ fxchg(&ST(0),&ST(code & 7));
+ return(0);
+ case 0x3b: /* ??? ??? wrong ???? ATS */
+ ST(code & 7) = ST(0);
+ fpop();
+ return(0);
+ case 0x98: /* fadd */
+ fadd(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ return(0);
+ case 0x99: /* fmul */
+ fmul(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ return(0);
+ case 0x9a: /* ???? , my manual don't list a direction bit
+for fcom , ??? ATS */
+ fcom(PST(code & 7),PST(0));
+ return(0);
+ case 0x9b: /* same as above , ATS */
+ fcom(PST(code & 7),PST(0));
+ fpop();
+ return(0);
+ case 0x9c: /* fsubr */
+ ST(code & 7).exponent ^= 0x8000;
+ fadd(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ return(0);
+ case 0x9d: /* fsub */
+ real_to_real(&ST(0),&tmp);
+ tmp.exponent ^= 0x8000;
+ fadd(PST(code & 7),&tmp,&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ return(0);
+ case 0x9e: /* fdivr */
+ fdiv(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ return(0);
+ case 0x9f: /* fdiv */
+ fdiv(PST(code & 7),PST(0),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ return(0);
+ case 0xb8: /* ffree */
+ printf("ffree not implemented\n\r");
+ math_abort(info,SIGILL);
+ case 0xb9: /* fstp ???? where is the pop ? ATS */
+ fxchg(&ST(0),&ST(code & 7));
+ return(0);
+ case 0xba: /* fst */
+ ST(code & 7) = ST(0);
+ return(0);
+ case 0xbb: /* ????? encoding of fstp to mem ? ATS */
+ ST(code & 7) = ST(0);
+ fpop();
+ return(0);
+ case 0xbc: /* fucom */
+ fucom(PST(code & 7),PST(0));
+ return(0);
+ case 0xbd: /* fucomp */
+ fucom(PST(code & 7),PST(0));
+ fpop();
+ return(0);
+ case 0xd8: /* faddp */
+ fadd(PST(code & 7),PST(0),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ fpop();
+ return(0);
+ case 0xd9: /* fmulp */
+ fmul(PST(code & 7),PST(0),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ fpop();
+ return(0);
+ case 0xda: /* ??? encoding of ficom with 16 bit mem ? ATS */
+ fcom(PST(code & 7),PST(0));
+ fpop();
+ return(0);
+ case 0xdc: /* fsubrp */
+ ST(code & 7).exponent ^= 0x8000;
+ fadd(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ fpop();
+ return(0);
+ case 0xdd: /* fsubp */
+ real_to_real(&ST(0),&tmp);
+ tmp.exponent ^= 0x8000;
+ fadd(PST(code & 7),&tmp,&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ fpop();
+ return(0);
+ case 0xde: /* fdivrp */
+ fdiv(PST(0),PST(code & 7),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ fpop();
+ return(0);
+ case 0xdf: /* fdivp */
+ fdiv(PST(code & 7),PST(0),&tmp);
+ real_to_real(&tmp,&ST(code & 7));
+ fpop();
+ return(0);
+ case 0xf8: /* fild 16-bit mem ???? ATS */
+ printf("ffree not implemented\n\r");
+ math_abort(info,SIGILL);
+ fpop();
+ return(0);
+ case 0xf9: /* ????? ATS */
+ fxchg(&ST(0),&ST(code & 7));
+ return(0);
+ case 0xfa: /* fist 16-bit mem ? ATS */
+ case 0xfb: /* fistp 16-bit mem ? ATS */
+ ST(code & 7) = ST(0);
+ fpop();
+ return(0);
+ }
+ switch ((code>>3) & 0xe7) {
+ case 0x22:
+ put_short_real(PST(0),info,code);
+ return(0);
+ case 0x23:
+ put_short_real(PST(0),info,code);
+ fpop();
+ return(0);
+ case 0x24:
+ address = ea(info,code);
+ for (code = 0 ; code < 7 ; code++) {
+ ((long *) & I387)[code] =
+ get_fs_long((unsigned long *) address);
+ address += 4;
+ }
+ return(0);
+ case 0x25:
+ address = ea(info,code);
+ *(unsigned short *) &I387.cwd =
+ get_fs_word((unsigned short *) address);
+ return(0);
+ case 0x26:
+ address = ea(info,code);
+ /*verify_area(address,28);*/
+ for (code = 0 ; code < 7 ; code++) {
+ put_fs_long( ((long *) & I387)[code],
+ (unsigned long *) address);
+ address += 4;
+ }
+ return(0);
+ case 0x27:
+ address = ea(info,code);
+ /*verify_area(address,2);*/
+ put_fs_word(I387.cwd,(short *) address);
+ return(0);
+ case 0x62:
+ put_long_int(PST(0),info,code);
+ return(0);
+ case 0x63:
+ put_long_int(PST(0),info,code);
+ fpop();
+ return(0);
+ case 0x65:
+ fpush();
+ get_temp_real(&tmp,info,code);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0x67:
+ put_temp_real(PST(0),info,code);
+ fpop();
+ return(0);
+ case 0xa2:
+ put_long_real(PST(0),info,code);
+ return(0);
+ case 0xa3:
+ put_long_real(PST(0),info,code);
+ fpop();
+ return(0);
+ case 0xa4:
+ address = ea(info,code);
+ for (code = 0 ; code < 27 ; code++) {
+ ((long *) & I387)[code] =
+ get_fs_long((unsigned long *) address);
+ address += 4;
+ }
+ return(0);
+ case 0xa6:
+ address = ea(info,code);
+ /*verify_area(address,108);*/
+ for (code = 0 ; code < 27 ; code++) {
+ put_fs_long( ((long *) & I387)[code],
+ (unsigned long *) address);
+ address += 4;
+ }
+ I387.cwd = 0x037f;
+ I387.swd = 0x0000;
+ I387.twd = 0x0000;
+ return(0);
+ case 0xa7:
+ address = ea(info,code);
+ /*verify_area(address,2);*/
+ put_fs_word(I387.swd,(short *) address);
+ return(0);
+ case 0xe2:
+ put_short_int(PST(0),info,code);
+ return(0);
+ case 0xe3:
+ put_short_int(PST(0),info,code);
+ fpop();
+ return(0);
+ case 0xe4:
+ fpush();
+ get_BCD(&tmp,info,code);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0xe5:
+ fpush();
+ get_longlong_int(&tmp,info,code);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 0xe6:
+ put_BCD(PST(0),info,code);
+ fpop();
+ return(0);
+ case 0xe7:
+ put_longlong_int(PST(0),info,code);
+ fpop();
+ return(0);
+ }
+ switch (code >> 9) {
+ case 0:
+ get_short_real(&tmp,info,code);
+ break;
+ case 1:
+ get_long_int(&tmp,info,code);
+ break;
+ case 2:
+ get_long_real(&tmp,info,code);
+ break;
+ case 4:
+ get_short_int(&tmp,info,code);
+ }
+ switch ((code>>3) & 0x27) {
+ case 0:
+ fadd(&tmp,PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 1:
+ fmul(&tmp,PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 2:
+ fcom(&tmp,PST(0));
+ return(0);
+ case 3:
+ fcom(&tmp,PST(0));
+ fpop();
+ return(0);
+ case 4:
+ tmp.exponent ^= 0x8000;
+ fadd(&tmp,PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 5:
+ ST(0).exponent ^= 0x8000;
+ fadd(&tmp,PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 6:
+ fdiv(PST(0),&tmp,&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ case 7:
+ fdiv(&tmp,PST(0),&tmp);
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ }
+ if ((code & 0x138) == 0x100) {
+ fpush();
+ real_to_real(&tmp,&ST(0));
+ return(0);
+ }
+ printf("Unknown math-insns: %04x:%08x %04x\n\r",(u_short)info->tf_cs,
+ info->tf_eip,code);
+ math_abort(info,SIGFPE);
+}
+
+static void fpop(void)
+{
+ unsigned long tmp;
+
+ tmp = I387.swd & 0xffffc7ffUL;
+ I387.swd += 0x00000800;
+ I387.swd &= 0x00003800;
+ I387.swd |= tmp;
+}
+
+static void fpush(void)
+{
+ unsigned long tmp;
+
+ tmp = I387.swd & 0xffffc7ffUL;
+ I387.swd += 0x00003800;
+ I387.swd &= 0x00003800;
+ I387.swd |= tmp;
+}
+
+static void fxchg(temp_real_unaligned * a, temp_real_unaligned * b)
+{
+ temp_real_unaligned c;
+
+ c = *a;
+ *a = *b;
+ *b = c;
+}
+
+static temp_real_unaligned * __st(int i)
+{
+ i += I387.swd >> 11;
+ i &= 7;
+ return (temp_real_unaligned *) (i*10 + (char *)(I387.st_space));
+}
+
+/*
+ * linux/kernel/math/ea.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * Calculate the effective address.
+ */
+
+
+static int __regoffset[] = {
+ tEAX, tECX, tEDX, tEBX, tESP, tEBP, tESI, tEDI
+};
+
+#define REG(x) (curproc->p_regs[__regoffset[(x)]])
+
+static char * sib(struct trapframe * info, int mod)
+{
+ unsigned char ss,index,base;
+ long offset = 0;
+
+ base = get_fs_byte((char *) info->tf_eip);
+ info->tf_eip++;
+ ss = base >> 6;
+ index = (base >> 3) & 7;
+ base &= 7;
+ if (index == 4)
+ offset = 0;
+ else
+ offset = REG(index);
+ offset <<= ss;
+ if (mod || base != 5)
+ offset += REG(base);
+ if (mod == 1) {
+ offset += (signed char) get_fs_byte((char *) info->tf_eip);
+ info->tf_eip++;
+ } else if (mod == 2 || base == 5) {
+ offset += (signed) get_fs_long((unsigned long *) info->tf_eip);
+ info->tf_eip += 4;
+ }
+ I387.foo = offset;
+ I387.fos = 0x17;
+ return (char *) offset;
+}
+
+char * ea(struct trapframe * info, unsigned short code)
+{
+ unsigned char mod,rm;
+ long * tmp;
+ int offset = 0;
+
+ mod = (code >> 6) & 3;
+ rm = code & 7;
+ if (rm == 4 && mod != 3)
+ return sib(info,mod);
+ if (rm == 5 && !mod) {
+ offset = get_fs_long((unsigned long *) info->tf_eip);
+ info->tf_eip += 4;
+ I387.foo = offset;
+ I387.fos = 0x17;
+ return (char *) offset;
+ }
+ tmp = (long *) &REG(rm);
+ switch (mod) {
+ case 0: offset = 0; break;
+ case 1:
+ offset = (signed char) get_fs_byte((char *) info->tf_eip);
+ info->tf_eip++;
+ break;
+ case 2:
+ offset = (signed) get_fs_long((unsigned long *) info->tf_eip);
+ info->tf_eip += 4;
+ break;
+#ifdef notyet
+ case 3:
+ math_abort(info,1<<(SIGILL-1));
+#endif
+ }
+ I387.foo = offset;
+ I387.fos = 0x17;
+ return offset + (char *) *tmp;
+}
+/*
+ * linux/kernel/math/get_put.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * This file handles all accesses to user memory: getting and putting
+ * ints/reals/BCD etc. This is the only part that concerns itself with
+ * other than temporary real format. All other cals are strictly temp_real.
+ */
+
+void get_short_real(temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+ short_real sr;
+
+ addr = ea(info,code);
+ sr = get_fs_long((unsigned long *) addr);
+ short_to_temp(&sr,tmp);
+}
+
+void get_long_real(temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+ long_real lr;
+
+ addr = ea(info,code);
+ lr.a = get_fs_long((unsigned long *) addr);
+ lr.b = get_fs_long(1 + (unsigned long *) addr);
+ long_to_temp(&lr,tmp);
+}
+
+void get_temp_real(temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+
+ addr = ea(info,code);
+ tmp->a = get_fs_long((unsigned long *) addr);
+ tmp->b = get_fs_long(1 + (unsigned long *) addr);
+ tmp->exponent = get_fs_word(4 + (unsigned short *) addr);
+}
+
+void get_short_int(temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+ temp_int ti;
+
+ addr = ea(info,code);
+ ti.a = (signed short) get_fs_word((unsigned short *) addr);
+ ti.b = 0;
+ if (ti.sign = (ti.a < 0))
+ ti.a = - ti.a;
+ int_to_real(&ti,tmp);
+}
+
+void get_long_int(temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+ temp_int ti;
+
+ addr = ea(info,code);
+ ti.a = get_fs_long((unsigned long *) addr);
+ ti.b = 0;
+ if (ti.sign = (ti.a < 0))
+ ti.a = - ti.a;
+ int_to_real(&ti,tmp);
+}
+
+void get_longlong_int(temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+ temp_int ti;
+
+ addr = ea(info,code);
+ ti.a = get_fs_long((unsigned long *) addr);
+ ti.b = get_fs_long(1 + (unsigned long *) addr);
+ if (ti.sign = (ti.b < 0))
+ __asm__("notl %0 ; notl %1\n\t"
+ "addl $1,%0 ; adcl $0,%1"
+ :"=r" (ti.a),"=r" (ti.b)
+ :"0" (ti.a),"1" (ti.b));
+ int_to_real(&ti,tmp);
+}
+
+#define MUL10(low,high) \
+__asm__("addl %0,%0 ; adcl %1,%1\n\t" \
+"movl %0,%%ecx ; movl %1,%%ebx\n\t" \
+"addl %0,%0 ; adcl %1,%1\n\t" \
+"addl %0,%0 ; adcl %1,%1\n\t" \
+"addl %%ecx,%0 ; adcl %%ebx,%1" \
+:"=a" (low),"=d" (high) \
+:"0" (low),"1" (high):"cx","bx")
+
+#define ADD64(val,low,high) \
+__asm__("addl %4,%0 ; adcl $0,%1":"=r" (low),"=r" (high) \
+:"0" (low),"1" (high),"r" ((unsigned long) (val)))
+
+void get_BCD(temp_real * tmp, struct trapframe * info, unsigned short code)
+{
+ int k;
+ char * addr;
+ temp_int i;
+ unsigned char c;
+
+ addr = ea(info,code);
+ addr += 9;
+ i.sign = 0x80 & get_fs_byte(addr--);
+ i.a = i.b = 0;
+ for (k = 0; k < 9; k++) {
+ c = get_fs_byte(addr--);
+ MUL10(i.a, i.b);
+ ADD64((c>>4), i.a, i.b);
+ MUL10(i.a, i.b);
+ ADD64((c&0xf), i.a, i.b);
+ }
+ int_to_real(&i,tmp);
+}
+
+void put_short_real(const temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+ short_real sr;
+
+ addr = ea(info,code);
+ /*verify_area(addr,4);*/
+ temp_to_short(tmp,&sr);
+ put_fs_long(sr,(unsigned long *) addr);
+}
+
+void put_long_real(const temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+ long_real lr;
+
+ addr = ea(info,code);
+ /*verify_area(addr,8);*/
+ temp_to_long(tmp,&lr);
+ put_fs_long(lr.a, (unsigned long *) addr);
+ put_fs_long(lr.b, 1 + (unsigned long *) addr);
+}
+
+void put_temp_real(const temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+
+ addr = ea(info,code);
+ /*verify_area(addr,10);*/
+ put_fs_long(tmp->a, (unsigned long *) addr);
+ put_fs_long(tmp->b, 1 + (unsigned long *) addr);
+ put_fs_word(tmp->exponent, 4 + (short *) addr);
+}
+
+void put_short_int(const temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+ temp_int ti;
+
+ addr = ea(info,code);
+ real_to_int(tmp,&ti);
+ /*verify_area(addr,2);*/
+ if (ti.sign)
+ ti.a = -ti.a;
+ put_fs_word(ti.a,(short *) addr);
+}
+
+void put_long_int(const temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+ temp_int ti;
+
+ addr = ea(info,code);
+ real_to_int(tmp,&ti);
+ /*verify_area(addr,4);*/
+ if (ti.sign)
+ ti.a = -ti.a;
+ put_fs_long(ti.a,(unsigned long *) addr);
+}
+
+void put_longlong_int(const temp_real * tmp,
+ struct trapframe * info, unsigned short code)
+{
+ char * addr;
+ temp_int ti;
+
+ addr = ea(info,code);
+ real_to_int(tmp,&ti);
+ /*verify_area(addr,8);*/
+ if (ti.sign)
+ __asm__("notl %0 ; notl %1\n\t"
+ "addl $1,%0 ; adcl $0,%1"
+ :"=r" (ti.a),"=r" (ti.b)
+ :"0" (ti.a),"1" (ti.b));
+ put_fs_long(ti.a,(unsigned long *) addr);
+ put_fs_long(ti.b,1 + (unsigned long *) addr);
+}
+
+#define DIV10(low,high,rem) \
+__asm__("divl %6 ; xchgl %1,%2 ; divl %6" \
+ :"=d" (rem),"=a" (low),"=r" (high) \
+ :"0" (0),"1" (high),"2" (low),"c" (10))
+
+void put_BCD(const temp_real * tmp,struct trapframe * info, unsigned short code)
+{
+ int k,rem;
+ char * addr;
+ temp_int i;
+ unsigned char c;
+
+ addr = ea(info,code);
+ /*verify_area(addr,10);*/
+ real_to_int(tmp,&i);
+ if (i.sign)
+ put_fs_byte(0x80, addr+9);
+ else
+ put_fs_byte(0, addr+9);
+ for (k = 0; k < 9; k++) {
+ DIV10(i.a,i.b,rem);
+ c = rem;
+ DIV10(i.a,i.b,rem);
+ c += rem<<4;
+ put_fs_byte(c,addr++);
+ }
+}
+
+/*
+ * linux/kernel/math/mul.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * temporary real multiplication routine.
+ */
+
+
+static void shift(int * c)
+{
+ __asm__("movl (%0),%%eax ; addl %%eax,(%0)\n\t"
+ "movl 4(%0),%%eax ; adcl %%eax,4(%0)\n\t"
+ "movl 8(%0),%%eax ; adcl %%eax,8(%0)\n\t"
+ "movl 12(%0),%%eax ; adcl %%eax,12(%0)"
+ ::"r" ((long) c):"ax");
+}
+
+static void mul64(const temp_real * a, const temp_real * b, int * c)
+{
+ __asm__("movl (%0),%%eax\n\t"
+ "mull (%1)\n\t"
+ "movl %%eax,(%2)\n\t"
+ "movl %%edx,4(%2)\n\t"
+ "movl 4(%0),%%eax\n\t"
+ "mull 4(%1)\n\t"
+ "movl %%eax,8(%2)\n\t"
+ "movl %%edx,12(%2)\n\t"
+ "movl (%0),%%eax\n\t"
+ "mull 4(%1)\n\t"
+ "addl %%eax,4(%2)\n\t"
+ "adcl %%edx,8(%2)\n\t"
+ "adcl $0,12(%2)\n\t"
+ "movl 4(%0),%%eax\n\t"
+ "mull (%1)\n\t"
+ "addl %%eax,4(%2)\n\t"
+ "adcl %%edx,8(%2)\n\t"
+ "adcl $0,12(%2)"
+ ::"S" ((long) a),"c" ((long) b),"D" ((long) c)
+ :"ax","dx");
+}
+
+void fmul(const temp_real * src1, const temp_real * src2, temp_real * result)
+{
+ int i,sign;
+ int tmp[4] = {0,0,0,0};
+
+ sign = (src1->exponent ^ src2->exponent) & 0x8000;
+ i = (src1->exponent & 0x7fff) + (src2->exponent & 0x7fff) - 16383 + 1;
+ if (i<0) {
+ result->exponent = sign;
+ result->a = result->b = 0;
+ return;
+ }
+ if (i>0x7fff) {
+ set_OE();
+ return;
+ }
+ mul64(src1,src2,tmp);
+ if (tmp[0] || tmp[1] || tmp[2] || tmp[3])
+ while (i && tmp[3] >= 0) {
+ i--;
+ shift(tmp);
+ }
+ else
+ i = 0;
+ result->exponent = i | sign;
+ result->a = tmp[2];
+ result->b = tmp[3];
+}
+
+/*
+ * linux/kernel/math/div.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * temporary real division routine.
+ */
+
+static void shift_left(int * c)
+{
+ __asm__ __volatile__("movl (%0),%%eax ; addl %%eax,(%0)\n\t"
+ "movl 4(%0),%%eax ; adcl %%eax,4(%0)\n\t"
+ "movl 8(%0),%%eax ; adcl %%eax,8(%0)\n\t"
+ "movl 12(%0),%%eax ; adcl %%eax,12(%0)"
+ ::"r" ((long) c):"ax");
+}
+
+static void shift_right(int * c)
+{
+ __asm__("shrl $1,12(%0) ; rcrl $1,8(%0) ; rcrl $1,4(%0) ; rcrl $1,(%0)"
+ ::"r" ((long) c));
+}
+
+static int try_sub(int * a, int * b)
+{
+ char ok;
+
+ __asm__ __volatile__("movl (%1),%%eax ; subl %%eax,(%2)\n\t"
+ "movl 4(%1),%%eax ; sbbl %%eax,4(%2)\n\t"
+ "movl 8(%1),%%eax ; sbbl %%eax,8(%2)\n\t"
+ "movl 12(%1),%%eax ; sbbl %%eax,12(%2)\n\t"
+ "setae %%al":"=a" (ok):"c" ((long) a),"d" ((long) b));
+ return ok;
+}
+
+static void div64(int * a, int * b, int * c)
+{
+ int tmp[4];
+ int i;
+ unsigned int mask = 0;
+
+ c += 4;
+ for (i = 0 ; i<64 ; i++) {
+ if (!(mask >>= 1)) {
+ c--;
+ mask = 0x80000000UL;
+ }
+ tmp[0] = a[0]; tmp[1] = a[1];
+ tmp[2] = a[2]; tmp[3] = a[3];
+ if (try_sub(b,tmp)) {
+ *c |= mask;
+ a[0] = tmp[0]; a[1] = tmp[1];
+ a[2] = tmp[2]; a[3] = tmp[3];
+ }
+ shift_right(b);
+ }
+}
+
+void fdiv(const temp_real * src1, const temp_real * src2, temp_real * result)
+{
+ int i,sign;
+ int a[4],b[4],tmp[4] = {0,0,0,0};
+
+ sign = (src1->exponent ^ src2->exponent) & 0x8000;
+ if (!(src2->a || src2->b)) {
+ set_ZE();
+ return;
+ }
+ i = (src1->exponent & 0x7fff) - (src2->exponent & 0x7fff) + 16383;
+ if (i<0) {
+ set_UE();
+ result->exponent = sign;
+ result->a = result->b = 0;
+ return;
+ }
+ a[0] = a[1] = 0;
+ a[2] = src1->a;
+ a[3] = src1->b;
+ b[0] = b[1] = 0;
+ b[2] = src2->a;
+ b[3] = src2->b;
+ while (b[3] >= 0) {
+ i++;
+ shift_left(b);
+ }
+ div64(a,b,tmp);
+ if (tmp[0] || tmp[1] || tmp[2] || tmp[3]) {
+ while (i && tmp[3] >= 0) {
+ i--;
+ shift_left(tmp);
+ }
+ if (tmp[3] >= 0)
+ set_DE();
+ } else
+ i = 0;
+ if (i>0x7fff) {
+ set_OE();
+ return;
+ }
+ if (tmp[0] || tmp[1])
+ set_PE();
+ result->exponent = i | sign;
+ result->a = tmp[2];
+ result->b = tmp[3];
+}
+
+/*
+ * linux/kernel/math/add.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * temporary real addition routine.
+ *
+ * NOTE! These aren't exact: they are only 62 bits wide, and don't do
+ * correct rounding. Fast hack. The reason is that we shift right the
+ * values by two, in order not to have overflow (1 bit), and to be able
+ * to move the sign into the mantissa (1 bit). Much simpler algorithms,
+ * and 62 bits (61 really - no rounding) accuracy is usually enough. The
+ * only time you should notice anything weird is when adding 64-bit
+ * integers together. When using doubles (52 bits accuracy), the
+ * 61-bit accuracy never shows at all.
+ */
+
+#define NEGINT(a) \
+__asm__("notl %0 ; notl %1 ; addl $1,%0 ; adcl $0,%1" \
+ :"=r" (a->a),"=r" (a->b) \
+ :"0" (a->a),"1" (a->b))
+
+static void signify(temp_real * a)
+{
+ a->exponent += 2;
+ __asm__("shrdl $2,%1,%0 ; shrl $2,%1"
+ :"=r" (a->a),"=r" (a->b)
+ :"0" (a->a),"1" (a->b));
+ if (a->exponent < 0)
+ NEGINT(a);
+ a->exponent &= 0x7fff;
+}
+
+static void unsignify(temp_real * a)
+{
+ if (!(a->a || a->b)) {
+ a->exponent = 0;
+ return;
+ }
+ a->exponent &= 0x7fff;
+ if (a->b < 0) {
+ NEGINT(a);
+ a->exponent |= 0x8000;
+ }
+ while (a->b >= 0) {
+ a->exponent--;
+ __asm__("addl %0,%0 ; adcl %1,%1"
+ :"=r" (a->a),"=r" (a->b)
+ :"0" (a->a),"1" (a->b));
+ }
+}
+
+void fadd(const temp_real * src1, const temp_real * src2, temp_real * result)
+{
+ temp_real a,b;
+ int x1,x2,shift;
+
+ x1 = src1->exponent & 0x7fff;
+ x2 = src2->exponent & 0x7fff;
+ if (x1 > x2) {
+ a = *src1;
+ b = *src2;
+ shift = x1-x2;
+ } else {
+ a = *src2;
+ b = *src1;
+ shift = x2-x1;
+ }
+ if (shift >= 64) {
+ *result = a;
+ return;
+ }
+ if (shift >= 32) {
+ b.a = b.b;
+ b.b = 0;
+ shift -= 32;
+ }
+ __asm__("shrdl %4,%1,%0 ; shrl %4,%1"
+ :"=r" (b.a),"=r" (b.b)
+ :"0" (b.a),"1" (b.b),"c" ((char) shift));
+ signify(&a);
+ signify(&b);
+ __asm__("addl %4,%0 ; adcl %5,%1"
+ :"=r" (a.a),"=r" (a.b)
+ :"0" (a.a),"1" (a.b),"g" (b.a),"g" (b.b));
+ unsignify(&a);
+ *result = a;
+}
+
+/*
+ * linux/kernel/math/compare.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+/*
+ * temporary real comparison routines
+ */
+
+
+#define clear_Cx() (I387.swd &= ~0x4500)
+
+static void normalize(temp_real * a)
+{
+ int i = a->exponent & 0x7fff;
+ int sign = a->exponent & 0x8000;
+
+ if (!(a->a || a->b)) {
+ a->exponent = 0;
+ return;
+ }
+ while (i && a->b >= 0) {
+ i--;
+ __asm__("addl %0,%0 ; adcl %1,%1"
+ :"=r" (a->a),"=r" (a->b)
+ :"0" (a->a),"1" (a->b));
+ }
+ a->exponent = i | sign;
+}
+
+void ftst(const temp_real * a)
+{
+ temp_real b;
+
+ clear_Cx();
+ b = *a;
+ normalize(&b);
+ if (b.a || b.b || b.exponent) {
+ if (b.exponent < 0)
+ set_C0();
+ } else
+ set_C3();
+}
+
+void fcom(const temp_real * src1, const temp_real * src2)
+{
+ temp_real a;
+
+ a = *src1;
+ a.exponent ^= 0x8000;
+ fadd(&a,src2,&a);
+ ftst(&a);
+}
+
+void fucom(const temp_real * src1, const temp_real * src2)
+{
+ fcom(src1,src2);
+}
+
+/*
+ * linux/kernel/math/convert.c
+ *
+ * (C) 1991 Linus Torvalds
+ */
+
+
+/*
+ * NOTE!!! There is some "non-obvious" optimisations in the temp_to_long
+ * and temp_to_short conversion routines: don't touch them if you don't
+ * know what's going on. They are the adding of one in the rounding: the
+ * overflow bit is also used for adding one into the exponent. Thus it
+ * looks like the overflow would be incorrectly handled, but due to the
+ * way the IEEE numbers work, things are correct.
+ *
+ * There is no checking for total overflow in the conversions, though (ie
+ * if the temp-real number simply won't fit in a short- or long-real.)
+ */
+
+void short_to_temp(const short_real * a, temp_real * b)
+{
+ if (!(*a & 0x7fffffff)) {
+ b->a = b->b = 0;
+ if (*a)
+ b->exponent = 0x8000;
+ else
+ b->exponent = 0;
+ return;
+ }
+ b->exponent = ((*a>>23) & 0xff)-127+16383;
+ if (*a<0)
+ b->exponent |= 0x8000;
+ b->b = (*a<<8) | 0x80000000UL;
+ b->a = 0;
+}
+
+void long_to_temp(const long_real * a, temp_real * b)
+{
+ if (!a->a && !(a->b & 0x7fffffff)) {
+ b->a = b->b = 0;
+ if (a->b)
+ b->exponent = 0x8000;
+ else
+ b->exponent = 0;
+ return;
+ }
+ b->exponent = ((a->b >> 20) & 0x7ff)-1023+16383;
+ if (a->b<0)
+ b->exponent |= 0x8000;
+ b->b = 0x80000000UL | (a->b<<11) | (((unsigned long)a->a)>>21);
+ b->a = a->a<<11;
+}
+
+void temp_to_short(const temp_real * a, short_real * b)
+{
+ if (!(a->exponent & 0x7fff)) {
+ *b = (a->exponent)?0x80000000UL:0;
+ return;
+ }
+ *b = ((((long) a->exponent)-16383+127) << 23) & 0x7f800000;
+ if (a->exponent < 0)
+ *b |= 0x80000000UL;
+ *b |= (a->b >> 8) & 0x007fffff;
+ switch ((int)ROUNDING) {
+ case ROUND_NEAREST:
+ if ((a->b & 0xff) > 0x80)
+ ++*b;
+ break;
+ case ROUND_DOWN:
+ if ((a->exponent & 0x8000) && (a->b & 0xff))
+ ++*b;
+ break;
+ case ROUND_UP:
+ if (!(a->exponent & 0x8000) && (a->b & 0xff))
+ ++*b;
+ break;
+ }
+}
+
+void temp_to_long(const temp_real * a, long_real * b)
+{
+ if (!(a->exponent & 0x7fff)) {
+ b->a = 0;
+ b->b = (a->exponent)?0x80000000UL:0;
+ return;
+ }
+ b->b = (((0x7fff & (long) a->exponent)-16383+1023) << 20) & 0x7ff00000;
+ if (a->exponent < 0)
+ b->b |= 0x80000000UL;
+ b->b |= (a->b >> 11) & 0x000fffff;
+ b->a = a->b << 21;
+ b->a |= (a->a >> 11) & 0x001fffff;
+ switch ((int)ROUNDING) {
+ case ROUND_NEAREST:
+ if ((a->a & 0x7ff) > 0x400)
+ __asm__("addl $1,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ break;
+ case ROUND_DOWN:
+ if ((a->exponent & 0x8000) && (a->b & 0xff))
+ __asm__("addl $1,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ break;
+ case ROUND_UP:
+ if (!(a->exponent & 0x8000) && (a->b & 0xff))
+ __asm__("addl $1,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ break;
+ }
+}
+
+void frndint(const temp_real * a, temp_real * b)
+{
+ int shift = 16383 + 63 - (a->exponent & 0x7fff);
+ unsigned long underflow;
+
+ if ((shift < 0) || (shift == 16383+63)) {
+ *b = *a;
+ return;
+ }
+ b->a = b->b = underflow = 0;
+ b->exponent = a->exponent;
+ if (shift < 32) {
+ b->b = a->b; b->a = a->a;
+ } else if (shift < 64) {
+ b->a = a->b; underflow = a->a;
+ shift -= 32;
+ b->exponent += 32;
+ } else if (shift < 96) {
+ underflow = a->b;
+ shift -= 64;
+ b->exponent += 64;
+ } else {
+ underflow = 1;
+ shift = 0;
+ }
+ b->exponent += shift;
+ __asm__("shrdl %2,%1,%0"
+ :"=r" (underflow),"=r" (b->a)
+ :"c" ((char) shift),"0" (underflow),"1" (b->a));
+ __asm__("shrdl %2,%1,%0"
+ :"=r" (b->a),"=r" (b->b)
+ :"c" ((char) shift),"0" (b->a),"1" (b->b));
+ __asm__("shrl %1,%0"
+ :"=r" (b->b)
+ :"c" ((char) shift),"0" (b->b));
+ switch ((int)ROUNDING) {
+ case ROUND_NEAREST:
+ __asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b)
+ ,"r" (0x7fffffff + (b->a & 1))
+ ,"m" (*&underflow));
+ break;
+ case ROUND_UP:
+ if ((b->exponent >= 0) && underflow)
+ __asm__("addl $1,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ break;
+ case ROUND_DOWN:
+ if ((b->exponent < 0) && underflow)
+ __asm__("addl $1,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ break;
+ }
+ if (b->a || b->b)
+ while (b->b >= 0) {
+ b->exponent--;
+ __asm__("addl %0,%0 ; adcl %1,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ }
+ else
+ b->exponent = 0;
+}
+
+void Fscale(const temp_real *a, const temp_real *b, temp_real *c)
+{
+ temp_int ti;
+
+ *c = *a;
+ if(!c->a && !c->b) { /* 19 Sep 92*/
+ c->exponent = 0;
+ return;
+ }
+ real_to_int(b, &ti);
+ if(ti.sign)
+ c->exponent -= ti.a;
+ else
+ c->exponent += ti.a;
+}
+
+void real_to_int(const temp_real * a, temp_int * b)
+{
+ int shift = 16383 + 63 - (a->exponent & 0x7fff);
+ unsigned long underflow;
+
+ b->a = b->b = underflow = 0;
+ b->sign = (a->exponent < 0);
+ if (shift < 0) {
+ set_OE();
+ return;
+ }
+ if (shift < 32) {
+ b->b = a->b; b->a = a->a;
+ } else if (shift < 64) {
+ b->a = a->b; underflow = a->a;
+ shift -= 32;
+ } else if (shift < 96) {
+ underflow = a->b;
+ shift -= 64;
+ } else {
+ underflow = 1;
+ shift = 0;
+ }
+ __asm__("shrdl %2,%1,%0"
+ :"=r" (underflow),"=r" (b->a)
+ :"c" ((char) shift),"0" (underflow),"1" (b->a));
+ __asm__("shrdl %2,%1,%0"
+ :"=r" (b->a),"=r" (b->b)
+ :"c" ((char) shift),"0" (b->a),"1" (b->b));
+ __asm__("shrl %1,%0"
+ :"=r" (b->b)
+ :"c" ((char) shift),"0" (b->b));
+ switch ((int)ROUNDING) {
+ case ROUND_NEAREST:
+ __asm__("addl %4,%5 ; adcl $0,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b)
+ ,"r" (0x7fffffff + (b->a & 1))
+ ,"m" (*&underflow));
+ break;
+ case ROUND_UP:
+ if (!b->sign && underflow)
+ __asm__("addl $1,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ break;
+ case ROUND_DOWN:
+ if (b->sign && underflow)
+ __asm__("addl $1,%0 ; adcl $0,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ break;
+ }
+}
+
+void int_to_real(const temp_int * a, temp_real * b)
+{
+ b->a = a->a;
+ b->b = a->b;
+ if (b->a || b->b)
+ b->exponent = 16383 + 63 + (a->sign? 0x8000:0);
+ else {
+ b->exponent = 0;
+ return;
+ }
+ while (b->b >= 0) {
+ b->exponent--;
+ __asm__("addl %0,%0 ; adcl %1,%1"
+ :"=r" (b->a),"=r" (b->b)
+ :"0" (b->a),"1" (b->b));
+ }
+}
diff --git a/sys/i386/i386/mem.c b/sys/i386/i386/mem.c
new file mode 100644
index 0000000..c3899a1
--- /dev/null
+++ b/sys/i386/i386/mem.c
@@ -0,0 +1,260 @@
+/*-
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department, and code derived from software contributed to
+ * Berkeley by William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Utah $Hdr: mem.c 1.13 89/10/08$
+ * from: @(#)mem.c 7.2 (Berkeley) 5/9/91
+ * $Id: mem.c,v 1.6 1993/12/19 00:50:06 wollman Exp $
+ */
+
+/*
+ * Memory special file
+ */
+
+#include "param.h"
+#include "conf.h"
+#include "buf.h"
+#include "systm.h"
+#include "uio.h"
+#include "malloc.h"
+#include "proc.h"
+
+#include "machine/cpu.h"
+#include "machine/psl.h"
+
+#include "vm/vm_param.h"
+#include "vm/lock.h"
+#include "vm/vm_statistics.h"
+#include "vm/vm_prot.h"
+#include "vm/pmap.h"
+
+extern char *vmmap; /* poor name! */
+/*ARGSUSED*/
+int
+mmclose(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ struct trapframe *fp;
+
+ switch (minor(dev)) {
+ case 14:
+ fp = (struct trapframe *)curproc->p_regs;
+ fp->tf_eflags &= ~PSL_IOPL;
+ break;
+ default:
+ break;
+ }
+ return(0);
+}
+/*ARGSUSED*/
+int
+mmopen(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ struct trapframe *fp;
+
+ switch (minor(dev)) {
+ case 14:
+ fp = (struct trapframe *)curproc->p_regs;
+ fp->tf_eflags |= PSL_IOPL;
+ break;
+ default:
+ break;
+ }
+ return(0);
+}
+/*ARGSUSED*/
+int
+mmrw(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ register int o;
+ register u_int c, v;
+ register struct iovec *iov;
+ int error = 0;
+ caddr_t zbuf = NULL;
+
+ while (uio->uio_resid > 0 && error == 0) {
+ iov = uio->uio_iov;
+ if (iov->iov_len == 0) {
+ uio->uio_iov++;
+ uio->uio_iovcnt--;
+ if (uio->uio_iovcnt < 0)
+ panic("mmrw");
+ continue;
+ }
+ switch (minor(dev)) {
+
+/* minor device 0 is physical memory */
+ case 0:
+ v = uio->uio_offset;
+ pmap_enter(pmap_kernel(), (vm_offset_t)vmmap, v,
+ uio->uio_rw == UIO_READ ? VM_PROT_READ : VM_PROT_WRITE,
+ TRUE);
+ o = (int)uio->uio_offset & PGOFSET;
+ c = (u_int)(NBPG - ((int)iov->iov_base & PGOFSET));
+ c = MIN(c, (u_int)(NBPG - o));
+ c = MIN(c, (u_int)iov->iov_len);
+ error = uiomove((caddr_t)&vmmap[o], (int)c, uio);
+ pmap_remove(pmap_kernel(), (vm_offset_t)vmmap,
+ (vm_offset_t)&vmmap[NBPG]);
+ continue;
+
+/* minor device 1 is kernel memory */
+ case 1:
+ c = iov->iov_len;
+ if (!kernacc((caddr_t)uio->uio_offset, c,
+ uio->uio_rw == UIO_READ ? B_READ : B_WRITE))
+ return(EFAULT);
+ error = uiomove((caddr_t)uio->uio_offset, (int)c, uio);
+ continue;
+
+/* minor device 2 is EOF/RATHOLE */
+ case 2:
+ if (uio->uio_rw == UIO_READ)
+ return (0);
+ c = iov->iov_len;
+ break;
+
+/* minor device 12 (/dev/zero) is source of nulls on read, rathole on write */
+ case 12:
+ if (uio->uio_rw == UIO_WRITE) {
+ c = iov->iov_len;
+ break;
+ }
+ if (zbuf == NULL) {
+ zbuf = (caddr_t)
+ malloc(CLBYTES, M_TEMP, M_WAITOK);
+ bzero(zbuf, CLBYTES);
+ }
+ c = MIN(iov->iov_len, CLBYTES);
+ error = uiomove(zbuf, (int)c, uio);
+ continue;
+
+#ifdef notyet
+/* 386 I/O address space (/dev/ioport[bwl]) is a read/write access to seperate
+ i/o device address bus, different than memory bus. Semantics here are
+ very different than ordinary read/write, as if iov_len is a multiple
+ an implied string move from a single port will be done. Note that lseek
+ must be used to set the port number reliably. */
+ case 14:
+ if (iov->iov_len == 1) {
+ u_char tmp;
+ tmp = inb(uio->uio_offset);
+ error = uiomove (&tmp, iov->iov_len, uio);
+ } else {
+ if (!useracc((caddr_t)iov->iov_base,
+ iov->iov_len, uio->uio_rw))
+ return (EFAULT);
+ insb(uio->uio_offset, iov->iov_base,
+ iov->iov_len);
+ }
+ break;
+ case 15:
+ if (iov->iov_len == sizeof (short)) {
+ u_short tmp;
+ tmp = inw(uio->uio_offset);
+ error = uiomove (&tmp, iov->iov_len, uio);
+ } else {
+ if (!useracc((caddr_t)iov->iov_base,
+ iov->iov_len, uio->uio_rw))
+ return (EFAULT);
+ insw(uio->uio_offset, iov->iov_base,
+ iov->iov_len/ sizeof (short));
+ }
+ break;
+ case 16:
+ if (iov->iov_len == sizeof (long)) {
+ u_long tmp;
+ tmp = inl(uio->uio_offset);
+ error = uiomove (&tmp, iov->iov_len, uio);
+ } else {
+ if (!useracc((caddr_t)iov->iov_base,
+ iov->iov_len, uio->uio_rw))
+ return (EFAULT);
+ insl(uio->uio_offset, iov->iov_base,
+ iov->iov_len/ sizeof (long));
+ }
+ break;
+#endif
+
+ default:
+ return (ENXIO);
+ }
+ if (error)
+ break;
+ iov->iov_base += c;
+ iov->iov_len -= c;
+ uio->uio_offset += c;
+ uio->uio_resid -= c;
+ }
+ if (zbuf)
+ free(zbuf, M_TEMP);
+ return (error);
+}
+
+
+
+
+/*******************************************************\
+* allow user processes to MMAP some memory sections *
+* instead of going through read/write *
+\*******************************************************/
+int memmmap(dev_t dev, int offset, int nprot)
+{
+ switch (minor(dev))
+ {
+
+/* minor device 0 is physical memory */
+ case 0:
+ return i386_btop(offset);
+
+/* minor device 1 is kernel memory */
+ case 1:
+ return i386_btop(vtophys(offset));
+
+ default:
+ return -1;
+ }
+}
+
diff --git a/sys/i386/i386/microtime.s b/sys/i386/i386/microtime.s
new file mode 100644
index 0000000..3c4d86e
--- /dev/null
+++ b/sys/i386/i386/microtime.s
@@ -0,0 +1,137 @@
+/*-
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Steve McCanne's microtime code
+ * $Id: microtime.s,v 1.3 1994/04/02 07:00:27 davidg Exp $
+ */
+
+#include "machine/asmacros.h"
+#include "../isa/isa.h"
+#include "../isa/timerreg.h"
+
+/*
+ * Use a higher resolution version of microtime if HZ is not
+ * overridden (i.e. it is 100Hz).
+ */
+#ifndef HZ
+ENTRY(microtime)
+ pushl %edi # save registers
+ pushl %esi
+ pushl %ebx
+
+ movl $_time, %ebx # get timeval ptr
+ movl (%ebx), %edi # sec = time.tv_sec
+ movl 4(%ebx), %esi # usec = time.tv_usec
+
+ cli # disable interrupts
+
+ movl $(TIMER_SEL0|TIMER_LATCH), %eax
+ outb %al, $TIMER_MODE # latch timer 0's counter
+
+ xorl %ebx, %ebx # clear ebx
+ inb $TIMER_CNTR0, %al # Read counter value, LSB first
+ movb %al, %bl
+ inb $TIMER_CNTR0, %al
+ movb %al, %bh
+
+ # Now check for counter overflow. This is tricky because the
+ # timer chip doesn't let us atomically read the current counter
+ # value and the output state (i.e., overflow state). We have
+ # to read the ICU interrupt request register (IRR) to see if the
+ # overflow has occured. Because we lack atomicity, we use
+ # the (very accurate) heuristic that we only check for
+ # overflow if the value read is close to the interrupt period.
+ # E.g., if we just checked the IRR, we might read a non-overflowing
+ # value close to 0, experience overflow, then read this overflow
+ # from the IRR, and mistakenly add a correction to the "close
+ # to zero" value.
+ #
+ # We compare the counter value to heuristic constant 11890.
+ # If the counter value is less than this, we assume the counter
+ # didn't overflow between disabling interrupts above and latching
+ # the counter value. For example, we assume that the above 10 or so
+ # instructions take less than 11932 - 11890 = 42 microseconds to
+ # execute.
+ #
+ # Otherwise, the counter might have overflowed. We check for this
+ # condition by reading the interrupt request register out of the ICU.
+ # If it overflowed, we add in one clock period.
+ #
+ # The heuristic is "very accurate" because it works 100% if
+ # we're called from an ipl less than the clock. Otherwise,
+ # it might not work. Currently, only gettimeofday and bpf
+ # call microtime so it's not a problem.
+
+ movl _timer0_prescale, %eax # adjust value if timer is
+ addl _timer0_divisor, %eax # reprogrammed
+ addl $-11932, %eax
+ subl %eax, %ebx
+
+ cmpl $11890, %ebx # do we have a possible overflow condition
+ jle 1f
+
+ inb $IO_ICU1, %al # read IRR in ICU
+ testb $1, %al # is a timer interrupt pending?
+ je 1f
+ addl $-11932, %ebx # yes, subtract one clock period
+1:
+ sti # enable interrupts
+
+ movl $11932, %eax # subtract counter value from 11932 since
+ subl %ebx, %eax # it is a count-down value
+
+ movl %eax, %ebx # this really is a "imull $1000, %eax, %eax"
+ sall $10, %eax # instruction, but this saves us
+ sall $3, %ebx # 33/23 clocks on a 486/386 CPU
+ subl %ebx, %eax #
+ sall $1, %ebx # /sos
+ subl %ebx, %eax #
+
+ movl $0, %edx # zero extend eax into edx for div
+ movl $1193, %ecx
+ idivl %ecx # convert to usecs: mult by 1000/1193
+
+ addl %eax, %esi # add counter usecs to time.tv_usec
+ cmpl $1000000, %esi # carry in timeval?
+ jl 2f
+ subl $1000000, %esi # adjust usec
+ incl %edi # bump sec
+2:
+ movl 16(%esp), %ecx # load timeval pointer arg
+ movl %edi, (%ecx) # tvp->tv_sec = sec
+ movl %esi, 4(%ecx) # tvp->tv_usec = usec
+
+ popl %ebx # restore regs
+ popl %esi
+ popl %edi
+ ret
+#endif
diff --git a/sys/i386/i386/ns_cksum.c b/sys/i386/i386/ns_cksum.c
new file mode 100644
index 0000000..6b56172
--- /dev/null
+++ b/sys/i386/i386/ns_cksum.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 1982, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)ns_cksum.c 7.7 (Berkeley) 4/29/91
+ * from NetBSD: ns_cksum.c,v 1.2 1993/05/22 07:59:55 cgd Exp
+ * $Id: ns_cksum.c,v 1.1 1993/09/06 12:12:24 rgrimes Exp $
+ */
+
+#include "sys/param.h"
+#include "systm.h"
+#include "sys/mbuf.h"
+
+/*
+ * Checksum routine for Network Systems Protocol Packets (Big-Endian).
+ *
+ * This routine is very heavily used in the network
+ * code and should be modified for each CPU to be as fast as possible.
+ */
+
+#define ADDCARRY(x) { if ((x) > 65535) (x) -= 65535; }
+#define FOLD(x) {l_util.l = (x); (x) = l_util.s[0] + l_util.s[1]; ADDCARRY(x);}
+
+u_short
+ns_cksum(m, len)
+ register struct mbuf *m;
+ register int len;
+{
+ register u_short *w;
+ register int sum = 0;
+ register int mlen = 0;
+ register int sum2;
+
+ union {
+ u_short s[2];
+ long l;
+ } l_util;
+
+ for (;m && len; m = m->m_next) {
+ if (m->m_len == 0)
+ continue;
+ /*
+ * Each trip around loop adds in
+ * word from one mbuf segment.
+ */
+ w = mtod(m, u_short *);
+ if (mlen == -1) {
+ /*
+ * There is a byte left from the last segment;
+ * ones-complement add it into the checksum.
+ */
+#if BYTE_ORDER == BIG_ENDIAN
+ sum += *(u_char *)w;
+#else
+ sum += *(u_char *)w << 8;
+#endif
+ sum += sum;
+ w = (u_short *)(1 + (char *)w);
+ mlen = m->m_len - 1;
+ len--;
+ FOLD(sum);
+ } else
+ mlen = m->m_len;
+ if (len < mlen)
+ mlen = len;
+ len -= mlen;
+ /*
+ * We can do a 16 bit ones complement sum using
+ * 32 bit arithmetic registers for adding,
+ * with carries from the low added
+ * into the high (by normal carry-chaining)
+ * so long as we fold back before 16 carries have occured.
+ */
+ if (1 & (int) w)
+ goto uuuuglyy;
+#ifndef TINY
+/* -DTINY reduces the size from 1250 to 550, but slows it down by 22% */
+ while ((mlen -= 32) >= 0) {
+ sum += w[0]; sum += sum; sum += w[1]; sum += sum;
+ sum += w[2]; sum += sum; sum += w[3]; sum += sum;
+ sum += w[4]; sum += sum; sum += w[5]; sum += sum;
+ sum += w[6]; sum += sum; sum += w[7]; sum += sum;
+ FOLD(sum);
+ sum += w[8]; sum += sum; sum += w[9]; sum += sum;
+ sum += w[10]; sum += sum; sum += w[11]; sum += sum;
+ sum += w[12]; sum += sum; sum += w[13]; sum += sum;
+ sum += w[14]; sum += sum; sum += w[15]; sum += sum;
+ FOLD(sum);
+ w += 16;
+ }
+ mlen += 32;
+#endif
+ while ((mlen -= 8) >= 0) {
+ sum += w[0]; sum += sum; sum += w[1]; sum += sum;
+ sum += w[2]; sum += sum; sum += w[3]; sum += sum;
+ FOLD(sum);
+ w += 4;
+ }
+ mlen += 8;
+ while ((mlen -= 2) >= 0) {
+ sum += *w++; sum += sum;
+ }
+ goto commoncase;
+uuuuglyy:
+#if BYTE_ORDER == BIG_ENDIAN
+#define ww(n) (((u_char *)w)[n + n + 1])
+#define vv(n) (((u_char *)w)[n + n])
+#else
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define vv(n) (((u_char *)w)[n + n + 1])
+#define ww(n) (((u_char *)w)[n + n])
+#endif
+#endif
+ sum2 = 0;
+#ifndef TINY
+ while ((mlen -= 32) >= 0) {
+ sum += ww(0); sum += sum; sum += ww(1); sum += sum;
+ sum += ww(2); sum += sum; sum += ww(3); sum += sum;
+ sum += ww(4); sum += sum; sum += ww(5); sum += sum;
+ sum += ww(6); sum += sum; sum += ww(7); sum += sum;
+ FOLD(sum);
+ sum += ww(8); sum += sum; sum += ww(9); sum += sum;
+ sum += ww(10); sum += sum; sum += ww(11); sum += sum;
+ sum += ww(12); sum += sum; sum += ww(13); sum += sum;
+ sum += ww(14); sum += sum; sum += ww(15); sum += sum;
+ FOLD(sum);
+ sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2;
+ sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2;
+ sum2 += vv(4); sum2 += sum2; sum2 += vv(5); sum2 += sum2;
+ sum2 += vv(6); sum2 += sum2; sum2 += vv(7); sum2 += sum2;
+ FOLD(sum2);
+ sum2 += vv(8); sum2 += sum2; sum2 += vv(9); sum2 += sum2;
+ sum2 += vv(10); sum2 += sum2; sum2 += vv(11); sum2 += sum2;
+ sum2 += vv(12); sum2 += sum2; sum2 += vv(13); sum2 += sum2;
+ sum2 += vv(14); sum2 += sum2; sum2 += vv(15); sum2 += sum2;
+ FOLD(sum2);
+ w += 16;
+ }
+ mlen += 32;
+#endif
+ while ((mlen -= 8) >= 0) {
+ sum += ww(0); sum += sum; sum += ww(1); sum += sum;
+ sum += ww(2); sum += sum; sum += ww(3); sum += sum;
+ FOLD(sum);
+ sum2 += vv(0); sum2 += sum2; sum2 += vv(1); sum2 += sum2;
+ sum2 += vv(2); sum2 += sum2; sum2 += vv(3); sum2 += sum2;
+ FOLD(sum2);
+ w += 4;
+ }
+ mlen += 8;
+ while ((mlen -= 2) >= 0) {
+ sum += ww(0); sum += sum;
+ sum2 += vv(0); sum2 += sum2;
+ w++;
+ }
+ sum += (sum2 << 8);
+commoncase:
+ if (mlen == -1) {
+#if BYTE_ORDER == BIG_ENDIAN
+ sum += *(u_char *)w << 8;
+#else
+ sum += *(u_char *)w;
+#endif
+ }
+ FOLD(sum);
+ }
+ if (mlen == -1) {
+ /* We had an odd number of bytes to sum; assume a garbage
+ byte of zero and clean up */
+ sum += sum;
+ FOLD(sum);
+ }
+ /*
+ * sum has already been kept to low sixteen bits.
+ * just examine result and exit.
+ */
+ if(sum==0xffff) sum = 0;
+ return (sum);
+}
diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c
new file mode 100644
index 0000000..d5b556f
--- /dev/null
+++ b/sys/i386/i386/pmap.c
@@ -0,0 +1,1938 @@
+/*
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ * Copyright (c) 1994 John S. Dyson
+ * All rights reserved.
+ * Copyright (c) 1994 David Greenman
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department and William Jolitz of UUNET Technologies Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)pmap.c 7.7 (Berkeley) 5/12/91
+ * $Id: pmap.c,v 1.24 1994/04/20 07:06:14 davidg Exp $
+ */
+
+/*
+ * Derived from hp300 version by Mike Hibler, this version by William
+ * Jolitz uses a recursive map [a pde points to the page directory] to
+ * map the page tables using the pagetables themselves. This is done to
+ * reduce the impact on kernel virtual memory for lots of sparse address
+ * space, and to reduce the cost of memory to each process.
+ *
+ * Derived from: hp300/@(#)pmap.c 7.1 (Berkeley) 12/5/90
+ */
+/*
+ * Major modifications by John S. Dyson primarily to support
+ * pageable page tables, eliminating pmap_attributes,
+ * discontiguous memory pages, and using more efficient string
+ * instructions. Jan 13, 1994. Further modifications on Mar 2, 1994,
+ * general clean-up and efficiency mods.
+ */
+
+/*
+ * Manages physical address maps.
+ *
+ * In addition to hardware address maps, this
+ * module is called upon to provide software-use-only
+ * maps which may or may not be stored in the same
+ * form as hardware maps. These pseudo-maps are
+ * used to store intermediate results from copy
+ * operations to and from address spaces.
+ *
+ * Since the information managed by this module is
+ * also stored by the logical address mapping module,
+ * this module may throw away valid virtual-to-physical
+ * mappings at almost any time. However, invalidations
+ * of virtual-to-physical mappings must be done as
+ * requested.
+ *
+ * In order to cope with hardware architectures which
+ * make virtual-to-physical map invalidates expensive,
+ * this module may delay invalidate or reduced protection
+ * operations until such time as they are actually
+ * necessary. This module is given full information as
+ * to which processors are currently using which maps,
+ * and to when physical maps must be made correct.
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "malloc.h"
+#include "user.h"
+#include "i386/include/cpufunc.h"
+#include "i386/include/cputypes.h"
+
+#include "vm/vm.h"
+#include "vm/vm_kern.h"
+#include "vm/vm_page.h"
+
+#include "i386/isa/isa.h"
+
+/*
+ * Allocate various and sundry SYSMAPs used in the days of old VM
+ * and not yet converted. XXX.
+ */
+#define BSDVM_COMPAT 1
+
+/*
+ * Get PDEs and PTEs for user/kernel address space
+ */
+#define pmap_pde(m, v) (&((m)->pm_pdir[((vm_offset_t)(v) >> PD_SHIFT)&1023]))
+#define pdir_pde(m, v) (m[((vm_offset_t)(v) >> PD_SHIFT)&1023])
+
+#define pmap_pte_pa(pte) (*(int *)(pte) & PG_FRAME)
+
+#define pmap_pde_v(pte) ((*(int *)pte & PG_V) != 0)
+#define pmap_pte_w(pte) ((*(int *)pte & PG_W) != 0)
+#define pmap_pte_m(pte) ((*(int *)pte & PG_M) != 0)
+#define pmap_pte_u(pte) ((*(int *)pte & PG_U) != 0)
+#define pmap_pte_v(pte) ((*(int *)pte & PG_V) != 0)
+
+#define pmap_pte_set_w(pte, v) ((v)?(*(int *)pte |= PG_W):(*(int *)pte &= ~PG_W))
+#define pmap_pte_set_prot(pte, v) ((*(int *)pte &= ~PG_PROT), (*(int *)pte |= (v)))
+
+/*
+ * Given a map and a machine independent protection code,
+ * convert to a vax protection code.
+ */
+#define pte_prot(m, p) (protection_codes[p])
+int protection_codes[8];
+
+struct pmap kernel_pmap_store;
+pmap_t kernel_pmap;
+
+vm_offset_t phys_avail[6]; /* 2 entries + 1 null */
+vm_offset_t avail_start; /* PA of first available physical page */
+vm_offset_t avail_end; /* PA of last available physical page */
+vm_size_t mem_size; /* memory size in bytes */
+vm_offset_t virtual_avail; /* VA of first avail page (after kernel bss)*/
+vm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */
+int i386pagesperpage; /* PAGE_SIZE / I386_PAGE_SIZE */
+boolean_t pmap_initialized = FALSE; /* Has pmap_init completed? */
+vm_offset_t vm_first_phys, vm_last_phys;
+
+static inline boolean_t pmap_testbit();
+static inline void pmap_changebit();
+static inline int pmap_is_managed();
+static inline void *vm_get_pmap();
+static inline void vm_put_pmap();
+inline void pmap_use_pt();
+inline void pmap_unuse_pt();
+inline pt_entry_t * const pmap_pte();
+static inline pv_entry_t get_pv_entry();
+void pmap_alloc_pv_entry();
+void pmap_clear_modify();
+void i386_protection_init();
+extern vm_offset_t pager_sva, pager_eva;
+extern int cpu_class;
+
+#if BSDVM_COMPAT
+#include "msgbuf.h"
+
+/*
+ * All those kernel PT submaps that BSD is so fond of
+ */
+pt_entry_t *CMAP1, *CMAP2, *mmap;
+caddr_t CADDR1, CADDR2, vmmap;
+pt_entry_t *msgbufmap;
+struct msgbuf *msgbufp;
+#endif
+
+void init_pv_entries(int) ;
+
+/*
+ * Routine: pmap_pte
+ * Function:
+ * Extract the page table entry associated
+ * with the given map/virtual_address pair.
+ * [ what about induced faults -wfj]
+ */
+
+inline pt_entry_t *
+const pmap_pte(pmap, va)
+ register pmap_t pmap;
+ vm_offset_t va;
+{
+
+ if (pmap && *pmap_pde(pmap, va)) {
+ vm_offset_t frame = (int) pmap->pm_pdir[PTDPTDI] & PG_FRAME;
+ /* are we current address space or kernel? */
+ if ( (pmap == kernel_pmap) || (frame == ((int) PTDpde & PG_FRAME)))
+ return ((pt_entry_t *) vtopte(va));
+ /* otherwise, we are alternate address space */
+ else {
+ if ( frame != ((int) APTDpde & PG_FRAME) ) {
+ APTDpde = pmap->pm_pdir[PTDPTDI];
+ tlbflush();
+ }
+ return((pt_entry_t *) avtopte(va));
+ }
+ }
+ return(0);
+}
+
+/*
+ * Routine: pmap_extract
+ * Function:
+ * Extract the physical page address associated
+ * with the given map/virtual_address pair.
+ */
+
+vm_offset_t
+pmap_extract(pmap, va)
+ register pmap_t pmap;
+ vm_offset_t va;
+{
+ pd_entry_t save;
+ vm_offset_t pa;
+ int s;
+
+ if (pmap && *pmap_pde(pmap, va)) {
+ vm_offset_t frame = (int) pmap->pm_pdir[PTDPTDI] & PG_FRAME;
+ /* are we current address space or kernel? */
+ if ( (pmap == kernel_pmap)
+ || (frame == ((int) PTDpde & PG_FRAME)) ) {
+ pa = *(int *) vtopte(va);
+ /* otherwise, we are alternate address space */
+ } else {
+ if ( frame != ((int) APTDpde & PG_FRAME)) {
+ APTDpde = pmap->pm_pdir[PTDPTDI];
+ tlbflush();
+ }
+ pa = *(int *) avtopte(va);
+ }
+ pa = (pa & PG_FRAME) | (va & ~PG_FRAME);
+ return pa;
+ }
+ return 0;
+
+}
+
+/*
+ * determine if a page is managed (memory vs. device)
+ */
+static inline int
+pmap_is_managed(pa)
+ vm_offset_t pa;
+{
+ int i;
+
+ if (!pmap_initialized)
+ return 0;
+
+ for (i = 0; phys_avail[i + 1]; i += 2) {
+ if (pa >= phys_avail[i] && pa < phys_avail[i + 1])
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * find the vm_page_t of a pte (only) given va of pte and pmap
+ */
+inline vm_page_t
+pmap_pte_vm_page(pmap, pt)
+ pmap_t pmap;
+ vm_offset_t pt;
+{
+ pt = i386_trunc_page( pt);
+ pt = (pt - UPT_MIN_ADDRESS) / NBPG;
+ pt = ((vm_offset_t) pmap->pm_pdir[pt]) & PG_FRAME;
+ return PHYS_TO_VM_PAGE(pt);
+}
+
+/*
+ * Wire a page table page
+ */
+inline void
+pmap_use_pt(pmap, va)
+ pmap_t pmap;
+ vm_offset_t va;
+{
+ vm_offset_t pt;
+
+ if (va >= VM_MAX_ADDRESS || !pmap_initialized)
+ return;
+
+ pt = (vm_offset_t) vtopte(va);
+ vm_page_hold( pmap_pte_vm_page(pmap, pt));
+}
+
+/*
+ * Unwire a page table page
+ */
+inline void
+pmap_unuse_pt(pmap, va)
+ pmap_t pmap;
+ vm_offset_t va;
+{
+ vm_offset_t pt;
+
+ if (va >= VM_MAX_ADDRESS || !pmap_initialized)
+ return;
+
+ pt = (vm_offset_t) vtopte(va);
+ vm_page_unhold( pmap_pte_vm_page(pmap, pt));
+}
+
+/* [ macro again?, should I force kstack into user map here? -wfj ] */
+void
+pmap_activate(pmap, pcbp)
+ register pmap_t pmap;
+ struct pcb *pcbp;
+{
+ PMAP_ACTIVATE(pmap, pcbp);
+}
+
+/*
+ * Bootstrap the system enough to run with virtual memory.
+ * Map the kernel's code and data, and allocate the system page table.
+ *
+ * On the I386 this is called after mapping has already been enabled
+ * and just syncs the pmap module with what has already been done.
+ * [We can't call it easily with mapping off since the kernel is not
+ * mapped with PA == VA, hence we would have to relocate every address
+ * from the linked base (virtual) address "KERNBASE" to the actual
+ * (physical) address starting relative to 0]
+ */
+
+#define DMAPAGES 8
+void
+pmap_bootstrap(firstaddr, loadaddr)
+ vm_offset_t firstaddr;
+ vm_offset_t loadaddr;
+{
+#if BSDVM_COMPAT
+ vm_offset_t va;
+ pt_entry_t *pte;
+#endif
+ extern int IdlePTD;
+
+ avail_start = firstaddr + DMAPAGES*NBPG;
+
+ virtual_avail = (vm_offset_t) KERNBASE + avail_start;
+ virtual_end = VM_MAX_KERNEL_ADDRESS;
+ i386pagesperpage = PAGE_SIZE / NBPG;
+
+ /*
+ * Initialize protection array.
+ */
+ i386_protection_init();
+
+ /*
+ * The kernel's pmap is statically allocated so we don't
+ * have to use pmap_create, which is unlikely to work
+ * correctly at this part of the boot sequence.
+ */
+ kernel_pmap = &kernel_pmap_store;
+
+ kernel_pmap->pm_pdir = (pd_entry_t *)(KERNBASE + IdlePTD);
+
+ simple_lock_init(&kernel_pmap->pm_lock);
+ kernel_pmap->pm_count = 1;
+
+#if BSDVM_COMPAT
+ /*
+ * Allocate all the submaps we need
+ */
+#define SYSMAP(c, p, v, n) \
+ v = (c)va; va += ((n)*NBPG); p = pte; pte += (n);
+
+ va = virtual_avail;
+ pte = pmap_pte(kernel_pmap, va);
+
+ SYSMAP(caddr_t ,CMAP1 ,CADDR1 ,1 )
+ SYSMAP(caddr_t ,CMAP2 ,CADDR2 ,1 )
+ SYSMAP(caddr_t ,mmap ,vmmap ,1 )
+ SYSMAP(struct msgbuf * ,msgbufmap ,msgbufp ,1 )
+ virtual_avail = va;
+#endif
+ /*
+ * reserve special hunk of memory for use by bus dma as a bounce
+ * buffer (contiguous virtual *and* physical memory). for now,
+ * assume vm does not use memory beneath hole, and we know that
+ * the bootstrap uses top 32k of base memory. -wfj
+ */
+ {
+ extern vm_offset_t isaphysmem;
+ isaphysmem = va;
+
+ virtual_avail = pmap_map(va, firstaddr,
+ firstaddr + DMAPAGES*NBPG, VM_PROT_ALL);
+ }
+
+ *(int *)PTD = 0;
+ tlbflush();
+
+}
+
+/*
+ * Initialize the pmap module.
+ * Called by vm_init, to initialize any structures that the pmap
+ * system needs to map virtual memory.
+ * pmap_init has been enhanced to support in a fairly consistant
+ * way, discontiguous physical memory.
+ */
+void
+pmap_init(phys_start, phys_end)
+ vm_offset_t phys_start, phys_end;
+{
+ vm_offset_t addr, addr2;
+ vm_size_t npg, s;
+ int rv;
+ int i;
+ extern int KPTphys;
+ extern int IdlePTD;
+
+ /*
+ * Now that kernel map has been allocated, we can mark as
+ * unavailable regions which we have mapped in locore.
+ */
+ addr = atdevbase;
+ (void) vm_map_find(kernel_map, NULL, (vm_offset_t) 0,
+ &addr, (0x100000-0xa0000), FALSE);
+
+ addr = (vm_offset_t) KERNBASE + IdlePTD;
+ vm_object_reference(kernel_object);
+ (void) vm_map_find(kernel_map, kernel_object, addr,
+ &addr, (4 + NKPT) * NBPG, FALSE);
+
+
+ /*
+ * calculate the number of pv_entries needed
+ */
+ vm_first_phys = phys_avail[0];
+ for (i = 0; phys_avail[i + 1]; i += 2) ;
+ npg = (phys_avail[(i - 2) + 1] - vm_first_phys) / NBPG;
+
+ /*
+ * Allocate memory for random pmap data structures. Includes the
+ * pv_head_table.
+ */
+ s = (vm_size_t) (sizeof(struct pv_entry) * npg);
+ s = i386_round_page(s);
+ addr = (vm_offset_t) kmem_alloc(kernel_map, s);
+ pv_table = (pv_entry_t) addr;
+
+ /*
+ * init the pv free list
+ */
+ init_pv_entries(npg);
+ /*
+ * Now it is safe to enable pv_table recording.
+ */
+ pmap_initialized = TRUE;
+}
+
+/*
+ * Used to map a range of physical addresses into kernel
+ * virtual address space.
+ *
+ * For now, VM is already on, we only need to map the
+ * specified memory.
+ */
+vm_offset_t
+pmap_map(virt, start, end, prot)
+ vm_offset_t virt;
+ vm_offset_t start;
+ vm_offset_t end;
+ int prot;
+{
+ while (start < end) {
+ pmap_enter(kernel_pmap, virt, start, prot, FALSE);
+ virt += PAGE_SIZE;
+ start += PAGE_SIZE;
+ }
+ return(virt);
+}
+
+/*
+ * Create and return a physical map.
+ *
+ * If the size specified for the map
+ * is zero, the map is an actual physical
+ * map, and may be referenced by the
+ * hardware.
+ *
+ * If the size specified is non-zero,
+ * the map will be used in software only, and
+ * is bounded by that size.
+ *
+ * [ just allocate a ptd and mark it uninitialize -- should we track
+ * with a table which process has which ptd? -wfj ]
+ */
+
+pmap_t
+pmap_create(size)
+ vm_size_t size;
+{
+ register pmap_t pmap;
+
+ /*
+ * Software use map does not need a pmap
+ */
+ if (size)
+ return(NULL);
+
+ pmap = (pmap_t) malloc(sizeof *pmap, M_VMPMAP, M_WAITOK);
+ bzero(pmap, sizeof(*pmap));
+ pmap_pinit(pmap);
+ return (pmap);
+}
+
+
+struct pmaplist {
+ struct pmaplist *next;
+};
+
+static inline void *
+vm_get_pmap()
+{
+ struct pmaplist *rtval;
+
+ rtval = (struct pmaplist *)kmem_alloc(kernel_map, ctob(1));
+ bzero(rtval, ctob(1));
+ return rtval;
+}
+
+static inline void
+vm_put_pmap(up)
+ struct pmaplist *up;
+{
+ kmem_free(kernel_map, up, ctob(1));
+}
+
+/*
+ * Initialize a preallocated and zeroed pmap structure,
+ * such as one in a vmspace structure.
+ */
+void
+pmap_pinit(pmap)
+ register struct pmap *pmap;
+{
+ /*
+ * No need to allocate page table space yet but we do need a
+ * valid page directory table.
+ */
+ pmap->pm_pdir = (pd_entry_t *) vm_get_pmap();
+
+ /* wire in kernel global address entries */
+ bcopy(PTD+KPTDI, pmap->pm_pdir+KPTDI, NKPT*PTESIZE);
+
+ /* install self-referential address mapping entry */
+ *(int *)(pmap->pm_pdir+PTDPTDI) =
+ ((int)pmap_kextract((vm_offset_t)pmap->pm_pdir)) | PG_V | PG_KW;
+
+ pmap->pm_count = 1;
+ simple_lock_init(&pmap->pm_lock);
+}
+
+/*
+ * Retire the given physical map from service.
+ * Should only be called if the map contains
+ * no valid mappings.
+ */
+void
+pmap_destroy(pmap)
+ register pmap_t pmap;
+{
+ int count;
+
+ if (pmap == NULL)
+ return;
+
+ simple_lock(&pmap->pm_lock);
+ count = --pmap->pm_count;
+ simple_unlock(&pmap->pm_lock);
+ if (count == 0) {
+ pmap_release(pmap);
+ free((caddr_t)pmap, M_VMPMAP);
+ }
+}
+
+/*
+ * Release any resources held by the given physical map.
+ * Called when a pmap initialized by pmap_pinit is being released.
+ * Should only be called if the map contains no valid mappings.
+ */
+void
+pmap_release(pmap)
+ register struct pmap *pmap;
+{
+ vm_put_pmap((struct pmaplist *) pmap->pm_pdir);
+}
+
+/*
+ * Add a reference to the specified pmap.
+ */
+void
+pmap_reference(pmap)
+ pmap_t pmap;
+{
+ if (pmap != NULL) {
+ simple_lock(&pmap->pm_lock);
+ pmap->pm_count++;
+ simple_unlock(&pmap->pm_lock);
+ }
+}
+
+#define PV_FREELIST_MIN ((NBPG / sizeof (struct pv_entry)) / 2)
+
+/*
+ * Data for the pv entry allocation mechanism
+ */
+int pv_freelistcnt;
+pv_entry_t pv_freelist;
+vm_offset_t pvva;
+int npvvapg;
+
+/*
+ * free the pv_entry back to the free list
+ */
+inline static void
+free_pv_entry(pv)
+ pv_entry_t pv;
+{
+ if (!pv) return;
+ ++pv_freelistcnt;
+ pv->pv_next = pv_freelist;
+ pv_freelist = pv;
+}
+
+/*
+ * get a new pv_entry, allocating a block from the system
+ * when needed.
+ * the memory allocation is performed bypassing the malloc code
+ * because of the possibility of allocations at interrupt time.
+ */
+static inline pv_entry_t
+get_pv_entry()
+{
+ pv_entry_t tmp;
+
+ /*
+ * get more pv_entry pages if needed
+ */
+ while (pv_freelistcnt < PV_FREELIST_MIN || pv_freelist == 0) {
+ pmap_alloc_pv_entry();
+ }
+
+ /*
+ * get a pv_entry off of the free list
+ */
+ --pv_freelistcnt;
+ tmp = pv_freelist;
+ pv_freelist = tmp->pv_next;
+ tmp->pv_pmap = 0;
+ tmp->pv_va = 0;
+ tmp->pv_next = 0;
+ return tmp;
+}
+
+/*
+ * this *strange* allocation routine *statistically* eliminates the
+ * *possibility* of a malloc failure (*FATAL*) for a pv_entry_t data structure.
+ * also -- this code is MUCH MUCH faster than the malloc equiv...
+ */
+void
+pmap_alloc_pv_entry()
+{
+ /*
+ * do we have any pre-allocated map-pages left?
+ */
+ if (npvvapg) {
+ vm_page_t m;
+ /*
+ * we do this to keep recursion away
+ */
+ pv_freelistcnt += PV_FREELIST_MIN;
+ /*
+ * allocate a physical page out of the vm system
+ */
+ if (m = vm_page_alloc(kernel_object, pvva-vm_map_min(kernel_map))) {
+ int newentries;
+ int i;
+ pv_entry_t entry;
+ newentries = (NBPG/sizeof (struct pv_entry));
+ /*
+ * wire the page
+ */
+ vm_page_wire(m);
+ m->flags &= ~PG_BUSY;
+ /*
+ * let the kernel see it
+ */
+ pmap_enter(vm_map_pmap(kernel_map), pvva,
+ VM_PAGE_TO_PHYS(m), VM_PROT_DEFAULT,1);
+
+ entry = (pv_entry_t) pvva;
+ /*
+ * update the allocation pointers
+ */
+ pvva += NBPG;
+ --npvvapg;
+
+ /*
+ * free the entries into the free list
+ */
+ for (i = 0; i < newentries; i++) {
+ free_pv_entry(entry);
+ entry++;
+ }
+ }
+ pv_freelistcnt -= PV_FREELIST_MIN;
+ }
+ if (!pv_freelist)
+ panic("get_pv_entry: cannot get a pv_entry_t");
+}
+
+
+
+/*
+ * init the pv_entry allocation system
+ */
+#define PVSPERPAGE 64
+void
+init_pv_entries(npg)
+ int npg;
+{
+ /*
+ * allocate enough kvm space for PVSPERPAGE entries per page (lots)
+ * kvm space is fairly cheap, be generous!!! (the system can panic
+ * if this is too small.)
+ */
+ npvvapg = ((npg*PVSPERPAGE) * sizeof(struct pv_entry) + NBPG - 1)/NBPG;
+ pvva = kmem_alloc_pageable(kernel_map, npvvapg * NBPG);
+ /*
+ * get the first batch of entries
+ */
+ free_pv_entry(get_pv_entry());
+}
+
+static pt_entry_t *
+get_pt_entry(pmap)
+ pmap_t pmap;
+{
+ pt_entry_t *ptp;
+ vm_offset_t frame = (int) pmap->pm_pdir[PTDPTDI] & PG_FRAME;
+ /* are we current address space or kernel? */
+ if (pmap == kernel_pmap || frame == ((int) PTDpde & PG_FRAME)) {
+ ptp=PTmap;
+ /* otherwise, we are alternate address space */
+ } else {
+ if ( frame != ((int) APTDpde & PG_FRAME)) {
+ APTDpde = pmap->pm_pdir[PTDPTDI];
+ tlbflush();
+ }
+ ptp=APTmap;
+ }
+ return ptp;
+}
+
+/*
+ * If it is the first entry on the list, it is actually
+ * in the header and we must copy the following entry up
+ * to the header. Otherwise we must search the list for
+ * the entry. In either case we free the now unused entry.
+ */
+void
+pmap_remove_entry(pmap, pv, va)
+ struct pmap *pmap;
+ pv_entry_t pv;
+ vm_offset_t va;
+{
+ pv_entry_t npv;
+ int wired;
+ int s;
+ s = splimp();
+ if (pmap == pv->pv_pmap && va == pv->pv_va) {
+ npv = pv->pv_next;
+ if (npv) {
+ *pv = *npv;
+ free_pv_entry(npv);
+ } else {
+ pv->pv_pmap = NULL;
+ }
+ } else {
+ for (npv = pv->pv_next; npv; npv = npv->pv_next) {
+ if (pmap == npv->pv_pmap && va == npv->pv_va) {
+ break;
+ }
+ pv = npv;
+ }
+ if (npv) {
+ pv->pv_next = npv->pv_next;
+ free_pv_entry(npv);
+ }
+ }
+ splx(s);
+}
+
+/*
+ * Remove the given range of addresses from the specified map.
+ *
+ * It is assumed that the start and end are properly
+ * rounded to the page size.
+ */
+void
+pmap_remove(pmap, sva, eva)
+ struct pmap *pmap;
+ register vm_offset_t sva;
+ register vm_offset_t eva;
+{
+ register pt_entry_t *ptp,*ptq;
+ vm_offset_t pa;
+ register pv_entry_t pv;
+ vm_offset_t va;
+ vm_page_t m;
+ pt_entry_t oldpte;
+
+ if (pmap == NULL)
+ return;
+
+ ptp = get_pt_entry(pmap);
+
+/*
+ * special handling of removing one page. a very
+ * common operation and easy to short circuit some
+ * code.
+ */
+ if( (sva + NBPG) == eva) {
+
+ if( *pmap_pde( pmap, sva) == 0)
+ return;
+
+ ptq = ptp + i386_btop(sva);
+
+ if( !*ptq)
+ return;
+ /*
+ * Update statistics
+ */
+ if (pmap_pte_w(ptq))
+ pmap->pm_stats.wired_count--;
+ pmap->pm_stats.resident_count--;
+
+ pa = pmap_pte_pa(ptq);
+ oldpte = *ptq;
+ *ptq = 0;
+
+ if (pmap_is_managed(pa)) {
+ if ((((int) oldpte & PG_M) && (sva < USRSTACK || sva > UPT_MAX_ADDRESS))
+ || (sva >= USRSTACK && sva < USRSTACK+(UPAGES*NBPG))) {
+ if (sva < pager_sva || sva >= pager_eva) {
+ m = PHYS_TO_VM_PAGE(pa);
+ m->flags &= ~PG_CLEAN;
+ }
+ }
+
+ pv = pa_to_pvh(pa);
+ pmap_remove_entry(pmap, pv, sva);
+ pmap_unuse_pt(pmap, sva);
+ }
+ tlbflush();
+ return;
+ }
+
+ sva = i386_btop(sva);
+ eva = i386_btop(eva);
+
+ while (sva < eva) {
+ /*
+ * Weed out invalid mappings.
+ * Note: we assume that the page directory table is
+ * always allocated, and in kernel virtual.
+ */
+
+ if ( *pmap_pde(pmap, i386_ptob(sva)) == 0 ) {
+ /* We can race ahead here, straight to next pde.. */
+ nextpde:
+ sva = ((sva + NPTEPG) & ~(NPTEPG - 1));
+ continue;
+ }
+
+ ptq = ptp + sva;
+
+ /*
+ * search for page table entries, use string operations
+ * that are much faster than
+ * explicitly scanning when page tables are not fully
+ * populated.
+ */
+ if ( *ptq == 0) {
+ vm_offset_t pdnxt = ((sva + NPTEPG) & ~(NPTEPG - 1));
+ vm_offset_t nscan = pdnxt - sva;
+ int found = 0;
+
+ if ((nscan + sva) > eva)
+ nscan = eva - sva;
+
+ asm("xorl %%eax,%%eax;cld;repe;scasl;jz 1f;incl %%eax;1:;"
+ :"=D"(ptq),"=a"(found)
+ :"c"(nscan),"0"(ptq)
+ :"cx");
+
+ if( !found) {
+ sva = pdnxt;
+ continue;
+ }
+ ptq -= 1;
+
+ sva = ptq - ptp;
+ }
+
+ /*
+ * Update statistics
+ */
+ oldpte = *ptq;
+ if (((int)oldpte) & PG_W)
+ pmap->pm_stats.wired_count--;
+ pmap->pm_stats.resident_count--;
+
+ /*
+ * Invalidate the PTEs.
+ * XXX: should cluster them up and invalidate as many
+ * as possible at once.
+ */
+ *ptq = 0;
+
+ va = i386_ptob(sva);
+
+ /*
+ * Remove from the PV table (raise IPL since we
+ * may be called at interrupt time).
+ */
+ pa = ((int)oldpte) & PG_FRAME;
+ if (!pmap_is_managed(pa)) {
+ ++sva;
+ continue;
+ }
+
+ if ((((int) oldpte & PG_M) && (va < USRSTACK || va > UPT_MAX_ADDRESS))
+ || (va >= USRSTACK && va < USRSTACK+(UPAGES*NBPG))) {
+ if (va < pager_sva || va >= pager_eva) {
+ m = PHYS_TO_VM_PAGE(pa);
+ m->flags &= ~PG_CLEAN;
+ }
+ }
+
+ pv = pa_to_pvh(pa);
+ pmap_remove_entry(pmap, pv, va);
+ pmap_unuse_pt(pmap, va);
+ ++sva;
+ }
+ tlbflush();
+}
+
+/*
+ * Routine: pmap_remove_all
+ * Function:
+ * Removes this physical page from
+ * all physical maps in which it resides.
+ * Reflects back modify bits to the pager.
+ *
+ * Notes:
+ * Original versions of this routine were very
+ * inefficient because they iteratively called
+ * pmap_remove (slow...)
+ */
+void
+pmap_remove_all(pa)
+ vm_offset_t pa;
+{
+ register pv_entry_t pv, npv;
+ register pt_entry_t *pte, *ptp;
+ vm_offset_t va;
+ struct pmap *pmap;
+ struct map *map;
+ vm_page_t m;
+ int s;
+
+ /*
+ * Not one of ours
+ */
+ if (!pmap_is_managed(pa))
+ return;
+
+ pa = i386_trunc_page(pa);
+ pv = pa_to_pvh(pa);
+ m = PHYS_TO_VM_PAGE(pa);
+
+ s = splimp();
+ while (pv->pv_pmap != NULL) {
+ pmap = pv->pv_pmap;
+ ptp = get_pt_entry(pmap);
+ va = i386_btop(pv->pv_va);
+ pte = ptp + va;
+ if (pmap_pte_w(pte))
+ pmap->pm_stats.wired_count--;
+ if ( *pte)
+ pmap->pm_stats.resident_count--;
+
+ /*
+ * update the vm_page_t clean bit
+ */
+ if ( (m->flags & PG_CLEAN) &&
+ ((((int) *pte) & PG_M) && (pv->pv_va < USRSTACK || pv->pv_va > UPT_MAX_ADDRESS))
+ || (pv->pv_va >= USRSTACK && pv->pv_va < USRSTACK+(UPAGES*NBPG))) {
+ if (pv->pv_va < pager_sva || pv->pv_va >= pager_eva) {
+ m->flags &= ~PG_CLEAN;
+ }
+ }
+
+ *pte = 0;
+ pmap_unuse_pt(pmap, pv->pv_va);
+
+ npv = pv->pv_next;
+ if (npv) {
+ *pv = *npv;
+ free_pv_entry(npv);
+ } else {
+ pv->pv_pmap = NULL;
+ }
+ }
+ splx(s);
+ tlbflush();
+}
+
+
+/*
+ * Set the physical protection on the
+ * specified range of this map as requested.
+ */
+void
+pmap_protect(pmap, sva, eva, prot)
+ register pmap_t pmap;
+ vm_offset_t sva, eva;
+ vm_prot_t prot;
+{
+ register pt_entry_t *pte;
+ register vm_offset_t va;
+ int i386prot;
+ register pt_entry_t *ptp;
+ int evap = i386_btop(eva);
+ int s;
+
+ if (pmap == NULL)
+ return;
+
+ if ((prot & VM_PROT_READ) == VM_PROT_NONE) {
+ pmap_remove(pmap, sva, eva);
+ return;
+ }
+ if (prot & VM_PROT_WRITE)
+ return;
+
+ ptp = get_pt_entry(pmap);
+
+ va = sva;
+ while (va < eva) {
+ int found=0;
+ int svap;
+ vm_offset_t nscan;
+ /*
+ * Page table page is not allocated.
+ * Skip it, we don't want to force allocation
+ * of unnecessary PTE pages just to set the protection.
+ */
+ if (! *pmap_pde(pmap, va)) {
+ /* XXX: avoid address wrap around */
+nextpde:
+ if (va >= i386_trunc_pdr((vm_offset_t)-1))
+ break;
+ va = i386_round_pdr(va + PAGE_SIZE);
+ continue;
+ }
+
+ pte = ptp + i386_btop(va);
+
+ if( *pte == 0) {
+ /*
+ * scan for a non-empty pte
+ */
+ svap = pte - ptp;
+ nscan = ((svap + NPTEPG) & ~(NPTEPG - 1)) - svap;
+
+ if (nscan + svap > evap)
+ nscan = evap - svap;
+
+ found = 0;
+ if (nscan)
+ asm("xorl %%eax,%%eax;cld;repe;scasl;jz 1f;incl %%eax;1:;"
+ :"=D"(pte),"=a"(found)
+ :"c"(nscan),"0"(pte):"cx");
+
+ if( !found)
+ goto nextpde;
+
+ pte -= 1;
+ svap = pte - ptp;
+
+ va = i386_ptob(svap);
+ }
+
+ i386prot = pte_prot(pmap, prot);
+ if (va < UPT_MAX_ADDRESS) {
+ i386prot |= PG_u;
+ if( va >= UPT_MIN_ADDRESS)
+ i386prot |= PG_RW;
+ }
+ pmap_pte_set_prot(pte, i386prot);
+ va += PAGE_SIZE;
+ }
+ tlbflush();
+}
+
+/*
+ * Insert the given physical page (p) at
+ * the specified virtual address (v) in the
+ * target physical map with the protection requested.
+ *
+ * If specified, the page will be wired down, meaning
+ * that the related pte can not be reclaimed.
+ *
+ * NB: This is the only routine which MAY NOT lazy-evaluate
+ * or lose information. That is, this routine must actually
+ * insert this page into the given map NOW.
+ */
+void
+pmap_enter(pmap, va, pa, prot, wired)
+ register pmap_t pmap;
+ vm_offset_t va;
+ register vm_offset_t pa;
+ vm_prot_t prot;
+ boolean_t wired;
+{
+ register pt_entry_t *pte;
+ register pt_entry_t npte;
+ vm_offset_t opa;
+ int cacheable=1;
+
+ if (pmap == NULL)
+ return;
+
+ va = i386_trunc_page(va);
+ pa = i386_trunc_page(pa);
+ if (va > VM_MAX_KERNEL_ADDRESS)panic("pmap_enter: toobig");
+
+ /*
+ * Page Directory table entry not valid, we need a new PT page
+ */
+ if ( *pmap_pde(pmap, va) == 0) {
+ pg("ptdi %x, va %x", pmap->pm_pdir[PTDPTDI], va);
+ }
+
+ pte = pmap_pte(pmap, va);
+ opa = pmap_pte_pa(pte);
+
+ /*
+ * Mapping has not changed, must be protection or wiring change.
+ */
+ if (opa == pa) {
+ /*
+ * Wiring change, just update stats.
+ * We don't worry about wiring PT pages as they remain
+ * resident as long as there are valid mappings in them.
+ * Hence, if a user page is wired, the PT page will be also.
+ */
+ if (wired && !pmap_pte_w(pte) || !wired && pmap_pte_w(pte)) {
+ if (wired)
+ pmap->pm_stats.wired_count++;
+ else
+ pmap->pm_stats.wired_count--;
+ }
+ goto validate;
+ }
+
+ /*
+ * Mapping has changed, invalidate old range and fall through to
+ * handle validating new mapping.
+ */
+ if (opa) {
+ pmap_remove(pmap, va, va + PAGE_SIZE);
+ }
+
+ /*
+ * Enter on the PV list if part of our managed memory
+ * Note that we raise IPL while manipulating pv_table
+ * since pmap_enter can be called at interrupt time.
+ */
+ if (pmap_is_managed(pa)) {
+ register pv_entry_t pv, npv;
+ int s;
+
+ pv = pa_to_pvh(pa);
+ s = splimp();
+ /*
+ * No entries yet, use header as the first entry
+ */
+ if (pv->pv_pmap == NULL) {
+ pv->pv_va = va;
+ pv->pv_pmap = pmap;
+ pv->pv_next = NULL;
+ }
+ /*
+ * There is at least one other VA mapping this page.
+ * Place this entry after the header.
+ */
+ else {
+ npv = get_pv_entry();
+ npv->pv_va = va;
+ npv->pv_pmap = pmap;
+ npv->pv_next = pv->pv_next;
+ pv->pv_next = npv;
+ }
+ splx(s);
+ cacheable = 1;
+ } else {
+ cacheable = 0;
+ }
+
+ pmap_use_pt(pmap, va);
+
+ /*
+ * Increment counters
+ */
+ pmap->pm_stats.resident_count++;
+ if (wired)
+ pmap->pm_stats.wired_count++;
+
+validate:
+ /*
+ * Now validate mapping with desired protection/wiring.
+ */
+ npte = (pt_entry_t) ( (int) (pa | pte_prot(pmap, prot) | PG_V));
+ /*
+ * for correctness:
+ */
+ if( !cacheable)
+ (int) npte |= PG_N;
+
+ /*
+ * When forking (copy-on-write, etc):
+ * A process will turn off write permissions for any of its writable
+ * pages. If the data (object) is only referred to by one process, the
+ * processes map is modified directly as opposed to using the
+ * object manipulation routine. When using pmap_protect, the
+ * modified bits are not kept in the vm_page_t data structure.
+ * Therefore, when using pmap_enter in vm_fault to bring back
+ * writability of a page, there has been no memory of the
+ * modified or referenced bits except at the pte level.
+ * this clause supports the carryover of the modified and
+ * used (referenced) bits.
+ */
+ if (pa == opa)
+ (int) npte |= (int) *pte & (PG_M|PG_U);
+
+
+ if (wired)
+ (int) npte |= PG_W;
+ if (va < UPT_MIN_ADDRESS)
+ (int) npte |= PG_u;
+ else if (va < UPT_MAX_ADDRESS)
+ (int) npte |= PG_u | PG_RW;
+
+ if( *pte != npte) {
+ *pte = npte;
+ tlbflush();
+ }
+}
+
+/*
+ * add a wired page to the kva
+ */
+void
+pmap_kenter(va, pa)
+ vm_offset_t va;
+ register vm_offset_t pa;
+{
+ register pt_entry_t *pte;
+ register pv_entry_t pv, npv;
+ vm_offset_t opa;
+ int s;
+
+ /*
+ * Enter on the PV list if part of our managed memory
+ * Note that we raise IPL while manipulating pv_table
+ * since pmap_enter can be called at interrupt time.
+ */
+
+ pte = vtopte(va);
+
+ opa = pmap_pte_pa(pte);
+ /*
+ * Mapping has not changed, must be protection or wiring change.
+ */
+ if (opa == pa) {
+ /*
+ * Wiring change, just update stats.
+ * We don't worry about wiring PT pages as they remain
+ * resident as long as there are valid mappings in them.
+ * Hence, if a user page is wired, the PT page will be also.
+ */
+ if (!pmap_pte_w(pte)) {
+ kernel_pmap->pm_stats.wired_count++;
+ }
+ goto validate;
+ }
+
+ if (opa) {
+ pmap_remove(kernel_pmap, va, va + PAGE_SIZE);
+ }
+
+ pv = pa_to_pvh(pa);
+ s = splimp();
+ /*
+ * No entries yet, use header as the first entry
+ */
+ if (pv->pv_pmap == NULL) {
+ pv->pv_va = va;
+ pv->pv_pmap = kernel_pmap;
+ pv->pv_next = NULL;
+ }
+ /*
+ * There is at least one other VA mapping this page.
+ * Place this entry after the header.
+ */
+ else {
+ npv = get_pv_entry();
+ npv->pv_va = va;
+ npv->pv_pmap = kernel_pmap;
+ npv->pv_next = pv->pv_next;
+ pv->pv_next = npv;
+ }
+ splx(s);
+
+ /*
+ * Increment counters
+ */
+ kernel_pmap->pm_stats.resident_count++;
+
+validate:
+
+ /*
+ * Now validate mapping with desired protection/wiring.
+ */
+ *pte = (pt_entry_t) ( (int) (pa | PG_RW | PG_V | PG_W));
+}
+
+/*
+ * this code makes some *MAJOR* assumptions:
+ * 1. Current pmap & pmap exists.
+ * 2. Not wired.
+ * 3. Read access.
+ * 4. No page table pages.
+ * 5. Tlbflush is deferred to calling procedure.
+ * 6. Page IS managed.
+ * but is *MUCH* faster than pmap_enter...
+ */
+
+static inline void
+pmap_enter_quick(pmap, va, pa)
+ register pmap_t pmap;
+ vm_offset_t va;
+ register vm_offset_t pa;
+{
+ register pt_entry_t *pte;
+ register pv_entry_t pv, npv;
+ int s;
+
+ /*
+ * Enter on the PV list if part of our managed memory
+ * Note that we raise IPL while manipulating pv_table
+ * since pmap_enter can be called at interrupt time.
+ */
+
+ pte = vtopte(va);
+ if (pmap_pte_pa(pte)) {
+ pmap_remove(pmap, va, va + PAGE_SIZE);
+ }
+
+ pv = pa_to_pvh(pa);
+ s = splimp();
+ /*
+ * No entries yet, use header as the first entry
+ */
+ if (pv->pv_pmap == NULL) {
+ pv->pv_va = va;
+ pv->pv_pmap = pmap;
+ pv->pv_next = NULL;
+ }
+ /*
+ * There is at least one other VA mapping this page.
+ * Place this entry after the header.
+ */
+ else {
+ npv = get_pv_entry();
+ npv->pv_va = va;
+ npv->pv_pmap = pmap;
+ npv->pv_next = pv->pv_next;
+ pv->pv_next = npv;
+ }
+ splx(s);
+
+ pmap_use_pt(pmap, va);
+
+ /*
+ * Increment counters
+ */
+ pmap->pm_stats.resident_count++;
+
+validate:
+
+ /*
+ * Now validate mapping with desired protection/wiring.
+ */
+ *pte = (pt_entry_t) ( (int) (pa | PG_RO | PG_V | PG_u));
+}
+
+/*
+ * pmap_object_init_pt preloads the ptes for a given object
+ * into the specified pmap. This eliminates the blast of soft
+ * faults on process startup and immediately after an mmap.
+ */
+void
+pmap_object_init_pt(pmap, addr, object, offset, size)
+ pmap_t pmap;
+ vm_offset_t addr;
+ vm_object_t object;
+ vm_offset_t offset;
+ vm_offset_t size;
+{
+
+ vm_offset_t tmpoff;
+ vm_page_t p;
+ int s;
+ vm_offset_t v, lastv=0;
+ pt_entry_t pte;
+ extern vm_map_t kernel_map;
+ vm_offset_t objbytes;
+
+ if (!pmap)
+ return;
+
+ /*
+ * if we are processing a major portion of the object, then
+ * scan the entire thing.
+ */
+ if( size > object->size / 2) {
+ objbytes = size;
+ p = (vm_page_t) queue_first(&object->memq);
+ while (!queue_end(&object->memq, (queue_entry_t) p) && objbytes != 0) {
+ tmpoff = p->offset;
+ if( tmpoff < offset) {
+ p = (vm_page_t) queue_next(&p->listq);
+ continue;
+ }
+ tmpoff -= offset;
+ if( tmpoff >= size) {
+ p = (vm_page_t) queue_next(&p->listq);
+ continue;
+ }
+
+ if ((p->flags & (PG_BUSY|PG_FICTITIOUS)) == 0 ) {
+ vm_page_hold(p);
+ v = i386_trunc_page(((vm_offset_t)vtopte( addr+tmpoff)));
+ /* a fault might occur here */
+ *(volatile char *)v += 0;
+ vm_page_unhold(p);
+ pmap_enter_quick(pmap, addr+tmpoff, VM_PAGE_TO_PHYS(p));
+ }
+ p = (vm_page_t) queue_next(&p->listq);
+ objbytes -= NBPG;
+ }
+ } else {
+ /*
+ * else lookup the pages one-by-one.
+ */
+ for(tmpoff = 0; tmpoff < size; tmpoff += NBPG) {
+ if( p = vm_page_lookup(object, tmpoff + offset)) {
+ if( (p->flags & (PG_BUSY|PG_FICTITIOUS)) == 0) {
+ vm_page_hold(p);
+ v = i386_trunc_page(((vm_offset_t)vtopte( addr+tmpoff)));
+ /* a fault might occur here */
+ *(volatile char *)v += 0;
+ vm_page_unhold(p);
+ pmap_enter_quick(pmap, addr+tmpoff, VM_PAGE_TO_PHYS(p));
+ }
+ }
+ }
+ }
+
+ tlbflush();
+}
+
+/*
+ * Routine: pmap_change_wiring
+ * Function: Change the wiring attribute for a map/virtual-address
+ * pair.
+ * In/out conditions:
+ * The mapping must already exist in the pmap.
+ */
+void
+pmap_change_wiring(pmap, va, wired)
+ register pmap_t pmap;
+ vm_offset_t va;
+ boolean_t wired;
+{
+ register pt_entry_t *pte;
+
+ if (pmap == NULL)
+ return;
+
+ pte = pmap_pte(pmap, va);
+ if (wired && !pmap_pte_w(pte) || !wired && pmap_pte_w(pte)) {
+ if (wired)
+ pmap->pm_stats.wired_count++;
+ else
+ pmap->pm_stats.wired_count--;
+ }
+ /*
+ * Wiring is not a hardware characteristic so there is no need
+ * to invalidate TLB.
+ */
+ pmap_pte_set_w(pte, wired);
+ /*
+ * When unwiring, set the modified bit in the pte -- could have
+ * been changed by the kernel
+ */
+ if (!wired)
+ (int) *pte |= PG_M;
+}
+
+
+
+/*
+ * Copy the range specified by src_addr/len
+ * from the source map to the range dst_addr/len
+ * in the destination map.
+ *
+ * This routine is only advisory and need not do anything.
+ */
+void
+pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr)
+ pmap_t dst_pmap, src_pmap;
+ vm_offset_t dst_addr;
+ vm_size_t len;
+ vm_offset_t src_addr;
+{
+}
+/*
+ * Require that all active physical maps contain no
+ * incorrect entries NOW. [This update includes
+ * forcing updates of any address map caching.]
+ *
+ * Generally used to insure that a thread about
+ * to run will see a semantically correct world.
+ */
+void
+pmap_update()
+{
+ tlbflush();
+}
+
+/*
+ * Routine: pmap_kernel
+ * Function:
+ * Returns the physical map handle for the kernel.
+ */
+pmap_t
+pmap_kernel()
+{
+ return (kernel_pmap);
+}
+
+/*
+ * pmap_zero_page zeros the specified (machine independent)
+ * page by mapping the page into virtual memory and using
+ * bzero to clear its contents, one machine dependent page
+ * at a time.
+ */
+void
+pmap_zero_page(phys)
+ vm_offset_t phys;
+{
+ *(int *)CMAP2 = PG_V | PG_KW | i386_trunc_page(phys);
+ tlbflush();
+ bzero(CADDR2,NBPG);
+}
+
+/*
+ * pmap_copy_page copies the specified (machine independent)
+ * page by mapping the page into virtual memory and using
+ * bcopy to copy the page, one machine dependent page at a
+ * time.
+ */
+void
+pmap_copy_page(src, dst)
+ vm_offset_t src;
+ vm_offset_t dst;
+{
+ *(int *)CMAP1 = PG_V | PG_KW | i386_trunc_page(src);
+ *(int *)CMAP2 = PG_V | PG_KW | i386_trunc_page(dst);
+ tlbflush();
+
+#if __GNUC__ > 1
+ memcpy(CADDR2, CADDR1, NBPG);
+#else
+ bcopy(CADDR1, CADDR2, NBPG);
+#endif
+}
+
+
+/*
+ * Routine: pmap_pageable
+ * Function:
+ * Make the specified pages (by pmap, offset)
+ * pageable (or not) as requested.
+ *
+ * A page which is not pageable may not take
+ * a fault; therefore, its page table entry
+ * must remain valid for the duration.
+ *
+ * This routine is merely advisory; pmap_enter
+ * will specify that these pages are to be wired
+ * down (or not) as appropriate.
+ */
+void
+pmap_pageable(pmap, sva, eva, pageable)
+ pmap_t pmap;
+ vm_offset_t sva, eva;
+ boolean_t pageable;
+{
+}
+
+/*
+ * this routine returns true if a physical page resides
+ * in the given pmap.
+ */
+boolean_t
+pmap_page_exists(pmap, pa)
+ pmap_t pmap;
+ vm_offset_t pa;
+{
+ register pv_entry_t pv;
+ int s;
+
+ if (!pmap_is_managed(pa))
+ return FALSE;
+
+ pv = pa_to_pvh(pa);
+ s = splimp();
+
+ /*
+ * Not found, check current mappings returning
+ * immediately if found.
+ */
+ if (pv->pv_pmap != NULL) {
+ for (; pv; pv = pv->pv_next) {
+ if (pv->pv_pmap == pmap) {
+ splx(s);
+ return TRUE;
+ }
+ }
+ }
+ splx(s);
+ return(FALSE);
+}
+
+/*
+ * pmap_testbit tests bits in pte's
+ * note that the testbit/changebit routines are inline,
+ * and a lot of things compile-time evaluate.
+ */
+static inline boolean_t
+pmap_testbit(pa, bit)
+ register vm_offset_t pa;
+ int bit;
+{
+ register pv_entry_t pv;
+ pt_entry_t *pte;
+ int s;
+
+ if (!pmap_is_managed(pa))
+ return FALSE;
+
+ pv = pa_to_pvh(pa);
+ s = splimp();
+
+ /*
+ * Not found, check current mappings returning
+ * immediately if found.
+ */
+ if (pv->pv_pmap != NULL) {
+ for (; pv; pv = pv->pv_next) {
+ /*
+ * if the bit being tested is the modified bit,
+ * then mark UPAGES as always modified, and
+ * ptes as never modified.
+ */
+ if (bit & PG_U ) {
+ if ((pv->pv_va >= pager_sva) && (pv->pv_va < pager_eva)) {
+ continue;
+ }
+ }
+ if (bit & PG_M ) {
+ if (pv->pv_va >= USRSTACK) {
+ if (pv->pv_va >= pager_sva && pv->pv_va < pager_eva) {
+ continue;
+ }
+ if (pv->pv_va < USRSTACK+(UPAGES*NBPG)) {
+ splx(s);
+ return TRUE;
+ }
+ else if (pv->pv_va < UPT_MAX_ADDRESS) {
+ splx(s);
+ return FALSE;
+ }
+ }
+ }
+ pte = pmap_pte(pv->pv_pmap, pv->pv_va);
+ if ((int) *pte & bit) {
+ splx(s);
+ return TRUE;
+ }
+ }
+ }
+ splx(s);
+ return(FALSE);
+}
+
+/*
+ * this routine is used to modify bits in ptes
+ */
+static inline void
+pmap_changebit(pa, bit, setem)
+ vm_offset_t pa;
+ int bit;
+ boolean_t setem;
+{
+ register pv_entry_t pv;
+ register pt_entry_t *pte, npte;
+ vm_offset_t va;
+ int s;
+
+ if (!pmap_is_managed(pa))
+ return;
+
+ pv = pa_to_pvh(pa);
+ s = splimp();
+
+ /*
+ * Loop over all current mappings setting/clearing as appropos
+ * If setting RO do we need to clear the VAC?
+ */
+ if (pv->pv_pmap != NULL) {
+ for (; pv; pv = pv->pv_next) {
+ va = pv->pv_va;
+
+ /*
+ * don't write protect pager mappings
+ */
+ if (!setem && (bit == PG_RW)) {
+ if (va >= pager_sva && va < pager_eva)
+ continue;
+ }
+
+ pte = pmap_pte(pv->pv_pmap, va);
+ if (setem)
+ (int) npte = (int) *pte | bit;
+ else
+ (int) npte = (int) *pte & ~bit;
+ *pte = npte;
+ }
+ }
+ splx(s);
+ tlbflush();
+}
+
+/*
+ * pmap_page_protect:
+ *
+ * Lower the permission for all mappings to a given page.
+ */
+void
+pmap_page_protect(phys, prot)
+ vm_offset_t phys;
+ vm_prot_t prot;
+{
+ if ((prot & VM_PROT_WRITE) == 0) {
+ if (prot & (VM_PROT_READ | VM_PROT_EXECUTE))
+ pmap_changebit(phys, PG_RW, FALSE);
+ else
+ pmap_remove_all(phys);
+ }
+}
+
+/*
+ * Clear the modify bits on the specified physical page.
+ */
+void
+pmap_clear_modify(pa)
+ vm_offset_t pa;
+{
+ pmap_changebit(pa, PG_M, FALSE);
+}
+
+/*
+ * pmap_clear_reference:
+ *
+ * Clear the reference bit on the specified physical page.
+ */
+void
+pmap_clear_reference(pa)
+ vm_offset_t pa;
+{
+ pmap_changebit(pa, PG_U, FALSE);
+}
+
+/*
+ * pmap_is_referenced:
+ *
+ * Return whether or not the specified physical page is referenced
+ * by any physical maps.
+ */
+
+boolean_t
+pmap_is_referenced(pa)
+ vm_offset_t pa;
+{
+ return(pmap_testbit(pa, PG_U));
+}
+
+/*
+ * pmap_is_modified:
+ *
+ * Return whether or not the specified physical page is modified
+ * by any physical maps.
+ */
+
+boolean_t
+pmap_is_modified(pa)
+ vm_offset_t pa;
+{
+ return(pmap_testbit(pa, PG_M));
+}
+
+/*
+ * Routine: pmap_copy_on_write
+ * Function:
+ * Remove write privileges from all
+ * physical maps for this physical page.
+ */
+void
+pmap_copy_on_write(pa)
+ vm_offset_t pa;
+{
+ pmap_changebit(pa, PG_RW, FALSE);
+}
+
+
+vm_offset_t
+pmap_phys_address(ppn)
+ int ppn;
+{
+ return(i386_ptob(ppn));
+}
+
+/*
+ * Miscellaneous support routines follow
+ */
+
+void
+i386_protection_init()
+{
+ register int *kp, prot;
+
+ kp = protection_codes;
+ for (prot = 0; prot < 8; prot++) {
+ switch (prot) {
+ case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE:
+ *kp++ = 0;
+ break;
+ case VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE:
+ case VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE:
+ case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE:
+ *kp++ = PG_RO;
+ break;
+ case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE:
+ case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE:
+ case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE:
+ case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE:
+ *kp++ = PG_RW;
+ break;
+ }
+ }
+}
+
+#ifdef DEBUG
+void
+pmap_pvdump(pa)
+ vm_offset_t pa;
+{
+ register pv_entry_t pv;
+
+ printf("pa %x", pa);
+ for (pv = pa_to_pvh(pa); pv; pv = pv->pv_next) {
+ printf(" -> pmap %x, va %x, flags %x",
+ pv->pv_pmap, pv->pv_va, pv->pv_flags);
+ pads(pv->pv_pmap);
+ }
+ printf(" ");
+}
+
+/* print address space of pmap*/
+void
+pads(pm)
+ pmap_t pm;
+{
+ unsigned va, i, j;
+ pt_entry_t *ptep;
+
+ if (pm == kernel_pmap) return;
+ for (i = 0; i < 1024; i++)
+ if (pm->pm_pdir[i])
+ for (j = 0; j < 1024 ; j++) {
+ va = (i<<PD_SHIFT)+(j<<PG_SHIFT);
+ if (pm == kernel_pmap && va < KERNBASE)
+ continue;
+ if (pm != kernel_pmap && va > UPT_MAX_ADDRESS)
+ continue;
+ ptep = pmap_pte(pm, va);
+ if (pmap_pte_v(ptep))
+ printf("%x:%x ", va, *(int *)ptep);
+ } ;
+
+}
+#endif
diff --git a/sys/i386/i386/support.s b/sys/i386/i386/support.s
new file mode 100644
index 0000000..e808222
--- /dev/null
+++ b/sys/i386/i386/support.s
@@ -0,0 +1,1153 @@
+/*-
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: support.s,v 1.6 1994/04/02 07:00:29 davidg Exp $
+ */
+
+#include "assym.s" /* system definitions */
+#include "errno.h" /* error return codes */
+#include "machine/asmacros.h" /* miscellaneous asm macros */
+#include "machine/cputypes.h" /* types of CPUs */
+
+#define KDSEL 0x10 /* kernel data selector */
+#define IDXSHIFT 10
+
+/*
+ * Support routines for GCC, general C-callable functions
+ */
+ENTRY(__udivsi3)
+ movl 4(%esp),%eax
+ xorl %edx,%edx
+ divl 8(%esp)
+ ret
+
+ENTRY(__divsi3)
+ movl 4(%esp),%eax
+ cltd
+ idivl 8(%esp)
+ ret
+
+ /*
+ * I/O bus instructions via C
+ */
+ENTRY(inb) /* val = inb(port) */
+ movl 4(%esp),%edx
+ subl %eax,%eax
+ inb %dx,%al
+ NOP
+ ret
+
+ENTRY(inw) /* val = inw(port) */
+ movl 4(%esp),%edx
+ subl %eax,%eax
+ inw %dx,%ax
+ NOP
+ ret
+
+ENTRY(insb) /* insb(port, addr, cnt) */
+ pushl %edi
+ movw 8(%esp),%dx
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ insb
+ NOP
+ movl %edi,%eax
+ popl %edi
+ ret
+
+ENTRY(insw) /* insw(port, addr, cnt) */
+ pushl %edi
+ movw 8(%esp),%dx
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ insw
+ NOP
+ movl %edi,%eax
+ popl %edi
+ ret
+
+ENTRY(insl) /* insl(port, addr, cnt) */
+ pushl %edi
+ movw 8(%esp),%dx
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ insl
+ NOP
+ movl %edi,%eax
+ popl %edi
+ ret
+
+ENTRY(rtcin) /* rtcin(val) */
+ movl 4(%esp),%eax
+ outb %al,$0x70
+ NOP
+ xorl %eax,%eax
+ inb $0x71,%al
+ NOP
+ ret
+
+ENTRY(outb) /* outb(port, val) */
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+ outb %al,%dx
+ NOP
+ ret
+
+ENTRY(outw) /* outw(port, val) */
+ movl 4(%esp),%edx
+ movl 8(%esp),%eax
+ outw %ax,%dx
+ NOP
+ ret
+
+ENTRY(outsb) /* outsb(port, addr, cnt) */
+ pushl %esi
+ movw 8(%esp),%dx
+ movl 12(%esp),%esi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ outsb
+ NOP
+ movl %esi,%eax
+ popl %esi
+ ret
+
+ENTRY(outsw) /* outsw(port, addr, cnt) */
+ pushl %esi
+ movw 8(%esp),%dx
+ movl 12(%esp),%esi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ outsw
+ NOP
+ movl %esi,%eax
+ popl %esi
+ ret
+
+ENTRY(outsl) /* outsl(port, addr, cnt) */
+ pushl %esi
+ movw 8(%esp),%dx
+ movl 12(%esp),%esi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ outsl
+ NOP
+ movl %esi,%eax
+ popl %esi
+ ret
+
+/*
+ * bcopy family
+ */
+/*
+ * void bzero(void *base, u_int cnt)
+ * Special code for I486 because stosl uses lots
+ * of clocks. Makes little or no difference on DX2 type
+ * machines, but about stosl is about 1/2 as fast as
+ * memory moves on standard DX !!!!!
+ */
+
+ENTRY(bzero)
+#if defined(I486_CPU) && (defined(I386_CPU) || defined(I586_CPU))
+ cmpl $CPUCLASS_486,_cpu_class
+ jz 1f
+#endif
+#if defined(I386_CPU) || defined(I586_CPU)
+ pushl %edi
+ movl 8(%esp),%edi
+ movl 12(%esp),%ecx
+ xorl %eax,%eax
+ shrl $2,%ecx
+ cld
+ rep
+ stosl
+ movl 12(%esp),%ecx
+ andl $3,%ecx
+ rep
+ stosb
+ popl %edi
+ ret
+ .align 4
+#endif
+#if defined(I486_CPU)
+1:
+ movl 4(%esp),%edx
+ movl 8(%esp),%ecx
+ xorl %eax,%eax
+/
+/ do 64 byte chunks first
+/
+2:
+ cmpl $64,%ecx
+ jb 3f
+ movl %eax,(%edx)
+ movl %eax,4(%edx)
+ movl %eax,8(%edx)
+ movl %eax,12(%edx)
+ movl %eax,16(%edx)
+ movl %eax,20(%edx)
+ movl %eax,24(%edx)
+ movl %eax,28(%edx)
+ movl %eax,32(%edx)
+ movl %eax,36(%edx)
+ movl %eax,40(%edx)
+ movl %eax,44(%edx)
+ movl %eax,48(%edx)
+ movl %eax,52(%edx)
+ movl %eax,56(%edx)
+ movl %eax,60(%edx)
+ addl $64,%edx
+ subl $64,%ecx
+ jnz 2b
+ ret
+ .align 4
+/
+/ do 16 byte chunks
+/
+3:
+ cmpl $16,%ecx
+ jb 4f
+ movl %eax,(%edx)
+ movl %eax,4(%edx)
+ movl %eax,8(%edx)
+ movl %eax,12(%edx)
+ addl $16,%edx
+ subl $16,%ecx
+ jnz 3b
+ ret
+ .align 4
+/
+/ do 4 byte chunks
+/
+4: cmpl $4,%ecx
+ jb 5f
+ movl %eax,(%edx)
+ addl $4,%edx
+ subl $4,%ecx
+ jnz 4b
+ ret
+/
+/ do 1 byte chunks -- this appears to be faster than a loop
+/
+ .align 4
+jtab: .long do0
+ .long do1
+ .long do2
+ .long do3
+
+ .align 4
+5: jmp jtab(,%ecx,4)
+
+ .align 2
+do3: movb $0,(%edx)
+ incl %edx
+ movw $0,(%edx)
+ ret
+ .align 2
+do2: movw $0,(%edx)
+ ret
+ .align 2
+do1: movb $0,(%edx)
+do0: ret
+
+#endif
+
+/* fillw(pat, base, cnt) */
+ENTRY(fillw)
+ pushl %edi
+ movl 8(%esp),%eax
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ stosw
+ popl %edi
+ ret
+
+/* filli(pat, base, cnt) */
+ENTRY(filli)
+ pushl %edi
+ movl 8(%esp),%eax
+ movl 12(%esp),%edi
+ movl 16(%esp),%ecx
+ cld
+ rep
+ stosl
+ popl %edi
+ ret
+
+ENTRY(bcopyb)
+bcopyb:
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ cmpl %esi,%edi /* potentially overlapping? */
+ jnb 1f
+ cld /* nope, copy forwards */
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ ret
+
+ ALIGN_TEXT
+1:
+ addl %ecx,%edi /* copy backwards. */
+ addl %ecx,%esi
+ std
+ decl %edi
+ decl %esi
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ cld
+ ret
+
+ENTRY(bcopyw)
+bcopyw:
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ cmpl %esi,%edi /* potentially overlapping? */
+ jnb 1f
+ cld /* nope, copy forwards */
+ shrl $1,%ecx /* copy by 16-bit words */
+ rep
+ movsw
+ adc %ecx,%ecx /* any bytes left? */
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ ret
+
+ ALIGN_TEXT
+1:
+ addl %ecx,%edi /* copy backwards */
+ addl %ecx,%esi
+ std
+ andl $1,%ecx /* any fractional bytes? */
+ decl %edi
+ decl %esi
+ rep
+ movsb
+ movl 20(%esp),%ecx /* copy remainder by 16-bit words */
+ shrl $1,%ecx
+ decl %esi
+ decl %edi
+ rep
+ movsw
+ popl %edi
+ popl %esi
+ cld
+ ret
+
+ENTRY(bcopyx)
+ movl 16(%esp),%eax
+ cmpl $2,%eax
+ je bcopyw /* not _bcopyw, to avoid multiple mcounts */
+ cmpl $4,%eax
+ je bcopy /* XXX the shared ret's break mexitcount */
+ jmp bcopyb
+
+/*
+ * (ov)bcopy(src, dst, cnt)
+ * ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
+ */
+ALTENTRY(ovbcopy)
+ENTRY(bcopy)
+bcopy:
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi
+ movl 16(%esp),%edi
+ movl 20(%esp),%ecx
+ cmpl %esi,%edi /* potentially overlapping? */
+ jnb 1f
+ cld /* nope, copy forwards */
+ shrl $2,%ecx /* copy by 32-bit words */
+ rep
+ movsl
+ movl 20(%esp),%ecx
+ andl $3,%ecx /* any bytes left? */
+ rep
+ movsb
+ popl %edi
+ popl %esi
+ ret
+
+ ALIGN_TEXT
+1:
+ addl %ecx,%edi /* copy backwards */
+ addl %ecx,%esi
+ std
+ andl $3,%ecx /* any fractional bytes? */
+ decl %edi
+ decl %esi
+ rep
+ movsb
+ movl 20(%esp),%ecx /* copy remainder by 32-bit words */
+ shrl $2,%ecx
+ subl $3,%esi
+ subl $3,%edi
+ rep
+ movsl
+ popl %edi
+ popl %esi
+ cld
+ ret
+
+ALTENTRY(ntohl)
+ENTRY(htonl)
+ movl 4(%esp),%eax
+#ifdef i486
+/* XXX */
+/* Since Gas 1.38 does not grok bswap this has been coded as the
+ * equivalent bytes. This can be changed back to bswap when we
+ * upgrade to a newer version of Gas
+ */
+ /* bswap %eax */
+ .byte 0x0f
+ .byte 0xc8
+#else
+ xchgb %al,%ah
+ roll $16,%eax
+ xchgb %al,%ah
+#endif
+ ret
+
+ALTENTRY(ntohs)
+ENTRY(htons)
+ movzwl 4(%esp),%eax
+ xchgb %al,%ah
+ ret
+
+/*****************************************************************************/
+/* copyout and fubyte family */
+/*****************************************************************************/
+/*
+ * Access user memory from inside the kernel. These routines and possibly
+ * the math- and DOS emulators should be the only places that do this.
+ *
+ * We have to access the memory with user's permissions, so use a segment
+ * selector with RPL 3. For writes to user space we have to additionally
+ * check the PTE for write permission, because the 386 does not check
+ * write permissions when we are executing with EPL 0. The 486 does check
+ * this if the WP bit is set in CR0, so we can use a simpler version here.
+ *
+ * These routines set curpcb->onfault for the time they execute. When a
+ * protection violation occurs inside the functions, the trap handler
+ * returns to *curpcb->onfault instead of the function.
+ */
+
+
+ENTRY(copyout) /* copyout(from_kernel, to_user, len) */
+ movl _curpcb,%eax
+ movl $copyout_fault,PCB_ONFAULT(%eax)
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+ movl 16(%esp),%esi
+ movl 20(%esp),%edi
+ movl 24(%esp),%ebx
+ orl %ebx,%ebx /* anything to do? */
+ jz done_copyout
+
+ /*
+ * Check explicitly for non-user addresses. If 486 write protection
+ * is being used, this check is essential because we are in kernel
+ * mode so the h/w does not provide any protection against writing
+ * kernel addresses.
+ *
+ * Otherwise, it saves having to load and restore %es to get the
+ * usual segment-based protection (the destination segment for movs
+ * is always %es). The other explicit checks for user-writablility
+ * are not quite sufficient. They fail for the user area because
+ * we mapped the user area read/write to avoid having an #ifdef in
+ * vm_machdep.c. They fail for user PTEs and/or PTDs! (107
+ * addresses including 0xff800000 and 0xfc000000). I'm not sure if
+ * this can be fixed. Marking the PTEs supervisor mode and the
+ * PDE's user mode would almost work, but there may be a problem
+ * with the self-referential PDE.
+ */
+ movl %edi,%eax
+ addl %ebx,%eax
+ jc copyout_fault
+/*
+ * XXX STOP USING VM_MAXUSER_ADDRESS.
+ * It is an end address, not a max, so every time it is used correctly it
+ * looks like there is an off by one error, and of course it caused an off
+ * by one error in several places.
+ */
+ cmpl $VM_MAXUSER_ADDRESS,%eax
+ ja copyout_fault
+
+#if defined(I386_CPU)
+
+#if defined(I486_CPU) || defined(I586_CPU)
+ cmpl $CPUCLASS_386,_cpu_class
+ jne 3f
+#endif
+/*
+ * We have to check each PTE for user write permission.
+ * The checking may cause a page fault, so it is important to set
+ * up everything for return via copyout_fault before here.
+ */
+ /* compute number of pages */
+ movl %edi,%ecx
+ andl $NBPG-1,%ecx
+ addl %ebx,%ecx
+ decl %ecx
+ shrl $IDXSHIFT+2,%ecx
+ incl %ecx
+
+ /* compute PTE offset for start address */
+ movl %edi,%edx
+ shrl $IDXSHIFT,%edx
+ andb $0xfc,%dl
+
+1: /* check PTE for each page */
+ movb _PTmap(%edx),%al
+ andb $0x07,%al /* Pages must be VALID + USERACC + WRITABLE */
+ cmpb $0x07,%al
+ je 2f
+
+ /* simulate a trap */
+ pushl %edx
+ pushl %ecx
+ shll $IDXSHIFT,%edx
+ pushl %edx
+ call _trapwrite /* trapwrite(addr) */
+ popl %edx
+ popl %ecx
+ popl %edx
+
+ orl %eax,%eax /* if not ok, return EFAULT */
+ jnz copyout_fault
+
+2:
+ addl $4,%edx
+ decl %ecx
+ jnz 1b /* check next page */
+#endif /* I386_CPU */
+
+ /* bcopy(%esi, %edi, %ebx) */
+3:
+ cld
+ movl %ebx,%ecx
+ shrl $2,%ecx
+ rep
+ movsl
+ movb %bl,%cl
+ andb $3,%cl
+ rep
+ movsb
+
+done_copyout:
+ popl %ebx
+ popl %edi
+ popl %esi
+ xorl %eax,%eax
+ movl _curpcb,%edx
+ movl %eax,PCB_ONFAULT(%edx)
+ ret
+
+ ALIGN_TEXT
+copyout_fault:
+ popl %ebx
+ popl %edi
+ popl %esi
+ movl _curpcb,%edx
+ movl $0,PCB_ONFAULT(%edx)
+ movl $EFAULT,%eax
+ ret
+
+/* copyin(from_user, to_kernel, len) */
+ENTRY(copyin)
+ movl _curpcb,%eax
+ movl $copyin_fault,PCB_ONFAULT(%eax)
+ pushl %esi
+ pushl %edi
+ movl 12(%esp),%esi /* caddr_t from */
+ movl 16(%esp),%edi /* caddr_t to */
+ movl 20(%esp),%ecx /* size_t len */
+
+ movb %cl,%al
+ shrl $2,%ecx /* copy longword-wise */
+ cld
+ gs
+ rep
+ movsl
+ movb %al,%cl
+ andb $3,%cl /* copy remaining bytes */
+ gs
+ rep
+ movsb
+
+ popl %edi
+ popl %esi
+ xorl %eax,%eax
+ movl _curpcb,%edx
+ movl %eax,PCB_ONFAULT(%edx)
+ ret
+
+ ALIGN_TEXT
+copyin_fault:
+ popl %edi
+ popl %esi
+ movl _curpcb,%edx
+ movl $0,PCB_ONFAULT(%edx)
+ movl $EFAULT,%eax
+ ret
+
+/*
+ * fu{byte,sword,word} : fetch a byte (sword, word) from user memory
+ */
+ALTENTRY(fuiword)
+ENTRY(fuword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx)
+ movl 4(%esp),%edx
+ gs
+ movl (%edx),%eax
+ movl $0,PCB_ONFAULT(%ecx)
+ ret
+
+ENTRY(fusword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx)
+ movl 4(%esp),%edx
+ gs
+ movzwl (%edx),%eax
+ movl $0,PCB_ONFAULT(%ecx)
+ ret
+
+ALTENTRY(fuibyte)
+ENTRY(fubyte)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx)
+ movl 4(%esp),%edx
+ gs
+ movzbl (%edx),%eax
+ movl $0,PCB_ONFAULT(%ecx)
+ ret
+
+ ALIGN_TEXT
+fusufault:
+ movl _curpcb,%ecx
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx)
+ decl %eax
+ ret
+
+/*
+ * su{byte,sword,word}: write a byte (word, longword) to user memory
+ */
+ALTENTRY(suiword)
+ENTRY(suword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx)
+ movl 4(%esp),%edx
+
+#if defined(I386_CPU)
+
+#if defined(I486_CPU) || defined(I586_CPU)
+ cmpl $CPUCLASS_386,_cpu_class
+ jne 2f /* we only have to set the right segment selector */
+#endif /* I486_CPU || I586_CPU */
+
+ /* XXX - page boundary crossing is still not handled */
+ movl %edx,%eax
+ shrl $IDXSHIFT,%edx
+ andb $0xfc,%dl
+ movb _PTmap(%edx),%dl
+ andb $0x7,%dl /* must be VALID + USERACC + WRITE */
+ cmpb $0x7,%dl
+ je 1f
+
+ /* simulate a trap */
+ pushl %eax
+ call _trapwrite
+ popl %edx /* remove junk parameter from stack */
+ movl _curpcb,%ecx /* restore trashed register */
+ orl %eax,%eax
+ jnz fusufault
+1:
+ movl 4(%esp),%edx
+#endif
+
+2:
+ movl 8(%esp),%eax
+ gs
+ movl %eax,(%edx)
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx)
+ ret
+
+ENTRY(susword)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx)
+ movl 4(%esp),%edx
+
+#if defined(I386_CPU)
+
+#if defined(I486_CPU) || defined(I586_CPU)
+ cmpl $CPUCLASS_386,_cpu_class
+ jne 2f
+#endif /* I486_CPU || I586_CPU */
+
+ /* XXX - page boundary crossing is still not handled */
+ movl %edx,%eax
+ shrl $IDXSHIFT,%edx
+ andb $0xfc,%dl
+ movb _PTmap(%edx),%dl
+ andb $0x7,%dl /* must be VALID + USERACC + WRITE */
+ cmpb $0x7,%dl
+ je 1f
+
+ /* simulate a trap */
+ pushl %eax
+ call _trapwrite
+ popl %edx /* remove junk parameter from stack */
+ movl _curpcb,%ecx /* restore trashed register */
+ orl %eax,%eax
+ jnz fusufault
+1:
+ movl 4(%esp),%edx
+#endif
+
+2:
+ movw 8(%esp),%ax
+ gs
+ movw %ax,(%edx)
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx)
+ ret
+
+ALTENTRY(suibyte)
+ENTRY(subyte)
+ movl _curpcb,%ecx
+ movl $fusufault,PCB_ONFAULT(%ecx)
+ movl 4(%esp),%edx
+
+#if defined(I386_CPU)
+
+#if defined(I486_CPU) || defined(I586_CPU)
+ cmpl $CPUCLASS_386,_cpu_class
+ jne 2f
+#endif /* I486_CPU || I586_CPU */
+
+ movl %edx,%eax
+ shrl $IDXSHIFT,%edx
+ andb $0xfc,%dl
+ movb _PTmap(%edx),%dl
+ andb $0x7,%dl /* must be VALID + USERACC + WRITE */
+ cmpb $0x7,%dl
+ je 1f
+
+ /* simulate a trap */
+ pushl %eax
+ call _trapwrite
+ popl %edx /* remove junk parameter from stack */
+ movl _curpcb,%ecx /* restore trashed register */
+ orl %eax,%eax
+ jnz fusufault
+1:
+ movl 4(%esp),%edx
+#endif
+
+2:
+ movb 8(%esp),%al
+ gs
+ movb %al,(%edx)
+ xorl %eax,%eax
+ movl %eax,PCB_ONFAULT(%ecx)
+ ret
+
+/*
+ * copyoutstr(from, to, maxlen, int *lencopied)
+ * copy a string from from to to, stop when a 0 character is reached.
+ * return ENAMETOOLONG if string is longer than maxlen, and
+ * EFAULT on protection violations. If lencopied is non-zero,
+ * return the actual length in *lencopied.
+ */
+ENTRY(copyoutstr)
+ pushl %esi
+ pushl %edi
+ movl _curpcb,%ecx
+ movl $cpystrflt,PCB_ONFAULT(%ecx)
+
+ movl 12(%esp),%esi /* %esi = from */
+ movl 16(%esp),%edi /* %edi = to */
+ movl 20(%esp),%edx /* %edx = maxlen */
+
+#if defined(I386_CPU)
+
+#if defined(I486_CPU) || defined(I586_CPU)
+ cmpl $CPUCLASS_386,_cpu_class
+ jne 5f
+#endif /* I486_CPU || I586_CPU */
+
+1:
+ /*
+ * It suffices to check that the first byte is in user space, because
+ * we look at a page at a time and the end address is on a page
+ * boundary.
+ */
+ cmpl $VM_MAXUSER_ADDRESS,%edi
+ jae cpystrflt
+
+ movl %edi,%eax
+ shrl $IDXSHIFT,%eax
+ andb $0xfc,%al
+ movb _PTmap(%eax),%al
+ andb $7,%al
+ cmpb $7,%al
+ je 2f
+
+ /* simulate trap */
+ pushl %edx
+ pushl %edi
+ call _trapwrite
+ popl %edi
+ popl %edx
+ orl %eax,%eax
+ jnz cpystrflt
+
+2: /* copy up to end of this page */
+ movl %edi,%eax
+ andl $NBPG-1,%eax
+ movl $NBPG,%ecx
+ subl %eax,%ecx /* ecx = NBPG - (src % NBPG) */
+ cmpl %ecx,%edx
+ jae 3f
+ movl %edx,%ecx /* ecx = min(ecx, edx) */
+3:
+ orl %ecx,%ecx
+ jz 4f
+ decl %ecx
+ decl %edx
+ lodsb
+ stosb
+ orb %al,%al
+ jnz 3b
+
+ /* Success -- 0 byte reached */
+ decl %edx
+ xorl %eax,%eax
+ jmp 6f
+
+4: /* next page */
+ orl %edx,%edx
+ jnz 1b
+
+ /* edx is zero -- return ENAMETOOLONG */
+ movl $ENAMETOOLONG,%eax
+ jmp cpystrflt_x
+#endif /* I386_CPU */
+
+#if defined(I486_CPU) || defined(I586_CPU)
+5:
+ incl %edx
+1:
+ decl %edx
+ jz 2f
+ /*
+ * gs override doesn't work for stosb. Use the same explicit check
+ * as in copyout(). It's much slower now because it is per-char.
+ * XXX - however, it would be faster to rewrite this function to use
+ * strlen() and copyout().
+ */
+ cmpl $VM_MAXUSER_ADDRESS,%edi
+ jae cpystrflt
+
+ lodsb
+ stosb
+ orb %al,%al
+ jnz 1b
+
+ /* Success -- 0 byte reached */
+ decl %edx
+ xorl %eax,%eax
+ jmp cpystrflt_x
+2:
+ /* edx is zero -- return ENAMETOOLONG */
+ movl $ENAMETOOLONG,%eax
+ jmp cpystrflt_x
+
+#endif /* I486_CPU || I586_CPU */
+
+/*
+ * copyinstr(from, to, maxlen, int *lencopied)
+ * copy a string from from to to, stop when a 0 character is reached.
+ * return ENAMETOOLONG if string is longer than maxlen, and
+ * EFAULT on protection violations. If lencopied is non-zero,
+ * return the actual length in *lencopied.
+ */
+ENTRY(copyinstr)
+ pushl %esi
+ pushl %edi
+ movl _curpcb,%ecx
+ movl $cpystrflt,PCB_ONFAULT(%ecx)
+
+ movl 12(%esp),%esi /* %esi = from */
+ movl 16(%esp),%edi /* %edi = to */
+ movl 20(%esp),%edx /* %edx = maxlen */
+ incl %edx
+
+1:
+ decl %edx
+ jz 4f
+ gs
+ lodsb
+ stosb
+ orb %al,%al
+ jnz 1b
+
+ /* Success -- 0 byte reached */
+ decl %edx
+ xorl %eax,%eax
+ jmp 6f
+4:
+ /* edx is zero -- return ENAMETOOLONG */
+ movl $ENAMETOOLONG,%eax
+ jmp 6f
+
+cpystrflt:
+ movl $EFAULT,%eax
+cpystrflt_x:
+6:
+ /* set *lencopied and return %eax */
+ movl _curpcb,%ecx
+ movl $0,PCB_ONFAULT(%ecx)
+ movl 20(%esp),%ecx
+ subl %edx,%ecx
+ movl 24(%esp),%edx
+ orl %edx,%edx
+ jz 7f
+ movl %ecx,(%edx)
+7:
+ popl %edi
+ popl %esi
+ ret
+
+
+/*
+ * copystr(from, to, maxlen, int *lencopied)
+ */
+ENTRY(copystr)
+ pushl %esi
+ pushl %edi
+
+ movl 12(%esp),%esi /* %esi = from */
+ movl 16(%esp),%edi /* %edi = to */
+ movl 20(%esp),%edx /* %edx = maxlen */
+ incl %edx
+
+1:
+ decl %edx
+ jz 4f
+ lodsb
+ stosb
+ orb %al,%al
+ jnz 1b
+
+ /* Success -- 0 byte reached */
+ decl %edx
+ xorl %eax,%eax
+ jmp 6f
+4:
+ /* edx is zero -- return ENAMETOOLONG */
+ movl $ENAMETOOLONG,%eax
+
+6:
+ /* set *lencopied and return %eax */
+ movl 20(%esp),%ecx
+ subl %edx,%ecx
+ movl 24(%esp),%edx
+ orl %edx,%edx
+ jz 7f
+ movl %ecx,(%edx)
+7:
+ popl %edi
+ popl %esi
+ ret
+
+/*
+ * Handling of special 386 registers and descriptor tables etc
+ */
+/* void lgdt(struct region_descriptor *rdp); */
+ENTRY(lgdt)
+ /* reload the descriptor table */
+ movl 4(%esp),%eax
+ lgdt (%eax)
+
+ /* flush the prefetch q */
+ jmp 1f
+ nop
+1:
+ /* reload "stale" selectors */
+ movl $KDSEL,%eax
+ movl %ax,%ds
+ movl %ax,%es
+ movl %ax,%ss
+
+ /* reload code selector by turning return into intersegmental return */
+ movl (%esp),%eax
+ pushl %eax
+# movl $KCSEL,4(%esp)
+ movl $8,4(%esp)
+ lret
+
+/*
+ * void lidt(struct region_descriptor *rdp);
+ */
+ENTRY(lidt)
+ movl 4(%esp),%eax
+ lidt (%eax)
+ ret
+
+/*
+ * void lldt(u_short sel)
+ */
+ENTRY(lldt)
+ lldt 4(%esp)
+ ret
+
+/*
+ * void ltr(u_short sel)
+ */
+ENTRY(ltr)
+ ltr 4(%esp)
+ ret
+
+/* ssdtosd(*ssdp,*sdp) */
+ENTRY(ssdtosd)
+ pushl %ebx
+ movl 8(%esp),%ecx
+ movl 8(%ecx),%ebx
+ shll $16,%ebx
+ movl (%ecx),%edx
+ roll $16,%edx
+ movb %dh,%bl
+ movb %dl,%bh
+ rorl $8,%ebx
+ movl 4(%ecx),%eax
+ movw %ax,%dx
+ andl $0xf0000,%eax
+ orl %eax,%ebx
+ movl 12(%esp),%ecx
+ movl %edx,(%ecx)
+ movl %ebx,4(%ecx)
+ popl %ebx
+ ret
+
+#if 0
+/* tlbflush() */
+ENTRY(tlbflush)
+ movl %cr3,%eax
+ orl $I386_CR3PAT,%eax
+ movl %eax,%cr3
+ ret
+#endif
+
+/* load_cr0(cr0) */
+ENTRY(load_cr0)
+ movl 4(%esp),%eax
+ movl %eax,%cr0
+ ret
+
+/* rcr0() */
+ENTRY(rcr0)
+ movl %cr0,%eax
+ ret
+
+/* rcr2() */
+ENTRY(rcr2)
+ movl %cr2,%eax
+ ret
+
+/* rcr3() */
+ENTRY(rcr3)
+ movl %cr3,%eax
+ ret
+
+/* void load_cr3(caddr_t cr3) */
+ENTRY(load_cr3)
+ movl 4(%esp),%eax
+ orl $I386_CR3PAT,%eax
+ movl %eax,%cr3
+ ret
+
+
+/*****************************************************************************/
+/* setjump, longjump */
+/*****************************************************************************/
+
+ENTRY(setjmp)
+ movl 4(%esp),%eax
+ movl %ebx,(%eax) /* save ebx */
+ movl %esp,4(%eax) /* save esp */
+ movl %ebp,8(%eax) /* save ebp */
+ movl %esi,12(%eax) /* save esi */
+ movl %edi,16(%eax) /* save edi */
+ movl (%esp),%edx /* get rta */
+ movl %edx,20(%eax) /* save eip */
+ xorl %eax,%eax /* return(0); */
+ ret
+
+ENTRY(longjmp)
+ movl 4(%esp),%eax
+ movl (%eax),%ebx /* restore ebx */
+ movl 4(%eax),%esp /* restore esp */
+ movl 8(%eax),%ebp /* restore ebp */
+ movl 12(%eax),%esi /* restore esi */
+ movl 16(%eax),%edi /* restore edi */
+ movl 20(%eax),%edx /* get rta */
+ movl %edx,(%esp) /* put in return frame */
+ xorl %eax,%eax /* return(1); */
+ incl %eax
+ ret
diff --git a/sys/i386/i386/swapgeneric.c b/sys/i386/i386/swapgeneric.c
new file mode 100644
index 0000000..b987afb
--- /dev/null
+++ b/sys/i386/i386/swapgeneric.c
@@ -0,0 +1,169 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)swapgeneric.c 5.5 (Berkeley) 5/9/91
+ * $Id: swapgeneric.c,v 1.2 1993/10/16 14:15:09 rgrimes Exp $
+ */
+
+#include "machine/pte.h"
+
+#include "sys/param.h"
+#include "sys/conf.h"
+#include "sys/buf.h"
+#include "sys/vm.h"
+#include "sys/systm.h"
+#include "sys/reboot.h"
+
+/*
+ * Generic configuration; all in one
+ */
+dev_t rootdev = makedev(0,0);
+dev_t dumpdev = makedev(0,1);
+int nswap;
+struct swdevt swdevt[] = {
+ { 1, 0, 0 },
+ { 0, 1, 0 },
+};
+long dumplo;
+int dmmin, dmmax, dmtext;
+
+extern struct driver wddriver;
+extern struct driver wxdriver;
+
+struct genericconf {
+ caddr_t gc_driver;
+ char *gc_name;
+ dev_t gc_root;
+} genericconf[] = {
+ { (caddr_t)&wddriver, "wd", makedev(0, 0), },
+ { (caddr_t)&wxdriver, "wx", makedev(0, 0), },
+ { 0 },
+};
+
+setconf()
+{
+#ifdef notdef
+ register struct genericconf *gc;
+ int unit, swaponroot = 0;
+
+ if (rootdev != NODEV)
+ goto doswap;
+ if (boothowto & RB_ASKNAME) {
+ char name[128];
+retry:
+ printf("root device? ");
+ gets(name);
+ for (gc = genericconf; gc->gc_driver; gc++)
+ if (gc->gc_name[0] == name[0] &&
+ gc->gc_name[1] == name[1])
+ goto gotit;
+ goto bad;
+gotit:
+ if (name[3] == '*') {
+ name[3] = name[4];
+ swaponroot++;
+ }
+ if (name[2] >= '0' && name[2] <= '7' && name[3] == 0) {
+ unit = name[2] - '0';
+ goto found;
+ }
+ printf("bad/missing unit number\n");
+bad:
+ printf("use dk%%d\n");
+ goto retry;
+ }
+ unit = 0;
+ for (gc = genericconf; gc->gc_driver; gc++) {
+ for (ui = vbdinit; ui->ui_driver; ui++) {
+ if (ui->ui_alive == 0)
+ continue;
+ if (ui->ui_unit == 0 && ui->ui_driver ==
+ (struct vba_driver *)gc->gc_driver) {
+ printf("root on %s0\n",
+ ui->ui_driver->ud_dname);
+ goto found;
+ }
+ }
+ }
+ printf("no suitable root\n");
+ asm("halt");
+found:
+ gc->gc_root = makedev(major(gc->gc_root), unit*8);
+ rootdev = gc->gc_root;
+doswap:
+ swdevt[0].sw_dev = argdev = dumpdev =
+ makedev(major(rootdev), minor(rootdev)+1);
+ /* swap size and dumplo set during autoconfigure */
+ if (swaponroot)
+ rootdev = dumpdev;
+#endif
+}
+
+gets(cp)
+ char *cp;
+{
+ register char *lp;
+ register c;
+
+ lp = cp;
+ for (;;) {
+ printf("%c", c = cngetc()&0177);
+ switch (c) {
+ case '\n':
+ case '\r':
+ *lp++ = '\0';
+ return;
+ case '\b':
+ case '\177':
+ if (lp > cp) {
+ printf(" \b");
+ lp--;
+ }
+ continue;
+ case '#':
+ lp--;
+ if (lp < cp)
+ lp = cp;
+ continue;
+ case '@':
+ case 'u'&037:
+ lp = cp;
+ printf("%c", '\n');
+ continue;
+ default:
+ *lp++ = c;
+ }
+ }
+}
diff --git a/sys/i386/i386/swtch.s b/sys/i386/i386/swtch.s
new file mode 100644
index 0000000..4dbc672
--- /dev/null
+++ b/sys/i386/i386/swtch.s
@@ -0,0 +1,458 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: swtch.s,v 1.5 1994/04/02 07:00:30 davidg Exp $
+ */
+
+#include "npx.h" /* for NNPX */
+#include "assym.s" /* for preprocessor defines */
+#include "errno.h" /* for error codes */
+
+#include "machine/asmacros.h" /* for miscellaneous assembly macros */
+#define LOCORE /* XXX inhibit C declarations */
+#include "machine/spl.h" /* for SWI_AST_MASK ... */
+
+
+/*****************************************************************************/
+/* Scheduling */
+/*****************************************************************************/
+
+/*
+ * The following primitives manipulate the run queues.
+ * _whichqs tells which of the 32 queues _qs
+ * have processes in them. Setrq puts processes into queues, Remrq
+ * removes them from queues. The running process is on no queue,
+ * other processes are on a queue related to p->p_pri, divided by 4
+ * actually to shrink the 0-127 range of priorities into the 32 available
+ * queues.
+ */
+ .data
+ .globl _curpcb, _whichqs
+_curpcb: .long 0 /* pointer to curproc's PCB area */
+_whichqs: .long 0 /* which run queues have data */
+
+ .globl _qs,_cnt,_panic
+ .comm _noproc,4
+ .comm _runrun,4
+
+ .globl _want_resched
+_want_resched: .long 0 /* we need to re-run the scheduler */
+
+ .text
+/*
+ * Setrq(p)
+ *
+ * Call should be made at spl6(), and p->p_stat should be SRUN
+ */
+ENTRY(setrq)
+ movl 4(%esp),%eax
+ cmpl $0,P_RLINK(%eax) /* should not be on q already */
+ je set1
+ pushl $set2
+ call _panic
+set1:
+ movzbl P_PRI(%eax),%edx
+ shrl $2,%edx
+ btsl %edx,_whichqs /* set q full bit */
+ shll $3,%edx
+ addl $_qs,%edx /* locate q hdr */
+ movl %edx,P_LINK(%eax) /* link process on tail of q */
+ movl P_RLINK(%edx),%ecx
+ movl %ecx,P_RLINK(%eax)
+ movl %eax,P_RLINK(%edx)
+ movl %eax,P_LINK(%ecx)
+ ret
+
+set2: .asciz "setrq"
+
+/*
+ * Remrq(p)
+ *
+ * Call should be made at spl6().
+ */
+ENTRY(remrq)
+ movl 4(%esp),%eax
+ movzbl P_PRI(%eax),%edx
+ shrl $2,%edx
+ btrl %edx,_whichqs /* clear full bit, panic if clear already */
+ jb rem1
+ pushl $rem3
+ call _panic
+rem1:
+ pushl %edx
+ movl P_LINK(%eax),%ecx /* unlink process */
+ movl P_RLINK(%eax),%edx
+ movl %edx,P_RLINK(%ecx)
+ movl P_RLINK(%eax),%ecx
+ movl P_LINK(%eax),%edx
+ movl %edx,P_LINK(%ecx)
+ popl %edx
+ movl $_qs,%ecx
+ shll $3,%edx
+ addl %edx,%ecx
+ cmpl P_LINK(%ecx),%ecx /* q still has something? */
+ je rem2
+ shrl $3,%edx /* yes, set bit as still full */
+ btsl %edx,_whichqs
+rem2:
+ movl $0,P_RLINK(%eax) /* zap reverse link to indicate off list */
+ ret
+
+rem3: .asciz "remrq"
+sw0: .asciz "swtch"
+
+/*
+ * When no processes are on the runq, swtch() branches to _idle
+ * to wait for something to come ready.
+ */
+ ALIGN_TEXT
+_idle:
+ MCOUNT
+ movl _IdlePTD,%ecx
+ movl %ecx,%cr3
+ movl $tmpstk-4,%esp
+ sti
+
+ /*
+ * XXX callers of swtch() do a bogus splclock(). Locking should
+ * be left to swtch().
+ */
+ movl $SWI_AST_MASK,_cpl
+ testl $~SWI_AST_MASK,_ipending
+ je idle_loop
+ call _splz
+
+ ALIGN_TEXT
+idle_loop:
+ cli
+ cmpl $0,_whichqs
+ jne sw1a
+ sti
+ hlt /* wait for interrupt */
+ jmp idle_loop
+
+badsw:
+ pushl $sw0
+ call _panic
+ /*NOTREACHED*/
+
+/*
+ * Swtch()
+ */
+ENTRY(swtch)
+ incl _cnt+V_SWTCH
+
+ /* switch to new process. first, save context as needed */
+
+ movl _curproc,%ecx
+
+ /* if no process to save, don't bother */
+ testl %ecx,%ecx
+ je sw1
+
+ movl P_ADDR(%ecx),%ecx
+
+ movl (%esp),%eax /* Hardware registers */
+ movl %eax,PCB_EIP(%ecx)
+ movl %ebx,PCB_EBX(%ecx)
+ movl %esp,PCB_ESP(%ecx)
+ movl %ebp,PCB_EBP(%ecx)
+ movl %esi,PCB_ESI(%ecx)
+ movl %edi,PCB_EDI(%ecx)
+
+#if NNPX > 0
+ /* have we used fp, and need a save? */
+ mov _curproc,%eax
+ cmp %eax,_npxproc
+ jne 1f
+ pushl %ecx /* h/w bugs make saving complicated */
+ leal PCB_SAVEFPU(%ecx),%eax
+ pushl %eax
+ call _npxsave /* do it in a big C function */
+ popl %eax
+ popl %ecx
+1:
+#endif /* NNPX > 0 */
+
+ movl _CMAP2,%eax /* save temporary map PTE */
+ movl %eax,PCB_CMAP2(%ecx) /* in our context */
+ movl $0,_curproc /* out of process */
+
+# movw _cpl,%ax
+# movw %ax,PCB_IML(%ecx) /* save ipl */
+
+ /* save is done, now choose a new process or idle */
+sw1:
+ cli
+sw1a:
+ movl _whichqs,%edi
+2:
+ /* XXX - bsf is sloow */
+ bsfl %edi,%eax /* find a full q */
+ je _idle /* if none, idle */
+
+ /* XX update whichqs? */
+ btrl %eax,%edi /* clear q full status */
+ jnb 2b /* if it was clear, look for another */
+ movl %eax,%ebx /* save which one we are using */
+
+ shll $3,%eax
+ addl $_qs,%eax /* select q */
+ movl %eax,%esi
+
+#ifdef DIAGNOSTIC
+ cmpl P_LINK(%eax),%eax /* linked to self? (e.g. not on list) */
+ je badsw /* not possible */
+#endif
+
+ movl P_LINK(%eax),%ecx /* unlink from front of process q */
+ movl P_LINK(%ecx),%edx
+ movl %edx,P_LINK(%eax)
+ movl P_RLINK(%ecx),%eax
+ movl %eax,P_RLINK(%edx)
+
+ cmpl P_LINK(%ecx),%esi /* q empty */
+ je 3f
+ btsl %ebx,%edi /* nope, set to indicate full */
+3:
+ movl %edi,_whichqs /* update q status */
+
+ movl $0,%eax
+ movl %eax,_want_resched
+
+#ifdef DIAGNOSTIC
+ cmpl %eax,P_WCHAN(%ecx)
+ jne badsw
+ cmpb $SRUN,P_STAT(%ecx)
+ jne badsw
+#endif
+
+ movl %eax,P_RLINK(%ecx) /* isolate process to run */
+ movl P_ADDR(%ecx),%edx
+ movl PCB_CR3(%edx),%ebx
+
+ /* switch address space */
+ movl %ebx,%cr3
+
+ /* restore context */
+ movl PCB_EBX(%edx),%ebx
+ movl PCB_ESP(%edx),%esp
+ movl PCB_EBP(%edx),%ebp
+ movl PCB_ESI(%edx),%esi
+ movl PCB_EDI(%edx),%edi
+ movl PCB_EIP(%edx),%eax
+ movl %eax,(%esp)
+
+ movl PCB_CMAP2(%edx),%eax /* get temporary map */
+ movl %eax,_CMAP2 /* reload temporary map PTE */
+
+ movl %ecx,_curproc /* into next process */
+ movl %edx,_curpcb
+
+#ifdef USER_LDT
+ cmpl $0, PCB_USERLDT(%edx)
+ jnz 1f
+ movl __default_ldt,%eax
+ cmpl _currentldt,%eax
+ je 2f
+ lldt __default_ldt
+ movl %eax,_currentldt
+ jmp 2f
+1: pushl %edx
+ call _set_user_ldt
+ popl %edx
+2:
+#endif
+
+ pushl %edx /* save p to return */
+/*
+ * XXX - 0.0 forgot to save it - is that why this was commented out in 0.1?
+ * I think restoring the cpl is unnecessary, but we must turn off the cli
+ * now that spl*() don't do it as a side affect.
+ */
+ pushl PCB_IML(%edx)
+ sti
+#if 0
+ call _splx
+#endif
+ addl $4,%esp
+/*
+ * XXX - 0.0 gets here via swtch_to_inactive(). I think 0.1 gets here in the
+ * same way. Better return a value.
+ */
+ popl %eax /* return(p); */
+ ret
+
+ENTRY(mvesp)
+ movl %esp,%eax
+ ret
+/*
+ * struct proc *swtch_to_inactive(struct proc *p);
+ *
+ * At exit of a process, move off the address space of the
+ * process and onto a "safe" one. Then, on a temporary stack
+ * return and run code that disposes of the old state.
+ * Since this code requires a parameter from the "old" stack,
+ * pass it back as a return value.
+ */
+ENTRY(swtch_to_inactive)
+ popl %edx /* old pc */
+ popl %eax /* arg, our return value */
+ movl _IdlePTD,%ecx
+ movl %ecx,%cr3 /* good bye address space */
+ #write buffer?
+ movl $tmpstk-4,%esp /* temporary stack, compensated for call */
+ MEXITCOUNT
+ jmp %edx /* return, execute remainder of cleanup */
+
+/*
+ * savectx(pcb, altreturn)
+ * Update pcb, saving current processor state and arranging
+ * for alternate return ala longjmp in swtch if altreturn is true.
+ */
+ENTRY(savectx)
+ movl 4(%esp),%ecx
+ movw _cpl,%ax
+ movw %ax,PCB_IML(%ecx)
+ movl (%esp),%eax
+ movl %eax,PCB_EIP(%ecx)
+ movl %ebx,PCB_EBX(%ecx)
+ movl %esp,PCB_ESP(%ecx)
+ movl %ebp,PCB_EBP(%ecx)
+ movl %esi,PCB_ESI(%ecx)
+ movl %edi,PCB_EDI(%ecx)
+
+#if NNPX > 0
+ /*
+ * If npxproc == NULL, then the npx h/w state is irrelevant and the
+ * state had better already be in the pcb. This is true for forks
+ * but not for dumps (the old book-keeping with FP flags in the pcb
+ * always lost for dumps because the dump pcb has 0 flags).
+ *
+ * If npxproc != NULL, then we have to save the npx h/w state to
+ * npxproc's pcb and copy it to the requested pcb, or save to the
+ * requested pcb and reload. Copying is easier because we would
+ * have to handle h/w bugs for reloading. We used to lose the
+ * parent's npx state for forks by forgetting to reload.
+ */
+ mov _npxproc,%eax
+ testl %eax,%eax
+ je 1f
+
+ pushl %ecx
+ movl P_ADDR(%eax),%eax
+ leal PCB_SAVEFPU(%eax),%eax
+ pushl %eax
+ pushl %eax
+ call _npxsave
+ popl %eax
+ popl %eax
+ popl %ecx
+
+ pushl %ecx
+ pushl $108+8*2 /* XXX h/w state size + padding */
+ leal PCB_SAVEFPU(%ecx),%ecx
+ pushl %ecx
+ pushl %eax
+ call _bcopy
+ addl $12,%esp
+ popl %ecx
+1:
+#endif /* NNPX > 0 */
+
+ movl _CMAP2,%edx /* save temporary map PTE */
+ movl %edx,PCB_CMAP2(%ecx) /* in our context */
+
+ cmpl $0,8(%esp)
+ je 1f
+ movl %esp,%edx /* relocate current sp relative to pcb */
+ subl $_kstack,%edx /* (sp is relative to kstack): */
+ addl %edx,%ecx /* pcb += sp - kstack; */
+ movl %eax,(%ecx) /* write return pc at (relocated) sp@ */
+
+/* this mess deals with replicating register state gcc hides */
+ movl 12(%esp),%eax
+ movl %eax,12(%ecx)
+ movl 16(%esp),%eax
+ movl %eax,16(%ecx)
+ movl 20(%esp),%eax
+ movl %eax,20(%ecx)
+ movl 24(%esp),%eax
+ movl %eax,24(%ecx)
+1:
+ xorl %eax,%eax /* return 0 */
+ ret
+
+/*
+ * addupc(int pc, struct uprof *up, int ticks):
+ * update profiling information for the user process.
+ */
+ENTRY(addupc)
+ pushl %ebp
+ movl %esp,%ebp
+ movl 12(%ebp),%edx /* up */
+ movl 8(%ebp),%eax /* pc */
+
+ subl PR_OFF(%edx),%eax /* pc -= up->pr_off */
+ jb L1 /* if (pc was < off) return */
+
+ shrl $1,%eax /* praddr = pc >> 1 */
+ imull PR_SCALE(%edx),%eax /* praddr *= up->pr_scale */
+ shrl $15,%eax /* praddr = praddr << 15 */
+ andl $-2,%eax /* praddr &= ~1 */
+
+ cmpl PR_SIZE(%edx),%eax /* if (praddr > up->pr_size) return */
+ ja L1
+
+/* addl %eax,%eax /* praddr -> word offset */
+ addl PR_BASE(%edx),%eax /* praddr += up-> pr_base */
+ movl 16(%ebp),%ecx /* ticks */
+
+ movl _curpcb,%edx
+ movl $proffault,PCB_ONFAULT(%edx)
+ addl %ecx,(%eax) /* storage location += ticks */
+ movl $0,PCB_ONFAULT(%edx)
+L1:
+ leave
+ ret
+
+ ALIGN_TEXT
+proffault:
+ /* if we get a fault, then kill profiling all together */
+ movl $0,PCB_ONFAULT(%edx) /* squish the fault handler */
+ movl 12(%ebp),%ecx
+ movl $0,PR_SCALE(%ecx) /* up->pr_scale = 0 */
+ leave
+ ret
diff --git a/sys/i386/i386/symbols.raw b/sys/i386/i386/symbols.raw
new file mode 100644
index 0000000..0f5bafd
--- /dev/null
+++ b/sys/i386/i386/symbols.raw
@@ -0,0 +1,84 @@
+# @(#)symbols.raw 7.6 (Berkeley) 5/8/91
+#
+# $Id$
+#
+
+
+#gdb
+ _IdlePTD
+ _PTD
+ _curpcb
+ _kstack
+ _panicstr
+ _atdevbase
+# _version
+#dmesg
+ _msgbufp
+# _msgbuf
+#iostat
+ _dk_busy
+ _dk_time
+ _dk_xfer
+ _dk_wds
+ _tk_nin
+ _tk_nout
+ _dk_seek
+ _cp_time
+ _dk_wpms
+# _io_info
+#ps
+ _nswap
+ _maxslp
+ _ccpu
+ _fscale
+ _avail_start
+ _avail_end
+#pstat
+# _cons
+ _nswap
+ _swapmap
+#vmstat
+ _cp_time
+ _rate
+ _total
+ _sum
+# _rectime
+# _pgintime
+ _dk_xfer
+ _boottime
+#w
+ _swapdev
+ _nswap
+ _averunnable
+ _boottime
+#netstat
+ _mbstat
+ _ipstat
+ _tcb
+ _tcpstat
+ _udb
+ _udpstat
+ _rawcb
+ _Sysmap
+ _ifnet
+ _rthost
+ _rtnet
+ _icmpstat
+ _filehead
+ _nfiles
+ _rthashsize
+ _radix_node_head
+#routed
+ _ifnet
+#rwho
+ _boottime
+#savecore
+ _dumpdev
+ _dumplo
+ _version
+ _time
+ _dumpsize
+ _panicstr
+ _dumpmag
+#deprecated
+# _avenrun
diff --git a/sys/i386/i386/sys_machdep.c b/sys/i386/i386/sys_machdep.c
new file mode 100644
index 0000000..92758ad
--- /dev/null
+++ b/sys/i386/i386/sys_machdep.c
@@ -0,0 +1,328 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)sys_machdep.c 5.5 (Berkeley) 1/19/91
+ * $Id: sys_machdep.c,v 1.3 1993/10/16 14:15:10 rgrimes Exp $
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "ioctl.h"
+#include "file.h"
+#include "time.h"
+#include "proc.h"
+#include "uio.h"
+#include "kernel.h"
+#include "mtio.h"
+#include "buf.h"
+#include "trace.h"
+
+#ifdef USER_LDT
+#include "user.h"
+#include "machine/cpu.h"
+#include "machine/sysarch.h"
+#include "vm/vm_kern.h" /* for kernel_map */
+#endif
+
+#ifdef TRACE
+int nvualarm;
+
+struct vtrace_args {
+ int request;
+ int value;
+};
+
+vtrace(p, uap, retval)
+ struct proc *p;
+ register struct vtrace_args *uap;
+ int *retval;
+{
+ int vdoualarm();
+
+ switch (uap->request) {
+
+ case VTR_DISABLE: /* disable a trace point */
+ case VTR_ENABLE: /* enable a trace point */
+ if (uap->value < 0 || uap->value >= TR_NFLAGS)
+ return (EINVAL);
+ *retval = traceflags[uap->value];
+ traceflags[uap->value] = uap->request;
+ break;
+
+ case VTR_VALUE: /* return a trace point setting */
+ if (uap->value < 0 || uap->value >= TR_NFLAGS)
+ return (EINVAL);
+ *retval = traceflags[uap->value];
+ break;
+
+ case VTR_UALARM: /* set a real-time ualarm, less than 1 min */
+ if (uap->value <= 0 || uap->value > 60 * hz || nvualarm > 5)
+ return (EINVAL);
+ nvualarm++;
+ timeout(vdoualarm, (caddr_t)p->p_pid, uap->value);
+ break;
+
+ case VTR_STAMP:
+ trace(TR_STAMP, uap->value, p->p_pid);
+ break;
+ }
+ return (0);
+}
+
+vdoualarm(arg)
+ int arg;
+{
+ register struct proc *p;
+
+ p = pfind(arg);
+ if (p)
+ psignal(p, 16);
+ nvualarm--;
+}
+#endif
+
+#ifdef USER_LDT
+void
+set_user_ldt(struct pcb *pcb)
+{
+ gdt_segs[GUSERLDT_SEL].ssd_base = (unsigned)pcb->pcb_ldt;
+ gdt_segs[GUSERLDT_SEL].ssd_limit = (pcb->pcb_ldt_len * sizeof(union descriptor)) - 1;
+ ssdtosd(gdt_segs+GUSERLDT_SEL, gdt+GUSERLDT_SEL);
+ lldt(GSEL(GUSERLDT_SEL, SEL_KPL));
+ currentldt = GSEL(GUSERLDT_SEL, SEL_KPL);
+}
+
+struct i386_get_ldt_args {
+ int start;
+ union descriptor *desc;
+ int num;
+};
+
+int
+i386_get_ldt(p, args, retval)
+ struct proc *p;
+ char *args;
+ int *retval;
+{
+ int error = 0;
+ struct pcb *pcb = &p->p_addr->u_pcb;
+ int nldt, num;
+ union descriptor *lp;
+ int s;
+ struct i386_get_ldt_args ua, *uap;
+
+ if ((error = copyin(args, &ua, sizeof(struct i386_get_ldt_args))) < 0)
+ return(error);
+
+ uap = &ua;
+#ifdef DEBUG
+ printf("i386_get_ldt: start=%d num=%d descs=%x\n", uap->start, uap->num, uap->desc);
+#endif
+
+ if (uap->start < 0 || uap->num < 0)
+ return(EINVAL);
+
+ s = splhigh();
+
+ if (pcb->pcb_ldt) {
+ nldt = pcb->pcb_ldt_len;
+ num = min(uap->num, nldt);
+ lp = &((union descriptor *)(pcb->pcb_ldt))[uap->start];
+ } else {
+ nldt = sizeof(ldt)/sizeof(ldt[0]);
+ num = min(uap->num, nldt);
+ lp = &ldt[uap->start];
+ }
+ if (uap->start > nldt) {
+ splx(s);
+ return(EINVAL);
+ }
+
+ error = copyout(lp, uap->desc, num * sizeof(union descriptor));
+ if (!error)
+ *retval = num;
+
+ splx(s);
+ return(error);
+}
+
+struct i386_set_ldt_args {
+ int start;
+ union descriptor *desc;
+ int num;
+};
+
+int
+i386_set_ldt(p, args, retval)
+ struct proc *p;
+ char *args;
+ int *retval;
+{
+ int error = 0, i, n;
+ struct pcb *pcb = &p->p_addr->u_pcb;
+ union descriptor *lp;
+ int s;
+ struct i386_set_ldt_args ua, *uap;
+
+ if ((error = copyin(args, &ua, sizeof(struct i386_set_ldt_args))) < 0)
+ return(error);
+
+ uap = &ua;
+
+#ifdef DEBUG
+ printf("i386_set_ldt: start=%d num=%d descs=%x\n", uap->start, uap->num, uap->desc);
+#endif
+
+ if (uap->start < 0 || uap->num < 0)
+ return(EINVAL);
+
+ /* XXX Should be 8192 ! */
+ if (uap->start > 512 ||
+ (uap->start + uap->num) > 512)
+ return(EINVAL);
+
+ /* allocate user ldt */
+ if (!pcb->pcb_ldt) {
+ union descriptor *new_ldt =
+ (union descriptor *)kmem_alloc(kernel_map, 512*sizeof(union descriptor));
+ bzero(new_ldt, 512*sizeof(union descriptor));
+ bcopy(ldt, new_ldt, sizeof(ldt));
+ pcb->pcb_ldt = (caddr_t)new_ldt;
+ pcb->pcb_ldt_len = 512; /* XXX need to grow */
+#ifdef DEBUG
+ printf("i386_set_ldt(%d): new_ldt=%x\n", p->p_pid, new_ldt);
+#endif
+ }
+
+ /* Check descriptors for access violations */
+ for (i = 0, n = uap->start; i < uap->num; i++, n++) {
+ union descriptor desc, *dp;
+ dp = &uap->desc[i];
+ error = copyin(dp, &desc, sizeof(union descriptor));
+ if (error)
+ return(error);
+
+ /* Only user (ring-3) descriptors */
+ if (desc.sd.sd_dpl != SEL_UPL)
+ return(EACCES);
+
+ /* Must be "present" */
+ if (desc.sd.sd_p == 0)
+ return(EACCES);
+
+ switch (desc.sd.sd_type) {
+ case SDT_SYSNULL:
+ case SDT_SYS286CGT:
+ case SDT_SYS386CGT:
+ break;
+ case SDT_MEMRO:
+ case SDT_MEMROA:
+ case SDT_MEMRW:
+ case SDT_MEMRWA:
+ case SDT_MEMROD:
+ case SDT_MEMRODA:
+ case SDT_MEME:
+ case SDT_MEMEA:
+ case SDT_MEMER:
+ case SDT_MEMERA:
+ case SDT_MEMEC:
+ case SDT_MEMEAC:
+ case SDT_MEMERC:
+ case SDT_MEMERAC: {
+#if 0
+ unsigned long base = (desc.sd.sd_hibase << 24)&0xFF000000;
+ base |= (desc.sd.sd_lobase&0x00FFFFFF);
+ if (base >= KERNBASE)
+ return(EACCES);
+#endif
+ break;
+ }
+ default:
+ return(EACCES);
+ /*NOTREACHED*/
+ }
+ }
+
+ s = splhigh();
+
+ /* Fill in range */
+ for (i = 0, n = uap->start; i < uap->num && !error; i++, n++) {
+ union descriptor desc, *dp;
+ dp = &uap->desc[i];
+ lp = &((union descriptor *)(pcb->pcb_ldt))[n];
+#ifdef DEBUG
+ printf("i386_set_ldt(%d): ldtp=%x\n", p->p_pid, lp);
+#endif
+ error = copyin(dp, lp, sizeof(union descriptor));
+ }
+ if (!error) {
+ *retval = uap->start;
+/* need_resched(); */
+ }
+
+ splx(s);
+ return(error);
+}
+#endif /* USER_LDT */
+
+struct sysarch_args {
+ int op;
+ char *parms;
+};
+
+int
+sysarch(p, uap, retval)
+ struct proc *p;
+ register struct sysarch_args *uap;
+ int *retval;
+{
+ int error = 0;
+
+ switch(uap->op) {
+#ifdef USER_LDT
+ case I386_GET_LDT:
+ error = i386_get_ldt(p, uap->parms, retval);
+ break;
+
+ case I386_SET_LDT:
+ error = i386_set_ldt(p, uap->parms, retval);
+ break;
+#endif
+ default:
+ error = EINVAL;
+ break;
+ }
+ return(error);
+}
diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c
new file mode 100644
index 0000000..9bb38e1
--- /dev/null
+++ b/sys/i386/i386/trap.c
@@ -0,0 +1,728 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the University of Utah, and William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)trap.c 7.4 (Berkeley) 5/13/91
+ * $Id: trap.c,v 1.22 1994/04/07 10:51:00 davidg Exp $
+ */
+
+/*
+ * 386 Trap and System call handleing
+ */
+
+#include "isa.h"
+#include "npx.h"
+#include "ddb.h"
+#include "machine/cpu.h"
+#include "machine/psl.h"
+#include "machine/reg.h"
+#include "machine/eflags.h"
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "user.h"
+#include "acct.h"
+#include "kernel.h"
+#ifdef KTRACE
+#include "ktrace.h"
+#endif
+
+#include "vm/vm_param.h"
+#include "vm/pmap.h"
+#include "vm/vm_map.h"
+#include "vm/vm_user.h"
+#include "vm/vm_page.h"
+#include "sys/vmmeter.h"
+
+#include "machine/trap.h"
+
+#ifdef __GNUC__
+
+/*
+ * The "r" contraint could be "rm" except for fatal bugs in gas. As usual,
+ * we omit the size from the mov instruction to avoid nonfatal bugs in gas.
+ */
+#define read_gs() ({ u_short gs; __asm("mov %%gs,%0" : "=r" (gs)); gs; })
+#define write_gs(newgs) __asm("mov %0,%%gs" : : "r" ((u_short) newgs))
+
+#else /* not __GNUC__ */
+
+u_short read_gs __P((void));
+void write_gs __P((/* promoted u_short */ int gs));
+
+#endif /* __GNUC__ */
+
+extern int grow(struct proc *,int);
+
+struct sysent sysent[];
+int nsysent;
+
+#define MAX_TRAP_MSG 27
+char *trap_msg[] = {
+ "reserved addressing fault", /* 0 T_RESADFLT */
+ "privileged instruction fault", /* 1 T_PRIVINFLT */
+ "reserved operand fault", /* 2 T_RESOPFLT */
+ "breakpoint instruction fault", /* 3 T_BPTFLT */
+ "", /* 4 unused */
+ "system call trap", /* 5 T_SYSCALL */
+ "arithmetic trap", /* 6 T_ARITHTRAP */
+ "system forced exception", /* 7 T_ASTFLT */
+ "segmentation (limit) fault", /* 8 T_SEGFLT */
+ "protection fault", /* 9 T_PROTFLT */
+ "trace trap", /* 10 T_TRCTRAP */
+ "", /* 11 unused */
+ "page fault", /* 12 T_PAGEFLT */
+ "page table fault", /* 13 T_TABLEFLT */
+ "alignment fault", /* 14 T_ALIGNFLT */
+ "kernel stack pointer not valid", /* 15 T_KSPNOTVAL */
+ "bus error", /* 16 T_BUSERR */
+ "kernel debugger fault", /* 17 T_KDBTRAP */
+ "integer divide fault", /* 18 T_DIVIDE */
+ "non-maskable interrupt trap", /* 19 T_NMI */
+ "overflow trap", /* 20 T_OFLOW */
+ "FPU bounds check fault", /* 21 T_BOUND */
+ "FPU device not available", /* 22 T_DNA */
+ "double fault", /* 23 T_DOUBLEFLT */
+ "FPU operand fetch fault", /* 24 T_FPOPFLT */
+ "invalid TSS fault", /* 25 T_TSSFLT */
+ "segment not present fault", /* 26 T_SEGNPFLT */
+ "stack fault", /* 27 T_STKFLT */
+};
+
+#define pde_v(v) (PTD[((v)>>PD_SHIFT)&1023].pd_v)
+
+/*
+ * trap(frame):
+ * Exception, fault, and trap interface to BSD kernel. This
+ * common code is called from assembly language IDT gate entry
+ * routines that prepare a suitable stack frame, and restore this
+ * frame after the exception has been processed. Note that the
+ * effect is as if the arguments were passed call by reference.
+ */
+
+/*ARGSUSED*/
+void
+trap(frame)
+ struct trapframe frame;
+{
+ register int i;
+ register struct proc *p = curproc;
+ struct timeval syst;
+ int ucode, type, code, eva, fault_type;
+
+ frame.tf_eflags &= ~PSL_NT; /* clear nested trap XXX */
+ type = frame.tf_trapno;
+#if NDDB > 0
+ if (curpcb && curpcb->pcb_onfault) {
+ if (frame.tf_trapno == T_BPTFLT
+ || frame.tf_trapno == T_TRCTRAP)
+ if (kdb_trap (type, 0, &frame))
+ return;
+ }
+#endif
+
+ if (curpcb == 0 || curproc == 0)
+ goto skiptoswitch;
+ if (curpcb->pcb_onfault && frame.tf_trapno != T_PAGEFLT) {
+ extern int _udatasel;
+
+ if (read_gs() != (u_short) _udatasel)
+ /*
+ * Some user has corrupted %gs but we depend on it in
+ * copyout() etc. Fix it up and retry.
+ *
+ * (We don't preserve %fs or %gs, so users can change
+ * them to either _ucodesel, _udatasel or a not-present
+ * selector, possibly ORed with 0 to 3, making them
+ * volatile for other users. Not preserving them saves
+ * time and doesn't lose functionality or open security
+ * holes.)
+ */
+ write_gs(_udatasel);
+ else
+copyfault:
+ frame.tf_eip = (int)curpcb->pcb_onfault;
+ return;
+ }
+
+ syst = p->p_stime;
+ if (ISPL(frame.tf_cs) == SEL_UPL) {
+ type |= T_USER;
+ p->p_regs = (int *)&frame;
+ }
+
+skiptoswitch:
+ ucode=0;
+ eva = rcr2();
+ code = frame.tf_err;
+
+ if ((type & ~T_USER) == T_PAGEFLT)
+ goto pfault;
+
+ switch (type) {
+ case T_SEGNPFLT|T_USER:
+ case T_STKFLT|T_USER:
+ case T_PROTFLT|T_USER: /* protection fault */
+ ucode = code + BUS_SEGM_FAULT ;
+ i = SIGBUS;
+ break;
+
+ case T_PRIVINFLT|T_USER: /* privileged instruction fault */
+ case T_RESADFLT|T_USER: /* reserved addressing fault */
+ case T_RESOPFLT|T_USER: /* reserved operand fault */
+ case T_FPOPFLT|T_USER: /* coprocessor operand fault */
+ ucode = type &~ T_USER;
+ i = SIGILL;
+ break;
+
+ case T_ASTFLT|T_USER: /* Allow process switch */
+ astoff();
+ cnt.v_soft++;
+ if ((p->p_flag & SOWEUPC) && p->p_stats->p_prof.pr_scale) {
+ addupc(frame.tf_eip, &p->p_stats->p_prof, 1);
+ p->p_flag &= ~SOWEUPC;
+ }
+ goto out;
+
+ case T_DNA|T_USER:
+#if NNPX > 0
+ /* if a transparent fault (due to context switch "late") */
+ if (npxdna()) return;
+#endif /* NNPX > 0 */
+#if defined(MATH_EMULATE) || defined(GPL_MATH_EMULATE)
+ i = math_emulate(&frame);
+ if (i == 0) return;
+#else /* MATH_EMULATE || GPL_MATH_EMULATE */
+ panic("trap: math emulation necessary!");
+#endif /* MATH_EMULATE || GPL_MATH_EMULATE */
+ ucode = FPE_FPU_NP_TRAP;
+ break;
+
+ case T_BOUND|T_USER:
+ ucode = FPE_SUBRNG_TRAP;
+ i = SIGFPE;
+ break;
+
+ case T_OFLOW|T_USER:
+ ucode = FPE_INTOVF_TRAP;
+ i = SIGFPE;
+ break;
+
+ case T_DIVIDE|T_USER:
+ ucode = FPE_INTDIV_TRAP;
+ i = SIGFPE;
+ break;
+
+ case T_ARITHTRAP|T_USER:
+ ucode = code;
+ i = SIGFPE;
+ break;
+
+ pfault:
+ case T_PAGEFLT: /* allow page faults in kernel mode */
+ case T_PAGEFLT|T_USER: /* page fault */
+ {
+ vm_offset_t va;
+ struct vmspace *vm;
+ vm_map_t map = 0;
+ int rv = 0, oldflags;
+ vm_prot_t ftype;
+ unsigned v;
+ extern vm_map_t kernel_map;
+
+ va = trunc_page((vm_offset_t)eva);
+
+ /*
+ * Don't allow user-mode faults in kernel address space
+ */
+ if ((type == (T_PAGEFLT|T_USER)) && (va >= KERNBASE)) {
+ goto nogo;
+ }
+
+ if ((p == 0) || (type == T_PAGEFLT && va >= KERNBASE)) {
+ vm = 0;
+ map = kernel_map;
+ } else {
+ vm = p->p_vmspace;
+ map = &vm->vm_map;
+ }
+
+ if (code & PGEX_W)
+ ftype = VM_PROT_READ | VM_PROT_WRITE;
+ else
+ ftype = VM_PROT_READ;
+
+ oldflags = p->p_flag;
+ if (map != kernel_map) {
+ vm_offset_t pa;
+ vm_offset_t v = (vm_offset_t) vtopte(va);
+ vm_page_t ptepg;
+
+ /*
+ * Keep swapout from messing with us during this
+ * critical time.
+ */
+ p->p_flag |= SLOCK;
+
+ /*
+ * Grow the stack if necessary
+ */
+ if ((caddr_t)va > vm->vm_maxsaddr
+ && (caddr_t)va < (caddr_t)USRSTACK) {
+ if (!grow(p, va)) {
+ rv = KERN_FAILURE;
+ p->p_flag &= ~SLOCK;
+ p->p_flag |= (oldflags & SLOCK);
+ goto nogo;
+ }
+ }
+
+ /*
+ * Check if page table is mapped, if not,
+ * fault it first
+ */
+
+ /* Fault the pte only if needed: */
+ *(volatile char *)v += 0;
+
+ ptepg = (vm_page_t) pmap_pte_vm_page(vm_map_pmap(map), v);
+ vm_page_hold(ptepg);
+
+ /* Fault in the user page: */
+ rv = vm_fault(map, va, ftype, FALSE);
+
+ vm_page_unhold(ptepg);
+
+ /*
+ * page table pages don't need to be kept if they
+ * are not held
+ */
+ if( ptepg->hold_count == 0 && ptepg->wire_count == 0) {
+ pmap_page_protect( VM_PAGE_TO_PHYS(ptepg),
+ VM_PROT_NONE);
+ if( ptepg->flags & PG_CLEAN)
+ vm_page_free(ptepg);
+ }
+
+
+ p->p_flag &= ~SLOCK;
+ p->p_flag |= (oldflags & SLOCK);
+ } else {
+ /*
+ * Since we know that kernel virtual address addresses
+ * always have pte pages mapped, we just have to fault
+ * the page.
+ */
+ rv = vm_fault(map, va, ftype, FALSE);
+ }
+
+ if (rv == KERN_SUCCESS) {
+ if (type == T_PAGEFLT)
+ return;
+ goto out;
+ }
+nogo:
+ if (type == T_PAGEFLT) {
+ if (curpcb->pcb_onfault)
+ goto copyfault;
+
+ goto we_re_toast;
+ }
+ i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV;
+
+ /* kludge to pass faulting virtual address to sendsig */
+ ucode = type &~ T_USER;
+ frame.tf_err = eva;
+
+ break;
+ }
+
+#if NDDB == 0
+ case T_TRCTRAP: /* trace trap -- someone single stepping lcall's */
+ frame.tf_eflags &= ~PSL_T;
+
+ /* Q: how do we turn it on again? */
+ return;
+#endif
+
+ case T_BPTFLT|T_USER: /* bpt instruction fault */
+ case T_TRCTRAP|T_USER: /* trace trap */
+ frame.tf_eflags &= ~PSL_T;
+ i = SIGTRAP;
+ break;
+
+#if NISA > 0
+ case T_NMI:
+ case T_NMI|T_USER:
+#if NDDB > 0
+ /* NMI can be hooked up to a pushbutton for debugging */
+ printf ("NMI ... going to debugger\n");
+ if (kdb_trap (type, 0, &frame))
+ return;
+#endif
+ /* machine/parity/power fail/"kitchen sink" faults */
+ if (isa_nmi(code) == 0) return;
+ /* FALL THROUGH */
+#endif
+ default:
+ we_re_toast:
+
+ fault_type = type & ~T_USER;
+#if NDDB > 0
+ if ((fault_type == T_BPTFLT) || (fault_type == T_TRCTRAP)) {
+ if (kdb_trap (type, 0, &frame))
+ return;
+ }
+#endif
+ if (fault_type <= MAX_TRAP_MSG)
+ printf("\n\nFatal trap %d: %s while in %s mode\n",
+ fault_type, trap_msg[fault_type],
+ ISPL(frame.tf_cs) == SEL_UPL ? "user" : "kernel");
+ if (fault_type == T_PAGEFLT) {
+ printf("fault virtual address = 0x%x\n", eva);
+ printf("fault code = %s %s, %s\n",
+ code & PGEX_U ? "user" : "supervisor",
+ code & PGEX_W ? "write" : "read",
+ code & PGEX_P ? "protection violation" : "page not present");
+ }
+ printf("instruction pointer = 0x%x\n", frame.tf_eip);
+ printf("processor eflags = ");
+ if (frame.tf_eflags & EFL_TF)
+ printf("trace/trap, ");
+ if (frame.tf_eflags & EFL_IF)
+ printf("interrupt enabled, ");
+ if (frame.tf_eflags & EFL_NT)
+ printf("nested task, ");
+ if (frame.tf_eflags & EFL_RF)
+ printf("resume, ");
+ if (frame.tf_eflags & EFL_VM)
+ printf("vm86, ");
+ printf("IOPL = %d\n", (frame.tf_eflags & EFL_IOPL) >> 12);
+ printf("current process = ");
+ if (curproc) {
+ printf("%d (%s)\n",
+ curproc->p_pid, curproc->p_comm ?
+ curproc->p_comm : "");
+ } else {
+ printf("Idle\n");
+ }
+ printf("interrupt mask = ");
+ if ((cpl & net_imask) == net_imask)
+ printf("net ");
+ if ((cpl & tty_imask) == tty_imask)
+ printf("tty ");
+ if ((cpl & bio_imask) == bio_imask)
+ printf("bio ");
+ if (cpl == 0)
+ printf("none");
+ printf("\n");
+
+#ifdef KDB
+ if (kdb_trap(&psl))
+ return;
+#endif
+#if NDDB > 0
+ if (kdb_trap (type, 0, &frame))
+ return;
+#endif
+ if (fault_type <= MAX_TRAP_MSG)
+ panic(trap_msg[fault_type]);
+ else
+ panic("unknown/reserved trap");
+
+ /* NOTREACHED */
+ }
+
+ trapsignal(p, i, ucode);
+ if ((type & T_USER) == 0)
+ return;
+
+#ifdef DIAGNOSTIC
+ fault_type = type & ~T_USER;
+ if (fault_type <= MAX_TRAP_MSG) {
+ uprintf("fatal process exception: %s",
+ trap_msg[fault_type]);
+ if ((fault_type == T_PAGEFLT) || (fault_type == T_PROTFLT))
+ uprintf(", fault VA = 0x%x", eva);
+ uprintf("\n");
+ }
+#endif
+
+out:
+ while (i = CURSIG(p))
+ psig(i);
+ p->p_pri = p->p_usrpri;
+ if (want_resched) {
+ int s;
+ /*
+ * Since we are curproc, clock will normally just change
+ * our priority without moving us from one queue to another
+ * (since the running process is not on a queue.)
+ * If that happened after we setrq ourselves but before we
+ * swtch()'ed, we might not be on the queue indicated by
+ * our priority.
+ */
+ s = splclock();
+ setrq(p);
+ p->p_stats->p_ru.ru_nivcsw++;
+ swtch();
+ splx(s);
+ while (i = CURSIG(p))
+ psig(i);
+ }
+ if (p->p_stats->p_prof.pr_scale) {
+ int ticks;
+ struct timeval *tv = &p->p_stime;
+
+ ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
+ (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
+ if (ticks) {
+#ifdef PROFTIMER
+ extern int profscale;
+ addupc(frame.tf_eip, &p->p_stats->p_prof,
+ ticks * profscale);
+#else
+ addupc(frame.tf_eip, &p->p_stats->p_prof, ticks);
+#endif
+ }
+ }
+ curpri = p->p_pri;
+}
+
+/*
+ * Compensate for 386 brain damage (missing URKR).
+ * This is a little simpler than the pagefault handler in trap() because
+ * it the page tables have already been faulted in and high addresses
+ * are thrown out early for other reasons.
+ */
+int trapwrite(addr)
+ unsigned addr;
+{
+ struct proc *p;
+ vm_offset_t va, v;
+ struct vmspace *vm;
+ int oldflags;
+ int rv;
+
+ va = trunc_page((vm_offset_t)addr);
+ /*
+ * XXX - MAX is END. Changed > to >= for temp. fix.
+ */
+ if (va >= VM_MAXUSER_ADDRESS)
+ return (1);
+
+ p = curproc;
+ vm = p->p_vmspace;
+
+ oldflags = p->p_flag;
+ p->p_flag |= SLOCK;
+
+ if ((caddr_t)va >= vm->vm_maxsaddr
+ && (caddr_t)va < (caddr_t)USRSTACK) {
+ if (!grow(p, va)) {
+ p->p_flag &= ~SLOCK;
+ p->p_flag |= (oldflags & SLOCK);
+ return (1);
+ }
+ }
+
+ v = trunc_page(vtopte(va));
+
+ /*
+ * wire the pte page
+ */
+ if (va < USRSTACK) {
+ vm_map_pageable(&vm->vm_map, v, round_page(v+1), FALSE);
+ }
+
+ /*
+ * fault the data page
+ */
+ rv = vm_fault(&vm->vm_map, va, VM_PROT_READ|VM_PROT_WRITE, FALSE);
+
+ /*
+ * unwire the pte page
+ */
+ if (va < USRSTACK) {
+ vm_map_pageable(&vm->vm_map, v, round_page(v+1), TRUE);
+ }
+
+ p->p_flag &= ~SLOCK;
+ p->p_flag |= (oldflags & SLOCK);
+
+ if (rv != KERN_SUCCESS)
+ return 1;
+
+ return (0);
+}
+
+/*
+ * syscall(frame):
+ * System call request from POSIX system call gate interface to kernel.
+ * Like trap(), argument is call by reference.
+ */
+/*ARGSUSED*/
+void
+syscall(frame)
+ volatile struct trapframe frame;
+{
+ register int *locr0 = ((int *)&frame);
+ register caddr_t params;
+ register int i;
+ register struct sysent *callp;
+ register struct proc *p = curproc;
+ struct timeval syst;
+ int error, opc;
+ int args[8], rval[2];
+ int code;
+
+#ifdef lint
+ r0 = 0; r0 = r0; r1 = 0; r1 = r1;
+#endif
+ syst = p->p_stime;
+ if (ISPL(frame.tf_cs) != SEL_UPL)
+ panic("syscall");
+
+ code = frame.tf_eax;
+ p->p_regs = (int *)&frame;
+ params = (caddr_t)frame.tf_esp + sizeof (int) ;
+
+ /*
+ * Reconstruct pc, assuming lcall $X,y is 7 bytes, as it is always.
+ */
+ opc = frame.tf_eip - 7;
+ if (code == 0) {
+ code = fuword(params);
+ params += sizeof (int);
+ }
+ if (code < 0 || code >= nsysent)
+ callp = &sysent[0];
+ else
+ callp = &sysent[code];
+
+ if ((i = callp->sy_narg * sizeof (int)) &&
+ (error = copyin(params, (caddr_t)args, (u_int)i))) {
+ frame.tf_eax = error;
+ frame.tf_eflags |= PSL_C; /* carry bit */
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSCALL))
+ ktrsyscall(p->p_tracep, code, callp->sy_narg, args);
+#endif
+ goto done;
+ }
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSCALL))
+ ktrsyscall(p->p_tracep, code, callp->sy_narg, args);
+#endif
+ rval[0] = 0;
+ rval[1] = frame.tf_edx;
+/*pg("%d. s %d\n", p->p_pid, code);*/
+ error = (*callp->sy_call)(p, args, rval);
+ if (error == ERESTART)
+ frame.tf_eip = opc;
+ else if (error != EJUSTRETURN) {
+ if (error) {
+/*pg("error %d", error);*/
+ frame.tf_eax = error;
+ frame.tf_eflags |= PSL_C; /* carry bit */
+ } else {
+ frame.tf_eax = rval[0];
+ frame.tf_edx = rval[1];
+ frame.tf_eflags &= ~PSL_C; /* carry bit */
+ }
+ }
+ /* else if (error == EJUSTRETURN) */
+ /* nothing to do */
+done:
+ /*
+ * Reinitialize proc pointer `p' as it may be different
+ * if this is a child returning from fork syscall.
+ */
+ p = curproc;
+ while (i = CURSIG(p))
+ psig(i);
+ p->p_pri = p->p_usrpri;
+ if (want_resched) {
+ int s;
+ /*
+ * Since we are curproc, clock will normally just change
+ * our priority without moving us from one queue to another
+ * (since the running process is not on a queue.)
+ * If that happened after we setrq ourselves but before we
+ * swtch()'ed, we might not be on the queue indicated by
+ * our priority.
+ */
+ s = splclock();
+ setrq(p);
+ p->p_stats->p_ru.ru_nivcsw++;
+ swtch();
+ splx(s);
+ while (i = CURSIG(p))
+ psig(i);
+ }
+ if (p->p_stats->p_prof.pr_scale) {
+ int ticks;
+ struct timeval *tv = &p->p_stime;
+
+ ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
+ (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
+ if (ticks) {
+#ifdef PROFTIMER
+ extern int profscale;
+ addupc(frame.tf_eip, &p->p_stats->p_prof,
+ ticks * profscale);
+#else
+ addupc(frame.tf_eip, &p->p_stats->p_prof, ticks);
+#endif
+ }
+ }
+ curpri = p->p_pri;
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSRET))
+ ktrsysret(p->p_tracep, code, error, rval[0]);
+#endif
+#ifdef DIAGNOSTICx
+{ extern int _udatasel, _ucodesel;
+ if (frame.tf_ss != _udatasel)
+ printf("ss %x call %d\n", frame.tf_ss, code);
+ if ((frame.tf_cs&0xffff) != _ucodesel)
+ printf("cs %x call %d\n", frame.tf_cs, code);
+ if (frame.tf_eip > VM_MAXUSER_ADDRESS) {
+ printf("eip %x call %d\n", frame.tf_eip, code);
+ frame.tf_eip = 0;
+ }
+}
+#endif
+}
diff --git a/sys/i386/i386/tsc.c b/sys/i386/i386/tsc.c
new file mode 100644
index 0000000..d338cd5
--- /dev/null
+++ b/sys/i386/i386/tsc.c
@@ -0,0 +1,430 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz and Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)clock.c 7.2 (Berkeley) 5/12/91
+ * $Id: clock.c,v 1.6 1994/02/06 22:48:13 davidg Exp $
+ */
+
+/*
+ * Primitive clock interrupt routines.
+ */
+#include "param.h"
+#include "systm.h"
+#include "time.h"
+#include "kernel.h"
+#include "machine/segments.h"
+#include "machine/frame.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/rtc.h"
+#include "i386/isa/timerreg.h"
+
+/* X-tals being what they are, it's nice to be able to fudge this one... */
+/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */
+#ifndef TIMER_FREQ
+#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
+#endif
+#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
+
+void hardclock();
+static int beeping;
+int timer0_divisor = TIMER_DIV(100); /* XXX should be hz */
+u_int timer0_prescale;
+static char timer0_state = 0, timer2_state = 0;
+static char timer0_reprogram = 0;
+static void (*timer_func)() = hardclock;
+static void (*new_function)();
+static u_int new_rate;
+static u_int hardclock_divisor;
+
+
+void
+timerintr(struct intrframe frame)
+{
+ timer_func(frame);
+ switch (timer0_state) {
+ case 0:
+ break;
+ case 1:
+ if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
+ hardclock(frame);
+ timer0_prescale = 0;
+ }
+ break;
+ case 2:
+ disable_intr();
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+ outb(TIMER_CNTR0, TIMER_DIV(new_rate)%256);
+ outb(TIMER_CNTR0, TIMER_DIV(new_rate)/256);
+ enable_intr();
+ timer0_divisor = TIMER_DIV(new_rate);
+ timer0_prescale = 0;
+ timer_func = new_function;
+ timer0_state = 1;
+ break;
+ case 3:
+ if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
+ hardclock(frame);
+ disable_intr();
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+ outb(TIMER_CNTR0, TIMER_DIV(hz)%256);
+ outb(TIMER_CNTR0, TIMER_DIV(hz)/256);
+ enable_intr();
+ timer0_divisor = TIMER_DIV(hz);
+ timer0_prescale = 0;
+ timer_func = hardclock;;
+ timer0_state = 0;
+ }
+ break;
+ }
+}
+
+
+int
+acquire_timer0(int rate, void (*function)() )
+{
+ if (timer0_state || !function)
+ return -1;
+
+ new_function = function;
+ new_rate = rate;
+ timer0_state = 2;
+ return 0;
+}
+
+
+int
+acquire_timer2(int mode)
+{
+ if (timer2_state)
+ return -1;
+ timer2_state = 1;
+ outb(TIMER_MODE, TIMER_SEL2 | (mode &0x3f));
+ return 0;
+}
+
+
+int
+release_timer0()
+{
+ if (!timer0_state)
+ return -1;
+ timer0_state = 3;
+ return 0;
+}
+
+
+int
+release_timer2()
+{
+ if (!timer2_state)
+ return -1;
+ timer2_state = 0;
+ outb(TIMER_MODE, TIMER_SEL2|TIMER_SQWAVE|TIMER_16BIT);
+ return 0;
+}
+
+
+static int
+getit()
+{
+ int high, low;
+
+ disable_intr();
+ /* select timer0 and latch counter value */
+ outb(TIMER_MODE, TIMER_SEL0);
+ low = inb(TIMER_CNTR0);
+ high = inb(TIMER_CNTR0);
+ enable_intr();
+ return ((high << 8) | low);
+}
+
+
+/*
+ * Wait "n" microseconds.
+ * Relies on timer 1 counting down from (TIMER_FREQ / hz)
+ * Note: timer had better have been programmed before this is first used!
+ */
+void
+DELAY(int n)
+{
+ int counter_limit, prev_tick, tick, ticks_left, sec, usec;
+
+#ifdef DELAYDEBUG
+ int getit_calls = 1;
+ int n1;
+ static int state = 0;
+
+ if (state == 0) {
+ state = 1;
+ for (n1 = 1; n1 <= 10000000; n1 *= 10)
+ DELAY(n1);
+ state = 2;
+ }
+ if (state == 1)
+ printf("DELAY(%d)...", n);
+#endif
+ /*
+ * Read the counter first, so that the rest of the setup overhead is
+ * counted. Guess the initial overhead is 20 usec (on most systems it
+ * takes about 1.5 usec for each of the i/o's in getit(). The loop
+ * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
+ * multiplications and divisions to scale the count take a while).
+ */
+ prev_tick = getit(0, 0);
+ n -= 20;
+ /*
+ * Calculate (n * (TIMER_FREQ / 1e6)) without using floating point
+ * and without any avoidable overflows.
+ */
+ sec = n / 1000000;
+ usec = n - sec * 1000000;
+ ticks_left = sec * TIMER_FREQ
+ + usec * (TIMER_FREQ / 1000000)
+ + usec * ((TIMER_FREQ % 1000000) / 1000) / 1000
+ + usec * (TIMER_FREQ % 1000) / 1000000;
+
+ while (ticks_left > 0) {
+ tick = getit(0, 0);
+#ifdef DELAYDEBUG
+ ++getit_calls;
+#endif
+ if (tick > prev_tick)
+ ticks_left -= prev_tick - (tick - timer0_divisor);
+ else
+ ticks_left -= prev_tick - tick;
+ prev_tick = tick;
+ }
+#ifdef DELAYDEBUG
+ if (state == 1)
+ printf(" %d calls to getit() at %d usec each\n",
+ getit_calls, (n + 5) / getit_calls);
+#endif
+}
+
+
+static void
+sysbeepstop()
+{
+ outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */
+ release_timer2();
+ beeping = 0;
+}
+
+
+int
+sysbeep(int pitch, int period)
+{
+
+ if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT))
+ return -1;
+ disable_intr();
+ outb(TIMER_CNTR2, pitch);
+ outb(TIMER_CNTR2, (pitch>>8));
+ enable_intr();
+ if (!beeping) {
+ outb(IO_PPI, inb(IO_PPI) | 3); /* enable counter2 output to speaker */
+ beeping = period;
+ timeout(sysbeepstop, 0, period);
+ }
+ return 0;
+}
+
+
+void
+startrtclock()
+{
+ int s;
+
+ /* initialize 8253 clock */
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+
+ /* Correct rounding will buy us a better precision in timekeeping */
+ outb (IO_TIMER1, TIMER_DIV(hz)%256);
+ outb (IO_TIMER1, TIMER_DIV(hz)/256);
+ timer0_divisor = hardclock_divisor = TIMER_DIV(hz);
+
+ /* initialize brain-dead battery powered clock */
+ outb (IO_RTC, RTC_STATUSA);
+ outb (IO_RTC+1, 0x26);
+ outb (IO_RTC, RTC_STATUSB);
+ outb (IO_RTC+1, 2);
+
+ outb (IO_RTC, RTC_DIAG);
+ if (s = inb (IO_RTC+1))
+ printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS);
+}
+
+
+/* convert 2 digit BCD number */
+int
+bcd(int i)
+{
+ return ((i/16)*10 + (i%16));
+}
+
+
+/* convert years to seconds (from 1970) */
+unsigned long
+ytos(int y)
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i = 1970; i < y; i++) {
+ if (i % 4) ret += 365*24*60*60;
+ else ret += 366*24*60*60;
+ }
+ return ret;
+}
+
+
+/* convert months to seconds */
+unsigned long
+mtos(int m, int leap)
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i=1; i<m; i++) {
+ switch(i){
+ case 1: case 3: case 5: case 7: case 8: case 10: case 12:
+ ret += 31*24*60*60; break;
+ case 4: case 6: case 9: case 11:
+ ret += 30*24*60*60; break;
+ case 2:
+ if (leap) ret += 29*24*60*60;
+ else ret += 28*24*60*60;
+ }
+ }
+ return ret;
+}
+
+
+/*
+ * Initialize the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+void
+inittodr(time_t base)
+{
+ unsigned long sec;
+ int leap, day_week, t, yd;
+ int sa,s;
+
+ /* do we have a realtime clock present? (otherwise we loop below) */
+ sa = rtcin(RTC_STATUSA);
+ if (sa == 0xff || sa == 0) return;
+
+ /* ready for a read? */
+ while ((sa&RTCSA_TUP) == RTCSA_TUP)
+ sa = rtcin(RTC_STATUSA);
+
+ sec = bcd(rtcin(RTC_YEAR)) + 1900;
+ if (sec < 1970)
+ sec += 100;
+
+ leap = !(sec % 4); sec = ytos(sec); /* year */
+ yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec+=yd; /* month */
+ t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec+=t; yd+=t; /* date */
+ day_week = rtcin(RTC_WDAY); /* day */
+ sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */
+ sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */
+ sec += bcd(rtcin(RTC_SEC)); /* seconds */
+ sec += tz.tz_minuteswest * 60;
+ time.tv_sec = sec;
+}
+
+
+#ifdef garbage
+/*
+ * Initialze the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+test_inittodr(time_t base)
+{
+
+ outb(IO_RTC,9); /* year */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,8); /* month */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,7); /* day */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,4); /* hour */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,2); /* minutes */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,0); /* seconds */
+ printf("%d\n",bcd(inb(IO_RTC+1)));
+
+ time.tv_sec = base;
+}
+#endif
+
+
+/*
+ * Restart the clock.
+ */
+void
+resettodr()
+{
+}
+
+
+/*
+ * Wire clock interrupt in.
+ */
+#define V(s) __CONCAT(V, s)
+extern void V(clk)();
+
+
+void
+enablertclock()
+{
+ setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL);
+ INTREN(IRQ0);
+}
+
+
+/*
+ * Delay for some number of milliseconds.
+ */
+void
+spinwait(int millisecs)
+{
+ DELAY(1000 * millisecs);
+}
diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c
new file mode 100644
index 0000000..a892c29
--- /dev/null
+++ b/sys/i386/i386/vm_machdep.c
@@ -0,0 +1,1151 @@
+/*-
+ * Copyright (c) 1982, 1986 The Regents of the University of California.
+ * Copyright (c) 1989, 1990 William Jolitz
+ * Copyright (c) 1994 John Dyson
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department, and William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91
+ * Utah $Hdr: vm_machdep.c 1.16.1.1 89/06/23$
+ * $Id: vm_machdep.c,v 1.20 1994/04/20 07:06:20 davidg Exp $
+ */
+
+#include "npx.h"
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "malloc.h"
+#include "buf.h"
+#include "user.h"
+
+#include "../include/cpu.h"
+
+#include "vm/vm.h"
+#include "vm/vm_kern.h"
+
+#define b_cylin b_resid
+
+#define MAXCLSTATS 256
+int clstats[MAXCLSTATS];
+int rqstats[MAXCLSTATS];
+
+
+#ifndef NOBOUNCE
+
+caddr_t bouncememory;
+vm_offset_t bouncepa, bouncepaend;
+int bouncepages, bpwait;
+vm_map_t io_map;
+int bmwait, bmfreeing;
+
+#define BITS_IN_UNSIGNED (8*sizeof(unsigned))
+int bounceallocarraysize;
+unsigned *bounceallocarray;
+int bouncefree;
+
+#define SIXTEENMEG (4096*4096)
+#define MAXBKVA 1024
+
+/* special list that can be used at interrupt time for eventual kva free */
+struct kvasfree {
+ vm_offset_t addr;
+ vm_offset_t size;
+} kvaf[MAXBKVA];
+
+int kvasfreecnt;
+
+vm_offset_t vm_bounce_kva();
+/*
+ * get bounce buffer pages (count physically contiguous)
+ * (only 1 inplemented now)
+ */
+vm_offset_t
+vm_bounce_page_find(count)
+ int count;
+{
+ int bit;
+ int s,i;
+
+ if (count != 1)
+ panic("vm_bounce_page_find -- no support for > 1 page yet!!!");
+
+ s = splbio();
+retry:
+ for (i = 0; i < bounceallocarraysize; i++) {
+ if (bounceallocarray[i] != 0xffffffff) {
+ if (bit = ffs(~bounceallocarray[i])) {
+ bounceallocarray[i] |= 1 << (bit - 1) ;
+ bouncefree -= count;
+ splx(s);
+ return bouncepa + (i * BITS_IN_UNSIGNED + (bit - 1)) * NBPG;
+ }
+ }
+ }
+ bpwait = 1;
+ tsleep((caddr_t) &bounceallocarray, PRIBIO, "bncwai", 0);
+ goto retry;
+}
+
+void
+vm_bounce_kva_free(addr, size, now)
+ vm_offset_t addr;
+ vm_offset_t size;
+ int now;
+{
+ int s = splbio();
+ kvaf[kvasfreecnt].addr = addr;
+ kvaf[kvasfreecnt++].size = size;
+ if( now) {
+ /*
+ * this will do wakeups
+ */
+ vm_bounce_kva(0,0);
+ } else {
+ if (bmwait) {
+ /*
+ * if anyone is waiting on the bounce-map, then wakeup
+ */
+ wakeup((caddr_t) io_map);
+ bmwait = 0;
+ }
+ }
+ splx(s);
+}
+
+/*
+ * free count bounce buffer pages
+ */
+void
+vm_bounce_page_free(pa, count)
+ vm_offset_t pa;
+ int count;
+{
+ int allocindex;
+ int index;
+ int bit;
+
+ if (count != 1)
+ panic("vm_bounce_page_free -- no support for > 1 page yet!!!\n");
+
+ index = (pa - bouncepa) / NBPG;
+
+ if ((index < 0) || (index >= bouncepages))
+ panic("vm_bounce_page_free -- bad index\n");
+
+ allocindex = index / BITS_IN_UNSIGNED;
+ bit = index % BITS_IN_UNSIGNED;
+
+ bounceallocarray[allocindex] &= ~(1 << bit);
+
+ bouncefree += count;
+ if (bpwait) {
+ bpwait = 0;
+ wakeup((caddr_t) &bounceallocarray);
+ }
+}
+
+/*
+ * allocate count bounce buffer kva pages
+ */
+vm_offset_t
+vm_bounce_kva(count, waitok)
+ int count;
+ int waitok;
+{
+ int tofree;
+ int i;
+ int startfree;
+ vm_offset_t kva = 0;
+ int s = splbio();
+ int size = count;
+ startfree = 0;
+more:
+ if (!bmfreeing && (tofree = kvasfreecnt)) {
+ bmfreeing = 1;
+ for (i = startfree; i < kvasfreecnt; i++) {
+ /*
+ * if we have a kva of the right size, no sense
+ * in freeing/reallocating...
+ * might affect fragmentation short term, but
+ * as long as the amount of io_map is
+ * significantly more than the maximum transfer
+ * size, I don't think that it is a problem.
+ */
+ pmap_remove(kernel_pmap,
+ kvaf[i].addr, kvaf[i].addr + kvaf[i].size);
+ if( size && !kva && kvaf[i].size == size) {
+ kva = kvaf[i].addr;
+ } else {
+ kmem_free_wakeup(io_map, kvaf[i].addr,
+ kvaf[i].size);
+ }
+ }
+ if (kvasfreecnt != tofree) {
+ startfree = i;
+ bmfreeing = 0;
+ goto more;
+ }
+ kvasfreecnt = 0;
+ bmfreeing = 0;
+ }
+
+ if( size == 0) {
+ splx(s);
+ return NULL;
+ }
+
+ if (!kva && !(kva = kmem_alloc_pageable(io_map, size))) {
+ if( !waitok) {
+ splx(s);
+ return NULL;
+ }
+ bmwait = 1;
+ tsleep((caddr_t) io_map, PRIBIO, "bmwait", 0);
+ goto more;
+ }
+ splx(s);
+
+ return kva;
+}
+
+/*
+ * same as vm_bounce_kva -- but really allocate
+ */
+vm_offset_t
+vm_bounce_kva_alloc(count)
+int count;
+{
+ int i;
+ vm_offset_t kva;
+ vm_offset_t pa;
+ if( bouncepages == 0) {
+ kva = (vm_offset_t) malloc(count*NBPG, M_TEMP, M_WAITOK);
+ return kva;
+ }
+ kva = vm_bounce_kva(count, 1);
+ for(i=0;i<count;i++) {
+ pa = vm_bounce_page_find(1);
+ pmap_kenter(kva + i * NBPG, pa);
+ }
+ return kva;
+}
+
+/*
+ * same as vm_bounce_kva_free -- but really free
+ */
+void
+vm_bounce_kva_alloc_free(kva, count)
+ vm_offset_t kva;
+ int count;
+{
+ int i;
+ vm_offset_t pa;
+ if( bouncepages == 0) {
+ free((caddr_t) kva, M_TEMP);
+ return;
+ }
+ for(i = 0; i < count; i++) {
+ pa = pmap_kextract(kva + i * NBPG);
+ vm_bounce_page_free(pa, 1);
+ }
+ vm_bounce_kva_free(kva, count);
+}
+
+/*
+ * do the things necessary to the struct buf to implement
+ * bounce buffers... inserted before the disk sort
+ */
+void
+vm_bounce_alloc(bp)
+ struct buf *bp;
+{
+ int countvmpg;
+ vm_offset_t vastart, vaend;
+ vm_offset_t vapstart, vapend;
+ vm_offset_t va, kva;
+ vm_offset_t pa;
+ int dobounceflag = 0;
+ int bounceindex;
+ int i;
+ int s;
+
+ if (bouncepages == 0)
+ return;
+
+ if (bp->b_bufsize < bp->b_bcount) {
+ printf("vm_bounce_alloc: b_bufsize(%d) < b_bcount(%d) !!!!\n",
+ bp->b_bufsize, bp->b_bcount);
+ bp->b_bufsize = bp->b_bcount;
+ }
+
+ vastart = (vm_offset_t) bp->b_un.b_addr;
+ vaend = (vm_offset_t) bp->b_un.b_addr + bp->b_bufsize;
+
+ vapstart = i386_trunc_page(vastart);
+ vapend = i386_round_page(vaend);
+ countvmpg = (vapend - vapstart) / NBPG;
+
+/*
+ * if any page is above 16MB, then go into bounce-buffer mode
+ */
+ va = vapstart;
+ for (i = 0; i < countvmpg; i++) {
+ pa = pmap_kextract(va);
+ if (pa >= SIXTEENMEG)
+ ++dobounceflag;
+ va += NBPG;
+ }
+ if (dobounceflag == 0)
+ return;
+
+ if (bouncepages < dobounceflag)
+ panic("Not enough bounce buffers!!!");
+
+/*
+ * allocate a replacement kva for b_addr
+ */
+ kva = vm_bounce_kva(countvmpg*NBPG, 1);
+ va = vapstart;
+ for (i = 0; i < countvmpg; i++) {
+ pa = pmap_kextract(va);
+ if (pa >= SIXTEENMEG) {
+ /*
+ * allocate a replacement page
+ */
+ vm_offset_t bpa = vm_bounce_page_find(1);
+ pmap_kenter(kva + (NBPG * i), bpa);
+ /*
+ * if we are writing, the copy the data into the page
+ */
+ if ((bp->b_flags & B_READ) == 0) {
+ pmap_update();
+ bcopy((caddr_t) va, (caddr_t) kva + (NBPG * i), NBPG);
+ }
+ } else {
+ /*
+ * use original page
+ */
+ pmap_kenter(kva + (NBPG * i), pa);
+ }
+ va += NBPG;
+ }
+ pmap_update();
+
+/*
+ * flag the buffer as being bounced
+ */
+ bp->b_flags |= B_BOUNCE;
+/*
+ * save the original buffer kva
+ */
+ bp->b_savekva = bp->b_un.b_addr;
+/*
+ * put our new kva into the buffer (offset by original offset)
+ */
+ bp->b_un.b_addr = (caddr_t) (((vm_offset_t) kva) |
+ ((vm_offset_t) bp->b_savekva & (NBPG - 1)));
+ return;
+}
+
+/*
+ * hook into biodone to free bounce buffer
+ */
+void
+vm_bounce_free(bp)
+ struct buf *bp;
+{
+ int i;
+ vm_offset_t origkva, bouncekva;
+ vm_offset_t vastart, vaend;
+ vm_offset_t vapstart, vapend;
+ int countbounce = 0;
+ vm_offset_t firstbouncepa = 0;
+ int firstbounceindex;
+ int countvmpg;
+ vm_offset_t bcount;
+ int s;
+
+/*
+ * if this isn't a bounced buffer, then just return
+ */
+ if ((bp->b_flags & B_BOUNCE) == 0)
+ return;
+
+ origkva = (vm_offset_t) bp->b_savekva;
+ bouncekva = (vm_offset_t) bp->b_un.b_addr;
+
+ vastart = bouncekva;
+ vaend = bouncekva + bp->b_bufsize;
+ bcount = bp->b_bufsize;
+
+ vapstart = i386_trunc_page(vastart);
+ vapend = i386_round_page(vaend);
+
+ countvmpg = (vapend - vapstart) / NBPG;
+
+/*
+ * check every page in the kva space for b_addr
+ */
+ for (i = 0; i < countvmpg; i++) {
+ vm_offset_t mybouncepa;
+ vm_offset_t copycount;
+
+ copycount = i386_round_page(bouncekva + 1) - bouncekva;
+ mybouncepa = pmap_kextract(i386_trunc_page(bouncekva));
+
+/*
+ * if this is a bounced pa, then process as one
+ */
+ if ((mybouncepa >= bouncepa) && (mybouncepa < bouncepaend)) {
+ if (copycount > bcount)
+ copycount = bcount;
+/*
+ * if this is a read, then copy from bounce buffer into original buffer
+ */
+ if (bp->b_flags & B_READ)
+ bcopy((caddr_t) bouncekva, (caddr_t) origkva, copycount);
+/*
+ * free the bounce allocation
+ */
+ vm_bounce_page_free(i386_trunc_page(mybouncepa), 1);
+ }
+
+ origkva += copycount;
+ bouncekva += copycount;
+ bcount -= copycount;
+ }
+
+/*
+ * add the old kva into the "to free" list
+ */
+ bouncekva = i386_trunc_page((vm_offset_t) bp->b_un.b_addr);
+ vm_bounce_kva_free( bouncekva, countvmpg*NBPG, 0);
+ bp->b_un.b_addr = bp->b_savekva;
+ bp->b_savekva = 0;
+ bp->b_flags &= ~B_BOUNCE;
+
+ return;
+}
+
+#endif /* NOBOUNCE */
+
+/*
+ * init the bounce buffer system
+ */
+void
+vm_bounce_init()
+{
+ vm_offset_t minaddr, maxaddr;
+
+ io_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, MAXBKVA * NBPG, FALSE);
+ kvasfreecnt = 0;
+
+#ifndef NOBOUNCE
+ if (bouncepages == 0)
+ return;
+
+ bounceallocarraysize = (bouncepages + BITS_IN_UNSIGNED - 1) / BITS_IN_UNSIGNED;
+ bounceallocarray = malloc(bounceallocarraysize * sizeof(unsigned), M_TEMP, M_NOWAIT);
+
+ if (!bounceallocarray)
+ panic("Cannot allocate bounce resource array\n");
+
+ bzero(bounceallocarray, bounceallocarraysize * sizeof(long));
+
+
+ bouncepa = pmap_kextract((vm_offset_t) bouncememory);
+ bouncepaend = bouncepa + bouncepages * NBPG;
+ bouncefree = bouncepages;
+#endif
+
+}
+
+
+static void
+cldiskvamerge( kvanew, orig1, orig1cnt, orig2, orig2cnt)
+ vm_offset_t kvanew;
+ vm_offset_t orig1, orig1cnt;
+ vm_offset_t orig2, orig2cnt;
+{
+ int i;
+ vm_offset_t pa;
+/*
+ * enter the transfer physical addresses into the new kva
+ */
+ for(i=0;i<orig1cnt;i++) {
+ vm_offset_t pa;
+ pa = pmap_kextract((caddr_t) orig1 + i * PAGE_SIZE);
+ pmap_kenter(kvanew + i * PAGE_SIZE, pa);
+ }
+
+ for(i=0;i<orig2cnt;i++) {
+ vm_offset_t pa;
+ pa = pmap_kextract((caddr_t) orig2 + i * PAGE_SIZE);
+ pmap_kenter(kvanew + (i + orig1cnt) * PAGE_SIZE, pa);
+ }
+ pmap_update();
+}
+
+void
+cldisksort(struct buf *dp, struct buf *bp, vm_offset_t maxio)
+{
+ register struct buf *ap, *newbp;
+ int i, trycount=0;
+ vm_offset_t orig1pages, orig2pages;
+ vm_offset_t orig1begin, orig2begin;
+ vm_offset_t kvanew, kvaorig;
+
+ if( bp->b_bcount < MAXCLSTATS*PAGE_SIZE)
+ ++rqstats[bp->b_bcount/PAGE_SIZE];
+ /*
+ * If nothing on the activity queue, then
+ * we become the only thing.
+ */
+ ap = dp->b_actf;
+ if(ap == NULL) {
+ dp->b_actf = bp;
+ dp->b_actl = bp;
+ bp->av_forw = NULL;
+ return;
+ }
+
+ /*
+ * If we lie after the first (currently active)
+ * request, then we must locate the second request list
+ * and add ourselves to it.
+ */
+
+ if (bp->b_pblkno < ap->b_pblkno) {
+ while (ap->av_forw) {
+ /*
+ * Check for an ``inversion'' in the
+ * normally ascending block numbers,
+ * indicating the start of the second request list.
+ */
+ if (ap->av_forw->b_pblkno < ap->b_pblkno) {
+ /*
+ * Search the second request list
+ * for the first request at a larger
+ * block number. We go before that;
+ * if there is no such request, we go at end.
+ */
+ do {
+ if (bp->b_pblkno < ap->av_forw->b_pblkno)
+ goto insert;
+ ap = ap->av_forw;
+ } while (ap->av_forw);
+ goto insert; /* after last */
+ }
+ ap = ap->av_forw;
+ }
+ /*
+ * No inversions... we will go after the last, and
+ * be the first request in the second request list.
+ */
+ goto insert;
+ }
+ /*
+ * Request is at/after the current request...
+ * sort in the first request list.
+ */
+ while (ap->av_forw) {
+ /*
+ * We want to go after the current request
+ * if there is an inversion after it (i.e. it is
+ * the end of the first request list), or if
+ * the next request is a larger block than our request.
+ */
+ if (ap->av_forw->b_pblkno < ap->b_pblkno ||
+ bp->b_pblkno < ap->av_forw->b_pblkno )
+ goto insert;
+ ap = ap->av_forw;
+ }
+
+insert:
+
+ /*
+ * read clustering with new read-ahead disk drives hurts mostly, so
+ * we don't bother...
+ */
+ if( bp->b_flags & B_READ)
+ goto nocluster;
+ /*
+ * we currently only cluster I/O transfers that are at page-aligned
+ * kvas and transfers that are multiples of page lengths.
+ */
+ if ((bp->b_flags & B_BAD) == 0 &&
+ ((bp->b_bcount & PAGE_MASK) == 0) &&
+ (((vm_offset_t) bp->b_un.b_addr & PAGE_MASK) == 0)) {
+ if( maxio > MAXCLSTATS*PAGE_SIZE)
+ maxio = MAXCLSTATS*PAGE_SIZE;
+ /*
+ * merge with previous?
+ * conditions:
+ * 1) We reside physically immediately after the previous block.
+ * 2) The previous block is not first on the device queue because
+ * such a block might be active.
+ * 3) The mode of the two I/Os is identical.
+ * 4) The previous kva is page aligned and the previous transfer
+ * is a multiple of a page in length.
+ * 5) And the total I/O size would be below the maximum.
+ */
+ if( (ap->b_pblkno + (ap->b_bcount / DEV_BSIZE) == bp->b_pblkno) &&
+ (dp->b_actf != ap) &&
+ ((ap->b_flags & ~B_CLUSTER) == bp->b_flags) &&
+ ((ap->b_flags & B_BAD) == 0) &&
+ ((ap->b_bcount & PAGE_MASK) == 0) &&
+ (((vm_offset_t) ap->b_un.b_addr & PAGE_MASK) == 0) &&
+ (ap->b_bcount + bp->b_bcount < maxio)) {
+
+ orig1begin = (vm_offset_t) ap->b_un.b_addr;
+ orig1pages = ap->b_bcount / PAGE_SIZE;
+
+ orig2begin = (vm_offset_t) bp->b_un.b_addr;
+ orig2pages = bp->b_bcount / PAGE_SIZE;
+ /*
+ * see if we can allocate a kva, if we cannot, the don't
+ * cluster.
+ */
+ kvanew = vm_bounce_kva( PAGE_SIZE * (orig1pages + orig2pages), 0);
+ if( !kvanew) {
+ goto nocluster;
+ }
+
+
+ if( (ap->b_flags & B_CLUSTER) == 0) {
+
+ /*
+ * get a physical buf pointer
+ */
+ newbp = (struct buf *)trypbuf();
+ if( !newbp) {
+ vm_bounce_kva_free( kvanew, PAGE_SIZE * (orig1pages + orig2pages), 1);
+ goto nocluster;
+ }
+
+ cldiskvamerge( kvanew, orig1begin, orig1pages, orig2begin, orig2pages);
+
+ /*
+ * build the new bp to be handed off to the device
+ */
+
+ --clstats[ap->b_bcount/PAGE_SIZE];
+ *newbp = *ap;
+ newbp->b_flags |= B_CLUSTER;
+ newbp->b_un.b_addr = (caddr_t) kvanew;
+ newbp->b_bcount += bp->b_bcount;
+ newbp->b_bufsize = newbp->b_bcount;
+ newbp->b_clusterf = ap;
+ newbp->b_clusterl = bp;
+ ++clstats[newbp->b_bcount/PAGE_SIZE];
+
+ /*
+ * enter the new bp onto the device queue
+ */
+ if( ap->av_forw)
+ ap->av_forw->av_back = newbp;
+ else
+ dp->b_actl = newbp;
+
+ if( dp->b_actf != ap )
+ ap->av_back->av_forw = newbp;
+ else
+ dp->b_actf = newbp;
+
+ /*
+ * enter the previous bps onto the cluster queue
+ */
+ ap->av_forw = bp;
+ bp->av_back = ap;
+
+ ap->av_back = NULL;
+ bp->av_forw = NULL;
+
+ } else {
+ vm_offset_t addr;
+
+ cldiskvamerge( kvanew, orig1begin, orig1pages, orig2begin, orig2pages);
+ /*
+ * free the old kva
+ */
+ vm_bounce_kva_free( orig1begin, ap->b_bufsize, 0);
+ --clstats[ap->b_bcount/PAGE_SIZE];
+
+ ap->b_un.b_addr = (caddr_t) kvanew;
+
+ ap->b_clusterl->av_forw = bp;
+ bp->av_forw = NULL;
+ bp->av_back = ap->b_clusterl;
+ ap->b_clusterl = bp;
+
+ ap->b_bcount += bp->b_bcount;
+ ap->b_bufsize = ap->b_bcount;
+ ++clstats[ap->b_bcount/PAGE_SIZE];
+ }
+ return;
+ /*
+ * merge with next?
+ * conditions:
+ * 1) We reside physically before the next block.
+ * 3) The mode of the two I/Os is identical.
+ * 4) The next kva is page aligned and the next transfer
+ * is a multiple of a page in length.
+ * 5) And the total I/O size would be below the maximum.
+ */
+ } else if( ap->av_forw &&
+ (bp->b_pblkno + (bp->b_bcount / DEV_BSIZE) == ap->av_forw->b_pblkno) &&
+ (bp->b_flags == (ap->av_forw->b_flags & ~B_CLUSTER)) &&
+ ((ap->av_forw->b_flags & B_BAD) == 0) &&
+ ((ap->av_forw->b_bcount & PAGE_MASK) == 0) &&
+ (((vm_offset_t) ap->av_forw->b_un.b_addr & PAGE_MASK) == 0) &&
+ (ap->av_forw->b_bcount + bp->b_bcount < maxio)) {
+
+ orig1begin = (vm_offset_t) bp->b_un.b_addr;
+ orig1pages = bp->b_bcount / PAGE_SIZE;
+
+ orig2begin = (vm_offset_t) ap->av_forw->b_un.b_addr;
+ orig2pages = ap->av_forw->b_bcount / PAGE_SIZE;
+
+ /*
+ * see if we can allocate a kva, if we cannot, the don't
+ * cluster.
+ */
+ kvanew = vm_bounce_kva( PAGE_SIZE * (orig1pages + orig2pages), 0);
+ if( !kvanew) {
+ goto nocluster;
+ }
+
+ /*
+ * if next isn't a cluster we need to create one
+ */
+ if( (ap->av_forw->b_flags & B_CLUSTER) == 0) {
+
+ /*
+ * get a physical buf pointer
+ */
+ newbp = (struct buf *)trypbuf();
+ if( !newbp) {
+ vm_bounce_kva_free( kvanew, PAGE_SIZE * (orig1pages + orig2pages), 1);
+ goto nocluster;
+ }
+
+ cldiskvamerge( kvanew, orig1begin, orig1pages, orig2begin, orig2pages);
+ ap = ap->av_forw;
+ --clstats[ap->b_bcount/PAGE_SIZE];
+ *newbp = *ap;
+ newbp->b_flags |= B_CLUSTER;
+ newbp->b_un.b_addr = (caddr_t) kvanew;
+ newbp->b_blkno = bp->b_blkno;
+ newbp->b_pblkno = bp->b_pblkno;
+ newbp->b_bcount += bp->b_bcount;
+ newbp->b_bufsize = newbp->b_bcount;
+ newbp->b_clusterf = bp;
+ newbp->b_clusterl = ap;
+ ++clstats[newbp->b_bcount/PAGE_SIZE];
+
+ if( ap->av_forw)
+ ap->av_forw->av_back = newbp;
+ else
+ dp->b_actl = newbp;
+
+ if( dp->b_actf != ap )
+ ap->av_back->av_forw = newbp;
+ else
+ dp->b_actf = newbp;
+
+ bp->av_forw = ap;
+ ap->av_back = bp;
+
+ bp->av_back = NULL;
+ ap->av_forw = NULL;
+ } else {
+ vm_offset_t addr;
+
+ cldiskvamerge( kvanew, orig1begin, orig1pages, orig2begin, orig2pages);
+ ap = ap->av_forw;
+ vm_bounce_kva_free( orig2begin, ap->b_bufsize, 0);
+
+ ap->b_un.b_addr = (caddr_t) kvanew;
+ bp->av_forw = ap->b_clusterf;
+ ap->b_clusterf->av_back = bp;
+ ap->b_clusterf = bp;
+ bp->av_back = NULL;
+ --clstats[ap->b_bcount/PAGE_SIZE];
+
+ ap->b_blkno = bp->b_blkno;
+ ap->b_pblkno = bp->b_pblkno;
+ ap->b_bcount += bp->b_bcount;
+ ap->b_bufsize = ap->b_bcount;
+ ++clstats[ap->b_bcount/PAGE_SIZE];
+
+ }
+ return;
+ }
+ }
+ /*
+ * don't merge
+ */
+nocluster:
+ ++clstats[bp->b_bcount/PAGE_SIZE];
+ bp->av_forw = ap->av_forw;
+ if( bp->av_forw)
+ bp->av_forw->av_back = bp;
+ else
+ dp->b_actl = bp;
+
+ ap->av_forw = bp;
+ bp->av_back = ap;
+}
+
+/*
+ * quick version of vm_fault
+ */
+
+void
+vm_fault_quick( v, prot)
+ vm_offset_t v;
+ int prot;
+{
+ if( (cpu_class == CPUCLASS_386) &&
+ (prot & VM_PROT_WRITE))
+ vm_fault(&curproc->p_vmspace->vm_map, v,
+ VM_PROT_READ|VM_PROT_WRITE, FALSE);
+ else if( prot & VM_PROT_WRITE)
+ *(volatile char *)v += 0;
+ else
+ *(volatile char *)v;
+}
+
+
+/*
+ * Finish a fork operation, with process p2 nearly set up.
+ * Copy and update the kernel stack and pcb, making the child
+ * ready to run, and marking it so that it can return differently
+ * than the parent. Returns 1 in the child process, 0 in the parent.
+ * We currently double-map the user area so that the stack is at the same
+ * address in each process; in the future we will probably relocate
+ * the frame pointers on the stack after copying.
+ */
+int
+cpu_fork(p1, p2)
+ register struct proc *p1, *p2;
+{
+ register struct user *up = p2->p_addr;
+ int foo, offset, addr, i;
+ extern char kstack[];
+ extern int mvesp();
+
+ /*
+ * Copy pcb and stack from proc p1 to p2.
+ * We do this as cheaply as possible, copying only the active
+ * part of the stack. The stack and pcb need to agree;
+ * this is tricky, as the final pcb is constructed by savectx,
+ * but its frame isn't yet on the stack when the stack is copied.
+ * swtch compensates for this when the child eventually runs.
+ * This should be done differently, with a single call
+ * that copies and updates the pcb+stack,
+ * replacing the bcopy and savectx.
+ */
+ p2->p_addr->u_pcb = p1->p_addr->u_pcb;
+ offset = mvesp() - (int)kstack;
+ bcopy((caddr_t)kstack + offset, (caddr_t)p2->p_addr + offset,
+ (unsigned) ctob(UPAGES) - offset);
+ p2->p_regs = p1->p_regs;
+
+ /*
+ * Wire top of address space of child to it's kstack.
+ * First, fault in a page of pte's to map it.
+ */
+#if 0
+ addr = trunc_page((u_int)vtopte(kstack));
+ vm_map_pageable(&p2->p_vmspace->vm_map, addr, addr+NBPG, FALSE);
+ for (i=0; i < UPAGES; i++)
+ pmap_enter(&p2->p_vmspace->vm_pmap, kstack+i*NBPG,
+ pmap_extract(kernel_pmap, ((int)p2->p_addr)+i*NBPG),
+ /*
+ * The user area has to be mapped writable because
+ * it contains the kernel stack (when CR0_WP is on
+ * on a 486 there is no user-read/kernel-write
+ * mode). It is protected from user mode access
+ * by the segment limits.
+ */
+ VM_PROT_READ|VM_PROT_WRITE, TRUE);
+#endif
+ pmap_activate(&p2->p_vmspace->vm_pmap, &up->u_pcb);
+
+ /*
+ *
+ * Arrange for a non-local goto when the new process
+ * is started, to resume here, returning nonzero from setjmp.
+ */
+ if (savectx(up, 1)) {
+ /*
+ * Return 1 in child.
+ */
+ return (1);
+ }
+ return (0);
+}
+
+#ifdef notyet
+/*
+ * cpu_exit is called as the last action during exit.
+ *
+ * We change to an inactive address space and a "safe" stack,
+ * passing thru an argument to the new stack. Now, safely isolated
+ * from the resources we're shedding, we release the address space
+ * and any remaining machine-dependent resources, including the
+ * memory for the user structure and kernel stack.
+ *
+ * Next, we assign a dummy context to be written over by swtch,
+ * calling it to send this process off to oblivion.
+ * [The nullpcb allows us to minimize cost in swtch() by not having
+ * a special case].
+ */
+struct proc *swtch_to_inactive();
+volatile void
+cpu_exit(p)
+ register struct proc *p;
+{
+ static struct pcb nullpcb; /* pcb to overwrite on last swtch */
+
+#if NNPX > 0
+ npxexit(p);
+#endif /* NNPX */
+
+ /* move to inactive space and stack, passing arg accross */
+ p = swtch_to_inactive(p);
+
+ /* drop per-process resources */
+ vmspace_free(p->p_vmspace);
+ kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES));
+
+ p->p_addr = (struct user *) &nullpcb;
+ splclock();
+ swtch();
+ /* NOTREACHED */
+}
+#else
+void
+cpu_exit(p)
+ register struct proc *p;
+{
+
+#if NNPX > 0
+ npxexit(p);
+#endif /* NNPX */
+ splclock();
+ curproc = 0;
+ swtch();
+ /*
+ * This is to shutup the compiler, and if swtch() failed I suppose
+ * this would be a good thing. This keeps gcc happy because panic
+ * is a volatile void function as well.
+ */
+ panic("cpu_exit");
+}
+
+void
+cpu_wait(p) struct proc *p; {
+/* extern vm_map_t upages_map; */
+ extern char kstack[];
+
+ /* drop per-process resources */
+ pmap_remove(vm_map_pmap(kernel_map), (vm_offset_t) p->p_addr,
+ ((vm_offset_t) p->p_addr) + ctob(UPAGES));
+ kmem_free(kernel_map, (vm_offset_t)p->p_addr, ctob(UPAGES));
+ vmspace_free(p->p_vmspace);
+}
+#endif
+
+/*
+ * Set a red zone in the kernel stack after the u. area.
+ */
+void
+setredzone(pte, vaddr)
+ u_short *pte;
+ caddr_t vaddr;
+{
+/* eventually do this by setting up an expand-down stack segment
+ for ss0: selector, allowing stack access down to top of u.
+ this means though that protection violations need to be handled
+ thru a double fault exception that must do an integral task
+ switch to a known good context, within which a dump can be
+ taken. a sensible scheme might be to save the initial context
+ used by sched (that has physical memory mapped 1:1 at bottom)
+ and take the dump while still in mapped mode */
+}
+
+/*
+ * Convert kernel VA to physical address
+ */
+u_long
+kvtop(void *addr)
+{
+ vm_offset_t va;
+
+ va = pmap_kextract((vm_offset_t)addr);
+ if (va == 0)
+ panic("kvtop: zero page frame");
+ return((int)va);
+}
+
+extern vm_map_t phys_map;
+
+/*
+ * Map an IO request into kernel virtual address space.
+ *
+ * All requests are (re)mapped into kernel VA space.
+ * Notice that we use b_bufsize for the size of the buffer
+ * to be mapped. b_bcount might be modified by the driver.
+ */
+void
+vmapbuf(bp)
+ register struct buf *bp;
+{
+ register int npf;
+ register caddr_t addr;
+ register long flags = bp->b_flags;
+ struct proc *p;
+ int off;
+ vm_offset_t kva;
+ register vm_offset_t pa;
+
+ if ((flags & B_PHYS) == 0)
+ panic("vmapbuf");
+ addr = bp->b_saveaddr = bp->b_un.b_addr;
+ off = (int)addr & PGOFSET;
+ p = bp->b_proc;
+ npf = btoc(round_page(bp->b_bufsize + off));
+ kva = kmem_alloc_wait(phys_map, ctob(npf));
+ bp->b_un.b_addr = (caddr_t) (kva + off);
+ while (npf--) {
+ pa = pmap_extract(&p->p_vmspace->vm_pmap, (vm_offset_t)addr);
+ if (pa == 0)
+ panic("vmapbuf: null page frame");
+ pmap_kenter(kva, trunc_page(pa));
+ addr += PAGE_SIZE;
+ kva += PAGE_SIZE;
+ }
+ pmap_update();
+}
+
+/*
+ * Free the io map PTEs associated with this IO operation.
+ * We also invalidate the TLB entries and restore the original b_addr.
+ */
+void
+vunmapbuf(bp)
+ register struct buf *bp;
+{
+ register int npf;
+ register caddr_t addr = bp->b_un.b_addr;
+ vm_offset_t kva;
+
+ if ((bp->b_flags & B_PHYS) == 0)
+ panic("vunmapbuf");
+ npf = btoc(round_page(bp->b_bufsize + ((int)addr & PGOFSET)));
+ kva = (vm_offset_t)((int)addr & ~PGOFSET);
+ kmem_free_wakeup(phys_map, kva, ctob(npf));
+ bp->b_un.b_addr = bp->b_saveaddr;
+ bp->b_saveaddr = NULL;
+}
+
+/*
+ * Force reset the processor by invalidating the entire address space!
+ */
+void
+cpu_reset() {
+
+ /* force a shutdown by unmapping entire address space ! */
+ bzero((caddr_t) PTD, NBPG);
+
+ /* "good night, sweet prince .... <THUNK!>" */
+ tlbflush();
+ /* NOTREACHED */
+ while(1);
+}
+
+/*
+ * Grow the user stack to allow for 'sp'. This version grows the stack in
+ * chunks of SGROWSIZ.
+ */
+int
+grow(p, sp)
+ struct proc *p;
+ int sp;
+{
+ unsigned int nss;
+ caddr_t v;
+ struct vmspace *vm = p->p_vmspace;
+
+ if ((caddr_t)sp <= vm->vm_maxsaddr || (unsigned)sp >= (unsigned)USRSTACK)
+ return (1);
+
+ nss = roundup(USRSTACK - (unsigned)sp, PAGE_SIZE);
+
+ if (nss > p->p_rlimit[RLIMIT_STACK].rlim_cur)
+ return (0);
+
+ if (vm->vm_ssize && roundup(vm->vm_ssize << PAGE_SHIFT,
+ SGROWSIZ) < nss) {
+ int grow_amount;
+ /*
+ * If necessary, grow the VM that the stack occupies
+ * to allow for the rlimit. This allows us to not have
+ * to allocate all of the VM up-front in execve (which
+ * is expensive).
+ * Grow the VM by the amount requested rounded up to
+ * the nearest SGROWSIZ to provide for some hysteresis.
+ */
+ grow_amount = roundup((nss - (vm->vm_ssize << PAGE_SHIFT)), SGROWSIZ);
+ v = (char *)USRSTACK - roundup(vm->vm_ssize << PAGE_SHIFT,
+ SGROWSIZ) - grow_amount;
+ /*
+ * If there isn't enough room to extend by SGROWSIZ, then
+ * just extend to the maximum size
+ */
+ if (v < vm->vm_maxsaddr) {
+ v = vm->vm_maxsaddr;
+ grow_amount = MAXSSIZ - (vm->vm_ssize << PAGE_SHIFT);
+ }
+ if (vm_allocate(&vm->vm_map, (vm_offset_t *)&v,
+ grow_amount, FALSE) != KERN_SUCCESS) {
+ return (0);
+ }
+ vm->vm_ssize += grow_amount >> PAGE_SHIFT;
+ }
+
+ return (1);
+}
diff --git a/sys/i386/include/_limits.h b/sys/i386/include/_limits.h
new file mode 100644
index 0000000..5aed870
--- /dev/null
+++ b/sys/i386/include/_limits.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)limits.h 7.2 (Berkeley) 6/28/90
+ * $Id: limits.h,v 1.5 1994/02/26 00:56:02 ache Exp $
+ */
+
+#ifndef _MACHINE_LIMITS_H_
+#define _MACHINE_LIMITS_H_ 1
+
+#define CHAR_BIT 8 /* number of bits in a char */
+#define MB_LEN_MAX 6 /* allow 21-bit UTF2 */
+
+#define SCHAR_MIN (-0x7f-1) /* max value for a signed char */
+#define SCHAR_MAX 0x7f /* min value for a signed char */
+
+#define UCHAR_MAX 0xff /* max value for an unsigned char */
+#define CHAR_MAX 0x7f /* max value for a char */
+#define CHAR_MIN (-0x7f-1) /* min value for a char */
+
+#define USHRT_MAX 0xffff /* max value for an unsigned short */
+#define SHRT_MAX 0x7fff /* max value for a short */
+#define SHRT_MIN (-0x7fff-1) /* min value for a short */
+
+#define UINT_MAX 0xffffffff /* max value for an unsigned int */
+#define INT_MAX 0x7fffffff /* max value for an int */
+#define INT_MIN (-0x7fffffff-1) /* min value for an int */
+
+#define ULONG_MAX 0xffffffff /* max value for an unsigned long */
+#define LONG_MAX 0x7fffffff /* max value for a long */
+#define LONG_MIN (-0x7fffffff-1) /* min value for a long */
+
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+#define CLK_TCK 128 /* ticks per second */
+#define UQUAD_MAX 0xffffffffffffffffLL /* max unsigned quad */
+#define QUAD_MAX 0x7fffffffffffffffLL /* max signed quad */
+#define QUAD_MIN (-0x7fffffffffffffffLL-1) /* min signed quad */
+#endif
+
+#endif /* _MACHINE_LIMITS_H_ */
diff --git a/sys/i386/include/ansi.h b/sys/i386/include/ansi.h
new file mode 100644
index 0000000..1665aad
--- /dev/null
+++ b/sys/i386/include/ansi.h
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)ansi.h 7.1 (Berkeley) 3/9/91
+ * $Id: ansi.h,v 1.2 1993/10/16 14:39:05 rgrimes Exp $
+ */
+
+#ifndef _ANSI_H_
+#define _ANSI_H_
+
+/*
+ * Types which are fundamental to the implementation and may appear in
+ * more than one standard header are defined here. Standard headers
+ * then use:
+ * #ifdef _SIZE_T_
+ * typedef _SIZE_T_ size_t;
+ * #undef _SIZE_T_
+ * #endif
+ *
+ * Thanks, ANSI!
+ */
+#define _CLOCK_T_ unsigned long /* clock() */
+#define _PTRDIFF_T_ int /* ptr1 - ptr2 */
+#define _SIZE_T_ unsigned int /* sizeof() */
+#define _TIME_T_ long /* time() */
+#define _VA_LIST_ char * /* va_list */
+
+/*
+ * Runes (wchar_t) is declared to be an ``int'' instead of the more natural
+ * ``unsigned long'' or ``long''. Two things are happening here. It is not
+ * unsigned so that EOF (-1) can be naturally assigned to it and used. Also,
+ * it looks like 10646 will be a 31 bit standard. This means that if your
+ * ints cannot hold 32 bits, you will be in trouble. The reason an int was
+ * chosen over a long is that the is*() and to*() routines take ints (says
+ * ANSI C), but they use _RUNE_T_ instead of int. By changing it here, you
+ * lose a bit of ANSI conformance, but your programs will still work.
+ *
+ * Note that _WCHAR_T_ and _RUNE_T_ must be of the same type. When wchar_t
+ * and rune_t are typedef'd, _WCHAR_T_ will be undef'd, but _RUNE_T remains
+ * defined for ctype.h.
+ */
+#define _BSD_WCHAR_T_ int /* wchar_t */
+#define _BSD_RUNE_T_ int /* rune_t */
+
+
+#endif /* _ANSI_H_ */
diff --git a/sys/i386/include/asmacros.h b/sys/i386/include/asmacros.h
new file mode 100644
index 0000000..4af0b97
--- /dev/null
+++ b/sys/i386/include/asmacros.h
@@ -0,0 +1,49 @@
+#define ALIGN_DATA .align 2 /* 4 byte alignment, zero filled */
+#define ALIGN_TEXT .align 2,0x90 /* 4-byte alignment, nop filled */
+#define SUPERALIGN_TEXT .align 4,0x90 /* 16-byte alignment (better for 486), nop filled */
+
+#define GEN_ENTRY(name) ALIGN_TEXT; .globl name; name:
+#define NON_GPROF_ENTRY(name) GEN_ENTRY(_/**/name)
+
+/* These three are place holders for future changes to the profiling code */
+#define MCOUNT_LABEL(name)
+#define MEXITCOUNT
+#define FAKE_MCOUNT(caller)
+
+#ifdef GPROF
+/*
+ * ALTENTRY() must be before a corresponding ENTRY() so that it can jump
+ * over the mcounting.
+ */
+#define ALTENTRY(name) GEN_ENTRY(_/**/name); MCOUNT; jmp 2f
+#define ENTRY(name) GEN_ENTRY(_/**/name); MCOUNT; 2:
+/*
+ * The call to mcount supports the usual (bad) conventions. We allocate
+ * some data and pass a pointer to it although the FreeBSD doesn't use
+ * the data. We set up a frame before calling mcount because that is
+ * the standard convention although it makes work for both mcount and
+ * callers.
+ */
+#define MCOUNT .data; ALIGN_DATA; 1:; .long 0; .text; \
+ pushl %ebp; movl %esp,%ebp; \
+ movl $1b,%eax; call mcount; popl %ebp
+#else
+/*
+ * ALTENTRY() has to align because it is before a corresponding ENTRY().
+ * ENTRY() has to align to because there may be no ALTENTRY() before it.
+ * If there is a previous ALTENTRY() then the alignment code is empty.
+ */
+#define ALTENTRY(name) GEN_ENTRY(_/**/name)
+#define ENTRY(name) GEN_ENTRY(_/**/name)
+#define MCOUNT
+
+#endif
+
+#ifdef DUMMY_NOPS /* this will break some older machines */
+#define FASTER_NOP
+#define NOP
+#else
+#define FASTER_NOP pushl %eax ; inb $0x84,%al ; popl %eax
+#define NOP pushl %eax ; inb $0x84,%al ; inb $0x84,%al ; popl %eax
+#endif
+
diff --git a/sys/i386/include/cons.h b/sys/i386/include/cons.h
new file mode 100644
index 0000000..f66277e
--- /dev/null
+++ b/sys/i386/include/cons.h
@@ -0,0 +1,6 @@
+/*
+ * Console support headers should be in <machine/cons.h> since MI software
+ * needs to access these functions. In the mean time, just include the
+ * header where it sits.
+ */
+#include <i386/i386/cons.h>
diff --git a/sys/i386/include/console.h b/sys/i386/include/console.h
new file mode 100644
index 0000000..e663dea
--- /dev/null
+++ b/sys/i386/include/console.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 1992, 1993, 1994 Søren Schmidt
+ *
+ * This program is free software; you may redistribute it and/or
+ * modify it, provided that it retain the above copyright notice
+ * and the following disclaimer.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Søren Schmidt Email: sos@login.dkuug.dk
+ * Tritonvej 36 UUCP: ...uunet!dkuug!login!sos
+ * DK9210 Aalborg SO Phone: +45 9814 8076
+ *
+ * from:@(#)console.h 1.1 940105
+ * $Id: console.h,v 1.7 1994/02/04 10:35:29 chmr Exp $
+ */
+
+#ifndef _CONSOLE_H_
+#define _CONSOLE_H_
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#define KDGKBMODE _IOR('K', 6, int)
+#define KDSKBMODE _IO('K', 7)
+#define KDMKTONE _IO('K', 8)
+#define KDGETMODE _IOR('K', 9, int)
+#define KDSETMODE _IO('K', 10)
+#define KDSBORDER _IO('K', 13)
+#define KDGKBSTATE _IOR('K', 19, int)
+#define KDSKBSTATE _IO('K', 20)
+#define KDENABIO _IO('K', 60)
+#define KDDISABIO _IO('K', 61)
+#define KIOCSOUND _IO('K', 63)
+#define KDGKBTYPE _IOR('K', 64, int)
+#define KDGETLED _IOR('K', 65, int)
+#define KDSETLED _IO('K', 66)
+#define KDSETRAD _IO('K', 67)
+
+#define GETFKEY _IOWR('k', 0, fkeyarg_t)
+#define SETFKEY _IOWR('k', 1, fkeyarg_t)
+#define GIO_SCRNMAP _IOR('k', 2, scrmap_t)
+#define PIO_SCRNMAP _IOW('k', 3, scrmap_t)
+#define GIO_KEYMAP _IOR('k', 6, keymap_t)
+#define PIO_KEYMAP _IOW('k', 7, keymap_t)
+
+#define CONS_BLANKTIME _IOW('c', 4, long)
+#define CONS_SSAVER _IOW('c', 5, ssaver_t)
+#define CONS_GSAVER _IOWR('c', 6, ssaver_t)
+#define PIO_FONT8x8 _IOW('c', 64, fnt8_t)
+#define GIO_FONT8x8 _IOR('c', 65, fnt8_t)
+#define PIO_FONT8x14 _IOW('c', 66, fnt14_t)
+#define GIO_FONT8x14 _IOR('c', 67, fnt14_t)
+#define PIO_FONT8x16 _IOW('c', 68, fnt16_t)
+#define GIO_FONT8x16 _IOR('c', 69, fnt16_t)
+#define CONS_GETINFO _IOWR('c', 73, vid_info_t)
+#define CONS_GETVERS _IOR('c', 74, long)
+#define CONS_80x25TEXT _IO('c', 102)
+#define CONS_80x50TEXT _IO('c', 103)
+
+#define VT_OPENQRY _IOR('v', 1, int)
+#define VT_SETMODE _IOW('v', 2, vtmode_t)
+#define VT_GETMODE _IOR('v', 3, vtmode_t)
+#define VT_RELDISP _IO('v', 4)
+#define VT_ACTIVATE _IO('v', 5)
+#define VT_WAITACTIVE _IO('v', 6)
+#define VT_GETACTIVE _IOR('v', 7, int)
+
+#define VT_FALSE 0
+#define VT_TRUE 1
+#define VT_ACKACQ 2
+
+#define VT_AUTO 0 /* switching is automatic */
+#define VT_PROCESS 1 /* switching controlled by prog */
+
+/* compatibility to old pccons & X386 */
+#define CONSOLE_X_MODE_ON _IO('t', 121)
+#define CONSOLE_X_MODE_OFF _IO('t', 122)
+#define CONSOLE_X_BELL _IOW('t',123,int[2])
+
+struct vt_mode {
+ char mode;
+ char waitv; /* not implemented yet SOS */
+ short relsig;
+ short acqsig;
+ short frsig; /* not implemented yet SOS */
+};
+
+
+#define KD_MONO 1 /* monochrome adapter */
+#define KD_HERCULES 2 /* hercules adapter */
+#define KD_CGA 3 /* color graphics adapter */
+#define KD_EGA 4 /* enhanced graphics adapter */
+#define KD_VGA 5 /* video graohics adapter */
+
+#define KD_TEXT 0 /* set text mode restore fonts */
+#define KD_TEXT0 0 /* ditto */
+#define KD_TEXT1 2 /* set text mode !restore fonts */
+#define KD_GRAPHICS 1 /* set graphics mode */
+
+#define K_RAW 0 /* keyboard returns scancodes */
+#define K_XLATE 1 /* keyboard returns ascii */
+
+#define KB_84 1 /* 'old' 84 key AT-keyboard */
+#define KB_101 2 /* MF-101 or MF-102 keyboard */
+#define KB_OTHER 3 /* keyboard not known */
+
+#define CLKED 1 /* Caps locked */
+#define NLKED 2 /* Num locked */
+#define SLKED 4 /* Scroll locked */
+#define ALKED 8 /* AltGr locked */
+#define LED_CAP 1 /* Caps lock LED */
+#define LED_NUM 2 /* Num lock LED */
+#define LED_SCR 4 /* Scroll lock LED */
+
+/* possible flag values */
+#define FLAG_LOCK_O 0
+#define FLAG_LOCK_C 1
+#define FLAG_LOCK_N 2
+
+#define NUM_KEYS 256 /* number of keys in table */
+#define NUM_STATES 8 /* states per key */
+#define ALTGR_OFFSET 128 /* offset for altlock keys */
+
+struct keymap {
+ u_short n_keys;
+ struct key_t {
+ u_char map[NUM_STATES];
+ u_char spcl;
+ u_char flgs;
+ } key[NUM_KEYS];
+};
+
+#define MAXFK 16
+
+struct fkeytab {
+ u_char str[MAXFK];
+ u_char len;
+};
+
+struct fkeyarg {
+ u_short keynum;
+ char keydef[MAXFK];
+ char flen;
+};
+
+struct colors {
+ char fore;
+ char back;
+};
+
+struct vid_info {
+ short size;
+ short m_num;
+ u_short mv_row, mv_col;
+ u_short mv_rsz, mv_csz;
+ struct colors mv_norm,
+ mv_rev,
+ mv_grfc;
+ u_char mv_ovscan;
+ u_char mk_keylock;
+};
+
+#define MAXSSAVER 16
+
+struct ssaver {
+ char name[MAXSSAVER];
+ int num;
+ long time;
+};
+
+typedef struct keymap keymap_t;
+typedef struct fkeytab fkeytab_t;
+typedef struct fkeyarg fkeyarg_t;
+typedef struct vid_info vid_info_t;
+typedef struct vt_mode vtmode_t;
+typedef struct {char scrmap[256];} scrmap_t;
+typedef struct {char fnt8x8[8*256];} fnt8_t;
+typedef struct {char fnt8x14[14*256];} fnt14_t;
+typedef struct {char fnt8x16[16*256];} fnt16_t;
+typedef struct ssaver ssaver_t;
+
+/* defines for "special" keys (spcl bit set in keymap) */
+#define NOP 0x00 /* nothing (dead key) */
+#define LSH 0x02 /* left shift key */
+#define RSH 0x03 /* right shift key */
+#define CLK 0x04 /* caps lock key */
+#define NLK 0x05 /* num lock key */
+#define SLK 0x06 /* scroll lock key */
+#define LALT 0x07 /* left alt key */
+#define LCTR 0x09 /* left control key */
+#define NEXT 0x0a /* switch to next screen */
+#define F_SCR 0x0b /* switch to first screen */
+#define L_SCR 0x1a /* switch to last screen */
+#define F_FN 0x1b /* first function key */
+#define L_FN 0x7a /* last function key */
+#define RCTR 0x7b /* right control key */
+#define RALT 0x7c /* right alt (altgr) key */
+#define ALK 0x7d /* alt lock key */
+#define ASH 0x7e /* alt shift key */
+#define META 0x7f /* meta key */
+#define RBT 0x80 /* boot machine */
+#define DBG 0x81 /* call debugger */
+
+#define F(x) ((x)+F_FN-1)
+#define S(x) ((x)+F_SCR-1)
+#define NOKEY 0x100 /* no key pressed marker */
+#define FKEY 0x200 /* funtion key marker */
+#define MKEY 0x400 /* meta key marker (prepend ESC)*/
+
+#define KB_DATA 0x60 /* kbd data port */
+#define KB_STAT 0x64 /* kbd status port */
+#define KB_BUF_FULL 0x01 /* kbd has char pending */
+#define KB_READY 0x02 /* kbd ready for command */
+#define KB_WRITE 0x60 /* kbd write command */
+#define KB_SETLEDS 0xed /* kbd set leds */
+#define KB_SETRAD 0xf3 /* kbd set repeat&delay command */
+#define KB_ACK 0xfa /* kbd acknowledge answer */
+#define KB_RESET_CPU 0xfe /* kbd reset main cpu command */
+#define KB_RESET 0xff /* kbd reset */
+
+#endif
diff --git a/sys/i386/include/cpu.h b/sys/i386/include/cpu.h
new file mode 100644
index 0000000..a2df023
--- /dev/null
+++ b/sys/i386/include/cpu.h
@@ -0,0 +1,110 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)cpu.h 5.4 (Berkeley) 5/9/91
+ * $Id: cpu.h,v 1.4 1993/11/07 17:42:46 wollman Exp $
+ */
+
+#ifndef _MACHINE_CPU_H_
+#define _MACHINE_CPU_H_ 1
+
+/*
+ * Definitions unique to i386 cpu support.
+ */
+#include "machine/frame.h"
+#include "machine/segments.h"
+
+/*
+ * definitions of cpu-dependent requirements
+ * referenced in generic code
+ */
+#undef COPY_SIGCODE /* don't copy sigcode above user stack in exec */
+
+#define cpu_exec(p) /* nothing */
+
+/*
+ * Arguments to hardclock, softclock and gatherstats
+ * encapsulate the previous machine state in an opaque
+ * clockframe; for now, use generic intrframe.
+ * XXX softclock() has been fixed. It never needed a
+ * whole frame, only a usermode flag, at least on this
+ * machine. Fix the rest.
+ */
+typedef struct intrframe clockframe;
+
+#define CLKF_USERMODE(framep) (ISPL((framep)->if_cs) == SEL_UPL)
+#define CLKF_BASEPRI(framep) (((framep)->if_ppl & ~SWI_AST_MASK) == 0)
+#define CLKF_PC(framep) ((framep)->if_eip)
+
+/*
+ * Preempt the current process if in interrupt from user mode,
+ * or after the current trap/syscall if in system mode.
+ */
+#define need_resched() { want_resched = 1; aston(); }
+
+/*
+ * Give a profiling tick to the current process from the softclock
+ * interrupt. On tahoe, request an ast to send us through trap(),
+ * marking the proc as needing a profiling tick.
+ */
+#define profile_tick(p, framep) { (p)->p_flag |= SOWEUPC; aston(); }
+
+/*
+ * Notify the current process (p) that it has a signal pending,
+ * process as soon as possible.
+ */
+#define signotify(p) aston()
+
+#define aston() setsoftast()
+#define astoff()
+
+/*
+ * pull in #defines for kinds of processors
+ */
+#include "machine/cputypes.h"
+
+struct cpu_nameclass {
+ char *cpu_name;
+ int cpu_class;
+};
+
+#ifdef KERNEL
+extern int want_resched; /* resched was called */
+
+extern int cpu;
+extern int cpu_class;
+extern struct cpu_nameclass i386_cpus[];
+#endif
+#endif /* _MACHINE_CPU_H_ */
diff --git a/sys/i386/include/cpufunc.h b/sys/i386/include/cpufunc.h
new file mode 100644
index 0000000..3c2dcc9
--- /dev/null
+++ b/sys/i386/include/cpufunc.h
@@ -0,0 +1,240 @@
+/*
+ * Functions to provide access to special i386 instructions.
+ * XXX - bezillions more are defined in locore.s but are not declared anywhere.
+ *
+ * $Id: cpufunc.h,v 1.9 1994/01/31 23:48:23 davidg Exp $
+ */
+
+#ifndef _MACHINE_CPUFUNC_H_
+#define _MACHINE_CPUFUNC_H_ 1
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include "machine/spl.h"
+
+#ifdef __GNUC__
+
+static inline int bdb(void)
+{
+ extern int bdb_exists;
+
+ if (!bdb_exists)
+ return (0);
+ __asm("int $3");
+ return (1);
+}
+
+static inline void
+disable_intr(void)
+{
+ __asm __volatile("cli");
+}
+
+static inline void
+enable_intr(void)
+{
+ __asm __volatile("sti");
+}
+
+/*
+ * This roundabout method of returning a u_char helps stop gcc-1.40 from
+ * generating unnecessary movzbl's.
+ */
+#define inb(port) ((u_char) u_int_inb(port))
+
+static inline u_int
+u_int_inb(u_int port)
+{
+ u_char data;
+ /*
+ * We use %%dx and not %1 here because i/o is done at %dx and not at
+ * %edx, while gcc-2.2.2 generates inferior code (movw instead of movl)
+ * if we tell it to load (u_short) port.
+ */
+ __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
+ return data;
+}
+
+static inline void
+outb(u_int port, u_char data)
+{
+ register u_char al asm("ax");
+
+ al = data; /* help gcc-1.40's register allocator */
+ __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
+}
+
+static inline void
+tlbflush()
+{
+ __asm __volatile("movl %%cr3, %%eax; movl %%eax, %%cr3" : : : "ax");
+}
+
+static inline
+int
+imin(a, b)
+ int a, b;
+{
+
+ return (a < b ? a : b);
+}
+
+static inline
+int
+imax(a, b)
+ int a, b;
+{
+
+ return (a > b ? a : b);
+}
+
+static inline
+unsigned int
+min(a, b)
+ unsigned int a, b;
+{
+
+ return (a < b ? a : b);
+}
+
+static inline
+unsigned int
+max(a, b)
+ unsigned int a, b;
+{
+
+ return (a > b ? a : b);
+}
+
+static inline
+long
+lmin(a, b)
+ long a, b;
+{
+
+ return (a < b ? a : b);
+}
+
+static inline
+long
+lmax(a, b)
+ long a, b;
+{
+
+ return (a > b ? a : b);
+}
+
+static inline
+unsigned long
+ulmin(a, b)
+ unsigned long a, b;
+{
+
+ return (a < b ? a : b);
+}
+
+static inline
+unsigned long
+ulmax(a, b)
+ unsigned long a, b;
+{
+
+ return (a > b ? a : b);
+}
+
+static inline
+int
+ffs(mask)
+ register long mask;
+{
+ register int bit;
+
+ if (!mask)
+ return(0);
+ for (bit = 1;; ++bit) {
+ if (mask&0x01)
+ return(bit);
+ mask >>= 1;
+ }
+}
+
+static inline
+int
+bcmp(v1, v2, len)
+ void *v1, *v2;
+ register unsigned len;
+{
+ register u_char *s1 = v1, *s2 = v2;
+
+ while (len--)
+ if (*s1++ != *s2++)
+ return (1);
+ return (0);
+}
+
+static inline
+size_t
+strlen(s1)
+ register const char *s1;
+{
+ register size_t len;
+
+ for (len = 0; *s1++ != '\0'; len++)
+ ;
+ return (len);
+}
+
+struct quehead {
+ struct quehead *qh_link;
+ struct quehead *qh_rlink;
+};
+
+static inline void
+insque(void *a, void *b)
+{
+ register struct quehead *element = a, *head = b;
+ element->qh_link = head->qh_link;
+ head->qh_link = (struct quehead *)element;
+ element->qh_rlink = (struct quehead *)head;
+ ((struct quehead *)(element->qh_link))->qh_rlink
+ = (struct quehead *)element;
+}
+
+static inline void
+remque(void *a)
+{
+ register struct quehead *element = a;
+ ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink;
+ ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link;
+ element->qh_rlink = 0;
+}
+
+#else /* not __GNUC__ */
+extern void insque __P((void *, void *));
+extern void remque __P((void *));
+
+int bdb __P((void));
+void disable_intr __P((void));
+void enable_intr __P((void));
+u_char inb __P((u_int port));
+void outb __P((u_int port, u_int data)); /* XXX - incompat */
+
+#endif /* __GNUC__ */
+
+void load_cr0 __P((u_int cr0));
+u_int rcr0 __P((void));
+void load_cr3(u_long);
+u_long rcr3(void);
+u_long rcr2(void);
+
+void setidt __P((int, void (*)(), int, int));
+extern u_long kvtop(void *);
+extern void outw(int /*u_short*/, int /*u_short*/); /* XXX inline!*/
+extern void outsb(int /*u_short*/, void *, size_t);
+extern void outsw(int /*u_short*/, void *, size_t);
+extern void insw(int /*u_short*/, void *, size_t);
+extern void fillw(int /*u_short*/, void *, size_t);
+extern void filli(int, void *, size_t);
+
+#endif /* _MACHINE_CPUFUNC_H_ */
diff --git a/sys/i386/include/cputypes.h b/sys/i386/include/cputypes.h
new file mode 100644
index 0000000..c85fe19
--- /dev/null
+++ b/sys/i386/include/cputypes.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1993 Christopher G. Demetriou
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: cputypes.h,v 1.1 1993/10/08 13:40:54 rgrimes Exp $
+ */
+
+#ifndef _MACHINE_CPUTYPES_H_
+#define _MACHINE_CPUTYPES_H_ 1
+
+/*
+ * Classes of Processor
+ */
+
+#define CPUCLASS_286 0
+#define CPUCLASS_386 1
+#define CPUCLASS_486 2
+#define CPUCLASS_586 3
+
+/*
+ * Kinds of Processor
+ */
+
+#define CPU_286 0 /* Intel 80286 */
+#define CPU_386SX 1 /* Intel 80386SX */
+#define CPU_386 2 /* Intel 80386DX */
+#define CPU_486SX 3 /* Intel 80486SX */
+#define CPU_486 4 /* Intel 80486DX */
+#define CPU_586 5 /* Intel P.....m (I hate lawyers; it's TM) */
+
+#endif /* _MACHINE_CPUTYPES_H_ */
diff --git a/sys/i386/include/db_machdep.h b/sys/i386/include/db_machdep.h
new file mode 100644
index 0000000..a3f4064
--- /dev/null
+++ b/sys/i386/include/db_machdep.h
@@ -0,0 +1,120 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * $Id: db_machdep.h,v 1.2 1993/10/16 14:39:10 rgrimes Exp $
+ */
+
+#ifndef _I386_DB_MACHDEP_H_
+#define _I386_DB_MACHDEP_H_
+
+/*
+ * Machine-dependent defines for new kernel debugger.
+ */
+
+
+/* #include <mach/i386/vm_types.h> */
+/* #include <mach/i386/vm_param.h> */
+#include <vm/vm_prot.h>
+#include <vm/vm_param.h>
+#include <vm/vm_inherit.h>
+#include <vm/lock.h>
+/* #include <i386/thread.h> */ /* for thread_status */
+#include <machine/frame.h> /* for struct trapframe */
+/* #include <i386/eflags.h> */
+#include <machine/eflags.h> /* from Mach... */
+/* #include <i386/trap.h> */
+#include <machine/trap.h>
+
+#define i386_saved_state trapframe
+/* end of mangling */
+
+typedef vm_offset_t db_addr_t; /* address - unsigned */
+typedef int db_expr_t; /* expression - signed */
+
+typedef struct i386_saved_state db_regs_t;
+extern db_regs_t ddb_regs; /* register state */
+#define DDB_REGS (&ddb_regs)
+
+#define PC_REGS(regs) ((db_addr_t)(regs)->tf_eip)
+
+#define BKPT_INST 0xcc /* breakpoint instruction */
+#define BKPT_SIZE (1) /* size of breakpoint inst */
+#define BKPT_SET(inst) (BKPT_INST)
+
+#define FIXUP_PC_AFTER_BREAK ddb_regs.tf_eip -= 1;
+
+#define db_clear_single_step(regs) ((regs)->tf_eflags &= ~EFL_TF)
+#define db_set_single_step(regs) ((regs)->tf_eflags |= EFL_TF)
+
+/* #define IS_BREAKPOINT_TRAP(type, code) ((type) == T_INT3) */
+/* #define IS_WATCHPOINT_TRAP(type, code) ((type) == T_WATCHPOINT) */
+/* using the 386bsd values, rather than the Mach ones: */
+#define IS_BREAKPOINT_TRAP(type, code) ((type) == T_BPTFLT)
+#define IS_WATCHPOINT_TRAP(type, code) ((type) == T_KDBTRAP)
+
+#define I_CALL 0xe8
+#define I_CALLI 0xff
+#define I_RET 0xc3
+#define I_IRET 0xcf
+
+#define inst_trap_return(ins) (((ins)&0xff) == I_IRET)
+#define inst_return(ins) (((ins)&0xff) == I_RET)
+#define inst_call(ins) (((ins)&0xff) == I_CALL || \
+ (((ins)&0xff) == I_CALLI && \
+ ((ins)&0x3800) == 0x1000))
+#define inst_load(ins) 0
+#define inst_store(ins) 0
+
+/* access capability and access macros */
+
+#define DB_ACCESS_LEVEL 2 /* access any space */
+#define DB_CHECK_ACCESS(addr,size,task) \
+ db_check_access(addr,size,task)
+#define DB_PHYS_EQ(task1,addr1,task2,addr2) \
+ db_phys_eq(task1,addr1,task2,addr2)
+#define DB_VALID_KERN_ADDR(addr) \
+ ((addr) >= VM_MIN_KERNEL_ADDRESS && \
+ (addr) < VM_MAX_KERNEL_ADDRESS)
+#define DB_VALID_ADDRESS(addr,user) \
+ ((!(user) && DB_VALID_KERN_ADDR(addr)) || \
+ ((user) && (addr) < VM_MIN_KERNEL_ADDRESS))
+
+boolean_t db_check_access(/* vm_offset_t, int, task_t */);
+boolean_t db_phys_eq(/* task_t, vm_offset_t, task_t, vm_offset_t */);
+
+/* macros for printing OS server dependent task name */
+
+#define DB_TASK_NAME(task) db_task_name(task)
+#define DB_TASK_NAME_TITLE "COMMAND "
+#define DB_TASK_NAME_LEN 23
+#define DB_NULL_TASK_NAME "? "
+
+void db_task_name(/* task_t */);
+
+/* macro for checking if a thread has used floating-point */
+
+#define db_thread_fp_used(thread) ((thread)->pcb->ims.ifps != 0)
+
+#endif /* _I386_DB_MACHDEP_H_ */
diff --git a/sys/i386/include/dkio.h b/sys/i386/include/dkio.h
new file mode 100644
index 0000000..af781be
--- /dev/null
+++ b/sys/i386/include/dkio.h
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)dkio.h 5.2 (Berkeley) 1/18/91
+ * $Id: dkio.h,v 1.2 1993/10/16 14:39:12 rgrimes Exp $
+ */
+
+#ifndef _MACHINE_DKIO_H_
+#define _MACHINE_DKIO_H_ 1
+
+/*
+ * Structures and definitions for disk io control commands
+ *
+ * THIS WHOLE AREA NEEDS MORE THOUGHT. FOR NOW JUST IMPLEMENT
+ * ENOUGH TO READ AND WRITE HEADERS ON MASSBUS DISKS. EVENTUALLY
+ * SHOULD BE ABLE TO DETERMINE DRIVE TYPE AND DO OTHER GOOD STUFF.
+ */
+
+/* disk io control commands */
+#define DKIOCHDR _IO(d, 1) /* next I/O will read/write header */
+#endif /* _MACHINE_DKIO_H_ */
diff --git a/sys/i386/include/eflags.h b/sys/i386/include/eflags.h
new file mode 100644
index 0000000..663b317
--- /dev/null
+++ b/sys/i386/include/eflags.h
@@ -0,0 +1,54 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * $Id$
+ */
+
+#ifndef _I386_EFLAGS_H_
+#define _I386_EFLAGS_H_
+
+/*
+ * i386 flags register
+ */
+#define EFL_CF 0x00000001 /* carry */
+#define EFL_PF 0x00000004 /* parity of low 8 bits */
+#define EFL_AF 0x00000010 /* carry out of bit 3 */
+#define EFL_ZF 0x00000040 /* zero */
+#define EFL_SF 0x00000080 /* sign */
+#define EFL_TF 0x00000100 /* trace trap */
+#define EFL_IF 0x00000200 /* interrupt enable */
+#define EFL_DF 0x00000400 /* direction */
+#define EFL_OF 0x00000800 /* overflow */
+#define EFL_IOPL 0x00003000 /* IO privilege level: */
+#define EFL_IOPL_KERNEL 0x00000000 /* kernel */
+#define EFL_IOPL_USER 0x00003000 /* user */
+#define EFL_NT 0x00004000 /* nested task */
+#define EFL_RF 0x00010000 /* resume without tracing */
+#define EFL_VM 0x00020000 /* virtual 8086 mode */
+
+#define EFL_USER_SET (EFL_IF)
+#define EFL_USER_CLEAR (EFL_IOPL|EFL_NT|EFL_RF)
+
+#endif _I386_EFLAGS_H_
diff --git a/sys/i386/include/endian.h b/sys/i386/include/endian.h
new file mode 100644
index 0000000..dc4e98c
--- /dev/null
+++ b/sys/i386/include/endian.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 1987, 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)endian.h 7.8 (Berkeley) 4/3/91
+ * $Id: endian.h,v 1.3 1993/11/07 17:42:52 wollman Exp $
+ */
+
+#ifndef _MACHINE_ENDIAN_H_
+#define _MACHINE_ENDIAN_H_ 1
+
+/*
+ * Define the order of 32-bit words in 64-bit words.
+ */
+#define _QUAD_HIGHWORD 1
+#define _QUAD_LOWWORD 0
+
+/*
+ * Definitions for byte order, according to byte significance from low
+ * address to high.
+ */
+#define LITTLE_ENDIAN 1234 /* LSB first: i386, vax */
+#define BIG_ENDIAN 4321 /* MSB first: 68000, ibm, net */
+#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long */
+
+#define BYTE_ORDER LITTLE_ENDIAN
+
+#ifndef KERNEL
+#include <sys/cdefs.h>
+#endif
+
+#define __word_swap_long(x) \
+({ register u_long X = (x); \
+ asm ("rorl $16, %1" \
+ : "=r" (X) \
+ : "0" (X)); \
+ X; })
+#if __GNUC__ >= 2
+#define __byte_swap_long(x) \
+({ register u_long X = (x); \
+ asm ("xchgb %h1, %b1\n\trorl $16, %1\n\txchgb %h1, %b1" \
+ : "=q" (X) \
+ : "0" (X)); \
+ X; })
+#define __byte_swap_word(x) \
+({ register u_short X = (x); \
+ asm ("xchgb %h1, %b1" \
+ : "=q" (X) \
+ : "0" (X)); \
+ X; })
+#else /* __GNUC__ >= 2 */
+#define __byte_swap_long(x) \
+({ register u_long X = (x); \
+ asm ("rorw $8, %w1\n\trorl $16, %1\n\trorw $8, %w1" \
+ : "=r" (X) \
+ : "0" (X)); \
+ X; })
+#define __byte_swap_word(x) \
+({ register u_short X = (x); \
+ asm ("rorw $8, %w1" \
+ : "=r" (X) \
+ : "0" (X)); \
+ X; })
+#endif /* __GNUC__ >= 2 */
+
+/*
+ * Macros for network/external number representation conversion.
+ */
+#if BYTE_ORDER == BIG_ENDIAN && !defined(lint)
+#define ntohl(x) (x)
+#define ntohs(x) (x)
+#define htonl(x) (x)
+#define htons(x) (x)
+
+#define NTOHL(x) (x)
+#define NTOHS(x) (x)
+#define HTONL(x) (x)
+#define HTONS(x) (x)
+
+#else
+
+#define ntohl __byte_swap_long
+#define ntohs __byte_swap_word
+#define htonl __byte_swap_long
+#define htons __byte_swap_word
+
+#define NTOHL(x) (x) = ntohl((u_long)x)
+#define NTOHS(x) (x) = ntohs((u_short)x)
+#define HTONL(x) (x) = htonl((u_long)x)
+#define HTONS(x) (x) = htons((u_short)x)
+#endif
+#endif /* _MACHINE_ENDIAN_H_ */
diff --git a/sys/i386/include/float.h b/sys/i386/include/float.h
new file mode 100644
index 0000000..fb5967e
--- /dev/null
+++ b/sys/i386/include/float.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)float.h 7.1 (Berkeley) 5/8/90
+ * $Id: float.h,v 1.4 1993/10/16 14:39:16 rgrimes Exp $
+ */
+
+#ifndef _MACHINE_FLOAT_H_
+#define _MACHINE_FLOAT_H_ 1
+
+#define FLT_RADIX 2 /* b */
+#define FLT_ROUNDS 1 /* FP addition rounds to nearest */
+
+#define FLT_MANT_DIG 24 /* p */
+#define FLT_EPSILON 1.19209290E-07F /* b**(1-p) */
+#define FLT_DIG 6 /* floor((p-1)*log10(b))+(b == 10) */
+#define FLT_MIN_EXP (-125) /* emin */
+#define FLT_MIN 1.17549435E-38F /* b**(emin-1) */
+#define FLT_MIN_10_EXP (-37) /* ceil(log10(b**(emin-1))) */
+#define FLT_MAX_EXP 128 /* emax */
+#define FLT_MAX 3.40282347E+38F /* (1-b**(-p))*b**emax */
+#define FLT_MAX_10_EXP 38 /* floor(log10((1-b**(-p))*b**emax)) */
+
+#define DBL_MANT_DIG 53
+#define DBL_EPSILON 2.2204460492503131E-16
+#define DBL_DIG 15
+#define DBL_MIN_EXP (-1021)
+#define DBL_MIN 2.2250738585072014E-308
+#define DBL_MIN_10_EXP (-307)
+#define DBL_MAX_EXP 1024
+#define DBL_MAX 1.7976931348623157E+308
+#define DBL_MAX_10_EXP 308
+
+#define LDBL_MANT_DIG DBL_MANT_DIG
+#define LDBL_EPSILON DBL_EPSILON
+#define LDBL_DIG DBL_DIG
+#define LDBL_MIN_EXP DBL_MIN_EXP
+#define LDBL_MIN DBL_MIN
+#define LDBL_MIN_10_EXP DBL_MIN_10_EXP
+#define LDBL_MAX_EXP DBL_MAX_EXP
+#define LDBL_MAX DBL_MAX
+#define LDBL_MAX_10_EXP DBL_MAX_10_EXP
+#endif /* _MACHINE_FLOAT_H_ */
diff --git a/sys/i386/include/floatingpoint.h b/sys/i386/include/floatingpoint.h
new file mode 100644
index 0000000..ed47cf6
--- /dev/null
+++ b/sys/i386/include/floatingpoint.h
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1993 Andrew Moore, Talke Studio
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#) floatingpoint.h 1.0 (Berkeley) 9/23/93
+ * $Id: floatingpoint.h,v 1.3 1993/10/16 14:39:18 rgrimes Exp $
+ */
+
+/*
+ * IEEE floating point structure and function definitions
+ */
+
+#ifndef _FLOATINGPOINT_H_
+#define _FLOATINGPOINT_H_
+
+#include <sys/cdefs.h>
+#include <sys/ieeefp.h>
+
+#ifdef __GNUC__
+
+#ifdef __i386__
+
+#define fnstcw(addr) __asm("fnstcw %0" : "=m" (*addr) : "0" (*addr))
+#define fnstsw(addr) __asm("fnstsw %0" : "=m" (*addr) : "0" (*addr))
+#define fnstenv(addr) __asm("fnstenv %0" : "=m" (*addr) : "0" (*addr))
+#define fldenv(addr) __asm("fldenv %0" : : "m" (*addr))
+
+
+/*
+ * return the contents of a FP register
+ */
+static __inline__ int
+__fpgetreg(int _reg)
+{
+ unsigned short _mem;
+
+ switch(_reg) {
+ default:
+ fnstcw(&_mem);
+ break;
+ case FP_STKY_REG:
+ fnstsw(&_mem);
+ break;
+ }
+ return _mem;
+}
+
+/*
+ * set a FP mode; return previous mode
+ */
+static __inline__ int
+__fpsetreg(int _m, int _reg, int _fld, int _off)
+{
+ unsigned _env[7];
+ unsigned _p;
+
+ fnstenv(_env);
+ _p = (_env[_reg] & _fld) >> _off;
+ _env[_reg] = (_env[_reg] & ~_fld) | (_m << _off & _fld);
+ fldenv(_env);
+ return _p;
+}
+
+#endif /* __i386__ */
+
+#endif /* __GNUC__ */
+
+/*
+ * SysV/386 FP control interface
+ */
+#define fpgetround() ((__fpgetreg(FP_RND_REG) & FP_RND_FLD) >> FP_RND_OFF)
+#define fpsetround(m) __fpsetreg((m), FP_RND_REG, FP_RND_FLD, FP_RND_OFF)
+#define fpgetprec() ((__fpgetreg(FP_PRC_REG) & FP_PRC_FLD) >> FP_PRC_OFF)
+#define fpsetprec(m) __fpsetreg((m), FP_PRC_REG, FP_PRC_FLD, FP_PRC_OFF)
+#define fpgetmask() ((~__fpgetreg(FP_MSKS_REG) & FP_MSKS_FLD) >> FP_MSKS_OFF)
+#define fpsetmask(m) __fpsetreg(~(m), FP_MSKS_REG, FP_MSKS_FLD, FP_MSKS_OFF)
+#define fpgetsticky() ((__fpgetreg(FP_STKY_REG) & FP_STKY_FLD) >> FP_STKY_OFF)
+#define fpresetsticky(m) __fpsetreg(0, FP_STKY_REG, (m), FP_STKY_OFF)
+#define fpsetsticky(m) fpresetsticky(m)
+
+#endif /* !_FLOATINGPOINT_H_ */
diff --git a/sys/i386/include/frame.h b/sys/i386/include/frame.h
new file mode 100644
index 0000000..05bf265
--- /dev/null
+++ b/sys/i386/include/frame.h
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)frame.h 5.2 (Berkeley) 1/18/91
+ * $Id: frame.h,v 1.7 1994/01/03 07:55:32 davidg Exp $
+ */
+
+#ifndef _MACHINE_FRAME_H_
+#define _MACHINE_FRAME_H_ 1
+
+#include <sys/signal.h>
+
+/*
+ * System stack frames.
+ */
+
+/*
+ * Exception/Trap Stack Frame
+ */
+
+struct trapframe {
+ int tf_es;
+ int tf_ds;
+ int tf_edi;
+ int tf_esi;
+ int tf_ebp;
+ int tf_isp;
+ int tf_ebx;
+ int tf_edx;
+ int tf_ecx;
+ int tf_eax;
+ int tf_trapno;
+ /* below portion defined in 386 hardware */
+ int tf_err;
+ int tf_eip;
+ int tf_cs;
+ int tf_eflags;
+ /* below only when transitting rings (e.g. user to kernel) */
+ int tf_esp;
+ int tf_ss;
+};
+
+extern int kdb_trap(int, int, struct trapframe *);
+
+/* Interrupt stack frame */
+
+struct intrframe {
+ int if_vec;
+ int if_ppl;
+ int if_es;
+ int if_ds;
+ int if_edi;
+ int if_esi;
+ int if_ebp;
+ int :32;
+ int if_ebx;
+ int if_edx;
+ int if_ecx;
+ int if_eax;
+ int :32; /* for compat with trap frame - trapno */
+ int :32; /* for compat with trap frame - err */
+ /* below portion defined in 386 hardware */
+ int if_eip;
+ int if_cs;
+ int if_eflags;
+ /* below only when transitting rings (e.g. user to kernel) */
+ int if_esp;
+ int if_ss;
+};
+
+/*
+ * Signal frame
+ */
+struct sigframe {
+ int sf_signum;
+ int sf_code;
+ struct sigcontext *sf_scp;
+ char *sf_addr;
+ sig_t sf_handler;
+ struct sigcontext sf_sc;
+};
+#endif /* _MACHINE_FRAME_H_ */
diff --git a/sys/i386/include/ioctl_fd.h b/sys/i386/include/ioctl_fd.h
new file mode 100644
index 0000000..2e3ac31
--- /dev/null
+++ b/sys/i386/include/ioctl_fd.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 1992-1993 by Joerg Wunsch, Dresden
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _IOCTL_FD_H
+#define _IOCTL_FD_H
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#define FD_FORMAT_VERSION 110 /* used to validate before formatting */
+#define FD_MAX_NSEC 36 /* highest known number of spt - allow for */
+ /* 2.88 MB drives */
+
+struct fd_formb {
+ int format_version; /* == FD_FORMAT_VERSION */
+ int cyl, head;
+ int transfer_rate; /* fdreg.h: FDC_???KBPS */
+
+ union {
+ struct fd_form_data {
+ /*
+ * DO NOT CHANGE THE LAYOUT OF THIS STRUCTS
+ * it is hardware-dependant since it exactly
+ * matches the byte sequence to write to FDC
+ * during its `format track' operation
+ */
+ u_char secshift; /* 0 -> 128, ...; usually 2 -> 512 */
+ u_char nsecs; /* must be <= FD_MAX_NSEC */
+ u_char gaplen; /* GAP 3 length; usually 84 */
+ u_char fillbyte; /* usually 0xf6 */
+ struct fd_idfield_data {
+ /*
+ * data to write into id fields;
+ * for obscure formats, they mustn't match
+ * the real values (but mostly do)
+ */
+ u_char cylno; /* 0 thru 79 (or 39) */
+ u_char headno; /* 0, or 1 */
+ u_char secno; /* starting at 1! */
+ u_char secsize; /* usually 2 */
+ } idfields[FD_MAX_NSEC]; /* 0 <= idx < nsecs used */
+ } structured;
+ u_char raw[1]; /* to have continuous indexed access */
+ } format_info;
+};
+
+/* make life easier */
+# define fd_formb_secshift format_info.structured.secshift
+# define fd_formb_nsecs format_info.structured.nsecs
+# define fd_formb_gaplen format_info.structured.gaplen
+# define fd_formb_fillbyte format_info.structured.fillbyte
+/* these data must be filled in for(i = 0; i < fd_formb_nsecs; i++) */
+# define fd_formb_cylno(i) format_info.structured.idfields[i].cylno
+# define fd_formb_headno(i) format_info.structured.idfields[i].headno
+# define fd_formb_secno(i) format_info.structured.idfields[i].secno
+# define fd_formb_secsize(i) format_info.structured.idfields[i].secsize
+
+struct fd_type {
+ int sectrac; /* sectors per track */
+ int secsize; /* size code for sectors */
+ int datalen; /* data len when secsize = 0 */
+ int gap; /* gap len between sectors */
+ int tracks; /* total num of tracks */
+ int size; /* size of disk in sectors */
+ int steptrac; /* steps per cylinder */
+ int trans; /* transfer speed code */
+ int heads; /* number of heads */
+ int f_gap; /* format gap len */
+ int f_inter; /* format interleave factor */
+};
+
+#define FD_FORM _IOW('F', 61, struct fd_formb) /* format a track */
+#define FD_GTYPE _IOR('F', 62, struct fd_type) /* get drive type */
+
+#endif /* !def _IOCTL_FD_H */
diff --git a/sys/i386/include/ioctl_pc.h b/sys/i386/include/ioctl_pc.h
new file mode 100644
index 0000000..bc6a255
--- /dev/null
+++ b/sys/i386/include/ioctl_pc.h
@@ -0,0 +1,797 @@
+/* Copyright 1992,1993 by Holger Veit
+ * May be freely used with Bill Jolitz's port of
+ * 386bsd and may be included in a 386bsd collection
+ * as long as binary and source are available and reproduce the above
+ * copyright.
+ *
+ * You may freely modify this code and contribute improvements based
+ * on this code as long as you don't claim to be the original author.
+ * Commercial use of this source requires permittance of the copyright
+ * holder. A general license for 386bsd will override this restriction.
+ *
+ * Use at your own risk. The copyright holder or any person who makes
+ * this code available for the public (administrators of public archives
+ * for instance) are not responsible for any harm to hardware or software
+ * that might happen due to wrong application or program faults.
+ *
+ * Addendum: The XFree86 developers and maintainers are hereby granted the
+ * right to distribute this file together with their source distributions
+ * and patchkits of XFree86 without further explicit permission of the
+ * above copyright holder.
+ * This and another file is a necessary include file for the unified
+ * pccons/codrv implementation of XFree86. This file is needed if
+ * someone wants to compile an Xserver on a system which does not have,
+ * for some reasons, the codrv console driver which comes with this file. The
+ * availability of this file avoids a large number of #ifdef's and
+ * allows to make the xserver code easier runtime-configurable.
+ * To make use of this file, it must be installed in /usr/include/sys.
+ * This file is not the complete console device driver, so it is possible
+ * that properties described in this file do not work without having the
+ * complete driver distribution. This is not a fault of the Xserver that
+ * was built with this file.
+ *
+ *
+ *
+ * From: @(#)$RCSfile: ioctl_pc.h,v
+ * Revision: 1.1.1.1 (Contributed to 386bsd)
+ * Date: 1993/06/12 14:58:11
+ *
+ * Important notice: #defined values are subject to be changed!!!
+ * Don't use the constant, use the name instead!
+ *
+ * codrv1-style uses ioctls 'K': 1-33,255
+ * 'V': 100-109
+ *
+ * -hv- Holger Veit, Holger.Veit@gmd.de
+ * -hm Hellmuth Michaelis, hm@hcshh.hcs.de
+ * -vak- Sergey Vakulenko, vak@kiae.su
+ *
+ * 25-07-92 -hv- First version
+ * 16-08-92 -hm adding vga ioctl for cursor shape
+ * 25-10-92 -hv- X11 + video related ioctls
+ * 01/12/92 -vak- 8x16 font loading, beep ioctl,
+ * LED reassignment ioctl.
+ * 22-04-93 -hv- unified most CODRV1/CODRV2 codes
+ * 24-04-93 -hv- revised parts of keymap structures
+ *
+ * $Id$
+ */
+
+#ifndef _IOCTL_PC_H_
+#define _IOCTL_PC_H_
+
+#ifdef NOTDEF
+#if __GNUC__ >= 2
+#pragma pack(1)
+#endif
+#endif
+
+#ifndef KERNEL
+#include <sys/ioctl.h>
+#ifndef _TYPES_H_
+#include <sys/types.h>
+#endif
+#else
+#include "ioctl.h"
+#endif
+
+
+/***************************************************************************
+ * Basic definitions
+ ***************************************************************************/
+
+/* Use this data type when manipulating characters, don't use 'char' or 'u_char'
+ * some day this will be changed to 'u_short' or 'u_long' size to allow
+ * characters > 255
+ */
+typedef u_char XCHAR;
+
+/***************************************************************************
+ * driver identification
+ ***************************************************************************/
+
+/*
+ * This defines the CONSOLE INFORMATION data structure, used to
+ * describe console capabilities, to distinguish between different
+ * versions. If this ioctl fail, you probably have an old style "pccons"
+ * driver (or an "improved" console driver, whose writer is not interested
+ * in providing compatibility for anything).
+ * In this case, a considerable number of features may not work as expected,
+ * or do not work at all.
+ */
+
+#define MAXINFOSIZE 16
+struct consinfo {
+ u_long info1;
+ u_long __reserved1__;
+ u_long __reserved2__;
+ u_long __reserved3__;
+ XCHAR drv_name[MAXINFOSIZE+1];
+ XCHAR emul_name[MAXINFOSIZE+1];
+ XCHAR __reserved1_name__[MAXINFOSIZE+1];
+ XCHAR __reserved2_name__[MAXINFOSIZE+1];
+};
+
+struct oldconsinfo {
+ u_long info1;
+ u_long __reserved__;
+};
+
+#define CONSGINFO _IOR('K',255,struct consinfo) /* Get console capabilities */
+#define OLDCONSGINFO _IOR('K',255,struct oldconsinfo) /* compatibility */
+#define CONS_ISPC 0x00000001 /* is derived from old PCCONS */
+#define CONS_ISCO 0x00000002 /* is derived from CO driver */
+#define CONS_reserved1 0x00000004 /* reserved for other console drivers */
+#define CONS_reserved2 0x00000008 /* reserved for other console drivers */
+#define CONS_HASKBD 0x00000010 /* has /dev/kbd */
+#define CONS_HASSCAN 0x00000020 /* uses Scan codes */
+#define CONS_HASKEYNUM 0x00000040 /* uses KEYNUMS */
+#define CONS_HASVTY 0x00000080 /* has /dev/vty* */
+#define CONS_HASPC3 0x00000100 /* unused, historical */
+#define CONS_HASVTHP 0x00000200 /* unused, historical */
+#define CONS_reserved3 0x00000400 /* reserved */
+#define CONS_reserved4 0x00000800 /* reserved */
+#define CONS_HASPX386 0x00001000 /* has X386 probing support +new CONSOLE_X_MODE */
+#define CONS_HASOX386 0x00002000 /* has old X386 support CONSOLE_X_MODE_ON/OFF */
+#define CONS_reserved5 0x00004000 /* reserved */
+#define CONS_reserved6 0x00008000 /* reserved */
+#define CONS_HASKCAP 0x00010000 /* has ioctl keycap support */
+#define CONS_HASFNT 0x00020000 /* has ioctl font support */
+#define CONS_reserved7 0x00040000 /* reserved */
+#define CONS_reserved8 0x00080000 /* reserved */
+#define CONS_USE7BIT 0x00100000 /* does not support 8bit characters */
+#define CONS_USEPC8 0x00200000 /* uses PC8 8-bit mapping */
+#define CONS_USELATIN1 0x00400000 /* uses ISO LATIN1 mapping */
+#define CONS_HAS10646 0x00800000 /* has /dev/unicode */
+#define CONS_PCCONS2 0x01000000 /* modified pccons */
+#define CONS_CODRV1 0x02000000 /* old codrv ioctls */
+#define CONS_CODRV2 0x04000000 /* codrv ioctls 0.1.2 */
+#define CONS_reserved9 0x08000000 /* reserved */
+#define CONS_reserved10 0x10000000 /* reserved */
+#define CONS_reserved11 0x20000000 /* reserved */
+#define CONS_reserved12 0x40000000 /* reserved */
+#define CONS_reserved13 0x80000000 /* reserved */
+
+
+/***************************************************************************
+ * IOCTLs for AT Keyboard
+ ***************************************************************************/
+
+/**** initializing the keyboard ****/
+
+/* reset keyboard, run selftests and set default values:
+ * default keymap, no overloaded keys, default typematic rate
+ * KBD_TPD500|KBD_TPM100, repetition on
+ */
+#define KBDCOLDRESET _IO('K', 1) /* reset keyboard and set default
+ * values:
+ * default keymap, no overloaded
+ * keys, default typematic rate
+ * KBD_TPD500|KBD_TPM100
+ */
+/* resets the mode in keyboard controller only */
+#define KBDWARMRESET _IO('K', 23)
+
+
+
+/**** key repetition (typematic) feature ****/
+
+/* get (G) / set (S) key repetition rate and delay
+ * see below for a definition of rate and delay and the necessary
+ * argument
+ */
+#define KBDGTPMAT _IOR('K', 2, int)
+#define KBDSTPMAT _IOW('K', 3, int)
+
+/* Typematic rates:
+ * Rate = 1 / Period, with
+ * Period = (8+ (Val&7)) * 2^((Val>>3)&3) * 0.00417 seconds,
+ * and Val the typematic value below
+ *
+ * The typematic delay is determined by
+ * Delay = (1+((Val>>5)&3)) * 250 msec +/- 20 %
+ *
+ * Source IBM/AT reference manual, 1987
+ *
+ * Note that you have to pass one TPD* and one TPM* value to the KBDSTPMAT
+ * ioctl: they are different flags of the same data word. Also note that
+ * 0x00 is a valid value: KBD_TPD250|KBD_TPM300 which is really fast, instead
+ * of turning off key repetition entirely. You can turn off key repetition
+ * with the ioctls KBDGREPSW/KBDSREPSW.
+*/
+
+#define KBD_TPD250 0x0000 /* 250 ms */
+#define KBD_TPD500 0x0020 /* 500 ms */
+#define KBD_TPD750 0x0040 /* 750 ms */
+#define KBD_TPD1000 0x0060 /* 1000 ms */
+
+#define KBD_TPM300 0x0000 /* 30.0 rate */
+#define KBD_TPM267 0x0001 /* 26.7 rate */
+#define KBD_TPM240 0x0002 /* 24.0 rate */
+#define KBD_TPM218 0x0003 /* 21.8 rate */
+#define KBD_TPM200 0x0004 /* 20.0 rate */
+#define KBD_TPM185 0x0005 /* 18.5 rate */
+#define KBD_TPM171 0x0006 /* 17.1 rate */
+#define KBD_TPM160 0x0007 /* 16.0 rate */
+#define KBD_TPM150 0x0008 /* 15.0 rate */
+#define KBD_TPM133 0x0009 /* 13.3 rate */
+#define KBD_TPM120 0x000a /* 12.0 rate */
+#define KBD_TPM109 0x000b /* 10.9 rate */
+#define KBD_TPM100 0x000c /* 10.0 rate */
+#define KBD_TPM92 0x000d /* 9.2 rate */
+#define KBD_TPM86 0x000e /* 8.6 rate */
+#define KBD_TPM80 0x000f /* 8.0 rate */
+#define KBD_TPM75 0x0010 /* 7.5 rate */
+#define KBD_TPM67 0x0011 /* 6.7 rate */
+#define KBD_TPM60 0x0012 /* 6.0 rate */
+#define KBD_TPM55 0x0013 /* 5.5 rate */
+#define KBD_TPM50 0x0014 /* 5.0 rate */
+#define KBD_TPM46 0x0015 /* 4.6 rate */
+#define KBD_TPM43 0x0016 /* 4.3 rate */
+#define KBD_TPM40 0x0017 /* 4.0 rate */
+#define KBD_TPM37 0x0018 /* 3.7 rate */
+#define KBD_TPM33 0x0019 /* 3.3 rate */
+#define KBD_TPM30 0x001a /* 3.0 rate */
+#define KBD_TPM27 0x001b /* 2.7 rate */
+#define KBD_TPM25 0x001c /* 2.5 rate */
+#define KBD_TPM23 0x001d /* 2.3 rate */
+#define KBD_TPM21 0x001e /* 2.1 rate */
+#define KBD_TPM20 0x001f /* 2.0 rate */
+
+
+/* get (G) / set (S) the key repetition switch */
+#define KBD_REPEATOFF 0
+#define KBD_REPEATON 1
+#define KBDGREPSW _IOR('K', 4, int)
+#define KBDSREPSW _IOW('K', 5, int)
+
+
+
+/**** handling keyboard LEDS and Lock keys ****/
+
+/* get (G) / set (S) the keyboard LEDs,
+ * does not influence the state of the lock keys.
+ * Note: if keyboard serves tty console mode (VTYs have keyboard focus),
+ * the lock keys will still modify the state when used
+ */
+#define KBDGLEDS _IOR('K', 6, int)
+#define KBDSLEDS _IOW('K', 7, int)
+
+/* get (G) / set (S) the SCROLL, NUM, CAPS ALTGRLOCK keys
+ * (note: ALTGRLOCK or SHIFTLOCK are not necessarily accessible
+ * on your keyboard)
+ */
+#define KBD_LOCKSCROLL 0x0001
+#define KBD_LOCKNUM 0x0002
+#define KBD_LOCKCAPS 0x0004
+#define KBD_LOCKALTGR 0x0008
+#define KBD_LOCKSHIFT 0x0010
+#define KBDGLOCK _IOR('K', 8, int)
+#define KBDSLOCK _IOW('K', 9, int)
+
+
+
+/**** making noise ****/
+
+/* get (G) / set (S) the beeper frequency and tone duration
+ * the nr param determines the VTY which parameters are changed
+ * VTY# = 0...n, n < max_vtys
+ * nr = -1: actual vty
+ * nr = -2: Set the system default beep frequency
+ *
+ * in some emulations, you can also set pitch and duration by an ESC code
+ */
+#define KBD_ACTVTY -1
+#define KBD_DEFLT -2
+struct kbd_bell {
+ int pitch;
+ int duration;
+ int nr;
+};
+
+#define KBDGETBEEP _IOWR('K',28, struct kbd_bell)
+#define KBDSETBEEP _IOW('K',29, struct kbd_bell)
+
+/* do a beep of specified frequency and duration
+ * the argument nr is unused
+ * a NULL arg performs a default system beep
+ */
+#define KBDBELL _IOW('K',30, struct kbd_bell)
+
+
+
+/**** I/O access ****/
+
+/* This call allows programs to access I/O ports.
+ * The ioctl is intended to perform several tasks for the XFree86 Xserver,
+ * but currently has other interesting applications. This is why it is
+ * priviledged and can only be executed by root (or with setuid-root).
+ * In future the ioctl might be restricted to allow access to video ports
+ * only.
+ */
+#define X_MODE_ON 1
+#define X_MODE_OFF 0
+#define CONSOLE_X_MODE _IOW('K',22,int)
+
+
+/**** keyboard overloading ****/
+
+/* Codrv allows loading of strings to keys in six layers.
+ * Any string may have a length of up to KBDMAXOVLKEYSIZE XCHARS.
+ * !!! Warning: This ioctl uses the type XCHAR. In future, this may
+ * !!! no longer be a char type, so str*** functions might not work any more
+ * !!! some day.
+ * The available layers are:
+ *
+ * - unshifted
+ * - with shift key
+ * - with ctrl key
+ * - with meta key (usually ALT-left)
+ * - with altgr key (usually ALT-right)
+ * - with shift+altgr key
+ *
+ * There are no combinations: shift-ctrl, ctrl-alt, shift-meta.
+ * The combination ctrl-altleft-somekey is reserved for system purposes.
+ * These keys are usually processed before the above keys. To gain control
+ * over these keys, you must run the keyboard in raw mode (/dev/kbd) and
+ * do ALL the processing yourself. The Xserver for instance does it this way.
+ * The following special keys are currently defined:
+ *
+ * CTRL-ALTLEFT-DELETE: Reboot
+ * CTRL-ALTLEFT-ESCAPE: Call the debugger (if compiled into the kernel)
+ * CTRL-ALTLEFT-KP+: Switch to next resolution (Xserver only)
+ * CTRL-ALTLEFT-KP-: Switch to previous resolution (Xserver only)
+ */
+
+/* values for type field of various kbd_overload ioctls */
+#define KBD_NONE 0 /* no function, key is disabled */
+#define KBD_SHIFT 1 /* keyboard shift */
+#define KBD_META 2 /* (ALT) alternate shift, sets bit8 to ASCII code */
+#define KBD_NUM 3 /* numeric shift cursors vs. numeric */
+#define KBD_CTL 4 /* control shift -- allows ctl function */
+#define KBD_CAPS 5 /* caps shift -- swaps case of letter */
+#define KBD_ASCII 6 /* ascii code for this key */
+#define KBD_SCROLL 7 /* stop output */
+#define KBD_FUNC 8 /* function key */
+#define KBD_KP 9 /* Keypad keys */
+#define KBD_BREAK 10 /* The damned BREAK key, ignored in ioctl */
+#define KBD_ALTGR 11 /* AltGr Translation feature */
+#define KBD_SHFTLOCK 12 /* some people are accustomed to this nonsense */
+#define KBD_ALTGRLOCK 13 /* Useful for 8-bit national kbds (cyrillic) */
+#define KBD_DOALTCAPS 0x0400 /* change by altgr + caps shift */
+#define KBD_DOCAPS 0x0800 /* change by caps shift */
+#define KBD_DIACPFX 0x4000 /* Key carries a diacritical prefix */
+#define KBD_OVERLOAD 0x8000 /* Key is overloaded, ignored in ioctl */
+#define KBD_MASK 0x001f /* mask for type */
+
+#define KBDMAXOVLKEYSIZE 15 /* excl. zero byte */
+struct kbd_ovlkey {
+ u_short keynum;
+ u_short type;
+ XCHAR unshift[KBDMAXOVLKEYSIZE+1];
+ XCHAR shift[KBDMAXOVLKEYSIZE+1];
+ XCHAR ctrl[KBDMAXOVLKEYSIZE+1];
+ XCHAR meta[KBDMAXOVLKEYSIZE+1];
+ XCHAR altgr[KBDMAXOVLKEYSIZE+1];
+ XCHAR shiftaltgr[KBDMAXOVLKEYSIZE+1];
+};
+
+
+/* Get (G) / Set (S) a key assignment. This will influence the current
+ * key value only
+ */
+#define KBDGCKEY _IOWR('K',16, struct kbd_ovlkey)
+#define KBDSCKEY _IOW('K',17, struct kbd_ovlkey)
+
+/* Get (G) the default (old) key assignment. You cannot overwrite the
+ * default setting, so this ioctl is unpaired
+ */
+#define KBDGOKEY _IOWR('K',18, struct kbd_ovlkey)
+
+
+
+/* Remove a key assignment for a key, i.e. restore default setting for key
+ * arg = keynum
+ */
+#define KBDRMKEY _IOW('K', 19, int)
+
+/* Restore the default key setting */
+#define KBDDEFAULT _IO('K',20)
+
+
+
+/* Set behavior of unassigned key layers
+ * Note that there is a hack from further versions which uses
+ * the flags KBD_C0 and KBD_A0 for this. This is still supported, but
+ * is not recommended way to do. It may disappear in future
+ * (what means that it won't :-))
+ */
+#define KBD_CLEARCTRL 2
+#define KBD_CLEARMETA 4
+#define KBD_CLEARALT 1
+#ifdef notyet
+ #define KBD_CLEARNORM 8
+ #define KBD_CLEARSHIFT 16
+ #define KBD_CLEARSHALT 32
+#endif
+#define KBDSCLRLYR _IOW('K',31,int)
+
+/* get (G) / set (S) CAPSLOCK LED behaviour.
+ * Not all of this keys may be accessible at your keyboard
+ * Note: For compatibility, the S ioctl returns the old state in arg
+ */
+#define KBD_CAPSCAPS 0 /* LED follows CAPSLOCK state */
+#define KBD_CAPSSHIFT 1 /* LED follows SHIFTLOCK state */
+#define KBD_CAPSALTGR 2 /* LED follows ALTGRLOCK state */
+#define KBD_CAPSINIT 0x04 /* bit to set to set a default for all VTYs */
+#define KBDGCAPSLED _IOR('K',27,int)
+#define KBDSCAPSLED _IOWR('K',25,int)
+
+/* extended functions: functions that are triggered by a keypress
+ * before key is converted to ASCII
+ *
+ * use function KBD_HOTKEYDELETE to remove a hotkey from a key
+ */
+struct kbd_hotkey {
+ u_short key;
+ u_short modifier;
+ u_short function;
+};
+#define KBDGSPECF _IOWR('K',32,struct kbd_hotkey)
+#define KBDSSPECF _IOW('K',33,struct kbd_hotkey)
+
+/* extended function prefixes (in modifier field)
+ * bit set triggers a special function on the key layer
+ */
+#define KBD_NOEXT 0x00 /* trigger never */
+#define KBD_EXT_N 0x01 /* on normal key (normal layer) */
+#define KBD_EXT_S 0x02 /* on shift key (shift layer) */
+#define KBD_EXT_C 0x04 /* on ctrl key (ctrl layer) */
+#define KBD_EXT_A 0x08 /* on alt key (alt layer) */
+#define KBD_EXT_SK 0x10 /* on syskey (PRINTSCREEN) (Meta Layer) */
+#define KBD_EXT_CA 0x20 /* on ctrl-alt (shift alt layer) */
+
+/* extended functions (in function field) */
+#define KBD_VTY0 0 /* select vty 0 */
+#define KBD_VTY1 1 /* select vty 1 */
+#define KBD_VTY2 2 /* select vty 2 */
+#define KBD_VTY3 3 /* select vty 3 */
+#define KBD_VTY4 4 /* select vty 4 */
+#define KBD_VTY5 5 /* select vty 5 */
+#define KBD_VTY6 6 /* select vty 6 */
+#define KBD_VTY7 7 /* select vty 7 */
+#define KBD_VTY8 8 /* select vty 8 */
+#define KBD_VTY9 9 /* select vty 9 */
+#define KBD_VTY10 10 /* select vty 10 */
+#define KBD_VTY11 11 /* select vty 11 */
+#define KBD_VTYUP 0x80 /* select next vty */
+#define KBD_VTYDOWN 0x81 /* select previous vty */
+#define KBD_RESETKEY 0x82 /* the CTRL-ALT-DEL key (movable) */
+#define KBD_DEBUGKEY 0x83 /* the CTRL-ALT-ESC key (debugger) */
+
+#define KBD_HOTKEYDELETE 0xff /* use to delete a hotkey KBDSSPECF */
+
+
+
+/* These are names used in older versions of keycap/codrv */
+/* do not use the following functions any longer in future */
+#ifdef COMPAT_CO011
+#define KBDRESET KBDCOLDRESET
+#define KBDRESET8042 KBDWARMRESET
+#define KBDFORCEASCII _IOW('K', 24, int) /* no op in codrv-0.1.2 */
+#define KBD_SCROLLLOCK KBD_LOCKSCROLL
+#define KBD_NUMLOCK KBD_LOCKNUM
+#define KBD_CAPSLOCK KBD_LOCKCAPS
+#define KBDASGNLEDS KBDSCAPSLED
+#ifndef KERNEL
+struct kbd_sound {
+ int pitch; /* Frequency in Hz */
+ int duration; /* Time in msec */
+};
+#endif
+#define KBDSETBELL _IOW('K',21, struct kbd_sound) /* do some music */
+#define OLDKBDSETBEEP _IOW('K',26, struct kbd_sound) /* change beep settings */
+
+struct oldkbd_ovlkey {
+ u_short keynum;
+ u_short type;
+ char unshift[KBDMAXOVLKEYSIZE+1];
+ char shift[KBDMAXOVLKEYSIZE+1];
+ char ctrl[KBDMAXOVLKEYSIZE+1];
+ char altgr[KBDMAXOVLKEYSIZE+1];
+};
+#define OLDKBDGCKEY _IOWR('K',16, struct oldkbd_ovlkey) /* get current key values */
+
+
+
+#endif /*COMPAT_CO011*/
+
+/***************************************************************************
+ * IOCTLs for Video Adapter
+ ***************************************************************************/
+
+/* to define the cursor shape for ioctl */
+struct cursorshape {
+ int start; /* topmost scanline, range 0...31 */
+ int end; /* bottom scanline, range 0...31 */
+};
+
+#define VGAGCURSOR _IOR('V',100, struct cursorshape) /* get cursor shape */
+#define VGASCURSOR _IOW('V',101, struct cursorshape) /* set cursor shape */
+
+
+
+/**** information ****/
+
+/* the video information structure for ioctl */
+struct videoinfo {
+ char name[20]; /* ASCIZ name of detected card */
+ short type; /* Adapter type, see below */
+ short subtype; /* Adapter specific subtype */
+ short ram; /* in KBytes */
+ short iobase; /* Address of 6845: 0x3b0 / 0x3d0 */
+};
+
+/* Get information about the videoboard */
+#define VGAGINFO _IOR('V',102, struct videoinfo)
+
+/* recognized Adapter types */
+#define VG_UNKNOWN 0
+#define VG_MONO 1
+#define VG_CGA 2
+#define VG_EGA 3
+#define VG_VGA 4
+#define VG_CHIPS 5
+/* CHIPS & TECHNOLOGIES has subtypes:
+ * 0x10 82c451
+ * 0x11 82c452
+ * 0x20 82c455
+ * 0x30 82c453
+ * 0x50 82c455
+ */
+#define VG_GENOA 6
+/* GENOA has subtypes:
+ * 0x33/0x55 5100-5400, ET3000 based
+ * 0x22 6100
+ * 0x00 6200,6300
+ * 0x11 6400,6600
+ */
+#define VG_PARADISE 7
+/* PARADISE has subtypes:
+ * 01 PVGA1A,WD90C90
+ * 02 WD90C00
+ * 03 WD90C10
+ * 04 WD90C11
+ */
+#define VG_TVGA 8
+/* TVGA has subtypes:
+ * 00-02 8800
+ * 03 8900B
+ * 04 8900C
+ * 13 8900C
+ * 23 9000
+ */
+#define VG_ET3000 9
+#define VG_ET4000 10
+#define VG_VIDEO7 11
+/* VIDEO7 has subtypes:
+ * 0x80-0xfe VEGA VGA
+ * 0x70-0x7e V7VGA FASTWRITE/VRAM
+ * 0x50-0x59 V7VGA version 5
+ * 0x41-0x49 1024i
+ */
+#define VG_ATI 12
+/* ATI has subtypes:
+ * 0x01nn 18800
+ * 0x02nn 18800-1
+ * 0x03nn 28800-2
+ * 0x04nn-05nn
+ * with nn:
+ * 0x01 VGA WONDER
+ * 0x02 EGA WONDER800+
+ * 0x03 VGA BASIC 16+
+ */
+
+
+
+/**** Screen blanking ****/
+
+/* Get (G) / Set (S) screen blanker timeout (seconds),
+ * time=0 disables blanking
+ *
+ * The blanking state is coded in bits 31 and 30 of word returned by get
+ */
+#define VGA_BLANKOFF 0x00000000 /* display is on, no blanking */
+#define VGA_BLANKON 0x40000000 /* display is on, wait for blank */
+#define VGA_BLANKED 0x80000000 /* display is dark */
+#define VGAGBLANK _IOR('V',2,int)
+#define VGASBLANK _IOW('V',3,int)
+
+
+
+/**** Text/Attribute direct access, block move ****/
+
+struct vga_block {
+ short mode;
+ short pagenum;
+ short x0,y0; /* upper left coordinates 0..x-1, 0..y-1 */
+ short x1,y1; /* lower right coordinates >= x0,y0 */
+ u_char *map; /* must be allocated by user process ! */
+};
+
+/* mode word */
+#define VGA_SCREEN 0x01 /* entire screen, ignore x,y */
+#define VGA_WINDOW 0x02 /* use x,y for a rectangular window */
+#define VGA_TEXT 0x10 /* copy text information only */
+#define VGA_ATTR 0x20 /* copy attribute information only */
+#define VGA_BOTH 0x30 /* copy text and attribute */
+#define VGA_ALL 0x31 /* copy complete screen */
+
+/* Get (G) / Set (S) a rectangular block of screen
+ * The virtual screen need not be visible.
+ * The buffer must be provided by the user process and must be large enough
+ * use VGAGVRES to find out how many bytes
+ * pagenum: 0..n, n < max_vty, VTY number
+ * -1, actual VTY
+ */
+#define VGAGBLOCK _IOWR('V',4,struct vga_block)
+#define VGASBLOCK _IOW('V',5,struct vga_block)
+
+
+
+#define VGA_TXTPAGE0 0
+#define VGA_TXTPAGE1 1
+#ifdef notyet
+#define VGA_GFXPAGE 2
+#endif
+#define VGA_PC8CODING 0x80 /* obsolete ! */
+
+/* maximum dimension of pixels
+ * Note: this is the space reserved in the fontchar map, but
+ * does not mean, that this resolution is accepted in the current release
+ * codrv-0.1.2 accepts 8x16 / "9x16" fonts only
+ */
+#define VGA_MAXX 16
+#define VGA_MAXY 16
+
+struct fchar {
+ XCHAR encoding; /* encoding of character */
+ char _f1_,_f2_,_f3_; /* filler */
+ u_char map[VGA_MAXX/8*VGA_MAXY];
+};
+
+struct fmap {
+ short page; /* page to load */
+ short nr; /* nr of characters to load */
+ char x,y; /* x,y pixel width */
+ XCHAR start; /* first character in sequence (get only) */
+ struct fchar *fntmap; /* allocated by user process */
+};
+
+/* get (G) / set (S) font map. Must provide page,nr,start for get */
+#define VGAGFONTMAP _IOWR('V',6,struct fmap)
+#define VGASFONTMAP _IOW('V',7,struct fmap)
+
+
+
+/* do not use the following functions any longer in future */
+#ifdef COMPAT_CO011
+/* miscellaneous functions: */
+#define VGA_DIS1 1 /* disable font 1 */
+#define VGA_GTENC 2 /* get current encoding */
+#define VGA_SBLANK 3 /* set screen blanking timeout (use VGASBLANK!) */
+#define VGA_GBLANK 4 /* get screen blanking timeout (use VGAGBLANK!) */
+
+struct miscfcns {
+ u_char cmd;
+ union {
+ short enc[2];
+ int timeout;
+ } u;
+};
+#define VGAMISCFCNS _IOWR('V',107,struct miscfcns) /* misc functions */
+
+
+/* Font mapping this needs at least an EGA card (else EINVAL) */
+#define VGAFNTLATIN1 0x00
+#define VGAFNTEXTEND1 0x01
+#define VGAFNTEXTEND2 0x02
+#define VGAFNTGREEK 0x03
+#define VGAFNTCYRILLIC 0x04
+#define VGAFNTHEBREW 0x05
+#define VGAFNTARABIAN 0x06
+
+#define VGA_FNTNCHARS 256
+#define VGA_FNTCSIZE 15
+
+struct fontchar {
+ u_char page; /* which font page */
+ u_char idx; /* which char in font page */
+ u_char cmap[VGA_FNTCSIZE]; /* character bitmap */
+};
+
+#define OLDVGAGCHAR _IOWR('V',105,struct fontchar) /* get character of font */
+#define OLDVGASCHAR _IOW('V',106,struct fontchar) /* set character in font */
+
+struct fontmap {
+ u_char page; /* page to load */
+ u_short encoding; /* font encoding */
+ u_char map[VGA_FNTNCHARS*VGA_FNTCSIZE];
+};
+
+#define OLDVGAGFNTMAP _IOWR('V',103,struct fontmap) /* get font */
+#define VGAGFNTMAP OLDVGAGFNTMAP
+#define OLDVGASFNTMAP _IOW('V',104,struct fontmap) /* set font */
+#define VGASFNTMAP OLDVGASFNTMAP
+
+#endif
+
+
+
+
+struct textpage {
+ u_char pagenum; /* note: only page 0 used by vtys */
+#define VGA_TEXTATTR 0
+#define VGA_TEXTDATA 1
+ u_char ad;
+#define VGA_LINES 50 /* only 25 used for now */
+#define VGA_COLUMNS 80
+ u_char map[VGA_LINES*VGA_COLUMNS];
+};
+
+#define VGAGPAGE _IOWR('V',108,struct textpage) /* get a data page */
+#define VGASPAGE _IOW('V',109,struct textpage) /* set a data page */
+
+/**** Signalling access ****/
+
+/* Use "take control" in an application program to signal the kernel
+ * that the program wants to use video memory (such as Xserver)
+ * before the program switches modes
+ *
+ * Use "give control" to return the control to the kernel. The application
+ * should have restored the original state before giving back control.
+ * Close /dev/vga also returns control.
+ *
+ * However, the kernel remains the master in the house, and reserves the right
+ * to grab control back at any time. (It usually doesn't).
+ *
+ */
+#define VGATAKECTRL _IO('V',8)
+#define VGAGIVECTRL _IO('V',9)
+
+/***************************************************************************
+ * Pandora's box, don't even think of using the following ioctl's
+ * (if you happen to find some; codrv_experimental might not be
+ * available at your system)
+ ***************************************************************************/
+
+#ifdef PANDORA
+#include "codrv_experimental.h"
+#endif
+
+
+
+/***************************************************************************
+ * XFree86 pccons support
+ ***************************************************************************/
+
+#ifdef COMPAT_PCCONS
+/* The following calls are special to the old pccons driver and are
+ * not understood or supported by codrv.
+ * This file serves as a central definition base for these calls
+ * in order to avoid defining them in applications that want to
+ * use them.
+ *
+ * One word of warning: There are different purpose tty ioctls
+ * with the same encoding, see <sys/ioctl.h>
+ * TIOCSDTR = _IO('t', 121)
+ * TIOCCBRK = _IO('t', 122)
+ *
+ */
+#define CONSOLE_X_MODE_ON _IO('t',121)
+#define CONSOLE_X_MODE_OFF _IO('t',122)
+#define CONSOLE_X_BELL _IOW('t',123,int[2])
+#endif /* COMPAT_PCCONS */
+
+#endif /* _IOCTL_PC_H_ */
+
diff --git a/sys/i386/include/ipl.h b/sys/i386/include/ipl.h
new file mode 100644
index 0000000..248ca56
--- /dev/null
+++ b/sys/i386/include/ipl.h
@@ -0,0 +1,7 @@
+#ifndef _ISA_IPL_H_
+#define _ISA_IPL_H_
+
+#define NHWI 16 /* number of h/w interrupts */
+#define HWI_MASK 0xffff /* bits corresponding to h/w interrupts */
+
+#endif /* _ISA_IPL_H_ */
diff --git a/sys/i386/include/limits.h b/sys/i386/include/limits.h
new file mode 100644
index 0000000..5aed870
--- /dev/null
+++ b/sys/i386/include/limits.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)limits.h 7.2 (Berkeley) 6/28/90
+ * $Id: limits.h,v 1.5 1994/02/26 00:56:02 ache Exp $
+ */
+
+#ifndef _MACHINE_LIMITS_H_
+#define _MACHINE_LIMITS_H_ 1
+
+#define CHAR_BIT 8 /* number of bits in a char */
+#define MB_LEN_MAX 6 /* allow 21-bit UTF2 */
+
+#define SCHAR_MIN (-0x7f-1) /* max value for a signed char */
+#define SCHAR_MAX 0x7f /* min value for a signed char */
+
+#define UCHAR_MAX 0xff /* max value for an unsigned char */
+#define CHAR_MAX 0x7f /* max value for a char */
+#define CHAR_MIN (-0x7f-1) /* min value for a char */
+
+#define USHRT_MAX 0xffff /* max value for an unsigned short */
+#define SHRT_MAX 0x7fff /* max value for a short */
+#define SHRT_MIN (-0x7fff-1) /* min value for a short */
+
+#define UINT_MAX 0xffffffff /* max value for an unsigned int */
+#define INT_MAX 0x7fffffff /* max value for an int */
+#define INT_MIN (-0x7fffffff-1) /* min value for an int */
+
+#define ULONG_MAX 0xffffffff /* max value for an unsigned long */
+#define LONG_MAX 0x7fffffff /* max value for a long */
+#define LONG_MIN (-0x7fffffff-1) /* min value for a long */
+
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+#define CLK_TCK 128 /* ticks per second */
+#define UQUAD_MAX 0xffffffffffffffffLL /* max unsigned quad */
+#define QUAD_MAX 0x7fffffffffffffffLL /* max signed quad */
+#define QUAD_MIN (-0x7fffffffffffffffLL-1) /* min signed quad */
+#endif
+
+#endif /* _MACHINE_LIMITS_H_ */
diff --git a/sys/i386/include/lpt.h b/sys/i386/include/lpt.h
new file mode 100644
index 0000000..87af5bc
--- /dev/null
+++ b/sys/i386/include/lpt.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 1994 Geoffrey M. Rehmet
+ *
+ * This program is free software; you may redistribute it and/or
+ * modify it, provided that it retain the above copyright notice
+ * and the following disclaimer.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Geoff Rehmet, Rhodes University, South Africa <csgr@cs.ru.ac.za>
+ *
+ */
+
+#ifndef _LPT_PRINTER_H_
+#define _LPT_PRINTER_H_
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#define LPT_IRQ _IOW('p', 1, long) /* set interrupt status */
+
+#endif
diff --git a/sys/i386/include/mtpr.h b/sys/i386/include/mtpr.h
new file mode 100644
index 0000000..e8347e6
--- /dev/null
+++ b/sys/i386/include/mtpr.h
@@ -0,0 +1,4 @@
+/*
+ * Unused in 386BSD port
+ * $Id$
+ */
diff --git a/sys/i386/include/npx.h b/sys/i386/include/npx.h
new file mode 100644
index 0000000..87cd6f9
--- /dev/null
+++ b/sys/i386/include/npx.h
@@ -0,0 +1,141 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)npx.h 5.3 (Berkeley) 1/18/91
+ * $Id: npx.h,v 1.2 1993/10/16 14:39:22 rgrimes Exp $
+ */
+
+/*
+ * 287/387 NPX Coprocessor Data Structures and Constants
+ * W. Jolitz 1/90
+ */
+
+#ifndef ___NPX87___
+#define ___NPX87___
+
+/* Environment information of floating point unit */
+struct env87 {
+ long en_cw; /* control word (16bits) */
+ long en_sw; /* status word (16bits) */
+ long en_tw; /* tag word (16bits) */
+ long en_fip; /* floating point instruction pointer */
+ u_short en_fcs; /* floating code segment selector */
+ u_short en_opcode; /* opcode last executed (11 bits ) */
+ long en_foo; /* floating operand offset */
+ long en_fos; /* floating operand segment selector */
+};
+
+/* Contents of each floating point accumulator */
+struct fpacc87 {
+#ifdef dontdef /* too unportable */
+ u_long fp_mantlo; /* mantissa low (31:0) */
+ u_long fp_manthi; /* mantissa high (63:32) */
+ int fp_exp:15; /* exponent */
+ int fp_sgn:1; /* mantissa sign */
+#else
+ u_char fp_bytes[10];
+#endif
+};
+
+/* Floating point context */
+struct save87 {
+ struct env87 sv_env; /* floating point control/status */
+ struct fpacc87 sv_ac[8]; /* accumulator contents, 0-7 */
+ u_long sv_ex_sw; /* status word for last exception (was pad) */
+ u_long sv_ex_tw; /* tag word for last exception (was pad) */
+#ifdef GPL_MATH_EMULATE
+ u_char sv_pad[60];
+#else
+ u_char sv_pad[8 * 2 - 2 * 4]; /* bogus historical padding */
+#endif /* GPL_MATH_EMULATE */
+};
+
+/* Cyrix EMC memory - mapped coprocessor context switch information */
+struct emcsts {
+ long em_msw; /* memory mapped status register when swtched */
+ long em_tar; /* memory mapped temp A register when swtched */
+ long em_dl; /* memory mapped D low register when swtched */
+};
+
+/* Intel prefers long real (53 bit) precision */
+#define __iBCS_NPXCW__ 0x262
+/* wfj prefers temporary real (64 bit) precision */
+#define __386BSD_NPXCW__ 0x362
+/*
+ * bde prefers 53 bit precision and all exceptions masked.
+ *
+ * The standard control word from finit is 0x37F, giving:
+ *
+ * round to nearest
+ * 64-bit precision
+ * all exceptions masked.
+ *
+ * Now I want:
+ *
+ * affine mode for 287's (if they work at all) (1 in bitfield 1<<12)
+ * 53-bit precision (2 in bitfield 3<<8)
+ * overflow exception unmasked (0 in bitfield 1<<3)
+ * zero divide exception unmasked (0 in bitfield 1<<2)
+ * invalid-operand exception unmasked (0 in bitfield 1<<0).
+ *
+ * 64-bit precision often gives bad results with high level languages
+ * because it makes the results of calculations depend on whether
+ * intermediate values are stored in memory or in FPU registers.
+ *
+ * The "Intel" and wfj control words have:
+ *
+ * underflow exception unmasked (0 in bitfield 1<<4)
+ *
+ * but that causes an unexpected exception in the test program 'paranoia'
+ * and makes denormals useless (DBL_MIN / 2 underflows). It doesn't make
+ * a lot of sense to trap underflow without trapping denormals.
+ *
+ * Later I will want the IEEE default of all exceptions masked. See the
+ * 0.0 math manpage for why this is better. The 0.1 math manpage is empty.
+ */
+#define __BDE_NPXCW__ 0x1272
+#define __BETTER_BDE_NPXCW__ 0x127f
+
+#ifdef __BROKEN_NPXCW__
+#ifdef __386BSD__
+#define __INITIAL_NPXCW__ __386BSD_NPXCW__
+#else
+#define __INITIAL_NPXCW__ __iBCS_NPXCW__
+#endif
+#else
+#define __INITIAL_NPXCW__ __BDE_NPXCW__
+#endif
+
+#endif ___NPX87___
diff --git a/sys/i386/include/param.h b/sys/i386/include/param.h
new file mode 100644
index 0000000..b847afc
--- /dev/null
+++ b/sys/i386/include/param.h
@@ -0,0 +1,167 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)param.h 5.8 (Berkeley) 6/28/91
+ * $Id: param.h,v 1.13 1994/01/31 04:18:54 davidg Exp $
+ */
+
+#ifndef _MACHINE_PARAM_H_
+#define _MACHINE_PARAM_H_ 1
+
+/*
+ * Machine dependent constants for Intel 386.
+ */
+
+#define MACHINE "i386"
+#define MID_MACHINE MID_I386
+
+/*
+ * Round p (pointer or byte index) up to a correctly-aligned value
+ * for all data types (int, long, ...). The result is u_int and
+ * must be cast to any desired pointer type.
+ */
+#define ALIGNBYTES (sizeof(int) - 1)
+#define ALIGN(p) (((u_int)(p) + ALIGNBYTES) &~ ALIGNBYTES)
+
+/* XXX PGSHIFT and PG_SHIFT are two names for the same thing */
+#define PGSHIFT 12 /* LOG2(NBPG) */
+#define PAGE_SHIFT 12
+#define NBPG (1 << PAGE_SHIFT) /* bytes/page */
+#define PAGE_SIZE (1 << PAGE_SHIFT)
+#define PAGE_MASK (PAGE_SIZE-1)
+#define PGOFSET (NBPG-1) /* byte offset into page */
+#define NPTEPG (NBPG/(sizeof (pt_entry_t)))
+
+/* XXX PDRSHIFT and PD_SHIFT are two names for the same thing */
+#define PDRSHIFT 22 /* LOG2(NBPDR) */
+#define NBPDR (1 << PDRSHIFT) /* bytes/page dir */
+#define PDROFSET (NBPDR-1) /* byte offset into page dir */
+
+/*
+ * XXX This should really be KPTDPTDI << PDRSHIFT, but since KPTDPTDI is
+ * defined in pmap.h which is included after this we can't do that
+ * (YET!)
+ */
+#define BTOPKERNBASE (KERNBASE >> PGSHIFT)
+
+#define DEV_BSHIFT 9 /* log2(DEV_BSIZE) */
+#define DEV_BSIZE (1 << DEV_BSHIFT)
+
+#define BLKDEV_IOSIZE 2048
+#define MAXPHYS (64 * 1024) /* max raw I/O transfer size */
+
+#define CLSIZELOG2 0
+#define CLSIZE (1 << CLSIZELOG2)
+
+/* NOTE: SSIZE, SINCR and UPAGES must be multiples of CLSIZE */
+#define SSIZE 1 /* initial stack size/NBPG */
+#define SINCR 1 /* increment of stack/NBPG */
+
+#define UPAGES 2 /* pages of u-area */
+
+/*
+ * Constants related to network buffer management.
+ * MCLBYTES must be no larger than CLBYTES (the software page size), and,
+ * on machines that exchange pages of input or output buffers with mbuf
+ * clusters (MAPPED_MBUFS), MCLBYTES must also be an integral multiple
+ * of the hardware page size.
+ */
+#ifndef MSIZE
+#define MSIZE 128 /* size of an mbuf */
+#endif /* MSIZE */
+
+#ifndef MCLSHIFT
+#define MCLSHIFT 12 /* convert bytes to m_buf clusters */
+#endif /* MCLSHIFT */
+#define MCLBYTES (1 << MCLSHIFT) /* size of an m_buf cluster */
+#define MCLOFSET (MCLBYTES - 1) /* offset within an m_buf cluster */
+
+#ifndef NMBCLUSTERS
+#ifdef GATEWAY
+#define NMBCLUSTERS 512 /* map size, max cluster allocation */
+#else
+#define NMBCLUSTERS 256 /* map size, max cluster allocation */
+#endif /* GATEWAY */
+#endif /* NMBCLUSTERS */
+
+/*
+ * Some macros for units conversion
+ */
+/* Core clicks (4096 bytes) to segments and vice versa */
+#define ctos(x) (x)
+#define stoc(x) (x)
+
+/* Core clicks (4096 bytes) to disk blocks */
+#define ctod(x) ((x)<<(PGSHIFT-DEV_BSHIFT))
+#define dtoc(x) ((x)>>(PGSHIFT-DEV_BSHIFT))
+#define dtob(x) ((x)<<DEV_BSHIFT)
+
+/* clicks to bytes */
+#define ctob(x) ((x)<<PGSHIFT)
+
+/* bytes to clicks */
+#define btoc(x) (((unsigned)(x)+(NBPG-1))>>PGSHIFT)
+
+#define btodb(bytes) /* calculates (bytes / DEV_BSIZE) */ \
+ ((unsigned)(bytes) >> DEV_BSHIFT)
+#define dbtob(db) /* calculates (db * DEV_BSIZE) */ \
+ ((unsigned)(db) << DEV_BSHIFT)
+
+/*
+ * Map a ``block device block'' to a file system block.
+ * This should be device dependent, and will be if we
+ * add an entry to cdevsw/bdevsw for that purpose.
+ * For now though just use DEV_BSIZE.
+ */
+#define bdbtofsb(bn) ((bn) / (BLKDEV_IOSIZE/DEV_BSIZE))
+
+/*
+ * Mach derived conversion macros
+ */
+#define trunc_page(x) ((unsigned)(x) & ~(NBPG-1))
+#define round_page(x) ((((unsigned)(x)) + NBPG - 1) & ~(NBPG-1))
+#define atop(x) ((unsigned)(x) >> PG_SHIFT)
+#define ptoa(x) ((unsigned)(x) << PG_SHIFT)
+
+#define i386_round_pdr(x) ((((unsigned)(x)) + NBPDR - 1) & ~(NBPDR-1))
+#define i386_trunc_pdr(x) ((unsigned)(x) & ~(NBPDR-1))
+#define i386_round_page(x) ((((unsigned)(x)) + NBPG - 1) & ~(NBPG-1))
+#define i386_trunc_page(x) ((unsigned)(x) & ~(NBPG-1))
+#define i386_btod(x) ((unsigned)(x) >> PDRSHIFT)
+#define i386_dtob(x) ((unsigned)(x) << PDRSHIFT)
+#define i386_btop(x) ((unsigned)(x) >> PGSHIFT)
+#define i386_ptob(x) ((unsigned)(x) << PGSHIFT)
+
+#endif /* _MACHINE_PARAM_H_ */
diff --git a/sys/i386/include/pc/display.h b/sys/i386/include/pc/display.h
new file mode 100644
index 0000000..9e64a3f
--- /dev/null
+++ b/sys/i386/include/pc/display.h
@@ -0,0 +1,45 @@
+/*
+ * IBM PC display definitions
+ *
+ * $Id$
+ */
+
+/* Color attributes for foreground text */
+
+#define FG_BLACK 0
+#define FG_BLUE 1
+#define FG_GREEN 2
+#define FG_CYAN 3
+#define FG_RED 4
+#define FG_MAGENTA 5
+#define FG_BROWN 6
+#define FG_LIGHTGREY 7
+#define FG_DARKGREY 8
+#define FG_LIGHTBLUE 9
+#define FG_LIGHTGREEN 10
+#define FG_LIGHTCYAN 11
+#define FG_LIGHTRED 12
+#define FG_LIGHTMAGENTA 13
+#define FG_YELLOW 14
+#define FG_WHITE 15
+#define FG_BLINK 0x80
+
+/* Color attributes for text background */
+
+#define BG_BLACK 0x00
+#define BG_BLUE 0x10
+#define BG_GREEN 0x20
+#define BG_CYAN 0x30
+#define BG_RED 0x40
+#define BG_MAGENTA 0x50
+#define BG_BROWN 0x60
+#define BG_LIGHTGREY 0x70
+
+/* Monochrome attributes for foreground text */
+
+#define FG_UNDERLINE 0x01
+#define FG_INTENSE 0x08
+
+/* Monochrome attributes for text background */
+
+#define BG_INTENSE 0x10
diff --git a/sys/i386/include/pc/msdos.h b/sys/i386/include/pc/msdos.h
new file mode 100644
index 0000000..ea221c7
--- /dev/null
+++ b/sys/i386/include/pc/msdos.h
@@ -0,0 +1,65 @@
+/*
+ * msdos common header file
+ * [obtained from mtools -wfj]
+ * how to decipher DOS disk structures in coexisting with DOS
+ *
+ * $Id$
+ */
+
+#define MSECTOR_SIZE 512 /* MSDOS sector size in bytes */
+#define MDIR_SIZE 32 /* MSDOS directory size in bytes */
+#define MAX_CLUSTER 8192 /* largest cluster size */
+#define MAX_PATH 128 /* largest MSDOS path length */
+#define MAX_DIR_SECS 64 /* largest directory (in sectors) */
+
+#define NEW 1
+#define OLD 0
+
+struct directory {
+ unsigned char name[8]; /* file name */
+ unsigned char ext[3]; /* file extension */
+ unsigned char attr; /* attribute byte */
+ unsigned char reserved[10]; /* ?? */
+ unsigned char time[2]; /* time stamp */
+ unsigned char date[2]; /* date stamp */
+ unsigned char start[2]; /* starting cluster number */
+ unsigned char size[4]; /* size of the file */
+};
+
+struct bootsector {
+ unsigned char jump[3]; /* Jump to boot code */
+ unsigned char banner[8]; /* OEM name & version */
+ unsigned char secsiz[2]; /* Bytes per sector hopefully 512 */
+ unsigned char clsiz; /* Cluster size in sectors */
+ unsigned char nrsvsect[2]; /* Number of reserved (boot) sectors */
+ unsigned char nfat; /* Number of FAT tables hopefully 2 */
+ unsigned char dirents[2]; /* Number of directory slots */
+ unsigned char psect[2]; /* Total sectors on disk */
+ unsigned char descr; /* Media descriptor=first byte of FAT */
+ unsigned char fatlen[2]; /* Sectors in FAT */
+ unsigned char nsect[2]; /* Sectors/track */
+ unsigned char nheads[2]; /* Heads */
+ unsigned char nhs[4]; /* number of hidden sectors */
+ unsigned char bigsect[4]; /* big total sectors */
+ unsigned char junk[476]; /* who cares? */
+};
+
+/* DOS partition table -- located in boot block */
+
+#define DOSBBSECTOR 0 /* DOS boot block relative sector number */
+#define DOSPARTOFF 446
+#define NDOSPART 4
+
+struct dos_partition {
+ unsigned char dp_flag; /* bootstrap flags */
+ unsigned char dp_shd; /* starting head */
+ unsigned char dp_ssect; /* starting sector */
+ unsigned char dp_scyl; /* starting cylinder */
+ unsigned char dp_typ; /* partition type */
+#define DOSPTYP_386BSD 0xa5 /* 386BSD partition type */
+ unsigned char dp_ehd; /* end head */
+ unsigned char dp_esect; /* end sector */
+ unsigned char dp_ecyl; /* end cylinder */
+ unsigned long dp_start; /* absolute starting sector number */
+ unsigned long dp_size; /* partition size in sectors */
+} dos_partitions[NDOSPART];
diff --git a/sys/i386/include/pcaudioio.h b/sys/i386/include/pcaudioio.h
new file mode 100644
index 0000000..30e5ad6
--- /dev/null
+++ b/sys/i386/include/pcaudioio.h
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#ifndef _PCAUDIOIO_H_
+#define _PCAUDIOIO_H_
+
+typedef struct audio_prinfo {
+ unsigned sample_rate; /* samples per second */
+ unsigned channels; /* # of channels (interleaved) */
+ unsigned precision; /* sample size in bits */
+ unsigned encoding; /* encoding method used */
+
+ unsigned gain; /* volume level: 0 - 255 */
+ unsigned port; /* input/output device */
+ unsigned _fill1[4];
+
+ unsigned samples; /* samples played */
+ unsigned eof; /* ?!? */
+ unsigned char pause; /* !=0 pause, ==0 continue */
+ unsigned char error; /* !=0 if overflow/underflow */
+ unsigned char waiting; /* !=0 if others wants access */
+ unsigned char _fill2[3];
+
+ unsigned char open; /* is device open */
+ unsigned char active; /* !=0 if sound hardware is active */
+} audio_prinfo_t;
+
+typedef struct audio_info {
+ audio_prinfo_t play;
+ audio_prinfo_t record;
+ unsigned monitor_gain;
+ unsigned _fill[4];
+} audio_info_t;
+
+#define AUDIO_ENCODING_ULAW (1) /* u-law encoding */
+#define AUDIO_ENCODING_ALAW (2) /* A-law encoding */
+#define AUDIO_ENCODING_RAW (3) /* linear encoding */
+
+#define AUDIO_MIN_GAIN (0) /* minimum volume value */
+#define AUDIO_MAX_GAIN (255) /* maximum volume value */
+
+#define AUDIO_INITINFO(i) memset((void*)i, 0xff, sizeof(audio_info_t))
+
+#define AUDIO_GETINFO _IOR('A', 1, audio_info_t)
+#define AUDIO_SETINFO _IOWR('A', 2, audio_info_t)
+#define AUDIO_DRAIN _IO('A', 3)
+#define AUDIO_FLUSH _IO('A', 4)
+
+#endif /*!_PCAUDIOIO_H*/
diff --git a/sys/i386/include/pcb.h b/sys/i386/include/pcb.h
new file mode 100644
index 0000000..a7a29df
--- /dev/null
+++ b/sys/i386/include/pcb.h
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)pcb.h 5.10 (Berkeley) 5/12/91
+ * $Id: pcb.h,v 1.3 1993/11/07 17:42:59 wollman Exp $
+ */
+
+#ifndef _I386_PCB_H_
+#define _I386_PCB_H_
+
+/*
+ * Intel 386 process control block
+ */
+#include "machine/tss.h"
+#include "machine/npx.h"
+
+struct pcb {
+ struct i386tss pcb_tss;
+#define pcb_ksp pcb_tss.tss_esp0
+#define pcb_ptd pcb_tss.tss_cr3
+#define pcb_cr3 pcb_ptd
+#define pcb_pc pcb_tss.tss_eip
+#define pcb_psl pcb_tss.tss_eflags
+#define pcb_usp pcb_tss.tss_esp
+#define pcb_fp pcb_tss.tss_ebp
+#ifdef notyet
+ u_char pcb_iomap[NPORT/sizeof(u_char)]; /* i/o port bitmap */
+#endif
+ caddr_t pcb_ldt; /* per process (user) LDT */
+ int pcb_ldt_len; /* number of LDT entries */
+ struct save87 pcb_savefpu; /* floating point state for 287/387 */
+ struct emcsts pcb_saveemc; /* Cyrix EMC state */
+/*
+ * Software pcb (extension)
+ */
+ int pcb_flags;
+#ifdef notused
+#define FP_WASUSED 0x01 /* process has used fltng pnt hardware */
+#define FP_NEEDSSAVE 0x02 /* ... that needs save on next context switch */
+#define FP_NEEDSRESTORE 0x04 /* ... that needs restore on next DNA fault */
+#endif
+#define FP_USESEMC 0x08 /* process uses EMC memory-mapped mode */
+#define FP_SOFTFP 0x20 /* process using software fltng pnt emulator */
+ short pcb_iml; /* interrupt mask level */
+ caddr_t pcb_onfault; /* copyin/out fault recovery */
+ long pcb_sigc[8]; /* XXX signal code trampoline */
+ int pcb_cmap2; /* XXX temporary PTE - will prefault instead */
+};
+
+#ifdef KERNEL
+extern struct pcb *curpcb; /* our current running pcb */
+#endif
+
+#endif /* _I386_PCB_H_ */
diff --git a/sys/i386/include/pio.h b/sys/i386/include/pio.h
new file mode 100644
index 0000000..ef9aba3
--- /dev/null
+++ b/sys/i386/include/pio.h
@@ -0,0 +1,48 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1990 Carnegie-Mellon University
+ * All rights reserved. The CMU software License Agreement specifies
+ * the terms and conditions for use and redistribution.
+ *
+ * from: Mach, unknown, 386BSD patch kit
+ * $Id: pio.h,v 1.2 1993/10/16 14:39:23 rgrimes Exp $
+ */
+
+#ifndef _MACHINE_PIO_H_
+#define _MACHINE_PIO_H_ 1
+
+#define inl(y) \
+({ unsigned long _tmp__; \
+ asm volatile("inl %1, %0" : "=a" (_tmp__) : "d" ((unsigned short)(y))); \
+ _tmp__; })
+
+#define inw(y) \
+({ unsigned short _tmp__; \
+ asm volatile(".byte 0x66; inl %1, %0" : "=a" (_tmp__) : "d" ((unsigned short)(y))); \
+ _tmp__; })
+
+/*
+ * only do this if it has not already be defined.. this is a crock for the
+ * patch kit for right now. Need to clean up all the inx, outx stuff for
+ * 0.1.5 to use 1 common header file, that has Bruces fast mode inb/outb
+ * stuff in it. Rgrimes 5/27/93
+ */
+#ifndef inb
+#define inb(y) \
+({ unsigned char _tmp__; \
+ asm volatile("inb %1, %0" : "=a" (_tmp__) : "d" ((unsigned short)(y))); \
+ _tmp__; })
+#endif
+
+
+#define outl(x, y) \
+{ asm volatile("outl %0, %1" : : "a" (y) , "d" ((unsigned short)(x))); }
+
+
+#define outw(x, y) \
+{asm volatile(".byte 0x66; outl %0, %1" : : "a" ((unsigned short)(y)) , "d" ((unsigned short)(x))); }
+
+
+#define outb(x, y) \
+{ asm volatile("outb %0, %1" : : "a" ((unsigned char)(y)) , "d" ((unsigned short)(x))); }
+#endif /* _MACHINE_PIO_H_ */
diff --git a/sys/i386/include/pmap.h b/sys/i386/include/pmap.h
new file mode 100644
index 0000000..74f002d
--- /dev/null
+++ b/sys/i386/include/pmap.h
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department and William Jolitz of UUNET Technologies Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Derived from hp300 version by Mike Hibler, this version by William
+ * Jolitz uses a recursive map [a pde points to the page directory] to
+ * map the page tables using the pagetables themselves. This is done to
+ * reduce the impact on kernel virtual memory for lots of sparse address
+ * space, and to reduce the cost of memory to each process.
+ *
+ * from: hp300: @(#)pmap.h 7.2 (Berkeley) 12/16/90
+ * from: @(#)pmap.h 7.4 (Berkeley) 5/12/91
+ * $Id: pmap.h,v 1.12 1994/03/24 23:12:48 davidg Exp $
+ */
+
+#ifndef _PMAP_MACHINE_
+#define _PMAP_MACHINE_ 1
+
+#include "vm/vm_prot.h"
+/*
+ * 386 page table entry and page table directory
+ * W.Jolitz, 8/89
+ */
+struct pde
+{
+unsigned int
+ pd_v:1, /* valid bit */
+ pd_prot:2, /* access control */
+ pd_mbz1:2, /* reserved, must be zero */
+ pd_u:1, /* hardware maintained 'used' bit */
+ :1, /* not used */
+ pd_mbz2:2, /* reserved, must be zero */
+ :3, /* reserved for software */
+ pd_pfnum:20; /* physical page frame number of pte's*/
+};
+
+#define PD_MASK 0xffc00000UL /* page directory address bits */
+#define PT_MASK 0x003ff000UL /* page table address bits */
+#define PD_SHIFT 22 /* page directory address shift */
+#define PG_SHIFT 12 /* page table address shift */
+
+struct pte
+{
+unsigned int
+ pg_v:1, /* valid bit */
+ pg_prot:2, /* access control */
+ pg_mbz1:2, /* reserved, must be zero */
+ pg_u:1, /* hardware maintained 'used' bit */
+ pg_m:1, /* hardware maintained modified bit */
+ pg_mbz2:2, /* reserved, must be zero */
+ pg_w:1, /* software, wired down page */
+ :1, /* software (unused) */
+ pg_nc:1, /* 'uncacheable page' bit */
+ pg_pfnum:20; /* physical page frame number */
+};
+
+#define PG_V 0x00000001
+#define PG_RO 0x00000000
+#define PG_RW 0x00000002
+#define PG_u 0x00000004
+#define PG_PROT 0x00000006 /* all protection bits . */
+#define PG_W 0x00000200
+#define PG_N 0x00000800 /* Non-cacheable */
+#define PG_M 0x00000040
+#define PG_U 0x00000020
+#define PG_FRAME 0xfffff000UL
+
+#define PG_NOACC 0
+#define PG_KR 0x00000000
+#define PG_KW 0x00000002
+#define PG_URKR 0x00000004
+#define PG_URKW 0x00000004
+#define PG_UW 0x00000006
+
+/* Garbage for current bastardized pager that assumes a hp300 */
+#define PG_NV 0
+#define PG_CI 0
+
+/*
+ * Page Protection Exception bits
+ */
+#define PGEX_P 0x01 /* Protection violation vs. not present */
+#define PGEX_W 0x02 /* during a Write cycle */
+#define PGEX_U 0x04 /* access from User mode (UPL) */
+
+/* typedef struct pde pd_entry_t; */ /* page directory entry */
+/* typedef struct pte pt_entry_t; */ /* Mach page table entry */
+typedef unsigned int *pd_entry_t;
+typedef unsigned int *pt_entry_t;
+
+/*
+ * NKPDE controls the virtual space of the kernel, what ever is left, minus
+ * the alternate page table area is given to the user (NUPDE)
+ */
+/*
+ * NKPDE controls the virtual space of the kernel, what ever is left is
+ * given to the user (NUPDE)
+ */
+#ifndef NKPT
+#define NKPT 15 /* actual number of kernel pte's */
+#endif
+#ifndef NKPDE
+#define NKPDE 63 /* addressable number of kpte's */
+#endif
+
+#define NUPDE (NPTEPG-NKPDE) /* number of user pde's */
+
+/*
+ * The *PTDI values control the layout of virtual memory
+ *
+ * XXX This works for now, but I am not real happy with it, I'll fix it
+ * right after I fix locore.s and the magic 28K hole
+ */
+#define APTDPTDI (NPTEPG-1) /* alt ptd entry that points to APTD */
+#define KPTDI (APTDPTDI-NKPDE)/* start of kernel virtual pde's */
+#define PTDPTDI (KPTDI-1) /* ptd entry that points to ptd! */
+#define KSTKPTDI (PTDPTDI-1) /* ptd entry for u./kernel&user stack */
+#define KSTKPTEOFF (NBPG/sizeof(pd_entry_t)-UPAGES) /* pte entry for kernel stack */
+
+#define PDESIZE sizeof(pd_entry_t) /* for assembly files */
+#define PTESIZE sizeof(pt_entry_t) /* for assembly files */
+
+/*
+ * Address of current and alternate address space page table maps
+ * and directories.
+ */
+#ifdef KERNEL
+extern pt_entry_t PTmap[], APTmap[], Upte;
+extern pd_entry_t PTD[], APTD[], PTDpde, APTDpde, Upde;
+extern pt_entry_t *Sysmap;
+
+extern int IdlePTD; /* physical address of "Idle" state directory */
+#endif
+
+/*
+ * virtual address to page table entry and
+ * to physical address. Likewise for alternate address space.
+ * Note: these work recursively, thus vtopte of a pte will give
+ * the corresponding pde that in turn maps it.
+ */
+#define vtopte(va) (PTmap + i386_btop(va))
+#define kvtopte(va) vtopte(va)
+#define ptetov(pt) (i386_ptob(pt - PTmap))
+#define vtophys(va) (((int) (*vtopte(va))&PG_FRAME) | ((int)(va) & PGOFSET))
+#define ispt(va) ((va) >= UPT_MIN_ADDRESS && (va) <= KPT_MAX_ADDRESS)
+
+#define avtopte(va) (APTmap + i386_btop(va))
+#define ptetoav(pt) (i386_ptob(pt - APTmap))
+#define avtophys(va) (((int) (*avtopte(va))&PG_FRAME) | ((int)(va) & PGOFSET))
+
+#ifdef KERNEL
+/*
+ * Routine: pmap_kextract
+ * Function:
+ * Extract the physical page address associated
+ * kernel virtual address.
+ */
+static inline vm_offset_t
+pmap_kextract(va)
+ vm_offset_t va;
+{
+ vm_offset_t pa = *(int *)vtopte(va);
+ pa = (pa & PG_FRAME) | (va & ~PG_FRAME);
+ return pa;
+}
+#endif
+
+/*
+ * macros to generate page directory/table indicies
+ */
+
+#define pdei(va) (((va)&PD_MASK)>>PD_SHIFT)
+#define ptei(va) (((va)&PT_MASK)>>PG_SHIFT)
+
+/*
+ * Pmap stuff
+ */
+
+struct pmap {
+ pd_entry_t *pm_pdir; /* KVA of page directory */
+ boolean_t pm_pdchanged; /* pdir changed */
+ short pm_dref; /* page directory ref count */
+ short pm_count; /* pmap reference count */
+ simple_lock_data_t pm_lock; /* lock on pmap */
+ struct pmap_statistics pm_stats; /* pmap statistics */
+ long pm_ptpages; /* more stats: PT pages */
+};
+
+typedef struct pmap *pmap_t;
+
+#ifdef KERNEL
+extern pmap_t kernel_pmap;
+#endif
+
+/*
+ * Macros for speed
+ */
+#define PMAP_ACTIVATE(pmapp, pcbp) \
+ if ((pmapp) != NULL /*&& (pmapp)->pm_pdchanged */) { \
+ (pcbp)->pcb_cr3 = \
+ pmap_extract(kernel_pmap, (vm_offset_t)(pmapp)->pm_pdir); \
+ if ((pmapp) == &curproc->p_vmspace->vm_pmap) \
+ load_cr3((pcbp)->pcb_cr3); \
+ (pmapp)->pm_pdchanged = FALSE; \
+ }
+
+#define PMAP_DEACTIVATE(pmapp, pcbp)
+
+/*
+ * For each vm_page_t, there is a list of all currently valid virtual
+ * mappings of that page. An entry is a pv_entry_t, the list is pv_table.
+ */
+typedef struct pv_entry {
+ struct pv_entry *pv_next; /* next pv_entry */
+ pmap_t pv_pmap; /* pmap where mapping lies */
+ vm_offset_t pv_va; /* virtual address for mapping */
+} *pv_entry_t;
+
+#define PV_ENTRY_NULL ((pv_entry_t) 0)
+
+#define PV_CI 0x01 /* all entries must be cache inhibited */
+#define PV_PTPAGE 0x02 /* entry maps a page table page */
+
+#ifdef KERNEL
+
+pv_entry_t pv_table; /* array of entries, one per page */
+
+#define pa_index(pa) atop(pa - vm_first_phys)
+#define pa_to_pvh(pa) (&pv_table[pa_index(pa)])
+
+#define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count)
+
+extern pmap_t pmap_create(vm_size_t);
+extern void pmap_pinit(struct pmap *);
+extern void pmap_destroy(pmap_t);
+extern void pmap_release(struct pmap *);
+extern void pmap_reference(pmap_t);
+extern void pmap_remove(struct pmap *, vm_offset_t, vm_offset_t);
+extern void pmap_protect(struct pmap *, vm_offset_t, vm_offset_t, vm_prot_t);
+extern void pmap_enter(pmap_t, vm_offset_t, vm_offset_t, vm_prot_t, boolean_t);
+extern void pmap_change_wiring(pmap_t, vm_offset_t, boolean_t);
+extern inline pt_entry_t *pmap_pte(pmap_t, vm_offset_t);
+extern vm_offset_t pmap_extract(pmap_t, vm_offset_t);
+extern void pmap_copy(pmap_t, pmap_t, vm_offset_t, vm_size_t, vm_offset_t);
+extern void pmap_collect(pmap_t);
+struct pcb; extern void pmap_activate(pmap_t, struct pcb *);
+extern pmap_t pmap_kernel(void);
+extern void pmap_pageable(pmap_t, vm_offset_t, vm_offset_t, boolean_t);
+
+
+#endif /* KERNEL */
+
+#endif /* _PMAP_MACHINE_ */
diff --git a/sys/i386/include/proc.h b/sys/i386/include/proc.h
new file mode 100644
index 0000000..1b9e4a2
--- /dev/null
+++ b/sys/i386/include/proc.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1991 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)proc.h 7.1 (Berkeley) 5/15/91
+ * $Id: proc.h,v 1.2 1993/10/16 14:39:24 rgrimes Exp $
+ */
+
+#ifndef _MACHINE_PROC_H_
+#define _MACHINE_PROC_H_ 1
+
+/*
+ * Machine-dependent part of the proc structure for hp300.
+ */
+struct mdproc {
+ int md_flags; /* machine-dependent flags */
+#ifdef notyet
+ int *p_regs; /* registers on current frame */
+#endif
+};
+
+/* md_flags */
+#define MDP_AST 0x0001 /* async trap pending */
+#endif /* _MACHINE_PROC_H_ */
diff --git a/sys/i386/include/psl.h b/sys/i386/include/psl.h
new file mode 100644
index 0000000..997fb23
--- /dev/null
+++ b/sys/i386/include/psl.h
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)psl.h 5.2 (Berkeley) 1/18/91
+ * $Id: psl.h,v 1.3 1993/11/07 17:43:04 wollman Exp $
+ */
+
+#ifndef _MACHINE_PSL_H_
+#define _MACHINE_PSL_H_ 1
+
+/*
+ * 386 processor status longword.
+ */
+#define PSL_C 0x00000001 /* carry bit */
+#define PSL_PF 0x00000004 /* parity bit */
+#define PSL_AF 0x00000010 /* bcd carry bit */
+#define PSL_Z 0x00000040 /* zero bit */
+#define PSL_N 0x00000080 /* negative bit */
+#define PSL_T 0x00000100 /* trace enable bit */
+#define PSL_I 0x00000200 /* interrupt enable bit */
+#define PSL_D 0x00000400 /* string instruction direction bit */
+#define PSL_V 0x00000800 /* overflow bit */
+#define PSL_IOPL 0x00003000 /* i/o priviledge level enable */
+#define PSL_NT 0x00004000 /* nested task bit */
+#define PSL_RF 0x00010000 /* restart flag bit */
+#define PSL_VM 0x00020000 /* virtual 8086 mode bit */
+
+#define PSL_MBZ 0xffc08028 /* must be zero bits */
+#define PSL_MBO 0x00000002 /* must be one bits */
+
+#define PSL_USERSET (PSL_MBO | PSL_I)
+#define PSL_USERCLR (PSL_MBZ | PSL_NT)
+#endif /* _MACHINE_PSL_H_ */
diff --git a/sys/i386/include/pte.h b/sys/i386/include/pte.h
new file mode 100644
index 0000000..227a8ae
--- /dev/null
+++ b/sys/i386/include/pte.h
@@ -0,0 +1,125 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)pte.h 5.5 (Berkeley) 5/9/91
+ * $Id: pte.h,v 1.4 1994/01/31 06:52:41 davidg Exp $
+ */
+
+#ifndef _MACHINE_PTE_H_
+#define _MACHINE_PTE_H_ 1
+
+/*
+ * 386 page table entry and page table directory
+ * W.Jolitz, 8/89
+ *
+ * There are two major kinds of pte's: those which have ever existed (and are
+ * thus either now in core or on the swap device), and those which have
+ * never existed, but which will be filled on demand at first reference.
+ * There is a structure describing each. There is also an ancillary
+ * structure used in page clustering.
+ */
+
+#ifndef LOCORE
+
+struct pde {
+unsigned int
+ pd_v:1, /* valid bit */
+ pd_prot:2, /* access control */
+ pd_ncpwt:1, /* page cache write through */
+ pd_ncpcd:1, /* page cache disable */
+ pd_u:1, /* hardware maintained 'used' bit */
+ pd_m:1, /* not used */
+ pd_mbz2:2, /* reserved, must be zero */
+ :3, /* reserved for software */
+ pd_pfnum:20; /* physical page frame number of pte's*/
+};
+
+struct pte {
+unsigned int
+ pg_v:1, /* valid bit */
+ pg_prot:2, /* access control */
+ pg_ncpwt:1, /* page cache write through */
+ pg_ncpcd:1, /* page cache disable */
+ pg_u:1, /* hardware maintained 'used' bit */
+ pg_m:1, /* hardware maintained modified bit */
+ pg_mbz2:2, /* reserved, must be zero */
+ :3, /* (unused) */
+ pg_pfnum:20; /* physical page frame number */
+};
+#endif
+
+#define PD_MASK 0xffc00000 /* page directory address bits */
+#define PD_SHIFT 22 /* page directory address bits */
+
+#define PG_V 0x00000001
+#define PG_PROT 0x00000006 /* all protection bits . */
+#define PG_NC_PWT 0x00000008 /* page cache write through */
+#define PG_NC_PCD 0x00000010 /* page cache disable */
+#define PG_N 0x00000018 /* Non-cacheable */
+#define PG_U 0x00000020 /* page was accessed */
+#define PG_M 0x00000040 /* page was modified */
+#define PG_FRAME 0xfffff000
+
+#define PG_NOACC 0
+#define PG_KR 0x00000000
+#define PG_KW 0x00000002
+#define PG_URKR 0x00000004
+#define PG_URKW 0x00000004
+#define PG_UW 0x00000006
+
+#define PG_FZERO 0
+#define PG_FTEXT 1
+#define PG_FMAX (PG_FTEXT)
+
+/*
+ * Page Protection Exception bits
+ */
+
+#define PGEX_P 0x01 /* Protection violation vs. not present */
+#define PGEX_W 0x02 /* during a Write cycle */
+#define PGEX_U 0x04 /* access from User mode (UPL) */
+
+/*
+ * Pte related macros
+ */
+#define dirty(pte) ((pte) & PG_M)
+
+#ifndef LOCORE
+#ifdef KERNEL
+/* utilities defined in pmap.c */
+extern struct pte *Sysmap;
+#endif
+#endif
+#endif /* _MACHINE_PTE_H_ */
diff --git a/sys/i386/include/reg.h b/sys/i386/include/reg.h
new file mode 100644
index 0000000..d20f8d0
--- /dev/null
+++ b/sys/i386/include/reg.h
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)reg.h 5.5 (Berkeley) 1/18/91
+ * $Id: reg.h,v 1.6 1994/01/03 07:55:34 davidg Exp $
+ */
+
+#ifndef _MACHINE_REG_H_
+#define _MACHINE_REG_H_ 1
+
+/*
+ * Location of the users' stored
+ * registers within appropriate frame of 'trap' and 'syscall', relative to
+ * base of stack frame.
+ * Normal usage is u.u_ar0[XX] in kernel.
+ */
+
+/* When referenced during a trap/exception, registers are at these offsets */
+
+#define tES (0)
+#define tDS (1)
+#define tEDI (2)
+#define tESI (3)
+#define tEBP (4)
+#define tISP (5)
+#define tEBX (6)
+#define tEDX (7)
+#define tECX (8)
+#define tEAX (9)
+
+#define tERR (11)
+
+#define tEIP (12)
+#define tCS (13)
+#define tEFLAGS (14)
+#define tESP (15)
+#define tSS (16)
+
+/*
+ * Registers accessible to ptrace(2) syscall for debugger
+ * The machine-dependent code for PT_{SET,GET}REGS needs to
+ * use whichver order, defined above, is correct, so that it
+ * is all invisible to the user.
+ */
+struct regs {
+ unsigned int r_es;
+ unsigned int r_ds;
+ unsigned int r_edi;
+ unsigned int r_esi;
+ unsigned int r_ebp;
+ unsigned int r_ebx;
+ unsigned int r_edx;
+ unsigned int r_ecx;
+ unsigned int r_eax;
+ unsigned int r_eip;
+ unsigned int r_cs;
+ unsigned int r_eflags;
+ unsigned int r_esp;
+ unsigned int r_ss;
+ unsigned int r_fs;
+ unsigned int r_gs;
+};
+
+#endif /* _MACHINE_REG_H_ */
diff --git a/sys/i386/include/segments.h b/sys/i386/include/segments.h
new file mode 100644
index 0000000..023a0cf
--- /dev/null
+++ b/sys/i386/include/segments.h
@@ -0,0 +1,235 @@
+/*-
+ * Copyright (c) 1989, 1990 William F. Jolitz
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)segments.h 7.1 (Berkeley) 5/9/91
+ * $Id: segments.h,v 1.3 1993/11/07 17:43:08 wollman Exp $
+ */
+
+#ifndef _MACHINE_SEGMENTS_H_
+#define _MACHINE_SEGMENTS_H_ 1
+
+/*
+ * 386 Segmentation Data Structures and definitions
+ * William F. Jolitz (william@ernie.berkeley.edu) 6/20/1989
+ */
+
+/*
+ * Selectors
+ */
+
+#define ISPL(s) ((s)&3) /* what is the priority level of a selector */
+#define SEL_KPL 0 /* kernel priority level */
+#define SEL_UPL 3 /* user priority level */
+#define ISLDT(s) ((s)&SEL_LDT) /* is it local or global */
+#define SEL_LDT 4 /* local descriptor table */
+#define IDXSEL(s) (((s)>>3) & 0x1fff) /* index of selector */
+#define LSEL(s,r) (((s)<<3) | SEL_LDT | r) /* a local selector */
+#define GSEL(s,r) (((s)<<3) | r) /* a global selector */
+
+/*
+ * Memory and System segment descriptors
+ */
+struct segment_descriptor {
+ unsigned sd_lolimit:16 ; /* segment extent (lsb) */
+ unsigned sd_lobase:24 __attribute__ ((packed));
+ /* segment base address (lsb) */
+ unsigned sd_type:5 ; /* segment type */
+ unsigned sd_dpl:2 ; /* segment descriptor priority level */
+ unsigned sd_p:1 ; /* segment descriptor present */
+ unsigned sd_hilimit:4 ; /* segment extent (msb) */
+ unsigned sd_xx:2 ; /* unused */
+ unsigned sd_def32:1 ; /* default 32 vs 16 bit size */
+ unsigned sd_gran:1 ; /* limit granularity (byte/page units)*/
+ unsigned sd_hibase:8 ; /* segment base address (msb) */
+} ;
+
+/*
+ * Gate descriptors (e.g. indirect descriptors)
+ */
+struct gate_descriptor {
+ unsigned gd_looffset:16 ; /* gate offset (lsb) */
+ unsigned gd_selector:16 ; /* gate segment selector */
+ unsigned gd_stkcpy:5 ; /* number of stack wds to cpy */
+ unsigned gd_xx:3 ; /* unused */
+ unsigned gd_type:5 ; /* segment type */
+ unsigned gd_dpl:2 ; /* segment descriptor priority level */
+ unsigned gd_p:1 ; /* segment descriptor present */
+ unsigned gd_hioffset:16 ; /* gate offset (msb) */
+} ;
+
+/*
+ * Generic descriptor
+ */
+union descriptor {
+ struct segment_descriptor sd;
+ struct gate_descriptor gd;
+};
+
+ /* system segments and gate types */
+#define SDT_SYSNULL 0 /* system null */
+#define SDT_SYS286TSS 1 /* system 286 TSS available */
+#define SDT_SYSLDT 2 /* system local descriptor table */
+#define SDT_SYS286BSY 3 /* system 286 TSS busy */
+#define SDT_SYS286CGT 4 /* system 286 call gate */
+#define SDT_SYSTASKGT 5 /* system task gate */
+#define SDT_SYS286IGT 6 /* system 286 interrupt gate */
+#define SDT_SYS286TGT 7 /* system 286 trap gate */
+#define SDT_SYSNULL2 8 /* system null again */
+#define SDT_SYS386TSS 9 /* system 386 TSS available */
+#define SDT_SYSNULL3 10 /* system null again */
+#define SDT_SYS386BSY 11 /* system 386 TSS busy */
+#define SDT_SYS386CGT 12 /* system 386 call gate */
+#define SDT_SYSNULL4 13 /* system null again */
+#define SDT_SYS386IGT 14 /* system 386 interrupt gate */
+#define SDT_SYS386TGT 15 /* system 386 trap gate */
+
+ /* memory segment types */
+#define SDT_MEMRO 16 /* memory read only */
+#define SDT_MEMROA 17 /* memory read only accessed */
+#define SDT_MEMRW 18 /* memory read write */
+#define SDT_MEMRWA 19 /* memory read write accessed */
+#define SDT_MEMROD 20 /* memory read only expand dwn limit */
+#define SDT_MEMRODA 21 /* memory read only expand dwn limit accessed */
+#define SDT_MEMRWD 22 /* memory read write expand dwn limit */
+#define SDT_MEMRWDA 23 /* memory read write expand dwn limit acessed */
+#define SDT_MEME 24 /* memory execute only */
+#define SDT_MEMEA 25 /* memory execute only accessed */
+#define SDT_MEMER 26 /* memory execute read */
+#define SDT_MEMERA 27 /* memory execute read accessed */
+#define SDT_MEMEC 28 /* memory execute only conforming */
+#define SDT_MEMEAC 29 /* memory execute only accessed conforming */
+#define SDT_MEMERC 30 /* memory execute read conforming */
+#define SDT_MEMERAC 31 /* memory execute read accessed conforming */
+
+/* is memory segment descriptor pointer ? */
+#define ISMEMSDP(s) ((s->d_type) >= SDT_MEMRO && (s->d_type) <= SDT_MEMERAC)
+
+/* is 286 gate descriptor pointer ? */
+#define IS286GDP(s) (((s->d_type) >= SDT_SYS286CGT \
+ && (s->d_type) < SDT_SYS286TGT))
+
+/* is 386 gate descriptor pointer ? */
+#define IS386GDP(s) (((s->d_type) >= SDT_SYS386CGT \
+ && (s->d_type) < SDT_SYS386TGT))
+
+/* is gate descriptor pointer ? */
+#define ISGDP(s) (IS286GDP(s) || IS386GDP(s))
+
+/* is segment descriptor pointer ? */
+#define ISSDP(s) (ISMEMSDP(s) || !ISGDP(s))
+
+/* is system segment descriptor pointer ? */
+#define ISSYSSDP(s) (!ISMEMSDP(s) && !ISGDP(s))
+
+/*
+ * Software definitions are in this convenient format,
+ * which are translated into inconvenient segment descriptors
+ * when needed to be used by the 386 hardware
+ */
+
+struct soft_segment_descriptor {
+ unsigned ssd_base ; /* segment base address */
+ unsigned ssd_limit ; /* segment extent */
+ unsigned ssd_type:5 ; /* segment type */
+ unsigned ssd_dpl:2 ; /* segment descriptor priority level */
+ unsigned ssd_p:1 ; /* segment descriptor present */
+ unsigned ssd_xx:4 ; /* unused */
+ unsigned ssd_xx1:2 ; /* unused */
+ unsigned ssd_def32:1 ; /* default 32 vs 16 bit size */
+ unsigned ssd_gran:1 ; /* limit granularity (byte/page units)*/
+};
+
+extern ssdtosd() ; /* to decode a ssd */
+extern sdtossd() ; /* to encode a sd */
+
+/*
+ * region descriptors, used to load gdt/idt tables before segments yet exist.
+ */
+struct region_descriptor {
+ unsigned rd_limit:16; /* segment extent */
+ unsigned rd_base:32 __attribute__ ((packed)); /* base address */
+};
+
+/*
+ * Segment Protection Exception code bits
+ */
+
+#define SEGEX_EXT 0x01 /* recursive or externally induced */
+#define SEGEX_IDT 0x02 /* interrupt descriptor table */
+#define SEGEX_TI 0x04 /* local descriptor table */
+ /* other bits are affected descriptor index */
+#define SEGEX_IDX(s) ((s)>>3)&0x1fff)
+
+/*
+ * Size of IDT table
+ */
+
+#define NIDT 256
+#define NRSVIDT 32 /* reserved entries for cpu exceptions */
+
+/*
+ * Entries in the Global Descriptor Table (GDT)
+ */
+#define GNULL_SEL 0 /* Null Descriptor */
+#define GCODE_SEL 1 /* Kernel Code Descriptor */
+#define GDATA_SEL 2 /* Kernel Data Descriptor */
+#define GLDT_SEL 3 /* LDT - eventually one per process */
+#define GTGATE_SEL 4 /* Process task switch gate */
+#define GPANIC_SEL 5 /* Task state to consider panic from */
+#define GPROC0_SEL 6 /* Task state process slot zero and up */
+#define GUSERLDT_SEL 7 /* User LDT */
+#define NGDT GUSERLDT_SEL+1
+
+/*
+ * Entries in the Local Descriptor Table (LDT)
+ */
+#define LSYS5CALLS_SEL 0 /* forced by intel BCS */
+#define LSYS5SIGR_SEL 1
+#define L43BSDCALLS_SEL 2 /* notyet */
+#define LUCODE_SEL 3
+#define LUDATA_SEL 4
+/* seperate stack, es,fs,gs sels ? */
+/* #define LPOSIXCALLS_SEL 5*/ /* notyet */
+#define NLDT LUDATA_SEL+1
+
+#ifdef KERNEL
+extern int currentldt;
+extern union descriptor gdt[NGDT];
+extern union descriptor ldt[NLDT];
+extern struct soft_segment_descriptor gdt_segs[];
+#endif
+
+#endif /* _MACHINE_SEGMENTS_H_ */
diff --git a/sys/i386/include/soundcard.h b/sys/i386/include/soundcard.h
new file mode 100644
index 0000000..ce28a14
--- /dev/null
+++ b/sys/i386/include/soundcard.h
@@ -0,0 +1,763 @@
+#ifndef _SOUNDCARD_H_
+#define _SOUNDCARD_H_
+/*
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *
+ */
+
+ /*
+ * If you make modifications to this file, please contact me before
+ * distributing the modified version. There is already enough
+ * divercity in the world.
+ *
+ * Regards,
+ * Hannu Savolainen
+ * hannu@voxware.pp.fi, Hannu.Savolainen@helsinki.fi
+ */
+
+#define SOUND_VERSION 205
+#define VOXWARE
+
+#include <sys/ioctl.h>
+
+/*
+ * Supported card ID numbers (Should be somewhere else?)
+ */
+
+#define SNDCARD_ADLIB 1
+#define SNDCARD_SB 2
+#define SNDCARD_PAS 3
+#define SNDCARD_GUS 4
+#define SNDCARD_MPU401 5
+#define SNDCARD_SB16 6
+#define SNDCARD_SB16MIDI 7
+
+/***********************************
+ * IOCTL Commands for /dev/sequencer
+ */
+
+#ifndef _IOWR
+/* @(#)ioctlp.h */
+
+/* Ioctl's have the command encoded in the lower word,
+ * and the size of any in or out parameters in the upper
+ * word. The high 2 bits of the upper word are used
+ * to encode the in/out status of the parameter; for now
+ * we restrict parameters to at most 128 bytes.
+ */
+/* #define IOCTYPE (0xff<<8) */
+#define IOCPARM_MASK 0x7f /* parameters must be < 128 bytes */
+#define IOC_VOID 0x00000000 /* no parameters */
+#define IOC_OUT 0x20000000 /* copy out parameters */
+#define IOC_IN 0x40000000 /* copy in parameters */
+#define IOC_INOUT (IOC_IN|IOC_OUT)
+/* the 0x20000000 is so we can distinguish new ioctl's from old */
+#define _IO(x,y) ((int)(IOC_VOID|(x<<8)|y))
+#define _IOR(x,y,t) ((int)(IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y))
+#define _IOW(x,y,t) ((int)(IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y))
+/* this should be _IORW, but stdio got there first */
+#define _IOWR(x,y,t) ((int)(IOC_INOUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y))
+#endif /* !_IOWR */
+
+#define SNDCTL_SEQ_RESET _IO ('Q', 0)
+#define SNDCTL_SEQ_SYNC _IO ('Q', 1)
+#define SNDCTL_SYNTH_INFO _IOWR('Q', 2, struct synth_info)
+#define SNDCTL_SEQ_CTRLRATE _IOWR('Q', 3, int) /* Set/get timer resolution (HZ) */
+#define SNDCTL_SEQ_GETOUTCOUNT _IOR ('Q', 4, int)
+#define SNDCTL_SEQ_GETINCOUNT _IOR ('Q', 5, int)
+#define SNDCTL_SEQ_PERCMODE _IOW ('Q', 6, int)
+#define SNDCTL_FM_LOAD_INSTR _IOW ('Q', 7, struct sbi_instrument) /* Valid for FM only */
+#define SNDCTL_SEQ_TESTMIDI _IOW ('Q', 8, int)
+#define SNDCTL_SEQ_RESETSAMPLES _IOW ('Q', 9, int)
+#define SNDCTL_SEQ_NRSYNTHS _IOR ('Q',10, int)
+#define SNDCTL_SEQ_NRMIDIS _IOR ('Q',11, int)
+#define SNDCTL_MIDI_INFO _IOWR('Q',12, struct midi_info)
+#define SNDCTL_SEQ_TRESHOLD _IOW ('Q',13, int)
+#define SNDCTL_SYNTH_MEMAVL _IOWR('Q',14, int) /* in=dev#, out=memsize */
+#define SNDCTL_FM_4OP_ENABLE _IOW ('Q',15, int) /* in=dev# */
+#define SNDCTL_PMGR_ACCESS _IOWR('Q',16, struct patmgr_info)
+
+/*
+ * Sample loading mechanism for internal synthesizers (/dev/sequencer)
+ * The following patch_info structure has been designed to support
+ * Gravis UltraSound. It tries to be universal format for uploading
+ * sample based patches but is propably too limited.
+ */
+
+struct patch_info {
+ short key; /* Use GUS_PATCH here */
+#define GUS_PATCH 0x04fd
+#define OBSOLETE_GUS_PATCH 0x02fd
+ short device_no; /* Synthesizer number */
+ short instr_no; /* Midi pgm# */
+
+ unsigned long mode;
+/*
+ * The least significant byte has the same format than the GUS .PAT
+ * files
+ */
+#define WAVE_16_BITS 0x01 /* bit 0 = 8 or 16 bit wave data. */
+#define WAVE_UNSIGNED 0x02 /* bit 1 = Signed - Unsigned data. */
+#define WAVE_LOOPING 0x04 /* bit 2 = looping enabled-1. */
+#define WAVE_BIDIR_LOOP 0x08 /* bit 3 = Set is bidirectional looping. */
+#define WAVE_LOOP_BACK 0x10 /* bit 4 = Set is looping backward. */
+#define WAVE_SUSTAIN_ON 0x20 /* bit 5 = Turn sustaining on. (Env. pts. 3)*/
+#define WAVE_ENVELOPES 0x40 /* bit 6 = Enable envelopes - 1 */
+ /* (use the env_rate/env_offs fields). */
+/* Linux specific bits */
+#define WAVE_VIBRATO 0x00010000 /* The vibrato info is valid */
+#define WAVE_TREMOLO 0x00020000 /* The tremolo info is valid */
+#define WAVE_SCALE 0x00040000 /* The scaling info is valid */
+/* Other bits must be zeroed */
+
+ long len; /* Size of the wave data in bytes */
+ long loop_start, loop_end; /* Byte offsets from the beginning */
+
+/*
+ * The base_freq and base_note fields are used when computing the
+ * playback speed for a note. The base_note defines the tone frequency
+ * which is heard if the sample is played using the base_freq as the
+ * playback speed.
+ *
+ * The low_note and high_note fields define the minimum and maximum note
+ * frequencies for which this sample is valid. It is possible to define
+ * more than one samples for a instrument number at the same time. The
+ * low_note and high_note fields are used to select the most suitable one.
+ *
+ * The fields base_note, high_note and low_note should contain
+ * the note frequency multiplied by 1000. For example value for the
+ * middle A is 440*1000.
+ */
+
+ unsigned int base_freq;
+ unsigned long base_note;
+ unsigned long high_note;
+ unsigned long low_note;
+ int panning; /* -128=left, 127=right */
+ int detuning;
+
+/* New fields introduced in version 1.99.5 */
+
+ /* Envelope. Enabled by mode bit WAVE_ENVELOPES */
+ unsigned char env_rate[ 6 ]; /* GUS HW ramping rate */
+ unsigned char env_offset[ 6 ]; /* 255 == 100% */
+
+ /*
+ * The tremolo, vibrato and scale info are not supported yet.
+ * Enable by setting the mode bits WAVE_TREMOLO, WAVE_VIBRATO or
+ * WAVE_SCALE
+ */
+
+ unsigned char tremolo_sweep;
+ unsigned char tremolo_rate;
+ unsigned char tremolo_depth;
+
+ unsigned char vibrato_sweep;
+ unsigned char vibrato_rate;
+ unsigned char vibrato_depth;
+
+ int scale_frequency;
+ unsigned int scale_factor; /* from 0 to 2048 or 0 to 2 */
+
+ int volume;
+ int spare[4];
+ char data[1]; /* The waveform data starts here */
+ };
+
+
+/*
+ * Patch management interface (/dev/sequencer, /dev/patmgr#)
+ * Don't use these calls if you want to maintain compatibility with
+ * the future versions of the driver.
+ */
+
+#define PS_NO_PATCHES 0 /* No patch support on device */
+#define PS_MGR_NOT_OK 1 /* Plain patch support (no mgr) */
+#define PS_MGR_OK 2 /* Patch manager supported */
+#define PS_MANAGED 3 /* Patch manager running */
+
+#define SNDCTL_PMGR_IFACE _IOWR('P', 1, struct patmgr_info)
+
+/*
+ * The patmgr_info is a fixed size structure which is used for two
+ * different purposes. The intended use is for communication between
+ * the application using /dev/sequencer and the patch manager daemon
+ * associated with a synthesizer device (ioctl(SNDCTL_PMGR_ACCESS)).
+ *
+ * This structure is also used with ioctl(SNDCTL_PGMR_IFACE) which allows
+ * a patch manager daemon to read and write device parameters. This
+ * ioctl available through /dev/sequencer also. Avoid using it since it's
+ * extremely hardware dependent. In addition access trough /dev/sequencer
+ * may confuse the patch manager daemon.
+ */
+
+struct patmgr_info { /* Note! size must be < 4k since kmalloc() is used */
+ unsigned long key; /* Don't worry. Reserved for communication
+ between the patch manager and the driver. */
+#define PM_K_EVENT 1 /* Event from the /dev/sequencer driver */
+#define PM_K_COMMAND 2 /* Request from a application */
+#define PM_K_RESPONSE 3 /* From patmgr to application */
+#define PM_ERROR 4 /* Error returned by the patmgr */
+ int device;
+ int command;
+
+/*
+ * Commands 0x000 to 0xfff reserved for patch manager programs
+ */
+#define PM_GET_DEVTYPE 1 /* Returns type of the patch mgr interface of dev */
+#define PMTYPE_FM2 1 /* 2 OP fm */
+#define PMTYPE_FM4 2 /* Mixed 4 or 2 op FM (OPL-3) */
+#define PMTYPE_WAVE 3 /* Wave table synthesizer (GUS) */
+#define PM_GET_NRPGM 2 /* Returns max # of midi programs in parm1 */
+#define PM_GET_PGMMAP 3 /* Returns map of loaded midi programs in data8 */
+#define PM_GET_PGM_PATCHES 4 /* Return list of patches of a program (parm1) */
+#define PM_GET_PATCH 5 /* Return patch header of patch parm1 */
+#define PM_SET_PATCH 6 /* Set patch header of patch parm1 */
+#define PM_READ_PATCH 7 /* Read patch (wave) data */
+#define PM_WRITE_PATCH 8 /* Write patch (wave) data */
+
+/*
+ * Commands 0x1000 to 0xffff are for communication between the patch manager
+ * and the client
+ */
+#define _PM_LOAD_PATCH 0x100
+
+/*
+ * Commands above 0xffff reserved for device specific use
+ */
+
+ long parm1;
+ long parm2;
+ long parm3;
+
+ union {
+ unsigned char data8[4000];
+ unsigned short data16[2000];
+ unsigned long data32[1000];
+ struct patch_info patch;
+ } data;
+ };
+
+/*
+ * When a patch manager daemon is present, it will be informed by the
+ * driver when something important happens. For example when the
+ * /dev/sequencer is opened or closed. A record with key == PM_K_EVENT is
+ * returned. The command field contains the event type:
+ */
+#define PM_E_OPENED 1 /* /dev/sequencer opened */
+#define PM_E_CLOSED 2 /* /dev/sequencer closed */
+#define PM_E_PATCH_RESET 3 /* SNDCTL_RESETSAMPLES called */
+#define PM_E_PATCH_LOADED 4 /* A patch has been loaded by appl */
+
+/*
+ * /dev/sequencer input events.
+ *
+ * The data written to the /dev/sequencer is a stream of events. Events
+ * are records of 4 or 8 bytes. The first byte defines the size.
+ * Any number of events can be written with a write call. There
+ * is a set of macros for sending these events. Use these macros if you
+ * want to maximize portability of your program.
+ *
+ * Events SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO. Are also input events.
+ * (All input events are currently 4 bytes long. Be prepared to support
+ * 8 byte events also. If you receive any event having first byte >= 0xf0,
+ * it's a 8 byte event.
+ *
+ * The events are documented at the end of this file.
+ *
+ * Normal events (4 bytes)
+ * There is also a 8 byte version of most of the 4 byte events. The
+ * 8 byte one is recommended.
+ */
+#define SEQ_NOTEOFF 0
+#define SEQ_FMNOTEOFF SEQ_NOTEOFF /* Just old name */
+#define SEQ_NOTEON 1
+#define SEQ_FMNOTEON SEQ_NOTEON
+#define SEQ_WAIT 2
+#define SEQ_PGMCHANGE 3
+#define SEQ_FMPGMCHANGE SEQ_PGMCHANGE
+#define SEQ_SYNCTIMER 4
+#define SEQ_MIDIPUTC 5
+#define SEQ_DRUMON 6 /*** OBSOLETE ***/
+#define SEQ_DRUMOFF 7 /*** OBSOLETE ***/
+#define SEQ_ECHO 8 /* For synching programs with output */
+#define SEQ_AFTERTOUCH 9
+#define SEQ_CONTROLLER 10
+#define CTRL_PITCH_BENDER 255
+#define CTRL_PITCH_BENDER_RANGE 254
+#define CTRL_EXPRESSION 253
+#define CTRL_MAIN_VOLUME 252
+#define SEQ_BALANCE 11
+#define SEQ_VOLMODE 12
+
+/*
+ * Volume mode decides how volumes are used
+ */
+
+#define VOL_METHOD_ADAGIO 1
+#define VOL_METHOD_LINEAR 2
+
+/*
+ * Note! SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO are used also as
+ * input events.
+ */
+
+/*
+ * Event codes 0xf0 to 0xfc are reserved for future extensions.
+ */
+
+#define SEQ_FULLSIZE 0xfd /* Long events */
+/*
+ * SEQ_FULLSIZE events are used for loading patches/samples to the
+ * synthesizer devices. These events are passed directly to the driver
+ * of the associated synthesizer device. There is no limit to the size
+ * of the extended events. These events are not queued but executed
+ * immediately when the write() is called (execution can take several
+ * seconds of time).
+ *
+ * When a SEQ_FULLSIZE message is written to the device, it must
+ * be written using exactly one write() call. Other events cannot
+ * be mixed to the same write.
+ *
+ * For FM synths (YM3812/OPL3) use struct sbi_instrument and write it to the
+ * /dev/sequencer. Don't write other data together with the instrument structure
+ * Set the key field of the structure to FM_PATCH. The device field is used to
+ * route the patch to the corresponding device.
+ *
+ * For Gravis UltraSound use struct patch_info. Initialize the key field
+ * to GUS_PATCH.
+ */
+#define SEQ_PRIVATE 0xfe /* Low level HW dependent events (8 bytes) */
+#define SEQ_EXTENDED 0xff /* Extended events (8 bytes) */
+
+/*
+ * Extended events for synthesizers (8 bytes)
+ *
+ * Format:
+ *
+ * b0 = SEQ_EXTENDED
+ * b1 = command
+ * b2 = device
+ * b3-b7 = parameters
+ *
+ * Command b3 b4 b5 b6 b7
+ * ----------------------------------------------------------------------------
+ * SEQ_NOTEON voice note volume 0 0
+ * SEQ_NOTEOFF voice note volume 0 0
+ * SEQ_PGMCHANGE voice pgm 0 0 0
+ * SEQ_DRUMON (voice) drum# volume 0 0
+ * SEQ_DRUMOFF (voice) drum# volume 0 0
+ */
+
+/*
+ * Record for FM patches
+ */
+
+typedef unsigned char sbi_instr_data[32];
+
+struct sbi_instrument {
+ unsigned short key; /* Initialize to FM_PATCH or OPL3_PATCH */
+#define FM_PATCH 0x01fd
+#define OPL3_PATCH 0x03fd
+ short device; /* Synth# (0-4) */
+ int channel; /* Program# to be initialized */
+ sbi_instr_data operators; /* Register settings for operator cells (.SBI format) */
+ };
+
+struct synth_info { /* Read only */
+ char name[30];
+ int device; /* 0-N. INITIALIZE BEFORE CALLING */
+ int synth_type;
+#define SYNTH_TYPE_FM 0
+#define SYNTH_TYPE_SAMPLE 1
+
+ int synth_subtype;
+#define FM_TYPE_ADLIB 0x00
+#define FM_TYPE_OPL3 0x01
+
+#define SAMPLE_TYPE_GUS 0x10
+
+ int perc_mode; /* No longer supported */
+ int nr_voices;
+ int nr_drums; /* Obsolete field */
+ int instr_bank_size;
+ unsigned long capabilities;
+#define SYNTH_CAP_PERCMODE 0x00000001 /* No longer used */
+#define SYNTH_CAP_OPL3 0x00000002 /* Set if OPL3 supported */
+ int dummies[19]; /* Reserve space */
+ };
+
+struct midi_info {
+ char name[30];
+ int device; /* 0-N. INITIALIZE BEFORE CALLING */
+ unsigned long capabilities; /* To be defined later */
+ int dev_type;
+ int dummies[18]; /* Reserve space */
+ };
+
+/********************************************
+ * IOCTL commands for /dev/dsp and /dev/audio
+ */
+
+#define SNDCTL_DSP_RESET _IO ('P', 0)
+#define SNDCTL_DSP_SYNC _IO ('P', 1)
+#define SNDCTL_DSP_SPEED _IOWR('P', 2, int)
+#define SNDCTL_DSP_STEREO _IOWR('P', 3, int)
+#define SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int)
+#define SNDCTL_DSP_SAMPLESIZE _IOWR('P', 5, int) /* 8, 12 or 16 */
+#define SOUND_PCM_WRITE_CHANNELS _IOWR('P', 6, int)
+#define SOUND_PCM_WRITE_FILTER _IOWR('P', 7, int)
+#define SNDCTL_DSP_POST _IO ('P', 8)
+#define SNDCTL_DSP_SUBDIVIDE _IOWR('P', 9, int)
+
+#define SOUND_PCM_READ_RATE _IOR ('P', 2, int)
+#define SOUND_PCM_READ_CHANNELS _IOR ('P', 6, int)
+#define SOUND_PCM_READ_BITS _IOR ('P', 5, int)
+#define SOUND_PCM_READ_FILTER _IOR ('P', 7, int)
+
+/* Some alias names */
+#define SOUND_PCM_WRITE_BITS SNDCTL_DSP_SAMPLESIZE
+#define SOUND_PCM_WRITE_RATE SNDCTL_DSP_SPEED
+#define SOUND_PCM_POST SNDCTL_DSP_POST
+#define SOUND_PCM_RESET SNDCTL_DSP_RESET
+#define SOUND_PCM_SYNC SNDCTL_DSP_SYNC
+#define SOUND_PCM_SUBDIVIDE SNDCTL_DSP_SUBDIVIDE
+
+/*********************************************
+ * IOCTL commands for /dev/mixer
+ */
+
+/*
+ * Mixer devices
+ *
+ * There can be up to 20 different analog mixer channels. The
+ * SOUND_MIXER_NRDEVICES gives the currently supported maximum.
+ * The SOUND_MIXER_READ_DEVMASK returns a bitmask which tells
+ * the devices supported by the particular mixer.
+ */
+
+#define SOUND_MIXER_NRDEVICES 12
+#define SOUND_MIXER_VOLUME 0
+#define SOUND_MIXER_BASS 1
+#define SOUND_MIXER_TREBLE 2
+#define SOUND_MIXER_SYNTH 3
+#define SOUND_MIXER_PCM 4
+#define SOUND_MIXER_SPEAKER 5
+#define SOUND_MIXER_LINE 6
+#define SOUND_MIXER_MIC 7
+#define SOUND_MIXER_CD 8
+#define SOUND_MIXER_IMIX 9 /* Recording monitor */
+#define SOUND_MIXER_ALTPCM 10
+#define SOUND_MIXER_RECLEV 11 /* Recording level */
+
+/* Some on/off settings (SOUND_SPECIAL_MIN - SOUND_SPECIAL_MAX) */
+/* Not counted to SOUND_MIXER_NRDEVICES, but use the same number space */
+#define SOUND_ONOFF_MIN 28
+#define SOUND_ONOFF_MAX 30
+#define SOUND_MIXER_MUTE 28 /* 0 or 1 */
+#define SOUND_MIXER_ENHANCE 29 /* Enhanced stereo (0, 40, 60 or 80) */
+#define SOUND_MIXER_LOUD 30 /* 0 or 1 */
+
+/* Note! Number 31 cannot be used since the sign bit is reserved */
+
+#define SOUND_DEVICE_LABELS {"Vol ", "Bass ", "Trebl", "Synth", "Pcm ", "Spkr ", "Line ", \
+ "Mic ", "CD ", "Mix ", "Pcm2 ", "rec"}
+
+#define SOUND_DEVICE_NAMES {"vol", "bass", "treble", "synth", "pcm", "speaker", "line", \
+ "mic", "cd", "mix", "pcm2", "rec"}
+
+/* Device bitmask identifiers */
+
+#define SOUND_MIXER_RECSRC 0xff /* Arg contains a bit for each recording source */
+#define SOUND_MIXER_DEVMASK 0xfe /* Arg contains a bit for each supported device */
+#define SOUND_MIXER_RECMASK 0xfd /* Arg contains a bit for each supported recording source */
+#define SOUND_MIXER_CAPS 0xfc
+ #define SOUND_CAP_EXCL_INPUT 0x00000001 /* Only one recording source at a time */
+#define SOUND_MIXER_STEREODEVS 0xfb /* Mixer channels supporting stereo */
+
+/* Device mask bits */
+
+#define SOUND_MASK_VOLUME (1 << SOUND_MIXER_VOLUME)
+#define SOUND_MASK_BASS (1 << SOUND_MIXER_BASS)
+#define SOUND_MASK_TREBLE (1 << SOUND_MIXER_TREBLE)
+#define SOUND_MASK_SYNTH (1 << SOUND_MIXER_SYNTH)
+#define SOUND_MASK_PCM (1 << SOUND_MIXER_PCM)
+#define SOUND_MASK_SPEAKER (1 << SOUND_MIXER_SPEAKER)
+#define SOUND_MASK_LINE (1 << SOUND_MIXER_LINE)
+#define SOUND_MASK_MIC (1 << SOUND_MIXER_MIC)
+#define SOUND_MASK_CD (1 << SOUND_MIXER_CD)
+#define SOUND_MASK_IMIX (1 << SOUND_MIXER_IMIX)
+#define SOUND_MASK_ALTPCM (1 << SOUND_MIXER_ALTPCM)
+#define SOUND_MASK_RECLEV (1 << SOUND_MIXER_RECLEV)
+
+#define SOUND_MASK_MUTE (1 << SOUND_MIXER_MUTE)
+#define SOUND_MASK_ENHANCE (1 << SOUND_MIXER_ENHANCE)
+#define SOUND_MASK_LOUD (1 << SOUND_MIXER_LOUD)
+
+#define MIXER_READ(dev) _IOR('M', dev, int)
+#define SOUND_MIXER_READ_VOLUME MIXER_READ(SOUND_MIXER_VOLUME)
+#define SOUND_MIXER_READ_BASS MIXER_READ(SOUND_MIXER_BASS)
+#define SOUND_MIXER_READ_TREBLE MIXER_READ(SOUND_MIXER_TREBLE)
+#define SOUND_MIXER_READ_SYNTH MIXER_READ(SOUND_MIXER_SYNTH)
+#define SOUND_MIXER_READ_PCM MIXER_READ(SOUND_MIXER_PCM)
+#define SOUND_MIXER_READ_SPEAKER MIXER_READ(SOUND_MIXER_SPEAKER)
+#define SOUND_MIXER_READ_LINE MIXER_READ(SOUND_MIXER_LINE)
+#define SOUND_MIXER_READ_MIC MIXER_READ(SOUND_MIXER_MIC)
+#define SOUND_MIXER_READ_CD MIXER_READ(SOUND_MIXER_CD)
+#define SOUND_MIXER_READ_IMIX MIXER_READ(SOUND_MIXER_IMIX)
+#define SOUND_MIXER_READ_ALTPCM MIXER_READ(SOUND_MIXER_ALTPCM)
+#define SOUND_MIXER_READ_RECLEV MIXER_READ(SOUND_MIXER_RECLEV)
+#define SOUND_MIXER_READ_MUTE MIXER_READ(SOUND_MIXER_MUTE)
+#define SOUND_MIXER_READ_ENHANCE MIXER_READ(SOUND_MIXER_ENHANCE)
+#define SOUND_MIXER_READ_LOUD MIXER_READ(SOUND_MIXER_LOUD)
+
+#define SOUND_MIXER_READ_RECSRC MIXER_READ(SOUND_MIXER_RECSRC)
+#define SOUND_MIXER_READ_DEVMASK MIXER_READ(SOUND_MIXER_DEVMASK)
+#define SOUND_MIXER_READ_RECMASK MIXER_READ(SOUND_MIXER_RECMASK)
+#define SOUND_MIXER_READ_STEREODEVS MIXER_READ(SOUND_MIXER_STEREODEVS)
+#define SOUND_MIXER_READ_CAPS MIXER_READ(SOUND_MIXER_CAPS)
+
+#define MIXER_WRITE(dev) _IOWR('M', dev, int)
+#define SOUND_MIXER_WRITE_VOLUME MIXER_WRITE(SOUND_MIXER_VOLUME)
+#define SOUND_MIXER_WRITE_BASS MIXER_WRITE(SOUND_MIXER_BASS)
+#define SOUND_MIXER_WRITE_TREBLE MIXER_WRITE(SOUND_MIXER_TREBLE)
+#define SOUND_MIXER_WRITE_SYNTH MIXER_WRITE(SOUND_MIXER_SYNTH)
+#define SOUND_MIXER_WRITE_PCM MIXER_WRITE(SOUND_MIXER_PCM)
+#define SOUND_MIXER_WRITE_SPEAKER MIXER_WRITE(SOUND_MIXER_SPEAKER)
+#define SOUND_MIXER_WRITE_LINE MIXER_WRITE(SOUND_MIXER_LINE)
+#define SOUND_MIXER_WRITE_MIC MIXER_WRITE(SOUND_MIXER_MIC)
+#define SOUND_MIXER_WRITE_CD MIXER_WRITE(SOUND_MIXER_CD)
+#define SOUND_MIXER_WRITE_IMIX MIXER_WRITE(SOUND_MIXER_IMIX)
+#define SOUND_MIXER_WRITE_ALTPCM MIXER_WRITE(SOUND_MIXER_ALTPCM)
+#define SOUND_MIXER_WRITE_RECLEV MIXER_WRITE(SOUND_MIXER_RECLEV)
+#define SOUND_MIXER_WRITE_MUTE MIXER_WRITE(SOUND_MIXER_MUTE)
+#define SOUND_MIXER_WRITE_ENHANCE MIXER_WRITE(SOUND_MIXER_ENHANCE)
+#define SOUND_MIXER_WRITE_LOUD MIXER_WRITE(SOUND_MIXER_LOUD)
+
+#define SOUND_MIXER_WRITE_RECSRC MIXER_WRITE(SOUND_MIXER_RECSRC)
+
+/*
+ * The following mixer ioctl calls are compatible with the BSD driver by
+ * Steve Haehnichen <shaehnic@ucsd.edu>
+ *
+ * Since this interface is entirely SB specific, it will be dropped in the
+ * near future.
+ */
+
+typedef unsigned char S_BYTE;
+typedef unsigned char S_FLAG;
+struct stereo_vol
+{
+ S_BYTE l; /* Left volume */
+ S_BYTE r; /* Right volume */
+};
+
+#define MIXER_IOCTL_SET_LEVELS _IOW ('s', 20, struct sb_mixer_levels)
+#define MIXER_IOCTL_SET_PARAMS _IOW ('s', 21, struct sb_mixer_params)
+#define MIXER_IOCTL_READ_LEVELS _IOR ('s', 22, struct sb_mixer_levels)
+#define MIXER_IOCTL_READ_PARAMS _IOR ('s', 23, struct sb_mixer_params)
+#define MIXER_IOCTL_RESET _IO ('s', 24)
+
+/*
+ * Mixer volume levels for MIXER_IOCTL_SET_VOL & MIXER_IOCTL_READ_VOL
+ */
+struct sb_mixer_levels
+{
+ struct stereo_vol master; /* Master volume */
+ struct stereo_vol voc; /* DSP Voice volume */
+ struct stereo_vol fm; /* FM volume */
+ struct stereo_vol line; /* Line-in volume */
+ struct stereo_vol cd; /* CD audio */
+ S_BYTE mic; /* Microphone level */
+};
+
+/*
+ * Mixer parameters for MIXER_IOCTL_SET_PARAMS & MIXER_IOCTL_READ_PARAMS
+ */
+struct sb_mixer_params
+{
+ S_BYTE record_source; /* Recording source (See SRC_xxx below) */
+ S_FLAG hifreq_filter; /* Filter frequency (hi/low) */
+ S_FLAG filter_input; /* ANFI input filter */
+ S_FLAG filter_output; /* DNFI output filter */
+ S_FLAG dsp_stereo; /* 1 if DSP is in Stereo mode */
+};
+
+#define SRC_MIC 1 /* Select Microphone recording source */
+#define SRC_CD 3 /* Select CD recording source */
+#define SRC_LINE 7 /* Use Line-in for recording source */
+
+#if !defined(KERNEL) && !defined(INKERNEL)
+/*
+ * Some convenience macros to simplify programming of the
+ * /dev/sequencer interface
+ *
+ * These macros define the API which should be used when possible.
+ */
+
+void seqbuf_dump(void); /* This function must be provided by programs */
+
+/* Sample seqbuf_dump() implementation:
+ *
+ * SEQ_DEFINEBUF (2048); -- Defines a buffer for 2048 bytes
+ *
+ * int seqfd; -- The file descriptor for /dev/sequencer.
+ *
+ * void
+ * seqbuf_dump ()
+ * {
+ * if (_seqbufptr)
+ * if (write (seqfd, _seqbuf, _seqbufptr) == -1)
+ * {
+ * perror ("write /dev/sequencer");
+ * exit (-1);
+ * }
+ * _seqbufptr = 0;
+ * }
+ */
+
+#define SEQ_DEFINEBUF(len) unsigned char _seqbuf[len]; int _seqbuflen = len; int _seqbufptr = 0
+#define SEQ_DECLAREBUF() extern unsigned char _seqbuf[]; extern int _seqbuflen;extern int _seqbufptr
+#define SEQ_PM_DEFINES struct patmgr_info _pm_info
+#define _SEQ_NEEDBUF(len) if ((_seqbufptr+(len)) > _seqbuflen) seqbuf_dump()
+#define _SEQ_ADVBUF(len) _seqbufptr += len
+#define SEQ_DUMPBUF seqbuf_dump
+#define PM_LOAD_PATCH(dev, bank, pgm) (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \
+ _pm_info.device=dev, _pm_info.data.data8[0]=pgm, \
+ _pm_info.parm1 = bank, _pm_info.parm2 = 1, \
+ ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info))
+#define PM_LOAD_PATCHES(dev, bank, pgm) (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \
+ _pm_info.device=dev, memcpy(_pm_info.data.data8, pgm, 128), \
+ _pm_info.parm1 = bank, _pm_info.parm2 = 128, \
+ ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info))
+
+#define SEQ_VOLUME_MODE(dev, mode) {_SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+ _seqbuf[_seqbufptr+1] = SEQ_VOLMODE;\
+ _seqbuf[_seqbufptr+2] = (dev);\
+ _seqbuf[_seqbufptr+3] = (mode);\
+ _seqbuf[_seqbufptr+4] = 0;\
+ _seqbuf[_seqbufptr+5] = 0;\
+ _seqbuf[_seqbufptr+6] = 0;\
+ _seqbuf[_seqbufptr+7] = 0;\
+ _SEQ_ADVBUF(8);}
+
+#define SEQ_START_NOTE(dev, voice, note, vol) {_SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+ _seqbuf[_seqbufptr+1] = SEQ_NOTEON;\
+ _seqbuf[_seqbufptr+2] = (dev);\
+ _seqbuf[_seqbufptr+3] = (voice);\
+ _seqbuf[_seqbufptr+4] = (note);\
+ _seqbuf[_seqbufptr+5] = (vol);\
+ _seqbuf[_seqbufptr+6] = 0;\
+ _seqbuf[_seqbufptr+7] = 0;\
+ _SEQ_ADVBUF(8);}
+
+#define SEQ_STOP_NOTE(dev, voice, note, vol) {_SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+ _seqbuf[_seqbufptr+1] = SEQ_NOTEOFF;\
+ _seqbuf[_seqbufptr+2] = (dev);\
+ _seqbuf[_seqbufptr+3] = (voice);\
+ _seqbuf[_seqbufptr+4] = (note);\
+ _seqbuf[_seqbufptr+5] = (vol);\
+ _seqbuf[_seqbufptr+6] = 0;\
+ _seqbuf[_seqbufptr+7] = 0;\
+ _SEQ_ADVBUF(8);}
+
+#define SEQ_CHN_PRESSURE(dev, voice, pressure) {_SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+ _seqbuf[_seqbufptr+1] = SEQ_AFTERTOUCH;\
+ _seqbuf[_seqbufptr+2] = (dev);\
+ _seqbuf[_seqbufptr+3] = (voice);\
+ _seqbuf[_seqbufptr+4] = (pressure);\
+ _seqbuf[_seqbufptr+5] = 0;\
+ _seqbuf[_seqbufptr+6] = 0;\
+ _seqbuf[_seqbufptr+7] = 0;\
+ _SEQ_ADVBUF(8);}
+
+#define SEQ_PANNING(dev, voice, pos) {_SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+ _seqbuf[_seqbufptr+1] = SEQ_BALANCE;\
+ _seqbuf[_seqbufptr+2] = (dev);\
+ _seqbuf[_seqbufptr+3] = (voice);\
+ (char)_seqbuf[_seqbufptr+4] = (pos);\
+ _seqbuf[_seqbufptr+5] = 0;\
+ _seqbuf[_seqbufptr+6] = 0;\
+ _seqbuf[_seqbufptr+7] = 0;\
+ _SEQ_ADVBUF(8);}
+
+#define SEQ_CONTROL(dev, voice, controller, value) {_SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+ _seqbuf[_seqbufptr+1] = SEQ_CONTROLLER;\
+ _seqbuf[_seqbufptr+2] = (dev);\
+ _seqbuf[_seqbufptr+3] = (voice);\
+ _seqbuf[_seqbufptr+4] = (controller);\
+ *(short *)&_seqbuf[_seqbufptr+5] = (value);\
+ _seqbuf[_seqbufptr+7] = 0;\
+ _SEQ_ADVBUF(8);}
+
+#define SEQ_PITCHBEND(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_PITCH_BENDER, value)
+#define SEQ_BENDER_RANGE(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_PITCH_BENDER_RANGE, value)
+#define SEQ_EXPRESSION(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_EXPRESSION, value)
+#define SEQ_MAIN_VOLUME(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_MAIN_VOLUME, value)
+
+#define SEQ_START_TIMER() {_SEQ_NEEDBUF(4);\
+ _seqbuf[_seqbufptr] = SEQ_SYNCTIMER;\
+ _seqbuf[_seqbufptr+1] = 0;\
+ _seqbuf[_seqbufptr+2] = 0;\
+ _seqbuf[_seqbufptr+3] = 0;\
+ _SEQ_ADVBUF(4);}
+#define SEQ_SET_PATCH(dev, voice, patch) {_SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+ _seqbuf[_seqbufptr+1] = SEQ_PGMCHANGE;\
+ _seqbuf[_seqbufptr+2] = (dev);\
+ _seqbuf[_seqbufptr+3] = (voice);\
+ _seqbuf[_seqbufptr+4] = (patch);\
+ _seqbuf[_seqbufptr+5] = 0;\
+ _seqbuf[_seqbufptr+6] = 0;\
+ _seqbuf[_seqbufptr+7] = 0;\
+ _SEQ_ADVBUF(8);}
+
+#define SEQ_WAIT_TIME(ticks) {_SEQ_NEEDBUF(4);\
+ *(unsigned long *)&_seqbuf[_seqbufptr] = SEQ_WAIT | ((ticks) << 8);\
+ _SEQ_ADVBUF(4);}
+
+#define SEQ_ECHO_BACK(key) {_SEQ_NEEDBUF(4);\
+ *(unsigned long *)&_seqbuf[_seqbufptr] = SEQ_ECHO | ((key) << 8);\
+ _SEQ_ADVBUF(4);}
+
+#define SEQ_MIDIOUT(device, byte) {_SEQ_NEEDBUF(4);\
+ _seqbuf[_seqbufptr] = SEQ_MIDIPUTC;\
+ _seqbuf[_seqbufptr+1] = (byte);\
+ _seqbuf[_seqbufptr+2] = (device);\
+ _seqbuf[_seqbufptr+3] = 0;\
+ _SEQ_ADVBUF(4);}
+#define SEQ_WRPATCH(patchx, len) {if (_seqbufptr) seqbuf_dump();\
+ if (write(seqfd, (char*)(patchx), len)==-1) \
+ perror("Write patch: /dev/sequencer");}
+
+#endif
+long soundcard_init(long mem_start);
+#endif /* _SOUNDCARD_H_ */
diff --git a/sys/i386/include/speaker.h b/sys/i386/include/speaker.h
new file mode 100644
index 0000000..af80a28
--- /dev/null
+++ b/sys/i386/include/speaker.h
@@ -0,0 +1,30 @@
+/*
+ * speaker.h -- interface definitions for speaker ioctl()
+ *
+ * v1.4 by Eric S. Raymond (esr@snark.thyrsus.com) Aug 1993
+ * modified for FreeBSD by Andrew A. Chernov <ache@astral.msk.su>
+ */
+
+#ifndef _SPEAKER_H_
+#define _SPEAKER_H_
+
+#include <sys/ioctl.h>
+
+#define SPKRTONE _IOW('S', 1, tone_t) /* emit tone */
+#define SPKRTUNE _IO('S', 2) /* emit tone sequence*/
+
+typedef struct
+{
+ int frequency; /* in hertz */
+ int duration; /* in 1/100ths of a second */
+}
+tone_t;
+
+/*
+ * Strings written to the speaker device are interpreted as tunes and played;
+ * see the spkr(4) man page for details.
+ */
+
+#endif /* _SPEAKER_H_ */
+
+/* speaker.h ends here */
diff --git a/sys/i386/include/specialreg.h b/sys/i386/include/specialreg.h
new file mode 100644
index 0000000..935b1ed
--- /dev/null
+++ b/sys/i386/include/specialreg.h
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)specialreg.h 7.1 (Berkeley) 5/9/91
+ * $Id: specialreg.h,v 1.2 1993/10/16 14:39:32 rgrimes Exp $
+ */
+
+#ifndef _MACHINE_SPECIALREG_H_
+#define _MACHINE_SPECIALREG_H_ 1
+
+/*
+ * Bits in 386 special registers:
+ */
+
+#define CR0_PE 0x00000001 /* Protected mode Enable */
+#define CR0_MP 0x00000002 /* "Math" Present (NPX or NPX emulator) */
+#ifdef notused
+#define CR0_EM 0x00000004 /* EMulate non-NPX coproc. (trap ESC only) */
+#endif
+#define CR0_TS 0x00000008 /* Task Switched (if MP, trap ESC and WAIT) */
+#ifdef notused
+#define CR0_ET 0x00000010 /* Extension Type (387 (if set) vs 287) */
+#endif
+#define CR0_PG 0x80000000 /* PaGing enable */
+
+/*
+ * Bits in 486 special registers:
+ */
+
+#define CR0_NE 0x00000020 /* Numeric Error enable (EX16 vs IRQ13) */
+#define CR0_WP 0x00010000 /* Write Protect (honor ~PG_W in all modes) */
+#ifdef notyet
+#define CR0_AM 0x00040000 /* Alignment Mask (set to enable AC flag) */
+#endif
+#endif /* _MACHINE_SPECIALREG_H_ */
diff --git a/sys/i386/include/spl.h b/sys/i386/include/spl.h
new file mode 100644
index 0000000..0be9364
--- /dev/null
+++ b/sys/i386/include/spl.h
@@ -0,0 +1,104 @@
+#ifndef _MACHINE_IPL_H_
+#define _MACHINE_IPL_H_
+
+#include "machine/../isa/ipl.h" /* XXX "machine" means cpu for i386 */
+
+/*
+ * Software interrupt bit numbers in priority order. The priority only
+ * determines which swi will be dispatched next; a higher priority swi
+ * may be dispatched when a nested h/w interrupt handler returns.
+ */
+#define SWI_TTY (NHWI + 0)
+#define SWI_NET (NHWI + 1)
+#define SWI_CLOCK 30
+#define SWI_AST 31
+
+/*
+ * Corresponding interrupt-pending bits for ipending.
+ */
+#define SWI_TTY_PENDING (1 << SWI_TTY)
+#define SWI_NET_PENDING (1 << SWI_NET)
+#define SWI_CLOCK_PENDING (1 << SWI_CLOCK)
+#define SWI_AST_PENDING (1 << SWI_AST)
+
+/*
+ * Corresponding interrupt-disable masks for cpl. The ordering is now by
+ * inclusion (where each mask is considered as a set of bits). Everything
+ * except SWI_AST_MASK includes SWI_CLOCK_MASK so that softclock() doesn't
+ * run while other swi handlers are running and timeout routines can call
+ * swi handlers. Everything includes SWI_AST_MASK so that AST's are masked
+ * until just before return to user mode.
+ */
+#define SWI_TTY_MASK (SWI_TTY_PENDING | SWI_CLOCK_MASK)
+#define SWI_NET_MASK (SWI_NET_PENDING | SWI_CLOCK_MASK)
+#define SWI_CLOCK_MASK (SWI_CLOCK_PENDING | SWI_AST_MASK)
+#define SWI_AST_MASK SWI_AST_PENDING
+#define SWI_MASK (~HWI_MASK)
+
+#ifndef LOCORE
+
+extern unsigned bio_imask; /* group of interrupts masked with splbio() */
+extern unsigned cpl; /* current priority level mask */
+extern unsigned high_imask; /* group of interrupts masked with splhigh() */
+extern unsigned net_imask; /* group of interrupts masked with splimp() */
+extern volatile unsigned ipending; /* active interrupts masked by cpl */
+extern volatile unsigned netisr;
+extern unsigned tty_imask; /* group of interrupts masked with spltty() */
+
+/*
+ * ipending has to be volatile so that it is read every time it is accessed
+ * in splx() and spl0(), but we don't want it to be read nonatomically when
+ * it is changed. Pretending that ipending is a plain int happens to give
+ * suitable atomic code for "ipending |= constant;".
+ */
+#define setsoftast() (*(unsigned *)&ipending |= SWI_AST_PENDING)
+#define setsoftclock() (*(unsigned *)&ipending |= SWI_CLOCK_PENDING)
+#define setsoftnet() (*(unsigned *)&ipending |= SWI_NET_PENDING)
+#define setsofttty() (*(unsigned *)&ipending |= SWI_TTY_PENDING)
+
+void unpend_V __P((void));
+
+#ifdef __GNUC__
+
+void splz __P((void));
+
+#define GENSPL(name, set_cpl) \
+static __inline int name(void) \
+{ \
+ unsigned x; \
+ \
+ x = cpl; \
+ set_cpl; \
+ return (x); \
+}
+
+GENSPL(splbio, cpl |= bio_imask)
+GENSPL(splclock, cpl = HWI_MASK | SWI_MASK)
+GENSPL(splhigh, cpl = HWI_MASK | SWI_MASK)
+GENSPL(splimp, cpl |= net_imask)
+GENSPL(splnet, cpl |= SWI_NET_MASK)
+GENSPL(splsoftclock, cpl = SWI_CLOCK_MASK)
+GENSPL(splsofttty, cpl |= SWI_TTY_MASK)
+GENSPL(spltty, cpl |= tty_imask)
+
+static __inline void
+spl0(void)
+{
+ cpl = SWI_AST_MASK;
+ if (ipending & ~SWI_AST_MASK)
+ splz();
+}
+
+static __inline void
+splx(int ipl)
+{
+ cpl = ipl;
+ if (ipending & ~ipl)
+ splz();
+}
+
+#endif /* __GNUC__ */
+
+#endif /* LOCORE */
+
+#endif /* _MACHINE_IPL_H_ */
diff --git a/sys/i386/include/stdarg.h b/sys/i386/include/stdarg.h
new file mode 100644
index 0000000..91dab8b
--- /dev/null
+++ b/sys/i386/include/stdarg.h
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdarg.h 7.2 (Berkeley) 5/4/91
+ * $Id: stdarg.h,v 1.2 1993/10/16 14:39:34 rgrimes Exp $
+ */
+
+#ifndef _MACHINE_STDARG_H_
+#define _MACHINE_STDARG_H_ 1
+
+typedef char *va_list;
+
+#ifdef KERNEL
+#define va_arg(ap, type) \
+ ((type *)(ap += sizeof(type)))[-1]
+#else
+#define va_arg(ap, type) \
+ ((type *)(ap += sizeof(type) < sizeof(int) ? \
+ (abort(), 0) : sizeof(type)))[-1]
+#endif
+
+#define va_end(ap)
+
+#define __va_promote(type) \
+ (((sizeof(type) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))
+
+#define va_start(ap, last) \
+ (ap = ((char *)&(last) + __va_promote(last)))
+#endif /* _MACHINE_STDARG_H_ */
diff --git a/sys/i386/include/sysarch.h b/sys/i386/include/sysarch.h
new file mode 100644
index 0000000..2649ba5
--- /dev/null
+++ b/sys/i386/include/sysarch.h
@@ -0,0 +1,24 @@
+/*
+ * Architecture specific syscalls (i386)
+ *
+ * $Id: sysarch.h,v 1.2 1993/10/16 14:39:35 rgrimes Exp $
+ */
+#ifndef _MACHINE_SYSARCH_H_
+#define _MACHINE_SYSARCH_H_ 1
+
+#include <sys/cdefs.h>
+
+#define I386_GET_LDT 0
+#define I386_SET_LDT 1
+
+#ifdef KERNEL
+/* nothing here yet... */
+#else /* not KERNEL */
+__BEGIN_DECLS
+
+int i386_get_ldt __P((int, union descriptor *, int));
+int i386_set_ldt __P((int, union descriptor *, int));
+
+__END_DECLS
+#endif /* not KERNEL */
+#endif /* _MACHINE_SYSARCH_H_ */
diff --git a/sys/i386/include/trap.h b/sys/i386/include/trap.h
new file mode 100644
index 0000000..aa832ff
--- /dev/null
+++ b/sys/i386/include/trap.h
@@ -0,0 +1,101 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)trap.h 5.4 (Berkeley) 5/9/91
+ * $Id: trap.h,v 1.2 1993/10/16 14:39:37 rgrimes Exp $
+ */
+
+#ifndef _MACHINE_TRAP_H_
+#define _MACHINE_TRAP_H_ 1
+
+/*
+ * Trap type values
+ * also known in trap.c for name strings
+ */
+
+#define T_RESADFLT 0 /* reserved addressing */
+#define T_PRIVINFLT 1 /* privileged instruction */
+#define T_RESOPFLT 2 /* reserved operand */
+#define T_BPTFLT 3 /* breakpoint instruction */
+#define T_SYSCALL 5 /* system call (kcall) */
+#define T_ARITHTRAP 6 /* arithmetic trap */
+#define T_ASTFLT 7 /* system forced exception */
+#define T_SEGFLT 8 /* segmentation (limit) fault */
+#define T_PROTFLT 9 /* protection fault */
+#define T_TRCTRAP 10 /* trace trap */
+#define T_PAGEFLT 12 /* page fault */
+#define T_TABLEFLT 13 /* page table fault */
+#define T_ALIGNFLT 14 /* alignment fault */
+#define T_KSPNOTVAL 15 /* kernel stack pointer not valid */
+#define T_BUSERR 16 /* bus error */
+#define T_KDBTRAP 17 /* kernel debugger trap */
+
+#define T_DIVIDE 18 /* integer divide fault */
+#define T_NMI 19 /* non-maskable trap */
+#define T_OFLOW 20 /* overflow trap */
+#define T_BOUND 21 /* bound instruction fault */
+#define T_DNA 22 /* device not available fault */
+#define T_DOUBLEFLT 23 /* double fault */
+#define T_FPOPFLT 24 /* fp coprocessor operand fetch fault */
+#define T_TSSFLT 25 /* invalid tss fault */
+#define T_SEGNPFLT 26 /* segment not present fault */
+#define T_STKFLT 27 /* stack fault */
+#define T_RESERVED 28 /* reserved fault base */
+
+/* definitions for <sys/signal.h> */
+#define ILL_RESAD_FAULT T_RESADFLT
+#define ILL_PRIVIN_FAULT T_PRIVINFLT
+#define ILL_RESOP_FAULT T_RESOPFLT
+#define ILL_ALIGN_FAULT T_ALIGNFLT
+#define ILL_FPOP_FAULT T_FPOPFLT /* coprocessor operand fault */
+
+/* codes for SIGFPE/ARITHTRAP */
+#define FPE_INTOVF_TRAP 0x1 /* integer overflow */
+#define FPE_INTDIV_TRAP 0x2 /* integer divide by zero */
+#define FPE_FLTDIV_TRAP 0x3 /* floating/decimal divide by zero */
+#define FPE_FLTOVF_TRAP 0x4 /* floating overflow */
+#define FPE_FLTUND_TRAP 0x5 /* floating underflow */
+#define FPE_FPU_NP_TRAP 0x6 /* floating point unit not present */
+#define FPE_SUBRNG_TRAP 0x7 /* subrange out of bounds */
+
+/* codes for SIGBUS */
+#define BUS_PAGE_FAULT T_PAGEFLT /* page fault protection base */
+#define BUS_SEGNP_FAULT T_SEGNPFLT /* segment not present */
+#define BUS_STK_FAULT T_STKFLT /* stack segment */
+#define BUS_SEGM_FAULT T_RESERVED /* segment protection base */
+
+/* Trap's coming from user mode */
+#define T_USER 0x100
+#endif /* _MACHINE_TRAP_H_ */
diff --git a/sys/i386/include/tss.h b/sys/i386/include/tss.h
new file mode 100644
index 0000000..1fada6e
--- /dev/null
+++ b/sys/i386/include/tss.h
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)tss.h 5.4 (Berkeley) 1/18/91
+ * $Id: tss.h,v 1.3 1993/11/07 17:43:16 wollman Exp $
+ */
+
+#ifndef _MACHINE_TSS_H_
+#define _MACHINE_TSS_H_ 1
+
+/*
+ * Intel 386 Context Data Type
+ */
+
+struct i386tss {
+ int tss_link; /* actually 16 bits: top 16 bits must be zero */
+ int tss_esp0; /* kernel stack pointer priviledge level 0 */
+#define tss_ksp tss_esp0
+ int tss_ss0; /* actually 16 bits: top 16 bits must be zero */
+ int tss_esp1; /* kernel stack pointer priviledge level 1 */
+ int tss_ss1; /* actually 16 bits: top 16 bits must be zero */
+ int tss_esp2; /* kernel stack pointer priviledge level 2 */
+ int tss_ss2; /* actually 16 bits: top 16 bits must be zero */
+ int tss_cr3; /* page table directory */
+#define tss_ptd tss_cr3
+ int tss_eip; /* program counter */
+#define tss_pc tss_eip
+ int tss_eflags; /* program status longword */
+#define tss_psl tss_eflags
+ int tss_eax;
+ int tss_ecx;
+ int tss_edx;
+ int tss_ebx;
+ int tss_esp; /* user stack pointer */
+#define tss_usp tss_esp
+ int tss_ebp; /* user frame pointer */
+#define tss_fp tss_ebp
+ int tss_esi;
+ int tss_edi;
+ int tss_es; /* actually 16 bits: top 16 bits must be zero */
+ int tss_cs; /* actually 16 bits: top 16 bits must be zero */
+ int tss_ss; /* actually 16 bits: top 16 bits must be zero */
+ int tss_ds; /* actually 16 bits: top 16 bits must be zero */
+ int tss_fs; /* actually 16 bits: top 16 bits must be zero */
+ int tss_gs; /* actually 16 bits: top 16 bits must be zero */
+ int tss_ldt; /* actually 16 bits: top 16 bits must be zero */
+ int tss_ioopt; /* options & io offset bitmap: currently zero */
+ /* XXX unimplemented .. i/o permission bitmap */
+};
+#endif /* _MACHINE_TSS_H_ */
diff --git a/sys/i386/include/types.h b/sys/i386/include/types.h
new file mode 100644
index 0000000..118290c
--- /dev/null
+++ b/sys/i386/include/types.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)types.h 7.5 (Berkeley) 3/9/91
+ * $Id$
+ */
+
+#ifndef _MACHTYPES_H_
+#define _MACHTYPES_H_
+
+typedef struct _physadr {
+ int r[1];
+} *physadr;
+
+typedef struct label_t {
+ int val[6];
+} label_t;
+
+typedef u_long vm_offset_t;
+typedef u_long vm_size_t;
+
+#endif /* _MACHTYPES_H_ */
diff --git a/sys/i386/include/ultrasound.h b/sys/i386/include/ultrasound.h
new file mode 100644
index 0000000..40e2443
--- /dev/null
+++ b/sys/i386/include/ultrasound.h
@@ -0,0 +1,121 @@
+#ifndef _ULTRASOUND_H_
+#define _ULTRASOUND_H_
+/*
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * ultrasound.h - Macros for programming the Gravis Ultrasound
+ * These macros are extremely device dependent
+ * and not portable.
+ */
+
+/*
+ * Private events for Gravis Ultrasound (GUS)
+ *
+ * Format:
+ * byte 0 - SEQ_PRIVATE (0xfe)
+ * byte 1 - Synthesizer device number (0-N)
+ * byte 2 - Command (see below)
+ * byte 3 - Voice number (0-31)
+ * bytes 4 and 5 - parameter P1 (unsigned short)
+ * bytes 6 and 7 - parameter P2 (unsigned short)
+ *
+ * Commands:
+ * Each command affects one voice defined in byte 3.
+ * Unused parameters (P1 and/or P2 *MUST* be initialized to zero).
+ * _GUS_NUMVOICES - Sets max. number of concurrent voices (P1=14-31, default 16)
+ * _GUS_VOICESAMPLE- ************ OBSOLETE *************
+ * _GUS_VOICEON - Starts voice (P1=voice mode)
+ * _GUS_VOICEOFF - Stops voice (no parameters)
+ * _GUS_VOICEFADE - Stops the voice smoothly.
+ * _GUS_VOICEMODE - Alters the voice mode, don't start or stop voice (P1=voice mode)
+ * _GUS_VOICEBALA - Sets voice balence (P1, 0=left, 7=middle and 15=right, default 7)
+ * _GUS_VOICEFREQ - Sets voice (sample) playback frequency (P1=Hz)
+ * _GUS_VOICEVOL - Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off)
+ * _GUS_VOICEVOL2 - Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off)
+ * (Like GUS_VOICEVOL but doesn't change the hw
+ * volume. It just updates volume in the voice table).
+ *
+ * _GUS_RAMPRANGE - Sets limits for volume ramping (P1=low volume, P2=high volume)
+ * _GUS_RAMPRATE - Sets the speed for volume ramping (P1=scale, P2=rate)
+ * _GUS_RAMPMODE - Sets the volume ramping mode (P1=ramping mode)
+ * _GUS_RAMPON - Starts volume ramping (no parameters)
+ * _GUS_RAMPOFF - Stops volume ramping (no parameters)
+ * _GUS_VOLUME_SCALE - Changes the volume calculation constants
+ * for all voices.
+ */
+
+#define _GUS_NUMVOICES 0x00
+#define _GUS_VOICESAMPLE 0x01 /* OBSOLETE */
+#define _GUS_VOICEON 0x02
+#define _GUS_VOICEOFF 0x03
+#define _GUS_VOICEMODE 0x04
+#define _GUS_VOICEBALA 0x05
+#define _GUS_VOICEFREQ 0x06
+#define _GUS_VOICEVOL 0x07
+#define _GUS_RAMPRANGE 0x08
+#define _GUS_RAMPRATE 0x09
+#define _GUS_RAMPMODE 0x0a
+#define _GUS_RAMPON 0x0b
+#define _GUS_RAMPOFF 0x0c
+#define _GUS_VOICEFADE 0x0d
+#define _GUS_VOLUME_SCALE 0x0e
+#define _GUS_VOICEVOL2 0x0f
+#define _GUS_VOICE_POS 0x10
+
+/*
+ * GUS API macros
+ */
+
+#define _GUS_CMD(chn, voice, cmd, p1, p2) \
+ {_SEQ_NEEDBUF(8); _seqbuf[_seqbufptr] = SEQ_PRIVATE;\
+ _seqbuf[_seqbufptr+1] = (chn); _seqbuf[_seqbufptr+2] = cmd;\
+ _seqbuf[_seqbufptr+3] = voice;\
+ *(unsigned short*)&_seqbuf[_seqbufptr+4] = p1;\
+ *(unsigned short*)&_seqbuf[_seqbufptr+6] = p2;\
+ _SEQ_ADVBUF(8);}
+
+#define GUS_NUMVOICES(chn, p1) _GUS_CMD(chn, 0, _GUS_NUMVOICES, (p1), 0)
+#define GUS_VOICESAMPLE(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICESAMPLE, (p1), 0) /* OBSOLETE */
+#define GUS_VOICEON(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEON, (p1), 0)
+#define GUS_VOICEOFF(chn, voice) _GUS_CMD(chn, voice, _GUS_VOICEOFF, 0, 0)
+#define GUS_VOICEFADE(chn, voice) _GUS_CMD(chn, voice, _GUS_VOICEFADE, 0, 0)
+#define GUS_VOICEMODE(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEMODE, (p1), 0)
+#define GUS_VOICEBALA(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEBALA, (p1), 0)
+#define GUS_VOICEFREQ(chn, voice, p) _GUS_CMD(chn, voice, _GUS_VOICEFREQ, \
+ (p) & 0xffff, ((p) >> 16) & 0xffff)
+#define GUS_VOICEVOL(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEVOL, (p1), 0)
+#define GUS_VOICEVOL2(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEVOL2, (p1), 0)
+#define GUS_RAMPRANGE(chn, voice, low, high) _GUS_CMD(chn, voice, _GUS_RAMPRANGE, (low), (high))
+#define GUS_RAMPRATE(chn, voice, p1, p2) _GUS_CMD(chn, voice, _GUS_RAMPRATE, (p1), (p2))
+#define GUS_RAMPMODE(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_RAMPMODE, (p1), 0)
+#define GUS_RAMPON(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_RAMPON, (p1), 0)
+#define GUS_RAMPOFF(chn, voice) _GUS_CMD(chn, voice, _GUS_RAMPOFF, 0, 0)
+#define GUS_VOLUME_SCALE(chn, voice, p1, p2) _GUS_CMD(chn, voice, _GUS_VOLUME_SCALE, (p1), (p2))
+#define GUS_VOICE_POS(chn, voice, p) _GUS_CMD(chn, voice, _GUS_VOICE_POS, \
+ (p) & 0xffff, ((p) >> 16) & 0xffff)
+
+#endif
diff --git a/sys/i386/include/vmparam.h b/sys/i386/include/vmparam.h
new file mode 100644
index 0000000..df90126
--- /dev/null
+++ b/sys/i386/include/vmparam.h
@@ -0,0 +1,277 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ * Copyright (c) 1994 John S. Dyson
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)vmparam.h 5.9 (Berkeley) 5/12/91
+ * $Id: vmparam.h,v 1.11 1994/01/14 16:24:00 davidg Exp $
+ */
+
+
+#ifndef _MACHINE_VMPARAM_H_
+#define _MACHINE_VMPARAM_H_ 1
+
+/*
+ * Machine dependent constants for 386.
+ */
+
+/*
+ * Virtual address space arrangement. On 386, both user and kernel
+ * share the address space, not unlike the vax.
+ * USRTEXT is the start of the user text/data space, while USRSTACK
+ * is the top (end) of the user stack. Immediately above the user stack
+ * resides the user structure, which is UPAGES long and contains the
+ * kernel stack.
+ *
+ * Immediately after the user structure is the page table map, and then
+ * kernal address space.
+ */
+#define USRTEXT 0UL
+/* #define USRSTACK 0xFDBFE000UL */
+#define BTOPUSRSTACK (0xFDC00-(UPAGES)) /* btop(USRSTACK) */
+#define LOWPAGES 0UL
+#define HIGHPAGES UPAGES
+
+/*
+ * Virtual memory related constants, all in bytes
+ */
+#define MAXTSIZ (16UL*1024*1024) /* max text size */
+#ifndef DFLDSIZ
+#define DFLDSIZ (64UL*1024*1024) /* initial data size limit */
+#endif
+#ifndef MAXDSIZ
+#define MAXDSIZ (128UL*1024*1024) /* max data size */
+#endif
+#ifndef DFLSSIZ
+#define DFLSSIZ (8UL*1024*1024) /* initial stack size limit */
+#endif
+#ifndef MAXSSIZ
+#define MAXSSIZ (64UL*1024*1024) /* max stack size */
+#endif
+#ifndef SGROWSIZ
+#define SGROWSIZ (128UL*1024) /* amount to grow stack */
+#endif
+
+/*
+ * Default sizes of swap allocation chunks (see dmap.h).
+ * The actual values may be changed in vminit() based on MAXDSIZ.
+ * With MAXDSIZ of 16Mb and NDMAP of 38, dmmax will be 1024.
+ */
+#define DMMIN 32 /* smallest swap allocation */
+#define DMMAX 4096 /* largest potential swap allocation */
+#define DMTEXT 1024 /* swap allocation for text */
+
+/*
+ * Sizes of the system and user portions of the system page table.
+ */
+#define SYSPTSIZE (2*NPTEPG)
+#define USRPTSIZE (2*NPTEPG)
+
+/*
+ * Size of the Shared Memory Pages page table.
+ */
+#ifndef SHMMAXPGS
+#define SHMMAXPGS 512 /* XXX until we have more kmap space */
+#endif
+
+/*
+ * Size of User Raw I/O map
+ */
+#define USRIOSIZE 1024
+
+/*
+ * The size of the clock loop.
+ */
+#define LOOPPAGES (maxfree - firstfree)
+
+/*
+ * The time for a process to be blocked before being very swappable.
+ * This is a number of seconds which the system takes as being a non-trivial
+ * amount of real time. You probably shouldn't change this;
+ * it is used in subtle ways (fractions and multiples of it are, that is, like
+ * half of a ``long time'', almost a long time, etc.)
+ * It is related to human patience and other factors which don't really
+ * change over time.
+ */
+#define MAXSLP 20
+
+/*
+ * A swapped in process is given a small amount of core without being bothered
+ * by the page replacement algorithm. Basically this says that if you are
+ * swapped in you deserve some resources. We protect the last SAFERSS
+ * pages against paging and will just swap you out rather than paging you.
+ * Note that each process has at least UPAGES+CLSIZE pages which are not
+ * paged anyways (this is currently 8+2=10 pages or 5k bytes), so this
+ * number just means a swapped in process is given around 25k bytes.
+ * Just for fun: current memory prices are 4600$ a megabyte on VAX (4/22/81),
+ * so we loan each swapped in process memory worth 100$, or just admit
+ * that we don't consider it worthwhile and swap it out to disk which costs
+ * $30/mb or about $0.75.
+ * { wfj 6/16/89: Retail AT memory expansion $800/megabyte, loan of $17
+ * on disk costing $7/mb or $0.18 (in memory still 100:1 in cost!) }
+ */
+#define SAFERSS 8 /* nominal ``small'' resident set size
+ protected against replacement */
+
+/*
+ * DISKRPM is used to estimate the number of paging i/o operations
+ * which one can expect from a single disk controller.
+ */
+#define DISKRPM 60
+
+/*
+ * Klustering constants. Klustering is the gathering
+ * of pages together for pagein/pageout, while clustering
+ * is the treatment of hardware page size as though it were
+ * larger than it really is.
+ *
+ * KLMAX gives maximum cluster size in CLSIZE page (cluster-page)
+ * units. Note that KLMAX*CLSIZE must be <= DMMIN in dmap.h.
+ */
+
+#define KLMAX (4/CLSIZE)
+#define KLSEQL (2/CLSIZE) /* in klust if vadvise(VA_SEQL) */
+#define KLIN (4/CLSIZE) /* default data/stack in klust */
+#define KLTXT (4/CLSIZE) /* default text in klust */
+#define KLOUT (4/CLSIZE)
+
+/*
+ * KLSDIST is the advance or retard of the fifo reclaim for sequential
+ * processes data space.
+ */
+#define KLSDIST 3 /* klusters advance/retard for seq. fifo */
+
+/*
+ * Paging thresholds (see vm_sched.c).
+ * Strategy of 1/19/85:
+ * lotsfree is 512k bytes, but at most 1/4 of memory
+ * desfree is 200k bytes, but at most 1/8 of memory
+ * minfree is 64k bytes, but at most 1/2 of desfree
+ */
+#define LOTSFREE (512 * 1024)
+#define LOTSFREEFRACT 4
+#define DESFREE (200 * 1024)
+#define DESFREEFRACT 8
+#define MINFREE (64 * 1024)
+#define MINFREEFRACT 2
+
+/*
+ * There are two clock hands, initially separated by HANDSPREAD bytes
+ * (but at most all of user memory). The amount of time to reclaim
+ * a page once the pageout process examines it increases with this
+ * distance and decreases as the scan rate rises.
+ */
+#define HANDSPREAD (2 * 1024 * 1024)
+
+/*
+ * The number of times per second to recompute the desired paging rate
+ * and poke the pagedaemon.
+ */
+#define RATETOSCHEDPAGING 4
+
+/*
+ * Believed threshold (in megabytes) for which interleaved
+ * swapping area is desirable.
+ */
+#define LOTSOFMEM 2
+
+#define mapin(pte, v, pfnum, prot) \
+ {(*(int *)(pte) = ((pfnum)<<PGSHIFT) | (prot)) ; }
+
+/*
+ * Mach derived constants
+ */
+
+/* user/kernel map constants */
+#define KERNBASE (0-(NKPDE+1)*(NBPG*NPTEPG))
+#define KERNSIZE (NKPDE*NBPG*NPTEPG)
+
+#define VM_MIN_ADDRESS ((vm_offset_t)0)
+#define VM_MAXUSER_ADDRESS ((vm_offset_t)KERNBASE - (NBPG*(NPTEPG+UPAGES)))
+#define USRSTACK VM_MAXUSER_ADDRESS
+#define UPT_MIN_ADDRESS ((vm_offset_t)KERNBASE - (NBPG*NPTEPG))
+#define UPT_MAX_ADDRESS ((vm_offset_t)KERNBASE - (NBPG*(NKPDE+2)))
+#define VM_MAX_ADDRESS UPT_MAX_ADDRESS
+#define VM_MIN_KERNEL_ADDRESS ((vm_offset_t)KERNBASE - (NBPG*(NKPDE+2)))
+#define UPDT VM_MIN_KERNEL_ADDRESS
+#define KPT_MIN_ADDRESS ((vm_offset_t)(KERNBASE) - (NBPG*(NKPDE+1)))
+#define KPT_MAX_ADDRESS ((vm_offset_t)(KERNBASE) - NBPG)
+#define VM_MAX_KERNEL_ADDRESS ((vm_offset_t)ALT_MIN_ADDRESS - NBPG)
+#define ALT_MIN_ADDRESS ((vm_offset_t)((APTDPTDI) << 22))
+#define HIGHPAGES UPAGES
+
+
+/* virtual sizes (bytes) for various kernel submaps */
+#define VM_MBUF_SIZE (NMBCLUSTERS*MCLBYTES)
+#define VM_KMEM_SIZE (16 * 1024 * 1024)
+#define VM_PHYS_SIZE (USRIOSIZE*CLBYTES)
+
+/* pcb base */
+#define pcbb(p) ((u_int)(p)->p_addr)
+
+/*
+ * Flush MMU TLB
+ */
+
+#ifndef I386_CR3PAT
+#define I386_CR3PAT 0x0
+#endif
+
+#ifdef notyet
+#define _cr3() ({u_long rtn; \
+ asm (" movl %%cr3,%%eax; movl %%eax,%0 " \
+ : "=g" (rtn) \
+ : \
+ : "ax"); \
+ rtn; \
+})
+
+#define load_cr3(s) ({ u_long val; \
+ val = (s) | I386_CR3PAT; \
+ asm ("movl %0,%%eax; movl %%eax,%%cr3" \
+ : \
+ : "g" (val) \
+ : "ax"); \
+})
+
+#define tlbflush() ({ u_long val; \
+ val = u.u_pcb.pcb_ptd | I386_CR3PAT; \
+ asm ("movl %0,%%eax; movl %%eax,%%cr3" \
+ : \
+ : "g" (val) \
+ : "ax"); \
+})
+#endif
+#endif /* _MACHINE_VMPARAM_H_ */
diff --git a/sys/i386/isa/aha1542.c b/sys/i386/isa/aha1542.c
new file mode 100644
index 0000000..84c5e57
--- /dev/null
+++ b/sys/i386/isa/aha1542.c
@@ -0,0 +1,1475 @@
+/*
+ * (Mostly) Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems for use under the MACH(2.5) operating system.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ * $Id: aha1542.c,v 1.25 1994/05/03 05:44:53 rgrimes Exp $
+ */
+
+/*
+ * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ */
+
+#include <sys/types.h>
+#ifdef KERNEL /* don't laugh.. look for main() */
+#include <aha.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <i386/isa/isa_device.h>
+#endif /* KERNEL */
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#ifdef KERNEL
+#include "ddb.h"
+#include "kernel.h"
+#else /*KERNEL */
+#define NAHA 1
+#endif /*KERNEL */
+
+/************************** board definitions *******************************/
+
+/*
+ * I/O Port Interface
+ */
+
+#define AHA_BASE aha->aha_base
+#define AHA_CTRL_STAT_PORT (AHA_BASE + 0x0) /* control & status */
+#define AHA_CMD_DATA_PORT (AHA_BASE + 0x1) /* cmds and datas */
+#define AHA_INTR_PORT (AHA_BASE + 0x2) /* Intr. stat */
+
+/*
+ * AHA_CTRL_STAT bits (write)
+ */
+
+#define AHA_HRST 0x80 /* Hardware reset */
+#define AHA_SRST 0x40 /* Software reset */
+#define AHA_IRST 0x20 /* Interrupt reset */
+#define AHA_SCRST 0x10 /* SCSI bus reset */
+
+/*
+ * AHA_CTRL_STAT bits (read)
+ */
+
+#define AHA_STST 0x80 /* Self test in Progress */
+#define AHA_DIAGF 0x40 /* Diagnostic Failure */
+#define AHA_INIT 0x20 /* Mbx Init required */
+#define AHA_IDLE 0x10 /* Host Adapter Idle */
+#define AHA_CDF 0x08 /* cmd/data out port full */
+#define AHA_DF 0x04 /* Data in port full */
+#define AHA_INVDCMD 0x01 /* Invalid command */
+
+/*
+ * AHA_CMD_DATA bits (write)
+ */
+
+#define AHA_NOP 0x00 /* No operation */
+#define AHA_MBX_INIT 0x01 /* Mbx initialization */
+#define AHA_START_SCSI 0x02 /* start scsi command */
+#define AHA_START_BIOS 0x03 /* start bios command */
+#define AHA_INQUIRE 0x04 /* Adapter Inquiry */
+#define AHA_MBO_INTR_EN 0x05 /* Enable MBO available interrupt */
+#define AHA_SEL_TIMEOUT_SET 0x06 /* set selection time-out */
+#define AHA_BUS_ON_TIME_SET 0x07 /* set bus-on time */
+#define AHA_BUS_OFF_TIME_SET 0x08 /* set bus-off time */
+#define AHA_SPEED_SET 0x09 /* set transfer speed */
+#define AHA_DEV_GET 0x0a /* return installed devices */
+#define AHA_CONF_GET 0x0b /* return configuration data */
+#define AHA_TARGET_EN 0x0c /* enable target mode */
+#define AHA_SETUP_GET 0x0d /* return setup data */
+#define AHA_WRITE_CH2 0x1a /* write channel 2 buffer */
+#define AHA_READ_CH2 0x1b /* read channel 2 buffer */
+#define AHA_WRITE_FIFO 0x1c /* write fifo buffer */
+#define AHA_READ_FIFO 0x1d /* read fifo buffer */
+#define AHA_ECHO 0x1e /* Echo command data */
+#define AHA_EXT_BIOS 0x28 /* return extended bios info */
+#define AHA_MBX_ENABLE 0x29 /* enable mail box interface */
+
+struct aha_cmd_buf {
+ u_char byte[16];
+};
+
+/*
+ * AHA_INTR_PORT bits (read)
+ */
+
+#define AHA_ANY_INTR 0x80 /* Any interrupt */
+#define AHA_SCRD 0x08 /* SCSI reset detected */
+#define AHA_HACC 0x04 /* Command complete */
+#define AHA_MBOA 0x02 /* MBX out empty */
+#define AHA_MBIF 0x01 /* MBX in full */
+
+/*
+ * Mail box defs
+ */
+
+#define AHA_MBX_SIZE 16 /* mail box size */
+
+struct aha_mbx {
+ struct aha_mbx_out {
+ unsigned char cmd;
+ unsigned char ccb_addr[3];
+ } mbo[AHA_MBX_SIZE];
+ struct aha_mbx_in {
+ unsigned char stat;
+ unsigned char ccb_addr[3];
+ } mbi[AHA_MBX_SIZE];
+};
+
+/*
+ * mbo.cmd values
+ */
+
+#define AHA_MBO_FREE 0x0 /* MBO entry is free */
+#define AHA_MBO_START 0x1 /* MBO activate entry */
+#define AHA_MBO_ABORT 0x2 /* MBO abort entry */
+
+/*
+ * mbi.stat values
+ */
+
+#define AHA_MBI_FREE 0x0 /* MBI entry is free */
+#define AHA_MBI_OK 0x1 /* completed without error */
+#define AHA_MBI_ABORT 0x2 /* aborted ccb */
+#define AHA_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */
+#define AHA_MBI_ERROR 0x4 /* Completed with error */
+
+/* FOR OLD VERSIONS OF THE !%$@ this may have to be 16 (yuk) */
+#define AHA_NSEG 17 /* Number of scatter gather segments <= 16 */
+ /* allow 64 K i/o (min) */
+
+struct aha_ccb {
+ unsigned char opcode;
+ unsigned char lun:3;
+ unsigned char data_in:1; /* must be 0 */
+ unsigned char data_out:1; /* must be 0 */
+ unsigned char target:3;
+ unsigned char scsi_cmd_length;
+ unsigned char req_sense_length;
+ unsigned char data_length[3];
+ unsigned char data_addr[3];
+ unsigned char link_addr[3];
+ unsigned char link_id;
+ unsigned char host_stat;
+ unsigned char target_stat;
+ unsigned char reserved[2];
+ struct scsi_generic scsi_cmd;
+ struct scsi_sense_data scsi_sense;
+ struct aha_scat_gath {
+ unsigned char seg_len[3];
+ unsigned char seg_addr[3];
+ } scat_gath[AHA_NSEG];
+ struct aha_ccb *next;
+ struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */
+ struct aha_mbx_out *mbx; /* pointer to mail box */
+ int flags;
+#define CCB_FREE 0
+#define CCB_ACTIVE 1
+#define CCB_ABORTED 2
+};
+
+/*
+ * opcode fields
+ */
+
+#define AHA_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */
+#define AHA_TARGET_CCB 0x01 /* SCSI Target CCB */
+#define AHA_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scatter gather */
+#define AHA_RESET_CCB 0x81 /* SCSI Bus reset */
+
+/*
+ * aha_ccb.host_stat values
+ */
+
+#define AHA_OK 0x00 /* cmd ok */
+#define AHA_LINK_OK 0x0a /* Link cmd ok */
+#define AHA_LINK_IT 0x0b /* Link cmd ok + int */
+#define AHA_SEL_TIMEOUT 0x11 /* Selection time out */
+#define AHA_OVER_UNDER 0x12 /* Data over/under run */
+#define AHA_BUS_FREE 0x13 /* Bus dropped at unexpected time */
+#define AHA_INV_BUS 0x14 /* Invalid bus phase/sequence */
+#define AHA_BAD_MBO 0x15 /* Incorrect MBO cmd */
+#define AHA_BAD_CCB 0x16 /* Incorrect ccb opcode */
+#define AHA_BAD_LINK 0x17 /* Not same values of LUN for links */
+#define AHA_INV_TARGET 0x18 /* Invalid target direction */
+#define AHA_CCB_DUP 0x19 /* Duplicate CCB received */
+#define AHA_INV_CCB 0x1a /* Invalid CCB or segment list */
+#define AHA_ABORTED 42
+
+struct aha_setup {
+ u_char sync_neg:1;
+ u_char parity:1;
+ u_char:6;
+ u_char speed;
+ u_char bus_on;
+ u_char bus_off;
+ u_char num_mbx;
+ u_char mbx[3];
+ struct {
+ u_char offset:4;
+ u_char period:3;
+ u_char valid:1;
+ } sync[8];
+ u_char disc_sts;
+};
+
+struct aha_config {
+ u_char chan;
+ u_char intr;
+ u_char scsi_dev:3;
+ u_char:5;
+};
+
+struct aha_inquire
+{
+ u_char boardid; /* type of board */
+ /* 0x20 = BusLogic 545, but it gets
+ the command wrong, only returns
+ one byte */
+ /* 0x31 = AHA-1540 */
+ /* 0x41 = AHA-1540A/1542A/1542B */
+ /* 0x42 = AHA-1640 */
+ /* 0x43 = AHA-1542C */
+ /* 0x44 = AHA-1542CF */
+ /* 0x45 = AHA-1542CF, BIOS v2.01 */
+ u_char spec_opts; /* special options ID */
+ /* 0x41 = Board is standard model */
+ u_char revision_1; /* firmware revision [0-9A-Z] */
+ u_char revision_2; /* firmware revision [0-9A-Z] */
+};
+
+struct aha_extbios
+{
+ u_char flags; /* Bit 3 == 1 extended bios enabled */
+ u_char mailboxlock; /* mail box lock code to unlock it */
+};
+
+#define INT9 0x01
+#define INT10 0x02
+#define INT11 0x04
+#define INT12 0x08
+#define INT14 0x20
+#define INT15 0x40
+
+#define CHAN0 0x01
+#define CHAN5 0x20
+#define CHAN6 0x40
+#define CHAN7 0x80
+
+/*********************************** end of board definitions***************/
+
+#define PHYSTOKV(x) (((long int)(x)) ^ aha->kv_phys_xor)
+#define KVTOPHYS(x) vtophys(x)
+#define AHA_DMA_PAGES AHA_NSEG
+
+#define PAGESIZ 4096
+#define INVALIDATE_CACHE {asm volatile( ".byte 0x0F ;.byte 0x08" ); }
+
+u_char aha_scratch_buf[256];
+#ifdef AHADEBUG
+int aha_debug = 1;
+#endif /*AHADEBUG */
+
+struct aha_data {
+ short aha_base; /* base port for each board */
+ /*
+ * xor this with a physaddr to get a kv addr and visa versa
+ * for items in THIS STRUCT only.
+ * Used to get the CCD's physical and kv addresses from each
+ * other.
+ */
+ long int kv_phys_xor;
+ struct aha_mbx aha_mbx; /* all the mailboxes */
+ struct aha_ccb *aha_ccb_free; /* the next free ccb */
+ struct aha_ccb aha_ccb[AHA_MBX_SIZE]; /* all the CCBs */
+ int aha_int; /* our irq level */
+ int aha_dma; /* out DMA req channel */
+ int aha_scsi_dev; /* ourscsi bus address */
+ struct scsi_link sc_link; /* prototype for subdevs */
+} *ahadata[NAHA];
+
+struct aha_ccb *aha_get_ccb();
+int ahaprobe();
+void aha_done();
+int ahaattach();
+int ahaintr();
+int32 aha_scsi_cmd();
+void aha_timeout(caddr_t, int);
+void ahaminphys();
+u_int32 aha_adapter_info();
+
+#ifdef KERNEL
+struct scsi_adapter aha_switch =
+{
+ aha_scsi_cmd,
+ ahaminphys,
+ 0,
+ 0,
+ aha_adapter_info,
+ "aha",
+ 0, 0
+};
+
+/* the below structure is so we have a default dev struct for out link struct */
+struct scsi_device aha_dev =
+{
+ NULL, /* Use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+ "aha",
+ 0,
+ 0, 0
+};
+
+struct isa_driver ahadriver =
+{
+ ahaprobe,
+ ahaattach,
+ "aha"
+};
+
+#endif /* KERNEL */
+
+static int ahaunit = 0;
+
+#define aha_abortmbx(mbx) \
+ (mbx)->cmd = AHA_MBO_ABORT; \
+ outb(AHA_CMD_DATA_PORT, AHA_START_SCSI);
+#define aha_startmbx(mbx) \
+ (mbx)->cmd = AHA_MBO_START; \
+ outb(AHA_CMD_DATA_PORT, AHA_START_SCSI);
+
+#define AHA_RESET_TIMEOUT 2000 /* time to wait for reset (mSec) */
+#ifndef KERNEL
+main()
+{
+ printf("size of aha_data is %d\n", sizeof(struct aha_data));
+ printf("size of aha_ccb is %d\n", sizeof(struct aha_ccb));
+ printf("size of aha_mbx is %d\n", sizeof(struct aha_mbx));
+}
+
+#else /*KERNEL */
+
+/*
+ * aha_cmd(unit,icnt, ocnt,wait, retval, opcode, args)
+ * Activate Adapter command
+ * icnt: number of args (outbound bytes written after opcode)
+ * ocnt: number of expected returned bytes
+ * wait: number of seconds to wait for response
+ * retval: buffer where to place returned bytes
+ * opcode: opcode AHA_NOP, AHA_MBX_INIT, AHA_START_SCSI ...
+ * args: parameters
+ *
+ * Performs an adapter command through the ports. Not to be confused
+ * with a scsi command, which is read in via the dma. One of the adapter
+ * commands tells it to read in a scsi command but that one is done
+ * separately. This is only called during set-up.
+ */
+int
+aha_cmd(unit, icnt, ocnt, wait, retval, opcode, args)
+ int unit;
+ int icnt;
+ int ocnt;
+ int wait;
+ u_char *retval;
+ unsigned opcode;
+ u_char args;
+{
+ struct aha_data *aha = ahadata[unit];
+ unsigned *ic = &opcode;
+ u_char oc;
+ register i;
+ int sts;
+
+ /*
+ * multiply the wait argument by a big constant
+ * zero defaults to 1 sec..
+ * all wait loops are in 50uSec cycles
+ */
+ if (wait)
+ wait *= 20000;
+ else
+ wait = 20000;
+ /*
+ * Wait for the adapter to go idle, unless it's one of
+ * the commands which don't need this
+ */
+ if (opcode != AHA_MBX_INIT && opcode != AHA_START_SCSI) {
+ i = 20000; /*do this for upto about a second */
+ while (--i) {
+ sts = inb(AHA_CTRL_STAT_PORT);
+ if (sts & AHA_IDLE) {
+ break;
+ }
+ DELAY(50);
+ }
+ if (!i) {
+ printf("aha%d: aha_cmd, host not idle(0x%x)\n",
+ unit, sts);
+ return (ENXIO);
+ }
+ }
+ /*
+ * Now that it is idle, if we expect output, preflush the
+ * queue feeding to us.
+ */
+ if (ocnt) {
+ while ((inb(AHA_CTRL_STAT_PORT)) & AHA_DF)
+ inb(AHA_CMD_DATA_PORT);
+ }
+ /*
+ * Output the command and the number of arguments given
+ * for each byte, first check the port is empty.
+ */
+ icnt++;
+ /* include the command */
+ while (icnt--) {
+ sts = inb(AHA_CTRL_STAT_PORT);
+ for (i = wait; i; i--) {
+ sts = inb(AHA_CTRL_STAT_PORT);
+ if (!(sts & AHA_CDF))
+ break;
+ DELAY(50);
+ }
+ if (i == 0) {
+ printf("aha%d: aha_cmd, cmd/data port full\n", unit);
+ outb(AHA_CTRL_STAT_PORT, AHA_SRST);
+ return (ENXIO);
+ }
+ outb(AHA_CMD_DATA_PORT, (u_char) (*ic++));
+ }
+ /*
+ * If we expect input, loop that many times, each time,
+ * looking for the data register to have valid data
+ */
+ while (ocnt--) {
+ sts = inb(AHA_CTRL_STAT_PORT);
+ for (i = wait; i; i--) {
+ sts = inb(AHA_CTRL_STAT_PORT);
+ if (sts & AHA_DF)
+ break;
+ DELAY(50);
+ }
+ if (i == 0) {
+ printf("aha%d: aha_cmd, cmd/data port empty %d\n",
+ unit, ocnt);
+ return (ENXIO);
+ }
+ oc = inb(AHA_CMD_DATA_PORT);
+ if (retval)
+ *retval++ = oc;
+ }
+ /*
+ * Wait for the board to report a finised instruction
+ */
+ i = 20000;
+ while (--i) {
+ sts = inb(AHA_INTR_PORT);
+ if (sts & AHA_HACC) {
+ break;
+ }
+ DELAY(50);
+ }
+ if (i == 0) {
+ printf("aha%d: aha_cmd, host not finished(0x%x)\n", unit, sts);
+ return (ENXIO);
+ }
+ outb(AHA_CTRL_STAT_PORT, AHA_IRST);
+ return 0;
+}
+
+/*
+ * Check if the device can be found at the port given
+ * and if so, set it up ready for further work
+ * as an argument, takes the isa_device structure from
+ * autoconf.c
+ */
+int
+ahaprobe(dev)
+ struct isa_device *dev;
+{
+ int unit = ahaunit;
+ struct aha_data *aha;
+
+ /*
+ * find unit and check we have that many defined
+ */
+ if (unit >= NAHA) {
+ printf("aha%d: unit number too high\n", unit);
+ return 0;
+ }
+ dev->id_unit = unit;
+
+ /*
+ * a quick safety check so we can be sleazy later
+ */
+ if (sizeof(struct aha_data) > PAGESIZ) {
+ printf("aha struct > pagesize\n");
+ return 0;
+ }
+ /*
+ * Allocate a storage area for us
+ */
+ if (ahadata[unit]) {
+ printf("aha%d: memory already allocated\n", unit);
+ return 0;
+ }
+ aha = malloc(sizeof(struct aha_data), M_TEMP, M_NOWAIT);
+ if (!aha) {
+ printf("aha%d: cannot malloc!\n", unit);
+ return 0;
+ }
+ bzero(aha, sizeof(struct aha_data));
+ ahadata[unit] = aha;
+ aha->aha_base = dev->id_iobase;
+ /*
+ * Try initialise a unit at this location
+ * sets up dma and bus speed, loads aha->aha_int
+ */
+ if (aha_init(unit) != 0) {
+ ahadata[unit] = NULL;
+ free(aha, M_TEMP);
+ return 0;
+ }
+ /*
+ * Calculate the xor product of the aha struct's
+ * physical and virtual address. This allows us
+ * to change addresses within the structure
+ * from physical to virtual easily, as long as
+ * the structure is less than 1 page in size.
+ * This is used to recognise CCBs which are in
+ * this struct and which are refered to by the
+ * hardware using physical addresses.
+ * (assumes malloc returns a chunk that doesn't
+ * span pages)
+ * eventually use the hash table in aha1742.c
+ */
+ aha->kv_phys_xor = (long int) aha ^ (KVTOPHYS(aha));
+
+ /*
+ * If it's there, put in it's interrupt vectors
+ */
+ dev->id_irq = (1 << aha->aha_int);
+ dev->id_drq = aha->aha_dma;
+ ahaunit++;
+ return 0x4;
+}
+
+/*
+ * Attach all the sub-devices we can find
+ */
+int
+ahaattach(dev)
+ struct isa_device *dev;
+{
+ int unit = dev->id_unit;
+ struct aha_data *aha = ahadata[unit];
+
+ /*
+ * fill in the prototype scsi_link.
+ */
+ aha->sc_link.adapter_unit = unit;
+ aha->sc_link.adapter_targ = aha->aha_scsi_dev;
+ aha->sc_link.adapter = &aha_switch;
+ aha->sc_link.device = &aha_dev;
+ aha->sc_link.flags = SDEV_BOUNCE;
+
+ /*
+ * ask the adapter what subunits are present
+ */
+ scsi_attachdevs(&(aha->sc_link));
+
+ return 1;
+}
+
+/*
+ * Return some information to the caller about the adapter and its
+ * capabilities.
+ */
+u_int32
+aha_adapter_info(unit)
+ int unit;
+{
+ return (2); /* 2 outstanding requests at a time per device */
+}
+
+/*
+ * Catch an interrupt from the adaptor
+ */
+int
+ahaintr(unit)
+ int unit;
+{
+ struct aha_ccb *ccb;
+ unsigned char stat;
+ register i;
+ struct aha_data *aha = ahadata[unit];
+
+#ifdef AHADEBUG
+ printf("ahaintr ");
+#endif /*AHADEBUG */
+ /*
+ * First acknowlege the interrupt, Then if it's not telling about
+ * a completed operation just return.
+ */
+ stat = inb(AHA_INTR_PORT);
+ outb(AHA_CTRL_STAT_PORT, AHA_IRST);
+ if (!(stat & AHA_MBIF))
+ return 1;
+#ifdef AHADEBUG
+ printf("mbxin ");
+#endif /*AHADEBUG */
+ /*
+ * If it IS then process the competed operation
+ */
+ for (i = 0; i < AHA_MBX_SIZE; i++) {
+ if (aha->aha_mbx.mbi[i].stat != AHA_MBI_FREE) {
+ ccb = (struct aha_ccb *) PHYSTOKV(
+ (_3btol(aha->aha_mbx.mbi[i].ccb_addr)));
+
+ if ((stat = aha->aha_mbx.mbi[i].stat) != AHA_MBI_OK) {
+ switch (stat) {
+ case AHA_MBI_ABORT:
+#ifdef AHADEBUG
+ if (aha_debug)
+ printf("abort");
+#endif /*AHADEBUG */
+ ccb->host_stat = AHA_ABORTED;
+ break;
+
+ case AHA_MBI_UNKNOWN:
+ ccb = (struct aha_ccb *) 0;
+#ifdef AHADEBUG
+ if (aha_debug)
+ printf("unknown ccb for abort ");
+#endif /*AHADEBUG */
+ /* may have missed it */
+ /* no such ccb known for abort */
+
+ case AHA_MBI_ERROR:
+ break;
+
+ default:
+ panic("Impossible mbxi status");
+
+ }
+#ifdef AHADEBUG
+ if (aha_debug && ccb) {
+ u_char *cp;
+ cp = (u_char *) (&(ccb->scsi_cmd));
+ printf("op=%x %x %x %x %x %x\n",
+ cp[0], cp[1], cp[2],
+ cp[3], cp[4], cp[5]);
+ printf("stat %x for mbi[%d]\n"
+ ,aha->aha_mbx.mbi[i].stat, i);
+ printf("addr = 0x%x\n", ccb);
+ }
+#endif /*AHADEBUG */
+ }
+ if (ccb) {
+ untimeout(aha_timeout, (caddr_t)ccb);
+ aha_done(unit, ccb);
+ }
+ aha->aha_mbx.mbi[i].stat = AHA_MBI_FREE;
+ }
+ }
+ return 1;
+}
+
+/*
+ * A ccb (and hence a mbx-out is put onto the
+ * free list.
+ */
+void
+aha_free_ccb(unit, ccb, flags)
+ int unit;
+ struct aha_ccb *ccb;
+ int flags;
+{
+ struct aha_data *aha = ahadata[unit];
+ unsigned int opri = 0;
+
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+
+ ccb->next = aha->aha_ccb_free;
+ aha->aha_ccb_free = ccb;
+ ccb->flags = CCB_FREE;
+ /*
+ * If there were none, wake anybody waiting for
+ * one to come free, starting with queued entries
+ */
+ if (!ccb->next) {
+ wakeup((caddr_t)&aha->aha_ccb_free);
+ }
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+}
+
+/*
+ * Get a free ccb (and hence mbox-out entry)
+ */
+struct aha_ccb *
+aha_get_ccb(unit, flags)
+ int unit;
+ int flags;
+{
+ struct aha_data *aha = ahadata[unit];
+ unsigned opri = 0;
+ struct aha_ccb *rc;
+
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+ /*
+ * If we can and have to, sleep waiting for one
+ * to come free
+ */
+ while ((!(rc = aha->aha_ccb_free)) && (!(flags & SCSI_NOSLEEP))) {
+ tsleep((caddr_t)&aha->aha_ccb_free, PRIBIO, "ahaccb", 0);
+ }
+ if (rc) {
+ aha->aha_ccb_free = aha->aha_ccb_free->next;
+ rc->flags = CCB_ACTIVE;
+ }
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+ return (rc);
+}
+
+/*
+ * We have a ccb which has been processed by the
+ * adaptor, now we look to see how the operation
+ * went. Wake up the owner if waiting
+ */
+void
+aha_done(unit, ccb)
+ int unit;
+ struct aha_ccb *ccb;
+{
+ struct aha_data *aha = ahadata[unit];
+ struct scsi_sense_data *s1, *s2;
+ struct scsi_xfer *xs = ccb->xfer;
+
+ SC_DEBUG(xs->sc_link, SDEV_DB2, ("aha_done\n"));
+ /*
+ * Otherwise, put the results of the operation
+ * into the xfer and call whoever started it
+ */
+ if (!(xs->flags & INUSE)) {
+ printf("aha%d: exiting but not in use!\n", unit);
+ Debugger("aha1542");
+ }
+ if (((ccb->host_stat != AHA_OK) || (ccb->target_stat != SCSI_OK))
+ && ((xs->flags & SCSI_ERR_OK) == 0)) {
+ /*
+ * We have an error, that we cannot ignore.
+ */
+ s1 = (struct scsi_sense_data *) (((char *) (&ccb->scsi_cmd))
+ + ccb->scsi_cmd_length);
+ s2 = &(xs->sense);
+
+ if (ccb->host_stat) {
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("host err 0x%x\n",
+ ccb->host_stat));
+ switch (ccb->host_stat) {
+ case AHA_ABORTED:
+ case AHA_SEL_TIMEOUT: /* No response */
+ xs->error = XS_TIMEOUT;
+ break;
+ default: /* Other scsi protocol messes */
+ xs->error = XS_DRIVER_STUFFUP;
+ printf("aha%d:host_stat%x\n",
+ unit, ccb->host_stat);
+ }
+ } else {
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("target err 0x%x\n",
+ ccb->target_stat));
+ switch (ccb->target_stat) {
+ case 0x02:
+ /* structure copy!!!!! */
+ *s2 = *s1;
+ xs->error = XS_SENSE;
+ break;
+ case 0x08:
+ xs->error = XS_BUSY;
+ break;
+ default:
+ printf("aha%d:target_stat%x\n",
+ unit, ccb->target_stat);
+ xs->error = XS_DRIVER_STUFFUP;
+ }
+ }
+ } else {
+ /* All went correctly OR errors expected */
+ xs->resid = 0;
+ }
+ xs->flags |= ITSDONE;
+ aha_free_ccb(unit, ccb, xs->flags);
+ scsi_done(xs);
+}
+
+/*
+ * Start the board, ready for normal operation
+ */
+int
+aha_init(unit)
+ int unit;
+{
+ struct aha_data *aha = ahadata[unit];
+ unsigned char ad[3];
+ volatile int i, sts;
+ struct aha_config conf;
+ struct aha_inquire inquire;
+ struct aha_extbios extbios;
+
+ /*
+ * reset board, If it doesn't respond, assume
+ * that it's not there.. good for the probe
+ */
+
+ outb(AHA_CTRL_STAT_PORT, AHA_HRST | AHA_SRST);
+
+ for (i = AHA_RESET_TIMEOUT; i; i--) {
+ sts = inb(AHA_CTRL_STAT_PORT);
+ if (sts == (AHA_IDLE | AHA_INIT)) {
+ break;
+ }
+ DELAY(1000); /* calibrated in msec */
+ }
+#ifdef AHADEBUG
+ printf("aha_init: AHA_RESET_TIMEOUT went to %d\n", i);
+#endif /* AHADEBUG */
+ if (i == 0) {
+#ifdef AHADEBUG
+ if (aha_debug)
+ printf("aha_init: No answer from board\n");
+#endif /*AHADEBUG */
+ return (ENXIO);
+ }
+
+ /*
+ * Assume we have a board at this stage, do an adapter inquire
+ * to find out what type of controller it is. If the AHA_INQUIRE
+ * command fails, blatter about it, nuke the boardid so the 1542C
+ * stuff gets skipped over, and reset the board again.
+ */
+ if(aha_cmd(unit, 0, sizeof(inquire), 1 ,&inquire, AHA_INQUIRE)) {
+ /*
+ * Blah.. not a real adaptec board!!!
+ * Seems that the Buslogic 545S and the DTC3290 both get
+ * this wrong.
+ */
+ printf ("aha%d: not a REAL adaptec board, may cause warnings\n",
+ unit);
+ inquire.boardid = 0;
+ outb(AHA_CTRL_STAT_PORT, AHA_HRST | AHA_SRST);
+ for (i = AHA_RESET_TIMEOUT; i; i--) {
+ sts = inb(AHA_CTRL_STAT_PORT);
+ if (sts == (AHA_IDLE | AHA_INIT)) {
+ break;
+ }
+ DELAY(1000); /* calibrated in msec */
+ }
+#ifdef AHADEBUG
+ printf("aha_init2: AHA_RESET_TIMEOUT went to %d\n", i);
+#endif /* AHADEBUG */
+ if (i == 0) {
+#ifdef AHADEBUG
+ if (aha_debug)
+ printf("aha_init2: No answer from board\n");
+#endif /*AHADEBUG */
+ return (ENXIO);
+ }
+ }
+#ifdef AHADEBUG
+ printf("aha%d: inquire %x, %x, %x, %x\n",
+ unit,
+ inquire.boardid, inquire.spec_opts,
+ inquire.revision_1, inquire.revision_2);
+#endif /* AHADEBUG */
+
+ /*
+ * If we are a 1542C or 1542CF disable the extended bios so that the
+ * mailbox interface is unlocked.
+ * No need to check the extended bios flags as some of the
+ * extensions that cause us problems are not flagged in that byte.
+ */
+ if ((inquire.boardid == 0x43) || (inquire.boardid == 0x44) ||
+ (inquire.boardid == 0x45)) {
+ aha_cmd(unit, 0, sizeof(extbios), 0, &extbios, AHA_EXT_BIOS);
+#ifdef AHADEBUG
+ printf("aha%d: extended bios flags %x\n", unit, extbios.flags);
+#endif /* AHADEBUG */
+ printf("aha%d: 1542C/CF detected, unlocking mailbox\n", unit);
+ aha_cmd(unit, 2, 0, 0, 0, AHA_MBX_ENABLE,
+ 0, extbios.mailboxlock);
+ }
+
+ /*
+ * setup dma channel from jumpers and save int
+ * level
+ */
+ printf("aha%d: reading board settings, ", unit);
+#define PRNT(x) printf(x)
+ DELAY(1000); /* for Bustek 545 */
+ aha_cmd(unit, 0, sizeof(conf), 0, &conf, AHA_CONF_GET);
+ switch (conf.chan) {
+ case CHAN0:
+ outb(0x0b, 0x0c);
+ outb(0x0a, 0x00);
+ aha->aha_dma = 0;
+ PRNT("dma=0 ");
+ break;
+ case CHAN5:
+ outb(0xd6, 0xc1);
+ outb(0xd4, 0x01);
+ aha->aha_dma = 5;
+ PRNT("dma=5 ");
+ break;
+ case CHAN6:
+ outb(0xd6, 0xc2);
+ outb(0xd4, 0x02);
+ aha->aha_dma = 6;
+ PRNT("dma=6 ");
+ break;
+ case CHAN7:
+ outb(0xd6, 0xc3);
+ outb(0xd4, 0x03);
+ aha->aha_dma = 7;
+ PRNT("dma=7 ");
+ break;
+ default:
+ printf("illegal dma jumper setting\n");
+ return (EIO);
+ }
+ switch (conf.intr) {
+ case INT9:
+ aha->aha_int = 9;
+ PRNT("int=9 ");
+ break;
+ case INT10:
+ aha->aha_int = 10;
+ PRNT("int=10 ");
+ break;
+ case INT11:
+ aha->aha_int = 11;
+ PRNT("int=11 ");
+ break;
+ case INT12:
+ aha->aha_int = 12;
+ PRNT("int=12 ");
+ break;
+ case INT14:
+ aha->aha_int = 14;
+ PRNT("int=14 ");
+ break;
+ case INT15:
+ aha->aha_int = 15;
+ PRNT("int=15 ");
+ break;
+ default:
+ printf("illegal int jumper setting\n");
+ return (EIO);
+ }
+
+ /* who are we on the scsi bus? */
+ aha->aha_scsi_dev = conf.scsi_dev;
+
+ /*
+ * Change the bus on/off times to not clash with other dma users.
+ */
+ aha_cmd(unit, 1, 0, 0, 0, AHA_BUS_ON_TIME_SET, 7);
+ aha_cmd(unit, 1, 0, 0, 0, AHA_BUS_OFF_TIME_SET, 4);
+
+#ifdef TUNE_1542
+ /*
+ * Initialize memory transfer speed
+ * Not compiled in by default because it breaks some machines
+ */
+ if (!(aha_set_bus_speed(unit))) {
+ return (EIO);
+ }
+#else
+ printf (" (bus speed defaulted)\n");
+#endif /*TUNE_1542*/
+ /*
+ * Initialize mail box
+ */
+ lto3b(KVTOPHYS(&aha->aha_mbx), ad);
+
+ aha_cmd(unit, 4, 0, 0, 0, AHA_MBX_INIT,
+ AHA_MBX_SIZE,
+ ad[0],
+ ad[1],
+ ad[2]);
+
+ /*
+ * link the ccb's with the mbox-out entries and
+ * into a free-list
+ * this is a kludge but it works
+ */
+ for (i = 0; i < AHA_MBX_SIZE; i++) {
+ aha->aha_ccb[i].next = aha->aha_ccb_free;
+ aha->aha_ccb_free = &aha->aha_ccb[i];
+ aha->aha_ccb_free->flags = CCB_FREE;
+ aha->aha_ccb_free->mbx = &aha->aha_mbx.mbo[i];
+ lto3b(KVTOPHYS(aha->aha_ccb_free), aha->aha_mbx.mbo[i].ccb_addr);
+ }
+ /*
+ * Note that we are going and return (to probe)
+ */
+ return 0;
+}
+
+void
+ahaminphys(bp)
+ struct buf *bp;
+{
+/* aha seems to explode with 17 segs (64k may require 17 segs) */
+/* on old boards so use a max of 16 segs if you have problems here */
+ if (bp->b_bcount > ((AHA_NSEG - 1) * PAGESIZ)) {
+ bp->b_bcount = ((AHA_NSEG - 1) * PAGESIZ);
+ }
+}
+
+/*
+ * start a scsi operation given the command and
+ * the data address. Also needs the unit, target
+ * and lu
+ */
+int32
+aha_scsi_cmd(xs)
+ struct scsi_xfer *xs;
+{
+ struct scsi_link *sc_link = xs->sc_link;
+ int unit = sc_link->adapter_unit;
+ struct aha_data *aha = ahadata[unit];
+ struct scsi_sense_data *s1, *s2;
+ struct aha_ccb *ccb;
+ struct aha_scat_gath *sg;
+ int seg; /* scatter gather seg being worked on */
+ int i = 0;
+ int rc = 0;
+ int thiskv;
+ int thisphys, nextphys;
+ int bytes_this_seg, bytes_this_page, datalen, flags;
+ struct iovec *iovp;
+ int s;
+
+ SC_DEBUG(xs->sc_link, SDEV_DB2, ("aha_scsi_cmd\n"));
+ /*
+ * get a ccb (mbox-out) to use. If the transfer
+ * is from a buf (possibly from interrupt time)
+ * then we can't allow it to sleep
+ */
+ flags = xs->flags;
+ if (!(ccb = aha_get_ccb(unit, flags))) {
+ xs->error = XS_DRIVER_STUFFUP;
+ return (TRY_AGAIN_LATER);
+ }
+ if (ccb->mbx->cmd != AHA_MBO_FREE)
+ printf("aha%d: MBO not free\n", unit);
+
+ /*
+ * Put all the arguments for the xfer in the ccb
+ */
+ ccb->xfer = xs;
+ if (flags & SCSI_RESET) {
+ ccb->opcode = AHA_RESET_CCB;
+ } else {
+ /* can't use S/G if zero length */
+ ccb->opcode = (xs->datalen ?
+ AHA_INIT_SCAT_GATH_CCB
+ : AHA_INITIATOR_CCB);
+ }
+ ccb->target = sc_link->target;
+ ccb->data_out = 0;
+ ccb->data_in = 0;
+ ccb->lun = sc_link->lun;
+ ccb->scsi_cmd_length = xs->cmdlen;
+ ccb->req_sense_length = sizeof(ccb->scsi_sense);
+
+ if ((xs->datalen) && (!(flags & SCSI_RESET))) {
+ /* can use S/G only if not zero length */
+ lto3b(KVTOPHYS(ccb->scat_gath), ccb->data_addr);
+ sg = ccb->scat_gath;
+ seg = 0;
+#ifdef TFS_ONLY
+ if (flags & SCSI_DATA_UIO) {
+ iovp = ((struct uio *) xs->data)->uio_iov;
+ datalen = ((struct uio *) xs->data)->uio_iovcnt;
+ while ((datalen) && (seg < AHA_NSEG)) {
+ lto3b(iovp->iov_base, sg->seg_addr);
+ lto3b(iovp->iov_len, sg->seg_len);
+ SC_DEBUGN(xs->sc_link, SDEV_DB4, ("UIO(0x%x@0x%x)"
+ ,iovp->iov_len
+ ,iovp->iov_base));
+ sg++;
+ iovp++;
+ seg++;
+ datalen--;
+ }
+ } else
+#endif /*TFS_ONLY */
+ {
+ /*
+ * Set up the scatter gather block
+ */
+
+ SC_DEBUG(xs->sc_link, SDEV_DB4,
+ ("%d @0x%x:- ", xs->datalen, xs->data));
+ datalen = xs->datalen;
+ thiskv = (int) xs->data;
+ thisphys = KVTOPHYS(thiskv);
+
+ while ((datalen) && (seg < AHA_NSEG)) {
+ bytes_this_seg = 0;
+
+ /* put in the base address */
+ lto3b(thisphys, sg->seg_addr);
+
+ SC_DEBUGN(xs->sc_link, SDEV_DB4,
+ ("0x%x", thisphys));
+
+ /* do it at least once */
+ nextphys = thisphys;
+ while ((datalen) && (thisphys == nextphys)) {
+ /*
+ * This page is contiguous (physically)
+ * with the the last, just extend the
+ * length
+ */
+ /* check it fits on the ISA bus */
+ if (thisphys > 0xFFFFFF)
+ {
+ printf("aha%d: DMA beyond"
+ " end Of ISA\n", unit);
+ xs->error = XS_DRIVER_STUFFUP;
+ aha_free_ccb(unit, ccb, flags);
+ return (HAD_ERROR);
+ }
+ /** how far to the end of the page ***/
+ nextphys = (thisphys & (~(PAGESIZ - 1)))
+ + PAGESIZ;
+ bytes_this_page = nextphys - thisphys;
+ /**** or the data ****/
+ bytes_this_page = min(bytes_this_page
+ ,datalen);
+ bytes_this_seg += bytes_this_page;
+ datalen -= bytes_this_page;
+
+ /**** get more ready for the next page ****/
+ thiskv = (thiskv & (~(PAGESIZ - 1)))
+ + PAGESIZ;
+ if (datalen)
+ thisphys = KVTOPHYS(thiskv);
+ }
+ /*
+ * next page isn't contiguous, finish the seg
+ */
+ SC_DEBUGN(xs->sc_link, SDEV_DB4,
+ ("(0x%x)", bytes_this_seg));
+ lto3b(bytes_this_seg, sg->seg_len);
+ sg++;
+ seg++;
+ }
+ }
+ lto3b(seg * sizeof(struct aha_scat_gath), ccb->data_length);
+ SC_DEBUGN(xs->sc_link, SDEV_DB4, ("\n"));
+
+ if (datalen) { /* there's still data, must have run out of segs! */
+ printf("aha%d: aha_scsi_cmd, more than %d DMA segs\n",
+ unit, AHA_NSEG);
+ xs->error = XS_DRIVER_STUFFUP;
+ aha_free_ccb(unit, ccb, flags);
+ return (HAD_ERROR);
+ }
+ } else { /* No data xfer, use non S/G values */
+ lto3b(0, ccb->data_addr);
+ lto3b(0, ccb->data_length);
+ }
+ lto3b(0, ccb->link_addr);
+ /*
+ * Put the scsi command in the ccb and start it
+ */
+ if (!(flags & SCSI_RESET))
+ bcopy(xs->cmd, &ccb->scsi_cmd, ccb->scsi_cmd_length);
+ if (!(flags & SCSI_NOMASK)) {
+ s = splbio(); /* stop instant timeouts */
+ timeout(aha_timeout, (caddr_t)ccb, (xs->timeout * hz) / 1000);
+ aha_startmbx(ccb->mbx);
+ /*
+ * Usually return SUCCESSFULLY QUEUED
+ */
+ splx(s);
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("sent\n"));
+ return (SUCCESSFULLY_QUEUED);
+ }
+ aha_startmbx(ccb->mbx);
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd sent, waiting\n"));
+
+ /*
+ * If we can't use interrupts, poll on completion
+ */
+ return (aha_poll(unit, xs, ccb)); /* only during boot */
+}
+
+/*
+ * Poll a particular unit, looking for a particular xs
+ */
+int
+aha_poll(unit, xs, ccb)
+ int unit;
+ struct scsi_xfer *xs;
+ struct aha_ccb *ccb;
+{
+ struct aha_data *aha = ahadata[unit];
+ int done = 0;
+ int count = xs->timeout;
+ u_char stat;
+
+ /*timeouts are in msec, so we loop in 1000uSec cycles */
+ while (count) {
+ /*
+ * If we had interrupts enabled, would we
+ * have got an interrupt?
+ */
+ stat = inb(AHA_INTR_PORT);
+ if (stat & AHA_ANY_INTR) {
+ ahaintr(unit);
+ }
+ if (xs->flags & ITSDONE) {
+ break;
+ }
+ DELAY(1000); /* only happens in boot so ok */
+ count--;
+ }
+ if (count == 0) {
+ /*
+ * We timed out, so call the timeout handler
+ * manually, accout for the fact that the
+ * clock is not running yet by taking out the
+ * clock queue entry it makes
+ */
+ aha_timeout((caddr_t)ccb, 0);
+
+ /*
+ * because we are polling,
+ * take out the timeout entry aha_timeout made
+ */
+ untimeout(aha_timeout, (caddr_t)ccb);
+ count = 2000;
+ while (count) {
+ /*
+ * Once again, wait for the int bit
+ */
+ stat = inb(AHA_INTR_PORT);
+ if (stat & AHA_ANY_INTR) {
+ ahaintr(unit);
+ }
+ if (xs->flags & ITSDONE) {
+ break;
+ }
+ DELAY(1000); /* only happens in boot so ok */
+ count--;
+ }
+ if (count == 0) {
+ /*
+ * We timed out again.. this is bad
+ * Notice that this time there is no
+ * clock queue entry to remove
+ */
+ aha_timeout((caddr_t)ccb, 0);
+ }
+ }
+ if (xs->error)
+ return (HAD_ERROR);
+ return (COMPLETE);
+
+}
+
+#ifdef TUNE_1542
+/*
+ * Try all the speeds from slowest to fastest.. if it finds a
+ * speed that fails, back off one notch from the last working
+ * speed (unless there is no other notch).
+ * Returns the nSEC value of the time used
+ * or 0 if it could get a working speed (or the NEXT speed
+ * failed)
+ */
+static struct bus_speed
+{
+ char arg;
+ int nsecs;
+}aha_bus_speeds[] =
+{
+ {0x88,100},
+ {0x99,150},
+ {0xaa,200},
+ {0xbb,250},
+ {0xcc,300},
+ {0xdd,350},
+ {0xee,400},
+ {0xff,450}
+};
+
+int
+aha_set_bus_speed(unit)
+ int unit;
+{
+ int speed;
+ int lastworking;
+ int retval,retval2;
+ struct aha_data *aha = ahadata[unit];
+
+ lastworking = -1;
+ speed = 7;
+ while (1) {
+ retval = aha_bus_speed_check(unit,speed);
+ if(retval != 0) {
+ lastworking = speed;
+ }
+ if((retval == 0) || (speed == 0)) {
+ if(lastworking == -1) {
+ printf("No working bus speed for aha154X\n");
+ return 0;
+ }
+ printf("%d nSEC ok, using "
+ ,aha_bus_speeds[lastworking].nsecs);
+ if(lastworking == 7) { /* is slowest already */
+ printf("marginal ");
+ } else {
+ lastworking++;
+ }
+ retval2 = aha_bus_speed_check(unit,lastworking);
+ if(retval2 == 0) {
+ printf("test retry failed.. aborting.\n");
+ return 0;
+ }
+ printf("%d nSEC\n",retval2);
+ return retval2 ;
+
+ }
+ speed--;
+ }
+}
+
+/*
+ * Set the DMA speed to the Nth speed and try an xfer. If it
+ * fails return 0, if it succeeds return the nSec value selected
+ * If there is no such speed return HAD_ERROR.
+ */
+static char aha_test_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz!@";
+
+int
+aha_bus_speed_check(unit, speed)
+ int unit, speed;
+{
+ int numspeeds = sizeof(aha_bus_speeds) / sizeof(struct bus_speed);
+ int loopcount;
+ u_char ad[3];
+ struct aha_data *aha = ahadata[unit];
+
+ /*
+ * Check we have such an entry
+ */
+ if (speed >= numspeeds)
+ return (HAD_ERROR); /* illegal speed */
+
+ /*
+ * Set the dma-speed
+ */
+ aha_cmd(unit, 1, 0, 0, 0, AHA_SPEED_SET, aha_bus_speeds[speed].arg);
+
+ /*
+ * put the test data into the buffer and calculate
+ * it's address. Read it onto the board
+ */
+ lto3b(KVTOPHYS(aha_scratch_buf), ad);
+ for(loopcount = 2000;loopcount;loopcount--)
+ {
+ strcpy(aha_scratch_buf, aha_test_string);
+
+ aha_cmd(unit, 3, 0, 0, 0, AHA_WRITE_FIFO, ad[0], ad[1], ad[2]);
+
+ /*
+ * clear the buffer then copy the contents back from the
+ * board.
+ */
+ bzero(aha_scratch_buf, 54); /* 54 bytes transfered by test */
+
+ aha_cmd(unit, 3, 0, 0, 0, AHA_READ_FIFO, ad[0], ad[1], ad[2]);
+
+ /*
+ * Compare the original data and the final data and
+ * return the correct value depending upon the result
+ */
+ if (strcmp(aha_test_string, aha_scratch_buf))
+ return 0; /* failed test */
+ }
+ /* copy succeded assume speed ok */
+
+ return (aha_bus_speeds[speed].nsecs);
+
+}
+#endif /*TUNE_1542*/
+
+void
+aha_timeout(caddr_t arg1, int arg2)
+{
+ struct aha_ccb * ccb = (struct aha_ccb *)arg1;
+ int unit;
+ int s = splbio();
+ struct aha_data *aha;
+
+ unit = ccb->xfer->sc_link->adapter_unit;
+ aha = ahadata[unit];
+ sc_print_addr(ccb->xfer->sc_link);
+ printf("timed out ");
+
+ /*
+ * If The ccb's mbx is not free, then
+ * the board has gone south
+ */
+ if (ccb->mbx->cmd != AHA_MBO_FREE) {
+ printf("\nadapter not taking commands.. frozen?!\n");
+ Debugger("aha1542");
+ }
+ /*
+ * If it has been through before, then
+ * a previous abort has failed, don't
+ * try abort again
+ */
+ if (ccb->flags == CCB_ABORTED) {
+ /* abort timed out */
+ printf(" AGAIN\n");
+ ccb->xfer->retries = 0; /* I MEAN IT ! */
+ ccb->host_stat = AHA_ABORTED;
+ aha_done(unit, ccb);
+ } else {
+ /* abort the operation that has timed out */
+ printf("\n");
+ aha_abortmbx(ccb->mbx);
+ /* 4 secs for the abort */
+ timeout(aha_timeout, (caddr_t)ccb, 4 * hz);
+ ccb->flags = CCB_ABORTED;
+ } splx(s);
+}
+#endif /* KERNEL */
diff --git a/sys/i386/isa/aha1742.c b/sys/i386/isa/aha1742.c
new file mode 100644
index 0000000..95c0aed
--- /dev/null
+++ b/sys/i386/isa/aha1742.c
@@ -0,0 +1,1244 @@
+/*
+ * Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems for use under the MACH(2.5) operating system.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ * commenced: Sun Sep 27 18:14:01 PDT 1992
+ *
+ * $Id: aha1742.c,v 1.14 1994/01/11 07:24:32 rgrimes Exp $
+ */
+
+#include <sys/types.h>
+
+#ifdef KERNEL /* don't laugh, it compiles as a program too.. look */
+#include <ahb.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <i386/include/pio.h>
+#include <i386/isa/isa_device.h>
+#endif /*KERNEL */
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+/* */
+
+#ifdef KERNEL
+# ifdef NetBSD
+# ifdef DDB
+int Debugger();
+# else /* DDB */
+#define Debugger() panic("should call debugger here (adaptec.c)")
+# endif /* DDB */
+# else
+#include "ddb.h"
+#endif /* netbsd */
+#else /* KERNEL */
+#define NAHB 1
+#endif /* kernel */
+
+#ifndef NetBSD
+typedef timeout_func_t timeout_t;
+#endif
+
+typedef unsigned long int physaddr;
+#include "kernel.h"
+
+#define KVTOPHYS(x) vtophys(x)
+
+#define AHB_ECB_MAX 32 /* store up to 32ECBs at any one time */
+ /* in aha1742 H/W ( Not MAX ? ) */
+#define ECB_HASH_SIZE 32 /* when we have a physical addr. for */
+ /* a ecb and need to find the ecb in */
+ /* space, look it up in the hash table */
+#define ECB_HASH_SHIFT 9 /* only hash on multiples of 512 */
+#define ECB_HASH(x) ((((long int)(x))>>ECB_HASH_SHIFT) % ECB_HASH_SIZE)
+
+#define AHB_NSEG 33 /* number of dma segments supported */
+
+/*
+ * AHA1740 standard EISA Host ID regs (Offset from slot base)
+ */
+#define HID0 0xC80 /* 0,1: msb of ID2, 3-7: ID1 */
+#define HID1 0xC81 /* 0-4: ID3, 4-7: LSB ID2 */
+#define HID2 0xC82 /* product, 0=174[20] 1 = 1744 */
+#define HID3 0xC83 /* firmware revision */
+
+#define CHAR1(B1,B2) (((B1>>2) & 0x1F) | '@')
+#define CHAR2(B1,B2) (((B1<<3) & 0x18) | ((B2>>5) & 0x7)|'@')
+#define CHAR3(B1,B2) ((B2 & 0x1F) | '@')
+
+/* AHA1740 EISA board control registers (Offset from slot base) */
+#define EBCTRL 0xC84
+#define CDEN 0x01
+/*
+ * AHA1740 EISA board mode registers (Offset from slot base)
+ */
+#define PORTADDR 0xCC0
+#define PORTADDR_ENHANCED 0x80
+#define BIOSADDR 0xCC1
+#define INTDEF 0xCC2
+#define SCSIDEF 0xCC3
+#define BUSDEF 0xCC4
+#define RESV0 0xCC5
+#define RESV1 0xCC6
+#define RESV2 0xCC7
+/**** bit definitions for INTDEF ****/
+#define INT9 0x00
+#define INT10 0x01
+#define INT11 0x02
+#define INT12 0x03
+#define INT14 0x05
+#define INT15 0x06
+#define INTHIGH 0x08 /* int high=ACTIVE (else edge) */
+#define INTEN 0x10
+/**** bit definitions for SCSIDEF ****/
+#define HSCSIID 0x0F /* our SCSI ID */
+#define RSTPWR 0x10 /* reset scsi bus on power up or reset */
+/**** bit definitions for BUSDEF ****/
+#define B0uS 0x00 /* give up bus immediatly */
+#define B4uS 0x01 /* delay 4uSec. */
+#define B8uS 0x02
+/*
+ * AHA1740 ENHANCED mode mailbox control regs (Offset from slot base)
+ */
+#define MBOXOUT0 0xCD0
+#define MBOXOUT1 0xCD1
+#define MBOXOUT2 0xCD2
+#define MBOXOUT3 0xCD3
+
+#define ATTN 0xCD4
+#define G2CNTRL 0xCD5
+#define G2INTST 0xCD6
+#define G2STAT 0xCD7
+
+#define MBOXIN0 0xCD8
+#define MBOXIN1 0xCD9
+#define MBOXIN2 0xCDA
+#define MBOXIN3 0xCDB
+
+#define G2STAT2 0xCDC
+
+/*
+ * Bit definitions for the 5 control/status registers
+ */
+#define ATTN_TARGET 0x0F
+#define ATTN_OPCODE 0xF0
+#define OP_IMMED 0x10
+#define AHB_TARG_RESET 0x80
+#define OP_START_ECB 0x40
+#define OP_ABORT_ECB 0x50
+
+#define G2CNTRL_SET_HOST_READY 0x20
+#define G2CNTRL_CLEAR_EISA_INT 0x40
+#define G2CNTRL_HARD_RESET 0x80
+
+#define G2INTST_TARGET 0x0F
+#define G2INTST_INT_STAT 0xF0
+#define AHB_ECB_OK 0x10
+#define AHB_ECB_RECOVERED 0x50
+#define AHB_HW_ERR 0x70
+#define AHB_IMMED_OK 0xA0
+#define AHB_ECB_ERR 0xC0
+#define AHB_ASN 0xD0 /* for target mode */
+#define AHB_IMMED_ERR 0xE0
+
+#define G2STAT_BUSY 0x01
+#define G2STAT_INT_PEND 0x02
+#define G2STAT_MBOX_EMPTY 0x04
+
+#define G2STAT2_HOST_READY 0x01
+
+struct ahb_dma_seg {
+ physaddr addr;
+ long len;
+};
+
+struct ahb_ecb_status {
+ u_short status;
+#define ST_DON 0x0001
+#define ST_DU 0x0002
+#define ST_QF 0x0008
+#define ST_SC 0x0010
+#define ST_DO 0x0020
+#define ST_CH 0x0040
+#define ST_INT 0x0080
+#define ST_ASA 0x0100
+#define ST_SNS 0x0200
+#define ST_INI 0x0800
+#define ST_ME 0x1000
+#define ST_ECA 0x4000
+ u_char ha_status;
+#define HS_OK 0x00
+#define HS_CMD_ABORTED_HOST 0x04
+#define HS_CMD_ABORTED_ADAPTER 0x05
+#define HS_TIMED_OUT 0x11
+#define HS_HARDWARE_ERR 0x20
+#define HS_SCSI_RESET_ADAPTER 0x22
+#define HS_SCSI_RESET_INCOMING 0x23
+ u_char targ_status;
+#define TS_OK 0x00
+#define TS_CHECK_CONDITION 0x02
+#define TS_BUSY 0x08
+ u_long resid_count;
+ u_long resid_addr;
+ u_short addit_status;
+ u_char sense_len;
+ u_char unused[9];
+ u_char cdb[6];
+};
+
+
+struct ecb {
+ u_char opcode;
+#define ECB_SCSI_OP 0x01
+ u_char:4;
+ u_char options:3;
+ u_char:1;
+ short opt1;
+#define ECB_CNE 0x0001
+#define ECB_DI 0x0080
+#define ECB_SES 0x0400
+#define ECB_S_G 0x1000
+#define ECB_DSB 0x4000
+#define ECB_ARS 0x8000
+ short opt2;
+#define ECB_LUN 0x0007
+#define ECB_TAG 0x0008
+#define ECB_TT 0x0030
+#define ECB_ND 0x0040
+#define ECB_DAT 0x0100
+#define ECB_DIR 0x0200
+#define ECB_ST 0x0400
+#define ECB_CHK 0x0800
+#define ECB_REC 0x4000
+#define ECB_NRB 0x8000
+ u_short unused1;
+ physaddr data;
+ u_long datalen;
+ physaddr status;
+ physaddr chain;
+ short unused2;
+ short unused3;
+ physaddr sense;
+ u_char senselen;
+ u_char cdblen;
+ short cksum;
+ u_char cdb[12];
+ /*-----------------end of hardware supported fields----------------*/
+ struct ecb *next; /* in free list */
+ struct scsi_xfer *xs; /* the scsi_xfer for this cmd */
+ int flags;
+#define ECB_FREE 0
+#define ECB_ACTIVE 1
+#define ECB_ABORTED 2
+#define ECB_IMMED 4
+#define ECB_IMMED_FAIL 8
+ struct ahb_dma_seg ahb_dma[AHB_NSEG];
+ struct ahb_ecb_status ecb_status;
+ struct scsi_sense_data ecb_sense;
+ struct ecb *nexthash;
+ physaddr hashkey; /* physaddr of this struct */
+};
+
+struct ahb_data {
+ int flags;
+#define AHB_INIT 0x01;
+ int baseport;
+ struct ecb *ecbhash[ECB_HASH_SIZE];
+ struct ecb *free_ecb;
+ int our_id; /* our scsi id */
+ int vect;
+ struct ecb *immed_ecb; /* an outstanding immediete command */
+ struct scsi_link sc_link;
+ int numecbs;
+} *ahbdata[NAHB];
+
+int ahbprobe();
+int ahbprobe1 __P((struct isa_device *dev));
+int ahb_attach();
+int ahb_init __P((int unit));
+int ahbintr();
+int32 ahb_scsi_cmd();
+void ahb_timeout(caddr_t, int);
+void ahb_done();
+struct ecb *cheat;
+void ahb_free_ecb();
+void ahbminphys();
+struct ecb *ahb_ecb_phys_kv();
+u_int32 ahb_adapter_info();
+
+#define MAX_SLOTS 8 /* XXX should this be 16?? Need EISA spec */
+static ahb_slot = 0; /* slot last board was found in */
+static ahb_unit = 0;
+int ahb_debug = 0;
+#define AHB_SHOWECBS 0x01
+#define AHB_SHOWINTS 0x02
+#define AHB_SHOWCMDS 0x04
+#define AHB_SHOWMISC 0x08
+#define FAIL 1
+#define SUCCESS 0
+#define PAGESIZ 4096
+
+#ifdef KERNEL
+struct isa_driver ahbdriver =
+{
+ ahbprobe,
+ ahb_attach,
+ "ahb"
+};
+
+struct scsi_adapter ahb_switch =
+{
+ ahb_scsi_cmd,
+ ahbminphys,
+ 0,
+ 0,
+ ahb_adapter_info,
+ "ahb",
+ { 0, 0 }
+};
+
+/* the below structure is so we have a default dev struct for our link struct */
+struct scsi_device ahb_dev =
+{
+ NULL, /* Use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+ "ahb",
+ 0,
+ { 0, 0 }
+};
+
+#endif /*KERNEL */
+
+#ifndef KERNEL
+main()
+{
+ printf("ahb_data size is %d\n", sizeof(struct ahb_data));
+ printf("ecb size is %d\n", sizeof(struct ecb));
+}
+
+#else /*KERNEL */
+
+/*
+ * Function to send a command out through a mailbox
+ */
+void
+ahb_send_mbox(int unit, int opcode, int target, struct ecb *ecb)
+{
+ int port = ahbdata[unit]->baseport;
+ int wait = 300; /* 3ms should be enough */
+ int stport = port + G2STAT;
+ int s = splbio();
+
+ while (--wait) {
+ if ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY))
+ == (G2STAT_MBOX_EMPTY))
+ break;
+ DELAY(10);
+ }
+ if (wait == 0) {
+ printf("ahb%d: board not responding\n", unit);
+ Debugger("aha1742");
+ }
+ outl(port + MBOXOUT0, KVTOPHYS(ecb)); /* don't know this will work */
+ outb(port + ATTN, opcode | target);
+
+ splx(s);
+}
+
+/*
+ * Function to poll for command completion when in poll mode
+ */
+int
+ahb_poll(int unit, int wait)
+{ /* in msec */
+ struct ahb_data *ahb = ahbdata[unit];
+ int port = ahb->baseport;
+ int stport = port + G2STAT;
+
+ retry:
+ while (--wait) {
+ if (inb(stport) & G2STAT_INT_PEND)
+ break;
+ DELAY(1000);
+ } if (wait == 0) {
+ printf("ahb%d: board not responding\n", unit);
+ return (EIO);
+ }
+ if (cheat != ahb_ecb_phys_kv(ahb, inl(port + MBOXIN0))) {
+ printf("discarding %x ", inl(port + MBOXIN0));
+ outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT);
+ DELAY(50000);
+ goto retry;
+ }
+ /* don't know this will work */
+ ahbintr(unit);
+ return (0);
+}
+
+/*
+ * Function to send an immediate type command to the adapter
+ */
+void
+ahb_send_immed(int unit, int target, u_long cmd)
+{
+ int port = ahbdata[unit]->baseport;
+ int s = splbio();
+ int stport = port + G2STAT;
+ int wait = 100; /* 1 ms enough? */
+
+ while (--wait) {
+ if ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY))
+ == (G2STAT_MBOX_EMPTY))
+ break;
+ DELAY(10);
+ } if (wait == 0) {
+ printf("ahb%d: board not responding\n", unit);
+ Debugger("aha1742");
+ }
+ outl(port + MBOXOUT0, cmd); /* don't know this will work */
+ outb(port + G2CNTRL, G2CNTRL_SET_HOST_READY);
+ outb(port + ATTN, OP_IMMED | target);
+ splx(s);
+}
+
+/*
+ * Check the slots looking for a board we recognise
+ * If we find one, note it's address (slot) and call
+ * the actual probe routine to check it out.
+ */
+int
+ahbprobe(dev)
+ struct isa_device *dev;
+{
+ int port;
+ u_char byte1, byte2, byte3;
+
+ ahb_slot++;
+ while (ahb_slot <= MAX_SLOTS) {
+ port = 0x1000 * ahb_slot;
+ byte1 = inb(port + HID0);
+ byte2 = inb(port + HID1);
+ byte3 = inb(port + HID2);
+ if (byte1 == 0xff) {
+ ahb_slot++;
+ continue;
+ }
+ if ((CHAR1(byte1, byte2) == 'A')
+ && (CHAR2(byte1, byte2) == 'D')
+ && (CHAR3(byte1, byte2) == 'P')
+ && ((byte3 == 0) || (byte3 == 1))) {
+ dev->id_iobase = port;
+ return ahbprobe1(dev);
+ }
+ ahb_slot++;
+ }
+ return 0;
+}
+
+/*
+ * Check if the device can be found at the port given
+ * and if so, set it up ready for further work
+ * as an argument, takes the isa_device structure from
+ * autoconf.c.
+ */
+int
+ahbprobe1(dev)
+ struct isa_device *dev;
+{
+ /*
+ * find unit and check we have that many defined
+ */
+ int unit = ahb_unit;
+ struct ahb_data *ahb;
+
+ if (unit >= NAHB) {
+ printf("ahb: unit number (%d) too high\n", unit);
+ return 0;
+ }
+ dev->id_unit = unit;
+
+ /*
+ * Allocate a storage area for us
+ */
+ if (ahbdata[unit]) {
+ printf("ahb%d: memory already allocated\n", unit);
+ return 0;
+ }
+ ahb = malloc(sizeof(struct ahb_data), M_TEMP, M_NOWAIT);
+ if (!ahb) {
+ printf("ahb%d: cannot malloc!\n", unit);
+ return 0;
+ }
+ bzero(ahb, sizeof(struct ahb_data));
+ ahbdata[unit] = ahb;
+ ahb->baseport = dev->id_iobase;
+ /*
+ * Try initialise a unit at this location
+ * sets up dma and bus speed, loads ahb->vect
+ */
+ if (ahb_init(unit) != 0) {
+ ahbdata[unit] = NULL;
+ free(ahb, M_TEMP);
+ return (0);
+ }
+ /*
+ * If it's there, put in it's interrupt vectors
+ */
+ dev->id_irq = (1 << ahb->vect);
+ dev->id_drq = -1; /* use EISA dma */
+
+ ahb_unit++;
+ return 0x1000;
+}
+
+/*
+ * Attach all the sub-devices we can find
+ */
+int
+ahb_attach(dev)
+ struct isa_device *dev;
+{
+#ifdef NetBSD
+ int unit = dev->id_masunit;
+#else
+ int unit = dev->id_unit;
+#endif
+ struct ahb_data *ahb = ahbdata[unit];
+
+ /*
+ * fill in the prototype scsi_link.
+ */
+ ahb->sc_link.adapter_unit = unit;
+ ahb->sc_link.adapter_targ = ahb->our_id;
+ ahb->sc_link.adapter = &ahb_switch;
+ ahb->sc_link.device = &ahb_dev;
+
+ /*
+ * ask the adapter what subunits are present
+ */
+ scsi_attachdevs(&(ahb->sc_link));
+
+ return 1;
+}
+
+/*
+ * Return some information to the caller about
+ * the adapter and it's capabilities
+ */
+u_int32
+ahb_adapter_info(unit)
+ int unit;
+{
+ return (2); /* 2 outstanding requests at a time per device */
+}
+
+/*
+ * Catch an interrupt from the adaptor
+ */
+int
+ahbintr(unit)
+ int unit;
+{
+ struct ecb *ecb;
+ unsigned char stat;
+ u_char ahbstat;
+ int target;
+ long int mboxval;
+ struct ahb_data *ahb = ahbdata[unit];
+
+ int port = ahb->baseport;
+
+#ifdef AHBDEBUG
+ printf("ahbintr ");
+#endif /*AHBDEBUG */
+
+ while (inb(port + G2STAT) & G2STAT_INT_PEND) {
+ /*
+ * First get all the information and then
+ * acknowlege the interrupt
+ */
+ ahbstat = inb(port + G2INTST);
+ target = ahbstat & G2INTST_TARGET;
+ stat = ahbstat & G2INTST_INT_STAT;
+ mboxval = inl(port + MBOXIN0); /* don't know this will work */
+ outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT);
+#ifdef AHBDEBUG
+ printf("status = 0x%x ", stat);
+#endif /*AHBDEBUG */
+ /*
+ * Process the completed operation
+ */
+
+ if (stat == AHB_ECB_OK) { /* common case is fast */
+ ecb = ahb_ecb_phys_kv(ahb, mboxval);
+ } else {
+ switch (stat) {
+ case AHB_IMMED_OK:
+ ecb = ahb->immed_ecb;
+ ahb->immed_ecb = 0;
+ break;
+ case AHB_IMMED_ERR:
+ ecb = ahb->immed_ecb;
+ ecb->flags |= ECB_IMMED_FAIL;
+ ahb->immed_ecb = 0;
+ break;
+ case AHB_ASN: /* for target mode */
+ printf("ahb%d: Unexpected ASN interrupt(%x)\n",
+ unit, mboxval);
+ ecb = 0;
+ break;
+ case AHB_HW_ERR:
+ printf("ahb%d: Hardware error interrupt(%x)\n",
+ unit, mboxval);
+ ecb = 0;
+ break;
+ case AHB_ECB_RECOVERED:
+ ecb = ahb_ecb_phys_kv(ahb, mboxval);
+ break;
+ case AHB_ECB_ERR:
+ ecb = ahb_ecb_phys_kv(ahb, mboxval);
+ break;
+ default:
+ printf(" Unknown return from ahb%d(%x)\n", unit, ahbstat);
+ ecb = 0;
+ }
+ } if (ecb) {
+#ifdef AHBDEBUG
+ if (ahb_debug & AHB_SHOWCMDS) {
+ show_scsi_cmd(ecb->xs);
+ }
+ if ((ahb_debug & AHB_SHOWECBS) && ecb)
+ printf("<int ecb(%x)>", ecb);
+#endif /*AHBDEBUG */
+ untimeout((timeout_t)ahb_timeout, (caddr_t)ecb);
+ ahb_done(unit, ecb, ((stat == AHB_ECB_OK) ? SUCCESS : FAIL));
+ }
+ }
+ return 1;
+}
+
+/*
+ * We have a ecb which has been processed by the
+ * adaptor, now we look to see how the operation
+ * went.
+ */
+void
+ahb_done(unit, ecb, state)
+ int unit, state;
+ struct ecb *ecb;
+{
+ struct ahb_ecb_status *stat = &ecb->ecb_status;
+ struct scsi_sense_data *s1, *s2;
+ struct scsi_xfer *xs = ecb->xs;
+
+ SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahb_done\n"));
+ /*
+ * Otherwise, put the results of the operation
+ * into the xfer and call whoever started it
+ */
+ if (ecb->flags & ECB_IMMED) {
+ if (ecb->flags & ECB_IMMED_FAIL) {
+ xs->error = XS_DRIVER_STUFFUP;
+ }
+ goto done;
+ }
+ if ((state == SUCCESS) || (xs->flags & SCSI_ERR_OK)) { /* All went correctly OR errors expected */
+ xs->resid = 0;
+ xs->error = 0;
+ } else {
+
+ s1 = &(ecb->ecb_sense);
+ s2 = &(xs->sense);
+
+ if (stat->ha_status) {
+ switch (stat->ha_status) {
+ case HS_SCSI_RESET_ADAPTER:
+ break;
+ case HS_SCSI_RESET_INCOMING:
+ break;
+ case HS_CMD_ABORTED_HOST: /* No response */
+ case HS_CMD_ABORTED_ADAPTER: /* No response */
+ break;
+ case HS_TIMED_OUT: /* No response */
+#ifdef AHBDEBUG
+ if (ahb_debug & AHB_SHOWMISC) {
+ printf("timeout reported back\n");
+ }
+#endif /*AHBDEBUG */
+ xs->error = XS_TIMEOUT;
+ break;
+ default: /* Other scsi protocol messes */
+ xs->error = XS_DRIVER_STUFFUP;
+#ifdef AHBDEBUG
+ if (ahb_debug & AHB_SHOWMISC) {
+ printf("unexpected ha_status: %x\n",
+ stat->ha_status);
+ }
+#endif /*AHBDEBUG */
+ }
+ } else {
+ switch (stat->targ_status) {
+ case TS_CHECK_CONDITION:
+ /* structure copy!!!!! */
+ *s2 = *s1;
+ xs->error = XS_SENSE;
+ break;
+ case TS_BUSY:
+ xs->error = XS_BUSY;
+ break;
+ default:
+#ifdef AHBDEBUG
+ if (ahb_debug & AHB_SHOWMISC) {
+ printf("unexpected targ_status: %x\n",
+ stat->targ_status);
+ }
+#endif /*AHBDEBUG */
+ xs->error = XS_DRIVER_STUFFUP;
+ }
+ }
+ }
+done: xs->flags |= ITSDONE;
+ ahb_free_ecb(unit, ecb, xs->flags);
+ scsi_done(xs);
+}
+
+/*
+ * A ecb (and hence a mbx-out is put onto the
+ * free list.
+ */
+void
+ahb_free_ecb(unit, ecb, flags)
+ int unit, flags;
+ struct ecb *ecb;
+{
+ unsigned int opri = 0;
+ struct ahb_data *ahb = ahbdata[unit];
+
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+
+ ecb->next = ahb->free_ecb;
+ ahb->free_ecb = ecb;
+ ecb->flags = ECB_FREE;
+ /*
+ * If there were none, wake abybody waiting for
+ * one to come free, starting with queued entries
+ */
+ if (!ecb->next) {
+ wakeup((caddr_t)&ahb->free_ecb);
+ }
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+}
+
+/*
+ * Get a free ecb
+ * If there are none, see if we can allocate a
+ * new one. If so, put it in the hash table too
+ * otherwise either return an error or sleep
+ */
+struct ecb *
+ahb_get_ecb(unit, flags)
+ int unit, flags;
+{
+ struct ahb_data *ahb = ahbdata[unit];
+ unsigned opri = 0;
+ struct ecb *ecbp;
+ int hashnum;
+
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+ /*
+ * If we can and have to, sleep waiting for one to come free
+ * but only if we can't allocate a new one.
+ */
+ while (!(ecbp = ahb->free_ecb)) {
+ if (ahb->numecbs < AHB_ECB_MAX) {
+ ecbp = (struct ecb *) malloc(sizeof(struct ecb),
+ M_TEMP,
+ M_NOWAIT);
+ if (ecbp) {
+ bzero(ecbp, sizeof(struct ecb));
+ ahb->numecbs++;
+ ecbp->flags = ECB_ACTIVE;
+ /*
+ * put in the phystokv hash table
+ * Never gets taken out.
+ */
+ ecbp->hashkey = KVTOPHYS(ecbp);
+ hashnum = ECB_HASH(ecbp->hashkey);
+ ecbp->nexthash = ahb->ecbhash[hashnum];
+ ahb->ecbhash[hashnum] = ecbp;
+ } else {
+ printf("ahb%d: Can't malloc ECB\n", unit);
+ } goto gottit;
+ } else {
+ if (!(flags & SCSI_NOSLEEP)) {
+ tsleep((caddr_t)&ahb->free_ecb, PRIBIO,
+ "ahbecb", 0);
+ }
+ }
+ } if (ecbp) {
+ /* Get ECB from from free list */
+ ahb->free_ecb = ecbp->next;
+ ecbp->flags = ECB_ACTIVE;
+ }
+gottit: if (!(flags & SCSI_NOMASK))
+ splx(opri);
+
+ return (ecbp);
+}
+
+/*
+ * given a physical address, find the ecb that
+ * it corresponds to:
+ */
+struct ecb *
+ahb_ecb_phys_kv(ahb, ecb_phys)
+ struct ahb_data *ahb;
+ physaddr ecb_phys;
+{
+ int hashnum = ECB_HASH(ecb_phys);
+ struct ecb *ecbp = ahb->ecbhash[hashnum];
+
+ while (ecbp) {
+ if (ecbp->hashkey == ecb_phys)
+ break;
+ ecbp = ecbp->nexthash;
+ }
+ return ecbp;
+}
+
+/*
+ * Start the board, ready for normal operation
+ */
+int
+ahb_init(unit)
+ int unit;
+{
+ struct ahb_data *ahb = ahbdata[unit];
+ int port = ahb->baseport;
+ int intdef;
+ int wait = 1000; /* 1 sec enough? */
+ int i;
+ int stport = port + G2STAT;
+#define NO_NO 1
+#ifdef NO_NO
+ /*
+ * reset board, If it doesn't respond, assume
+ * that it's not there.. good for the probe
+ */
+ outb(port + EBCTRL, CDEN); /* enable full card */
+ outb(port + PORTADDR, PORTADDR_ENHANCED);
+
+ outb(port + G2CNTRL, G2CNTRL_HARD_RESET);
+ DELAY(1000);
+ outb(port + G2CNTRL, 0);
+ DELAY(10000);
+ while (--wait) {
+ if ((inb(stport) & G2STAT_BUSY) == 0)
+ break;
+ DELAY(1000);
+ } if (wait == 0) {
+#ifdef AHBDEBUG
+ if (ahb_debug & AHB_SHOWMISC)
+ printf("ahb_init: No answer from aha1742 board\n");
+#endif /*AHBDEBUG */
+ return (ENXIO);
+ }
+ i = inb(port + MBOXIN0) & 0xff;
+ if (i) {
+ printf("self test failed, val = 0x%x\n", i);
+ return (EIO);
+ }
+#endif
+ while (inb(stport) & G2STAT_INT_PEND) {
+ printf(".");
+ outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT);
+ DELAY(10000);
+ }
+ outb(port + EBCTRL, CDEN); /* enable full card */
+ outb(port + PORTADDR, PORTADDR_ENHANCED);
+ /*
+ * Assume we have a board at this stage
+ * setup dma channel from jumpers and save int
+ * level
+ */
+ printf("ahb%d: reading board settings, ", unit);
+
+ intdef = inb(port + INTDEF);
+ switch (intdef & 0x07) {
+ case INT9:
+ ahb->vect = 9;
+ break;
+ case INT10:
+ ahb->vect = 10;
+ break;
+ case INT11:
+ ahb->vect = 11;
+ break;
+ case INT12:
+ ahb->vect = 12;
+ break;
+ case INT14:
+ ahb->vect = 14;
+ break;
+ case INT15:
+ ahb->vect = 15;
+ break;
+ default:
+ printf("illegal int setting\n");
+ return (EIO);
+ }
+ printf("int=%d\n", ahb->vect);
+
+ outb(port + INTDEF, (intdef | INTEN)); /* make sure we can interrupt */
+
+ /* who are we on the scsi bus? */
+ ahb->our_id = (inb(port + SCSIDEF) & HSCSIID);
+
+ /*
+ * Note that we are going and return (to probe)
+ */
+ ahb->flags |= AHB_INIT;
+ return (0);
+}
+
+#ifndef min
+#define min(x,y) (x < y ? x : y)
+#endif /* min */
+
+void
+ahbminphys(bp)
+ struct buf *bp;
+{
+ if (bp->b_bcount > ((AHB_NSEG - 1) * PAGESIZ)) {
+ bp->b_bcount = ((AHB_NSEG - 1) * PAGESIZ);
+ }
+}
+
+/*
+ * start a scsi operation given the command and
+ * the data address. Also needs the unit, target
+ * and lu
+ */
+int32
+ahb_scsi_cmd(xs)
+ struct scsi_xfer *xs;
+{
+ struct ecb *ecb;
+ struct ahb_dma_seg *sg;
+ int seg; /* scatter gather seg being worked on */
+ int thiskv;
+ physaddr thisphys, nextphys;
+ int unit = xs->sc_link->adapter_unit;
+ int bytes_this_seg, bytes_this_page, datalen, flags;
+ struct ahb_data *ahb = ahbdata[unit];
+ int s;
+
+ SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahb_scsi_cmd\n"));
+ /*
+ * get a ecb (mbox-out) to use. If the transfer
+ * is from a buf (possibly from interrupt time)
+ * then we can't allow it to sleep
+ */
+ flags = xs->flags;
+ if (xs->bp)
+ flags |= (SCSI_NOSLEEP); /* just to be sure */
+ if (flags & ITSDONE) {
+ printf("ahb%d: Already done?", unit);
+ xs->flags &= ~ITSDONE;
+ }
+ if (!(flags & INUSE)) {
+ printf("ahb%d: Not in use?", unit);
+ xs->flags |= INUSE;
+ }
+ if (!(ecb = ahb_get_ecb(unit, flags))) {
+ xs->error = XS_DRIVER_STUFFUP;
+ return (TRY_AGAIN_LATER);
+ }
+ cheat = ecb;
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("start ecb(%x)\n", ecb));
+ ecb->xs = xs;
+ /*
+ * If it's a reset, we need to do an 'immediate'
+ * command, and store it's ecb for later
+ * if there is already an immediate waiting,
+ * then WE must wait
+ */
+ if (flags & SCSI_RESET) {
+ ecb->flags |= ECB_IMMED;
+ if (ahb->immed_ecb) {
+ return (TRY_AGAIN_LATER);
+ }
+ ahb->immed_ecb = ecb;
+ if (!(flags & SCSI_NOMASK)) {
+ s = splbio();
+ ahb_send_immed(unit, xs->sc_link->target, AHB_TARG_RESET);
+ timeout(ahb_timeout, (caddr_t)ecb, (xs->timeout * hz) / 1000);
+ splx(s);
+ return (SUCCESSFULLY_QUEUED);
+ } else {
+ ahb_send_immed(unit, xs->sc_link->target, AHB_TARG_RESET);
+ /*
+ * If we can't use interrupts, poll on completion
+ */
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("wait\n"));
+ if (ahb_poll(unit, xs->timeout)) {
+ ahb_free_ecb(unit, ecb, flags);
+ xs->error = XS_TIMEOUT;
+ return (HAD_ERROR);
+ }
+ return (COMPLETE);
+ }
+ }
+ /*
+ * Put all the arguments for the xfer in the ecb
+ */
+ ecb->opcode = ECB_SCSI_OP;
+ ecb->opt1 = ECB_SES | ECB_DSB | ECB_ARS;
+ if (xs->datalen) {
+ ecb->opt1 |= ECB_S_G;
+ }
+ ecb->opt2 = xs->sc_link->lun | ECB_NRB;
+ ecb->cdblen = xs->cmdlen;
+ ecb->sense = KVTOPHYS(&(ecb->ecb_sense));
+ ecb->senselen = sizeof(ecb->ecb_sense);
+ ecb->status = KVTOPHYS(&(ecb->ecb_status));
+
+ if (xs->datalen) { /* should use S/G only if not zero length */
+ ecb->data = KVTOPHYS(ecb->ahb_dma);
+ sg = ecb->ahb_dma;
+ seg = 0;
+#ifdef TFS
+ if (flags & SCSI_DATA_UIO) {
+ iovp = ((struct uio *) xs->data)->uio_iov;
+ datalen = ((struct uio *) xs->data)->uio_iovcnt;
+ xs->datalen = 0;
+ while ((datalen) && (seg < AHB_NSEG)) {
+ sg->addr = (physaddr) iovp->iov_base;
+ xs->datalen += sg->len = iovp->iov_len;
+ SC_DEBUGN(xs->sc_link, SDEV_DB4,
+ ("(0x%x@0x%x)", iovp->iov_len
+ ,iovp->iov_base));
+ sg++;
+ iovp++;
+ seg++;
+ datalen--;
+ }
+ }
+ else
+#endif /*TFS */
+ {
+ /*
+ * Set up the scatter gather block
+ */
+
+ SC_DEBUG(xs->sc_link, SDEV_DB4,
+ ("%d @0x%x:- ", xs->datalen, xs->data));
+ datalen = xs->datalen;
+ thiskv = (int) xs->data;
+ thisphys = KVTOPHYS(thiskv);
+
+ while ((datalen) && (seg < AHB_NSEG)) {
+ bytes_this_seg = 0;
+
+ /* put in the base address */
+ sg->addr = thisphys;
+
+ SC_DEBUGN(xs->sc_link, SDEV_DB4, ("0x%x", thisphys));
+
+ /* do it at least once */
+ nextphys = thisphys;
+ while ((datalen) && (thisphys == nextphys)) {
+ /*
+ * This page is contiguous (physically) with
+ * the the last, just extend the length
+ */
+ /* how far to the end of the page */
+ nextphys = (thisphys & (~(PAGESIZ - 1)))
+ + PAGESIZ;
+ bytes_this_page = nextphys - thisphys;
+ /**** or the data ****/
+ bytes_this_page = min(bytes_this_page
+ ,datalen);
+ bytes_this_seg += bytes_this_page;
+ datalen -= bytes_this_page;
+
+ /* get more ready for the next page */
+ thiskv = (thiskv & (~(PAGESIZ - 1)))
+ + PAGESIZ;
+ if (datalen)
+ thisphys = KVTOPHYS(thiskv);
+ }
+ /*
+ * next page isn't contiguous, finish the seg
+ */
+ SC_DEBUGN(xs->sc_link, SDEV_DB4,
+ ("(0x%x)", bytes_this_seg));
+ sg->len = bytes_this_seg;
+ sg++;
+ seg++;
+ }
+ } /*end of iov/kv decision */
+ ecb->datalen = seg * sizeof(struct ahb_dma_seg);
+ SC_DEBUGN(xs->sc_link, SDEV_DB4, ("\n"));
+ if (datalen) { /* there's still data, must have run out of segs! */
+ printf("ahb_scsi_cmd%d: more than %d DMA segs\n",
+ unit, AHB_NSEG);
+ xs->error = XS_DRIVER_STUFFUP;
+ ahb_free_ecb(unit, ecb, flags);
+ return (HAD_ERROR);
+ }
+ } else { /* No data xfer, use non S/G values */
+ ecb->data = (physaddr) 0;
+ ecb->datalen = 0;
+ } ecb->chain = (physaddr) 0;
+ /*
+ * Put the scsi command in the ecb and start it
+ */
+ bcopy(xs->cmd, ecb->cdb, xs->cmdlen);
+ /*
+ * Usually return SUCCESSFULLY QUEUED
+ */
+ if (!(flags & SCSI_NOMASK)) {
+ s = splbio();
+ ahb_send_mbox(unit, OP_START_ECB, xs->sc_link->target, ecb);
+ timeout(ahb_timeout, (caddr_t)ecb, (xs->timeout * hz) / 1000);
+ splx(s);
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_sent\n"));
+ return (SUCCESSFULLY_QUEUED);
+ }
+ /*
+ * If we can't use interrupts, poll on completion
+ */
+ ahb_send_mbox(unit, OP_START_ECB, xs->sc_link->target, ecb);
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_wait\n"));
+ do {
+ if (ahb_poll(unit, xs->timeout)) {
+ if (!(xs->flags & SCSI_SILENT))
+ printf("cmd fail\n");
+ ahb_send_mbox(unit, OP_ABORT_ECB, xs->sc_link->target, ecb);
+ if (ahb_poll(unit, 2000)) {
+ printf("abort failed in wait\n");
+ ahb_free_ecb(unit, ecb, flags);
+ }
+ xs->error = XS_DRIVER_STUFFUP;
+ return (HAD_ERROR);
+ }
+ } while (!(xs->flags & ITSDONE)); /* something (?) else finished */
+ if (xs->error) {
+ return (HAD_ERROR);
+ }
+ return (COMPLETE);
+}
+
+void
+ahb_timeout(caddr_t arg1, int arg2)
+{
+ struct ecb * ecb = (struct ecb *)arg1;
+ int unit;
+ struct ahb_data *ahb;
+ int s = splbio();
+
+ unit = ecb->xs->sc_link->adapter_unit;
+ ahb = ahbdata[unit];
+ printf("ahb%d:%d:%d (%s%d) timed out ", unit
+ ,ecb->xs->sc_link->target
+ ,ecb->xs->sc_link->lun
+ ,ecb->xs->sc_link->device->name
+ ,ecb->xs->sc_link->dev_unit);
+
+#ifdef AHBDEBUG
+ if (ahb_debug & AHB_SHOWECBS)
+ ahb_print_active_ecb(unit);
+#endif /*AHBDEBUG */
+
+ /*
+ * If it's immediate, don't try abort it
+ */
+ if (ecb->flags & ECB_IMMED) {
+ ecb->xs->retries = 0; /* I MEAN IT ! */
+ ecb->flags |= ECB_IMMED_FAIL;
+ ahb_done(unit, ecb, FAIL);
+ splx(s);
+ return;
+ }
+ /*
+ * If it has been through before, then
+ * a previous abort has failed, don't
+ * try abort again
+ */
+ if (ecb->flags == ECB_ABORTED) {
+ /*
+ * abort timed out
+ */
+ printf("AGAIN");
+ ecb->xs->retries = 0; /* I MEAN IT ! */
+ ecb->ecb_status.ha_status = HS_CMD_ABORTED_HOST;
+ ahb_done(unit, ecb, FAIL);
+ } else { /* abort the operation that has timed out */
+ printf("\n");
+ ahb_send_mbox(unit, OP_ABORT_ECB, ecb->xs->sc_link->target, ecb);
+ /* 2 secs for the abort */
+ timeout(ahb_timeout, (caddr_t)ecb, 2 * hz);
+ ecb->flags = ECB_ABORTED;
+ }
+ splx(s);
+}
+
+#ifdef AHBDEBUG
+void
+ahb_print_ecb(ecb)
+ struct ecb *ecb;
+{
+ printf("ecb:%x op:%x cmdlen:%d senlen:%d\n"
+ ,ecb
+ ,ecb->opcode
+ ,ecb->cdblen
+ ,ecb->senselen);
+ printf(" datlen:%d hstat:%x tstat:%x flags:%x\n"
+ ,ecb->datalen
+ ,ecb->ecb_status.ha_status
+ ,ecb->ecb_status.targ_status
+ ,ecb->flags);
+ show_scsi_cmd(ecb->xs);
+}
+
+void
+ahb_print_active_ecb(int unit)
+{
+ struct ahb_data *ahb = ahbdata[unit];
+ struct ecb *ecb;
+ int i = 0;
+
+ while (i < ECB_HASH_SIZE) {
+ ecb = ahb->ecbhash[i];
+ while (ecb) {
+ if (ecb->flags != ECB_FREE) {
+ ahb_print_ecb(ecb);
+ }
+ ecb = ecb->nexthash;
+ } i++;
+ }
+}
+#endif /*AHBDEBUG */
+#endif /*KERNEL */
diff --git a/sys/i386/isa/bt742a.c b/sys/i386/isa/bt742a.c
new file mode 100644
index 0000000..ac24e81
--- /dev/null
+++ b/sys/i386/isa/bt742a.c
@@ -0,0 +1,1529 @@
+/*
+ * Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems for use under the MACH(2.5) operating system.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ * $Id: bt742a.c,v 1.14 1994/03/24 02:22:58 davidg Exp $
+ */
+
+/*
+ * bt742a SCSI driver
+ */
+
+#include <sys/types.h>
+
+#ifdef KERNEL /* don't laugh.. it compiles to a program too.. look */
+#include <bt.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#endif /* KERNEL */
+
+#include <i386/isa/isa_device.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#ifdef KERNEL
+#include "ddb.h"
+#include "kernel.h"
+#else /*KERNEL */
+#define NBT 1
+#endif /*KERNEL */
+
+typedef unsigned long int physaddr;
+
+/*
+ * I/O Port Interface
+ */
+
+#define BT_BASE bt->bt_base
+#define BT_CTRL_STAT_PORT (BT_BASE + 0x0) /* control & status */
+#define BT_CMD_DATA_PORT (BT_BASE + 0x1) /* cmds and datas */
+#define BT_INTR_PORT (BT_BASE + 0x2) /* Intr. stat */
+
+/*
+ * BT_CTRL_STAT bits (write)
+ */
+
+#define BT_HRST 0x80 /* Hardware reset */
+#define BT_SRST 0x40 /* Software reset */
+#define BT_IRST 0x20 /* Interrupt reset */
+#define BT_SCRST 0x10 /* SCSI bus reset */
+
+/*
+ * BT_CTRL_STAT bits (read)
+ */
+
+#define BT_STST 0x80 /* Self test in Progress */
+#define BT_DIAGF 0x40 /* Diagnostic Failure */
+#define BT_INIT 0x20 /* Mbx Init required */
+#define BT_IDLE 0x10 /* Host Adapter Idle */
+#define BT_CDF 0x08 /* cmd/data out port full */
+#define BT_DF 0x04 /* Data in port full */
+#define BT_INVDCMD 0x01 /* Invalid command */
+
+/*
+ * BT_CMD_DATA bits (write)
+ */
+
+#define BT_NOP 0x00 /* No operation */
+#define BT_MBX_INIT 0x01 /* Mbx initialization */
+#define BT_START_SCSI 0x02 /* start scsi command */
+#define BT_START_BIOS 0x03 /* start bios command */
+#define BT_INQUIRE 0x04 /* Adapter Inquiry */
+#define BT_MBO_INTR_EN 0x05 /* Enable MBO available interrupt */
+#define BT_SEL_TIMEOUT_SET 0x06 /* set selection time-out */
+#define BT_BUS_ON_TIME_SET 0x07 /* set bus-on time */
+#define BT_BUS_OFF_TIME_SET 0x08 /* set bus-off time */
+#define BT_SPEED_SET 0x09 /* set transfer speed */
+#define BT_DEV_GET 0x0a /* return installed devices */
+#define BT_CONF_GET 0x0b /* return configuration data */
+#define BT_TARGET_EN 0x0c /* enable target mode */
+#define BT_SETUP_GET 0x0d /* return setup data */
+#define BT_WRITE_CH2 0x1a /* write channel 2 buffer */
+#define BT_READ_CH2 0x1b /* read channel 2 buffer */
+#define BT_WRITE_FIFO 0x1c /* write fifo buffer */
+#define BT_READ_FIFO 0x1d /* read fifo buffer */
+#define BT_ECHO 0x1e /* Echo command data */
+#define BT_MBX_INIT_EXTENDED 0x81 /* Mbx initialization */
+#define BT_INQUIRE_EXTENDED 0x8D /* Adapter Setup Inquiry */
+
+/* Follows command appeared at FirmWare 3.31 */
+#define BT_ROUND_ROBIN 0x8f /* Enable/Disable(default) round robin */
+#define BT_DISABLE 0x00 /* Parameter value for Disable */
+#define BT_ENABLE 0x01 /* Parameter value for Enable */
+
+struct bt_cmd_buf {
+ u_char byte[16];
+};
+
+/*
+ * BT_INTR_PORT bits (read)
+ */
+
+#define BT_ANY_INTR 0x80 /* Any interrupt */
+#define BT_SCRD 0x08 /* SCSI reset detected */
+#define BT_HACC 0x04 /* Command complete */
+#define BT_MBOA 0x02 /* MBX out empty */
+#define BT_MBIF 0x01 /* MBX in full */
+
+/*
+ * Mail box defs etc.
+ * these could be bigger but we need the bt_data to fit on a single page..
+ */
+
+#define BT_MBX_SIZE 16 /* mail box size (MAX 255 MBxs) */
+ /* don't need that many really */
+#define BT_CCB_MAX 32 /* store up to 32CCBs at any one time */
+ /* in bt742a H/W ( Not MAX ? ) */
+#define CCB_HASH_SIZE 32 /* when we have a physical addr. for */
+ /* a ccb and need to find the ccb in */
+ /* space, look it up in the hash table */
+#define CCB_HASH_SHIFT 9 /* only hash on multiples of 512 */
+#define CCB_HASH(x) ((((long int)(x))>>CCB_HASH_SHIFT) % CCB_HASH_SIZE)
+
+#define bt_nextmbx( wmb, mbx, mbio ) \
+ if ( (wmb) == &((mbx)->mbio[BT_MBX_SIZE - 1 ]) ) \
+ (wmb) = &((mbx)->mbio[0]); \
+ else \
+ (wmb)++;
+
+typedef struct bt_mbx_out {
+ physaddr ccb_addr;
+ unsigned char dummy[3];
+ unsigned char cmd;
+} BT_MBO;
+
+typedef struct bt_mbx_in {
+ physaddr ccb_addr;
+ unsigned char btstat;
+ unsigned char sdstat;
+ unsigned char dummy;
+ unsigned char stat;
+} BT_MBI;
+
+struct bt_mbx {
+ BT_MBO mbo[BT_MBX_SIZE];
+ BT_MBI mbi[BT_MBX_SIZE];
+ BT_MBO *tmbo; /* Target Mail Box out */
+ BT_MBI *tmbi; /* Target Mail Box in */
+};
+
+/*
+ * mbo.cmd values
+ */
+
+#define BT_MBO_FREE 0x0 /* MBO entry is free */
+#define BT_MBO_START 0x1 /* MBO activate entry */
+#define BT_MBO_ABORT 0x2 /* MBO abort entry */
+
+/*
+ * mbi.stat values
+ */
+
+#define BT_MBI_FREE 0x0 /* MBI entry is free */
+#define BT_MBI_OK 0x1 /* completed without error */
+#define BT_MBI_ABORT 0x2 /* aborted ccb */
+#define BT_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */
+#define BT_MBI_ERROR 0x4 /* Completed with error */
+
+#if defined(BIG_DMA)
+WARNING...THIS WON'T WORK(won't fit on 1 page)
+/* #define BT_NSEG 2048*/ /* Number of scatter gather segments - to much vm */
+#define BT_NSEG 128
+#else
+#define BT_NSEG 33
+#endif /* BIG_DMA */
+
+struct bt_scat_gath {
+ unsigned long seg_len;
+ physaddr seg_addr;
+};
+
+struct bt_ccb {
+ unsigned char opcode;
+ unsigned char:3, data_in:1, data_out:1,:3;
+ unsigned char scsi_cmd_length;
+ unsigned char req_sense_length;
+ /*------------------------------------longword boundary */
+ unsigned long data_length;
+ /*------------------------------------longword boundary */
+ physaddr data_addr;
+ /*------------------------------------longword boundary */
+ unsigned char dummy[2];
+ unsigned char host_stat;
+ unsigned char target_stat;
+ /*------------------------------------longword boundary */
+ unsigned char target;
+ unsigned char lun;
+ unsigned char scsi_cmd[12]; /* 12 bytes (bytes only) */
+ unsigned char dummy2[1];
+ unsigned char link_id;
+ /*------------------------------------4 longword boundary */
+ physaddr link_addr;
+ /*------------------------------------longword boundary */
+ physaddr sense_ptr;
+/*-----end of HW fields-------------------------------longword boundary */
+ struct scsi_sense_data scsi_sense;
+ /*------------------------------------longword boundary */
+ struct bt_scat_gath scat_gath[BT_NSEG];
+ /*------------------------------------longword boundary */
+ struct bt_ccb *next;
+ /*------------------------------------longword boundary */
+ struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */
+ /*------------------------------------longword boundary */
+ struct bt_mbx_out *mbx; /* pointer to mail box */
+ /*------------------------------------longword boundary */
+ int flags;
+#define CCB_FREE 0
+#define CCB_ACTIVE 1
+#define CCB_ABORTED 2
+ /*------------------------------------longword boundary */
+ struct bt_ccb *nexthash; /* if two hash the same */
+ /*------------------------------------longword boundary */
+ physaddr hashkey; /*physaddr of this ccb */
+ /*------------------------------------longword boundary */
+};
+
+/*
+ * opcode fields
+ */
+
+#define BT_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */
+#define BT_TARGET_CCB 0x01 /* SCSI Target CCB */
+#define BT_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scattter gather */
+#define BT_RESET_CCB 0x81 /* SCSI Bus reset */
+
+/*
+ * bt_ccb.host_stat values
+ */
+
+#define BT_OK 0x00 /* cmd ok */
+#define BT_LINK_OK 0x0a /* Link cmd ok */
+#define BT_LINK_IT 0x0b /* Link cmd ok + int */
+#define BT_SEL_TIMEOUT 0x11 /* Selection time out */
+#define BT_OVER_UNDER 0x12 /* Data over/under run */
+#define BT_BUS_FREE 0x13 /* Bus dropped at unexpected time */
+#define BT_INV_BUS 0x14 /* Invalid bus phase/sequence */
+#define BT_BAD_MBO 0x15 /* Incorrect MBO cmd */
+#define BT_BAD_CCB 0x16 /* Incorrect ccb opcode */
+#define BT_BAD_LINK 0x17 /* Not same values of LUN for links */
+#define BT_INV_TARGET 0x18 /* Invalid target direction */
+#define BT_CCB_DUP 0x19 /* Duplicate CCB received */
+#define BT_INV_CCB 0x1a /* Invalid CCB or segment list */
+#define BT_ABORTED 42 /* pseudo value from driver */
+
+struct bt_boardID {
+ u_char board_type;
+ u_char custom_feture;
+ char firm_revision;
+ u_char firm_version;
+};
+
+struct bt_setup {
+ u_char sync_neg:1;
+ u_char parity:1;
+ u_char :6;
+ u_char speed;
+ u_char bus_on;
+ u_char bus_off;
+ u_char num_mbx;
+ u_char mbx[3]; /*XXX */
+ /* doesn't make sense with 32bit addresses */
+ struct {
+ u_char offset:4;
+ u_char period:3;
+ u_char valid:1;
+ } sync[8];
+ u_char disc_sts;
+};
+
+struct bt_config {
+ u_char chan;
+ u_char intr;
+ u_char scsi_dev:3;
+ u_char :5;
+};
+
+#define INT9 0x01
+#define INT10 0x02
+#define INT11 0x04
+#define INT12 0x08
+#define INT14 0x20
+#define INT15 0x40
+
+#define EISADMA 0x00
+#define CHAN0 0x01
+#define CHAN5 0x20
+#define CHAN6 0x40
+#define CHAN7 0x80
+
+#define KVTOPHYS(x) vtophys(x)
+#define PAGESIZ 4096
+#define INVALIDATE_CACHE {asm volatile( ".byte 0x0F ;.byte 0x08" ); }
+
+u_char bt_scratch_buf[256];
+
+struct bt_data {
+ short bt_base; /* base port for each board */
+ struct bt_mbx bt_mbx; /* all our mailboxes */
+ struct bt_ccb *bt_ccb_free; /* list of free CCBs */
+ struct bt_ccb *ccbhash[CCB_HASH_SIZE]; /* phys to kv hash */
+ int bt_int; /* int. read off board */
+ int bt_dma; /* DMA channel read of board */
+ int bt_scsi_dev; /* adapters scsi id */
+ int numccbs; /* how many we have malloc'd */
+ struct scsi_link sc_link; /* prototype for devs */
+} *btdata[NBT];
+
+/***********debug values *************/
+#define BT_SHOWCCBS 0x01
+#define BT_SHOWINTS 0x02
+#define BT_SHOWCMDS 0x04
+#define BT_SHOWMISC 0x08
+int bt_debug = 0;
+
+#ifdef KERNEL
+int btprobe();
+int btattach();
+int btintr();
+int32 bt_scsi_cmd();
+void bt_timeout(caddr_t, int);
+void bt_inquire_setup_information();
+void bt_done();
+void btminphys();
+u_int32 bt_adapter_info();
+struct bt_ccb *bt_get_ccb();
+struct bt_ccb *bt_ccb_phys_kv();
+
+static int btunit = 0;
+
+struct isa_driver btdriver =
+{
+ btprobe,
+ btattach,
+ "bt"
+};
+
+struct scsi_adapter bt_switch =
+{
+ bt_scsi_cmd,
+ btminphys,
+ 0,
+ 0,
+ bt_adapter_info,
+ "bt",
+ 0, 0
+};
+
+/* the below structure is so we have a default dev struct for out link struct */
+struct scsi_device bt_dev =
+{
+ NULL, /* Use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+ "bt",
+ 0,
+ 0, 0
+};
+
+#endif /*KERNEL */
+
+#define BT_RESET_TIMEOUT 1000
+#ifndef KERNEL
+main()
+{
+ printf("bt_data is %d bytes\n", sizeof(struct bt_data));
+ printf("bt_ccb is %d bytes\n", sizeof(struct bt_ccb));
+ printf("bt_mbx is %d bytes\n", sizeof(struct bt_mbx));
+}
+
+#else /*KERNEL */
+
+/*
+ * bt_cmd(unit,icnt, ocnt,wait, retval, opcode, args)
+ *
+ * Activate Adapter command
+ * icnt: number of args (outbound bytes written after opcode)
+ * ocnt: number of expected returned bytes
+ * wait: number of seconds to wait for response
+ * retval: buffer where to place returned bytes
+ * opcode: opcode BT_NOP, BT_MBX_INIT, BT_START_SCSI ...
+ * args: parameters
+ *
+ * Performs an adapter command through the ports. Not to be confused with a
+ * scsi command, which is read in via the dma; one of the adapter commands
+ * tells it to read in a scsi command.
+ */
+int
+bt_cmd(unit, icnt, ocnt, wait, retval, opcode, args)
+ int unit;
+ int icnt;
+ int ocnt;
+ int wait;
+ u_char *retval;
+ unsigned opcode;
+ u_char args;
+{
+ struct bt_data *bt = btdata[unit];
+ unsigned *ic = &opcode;
+ u_char oc;
+ register i;
+ int sts;
+
+ /*
+ * multiply the wait argument by a big constant
+ * zero defaults to 1
+ */
+ if (wait)
+ wait *= 100000;
+ else
+ wait = 100000;
+ /*
+ * Wait for the adapter to go idle, unless it's one of
+ * the commands which don't need this
+ */
+ if (opcode != BT_MBX_INIT && opcode != BT_START_SCSI) {
+ i = 100000; /* 1 sec? */
+ while (--i) {
+ sts = inb(BT_CTRL_STAT_PORT);
+ if (sts & BT_IDLE) {
+ break;
+ }
+ DELAY(10);
+ }
+ if (i == 0) {
+ printf("bt%d: bt_cmd, host not idle(0x%x)\n", unit, sts);
+ return (ENXIO);
+ }
+ }
+ /*
+ * Now that it is idle, if we expect output, preflush the
+ * queue feeding to us.
+ */
+ if (ocnt) {
+ while ((inb(BT_CTRL_STAT_PORT)) & BT_DF)
+ inb(BT_CMD_DATA_PORT);
+ }
+ /*
+ * Output the command and the number of arguments given
+ * for each byte, first check the port is empty.
+ */
+ icnt++;
+ /* include the command */
+ while (icnt--) {
+ sts = inb(BT_CTRL_STAT_PORT);
+ for (i = wait; i; i--) {
+ sts = inb(BT_CTRL_STAT_PORT);
+ if (!(sts & BT_CDF))
+ break;
+ DELAY(10);
+ }
+ if (i == 0) {
+ printf("bt%d: bt_cmd, cmd/data port full\n", unit);
+ outb(BT_CTRL_STAT_PORT, BT_SRST);
+ return (ENXIO);
+ }
+ outb(BT_CMD_DATA_PORT, (u_char) (*ic++));
+ }
+ /*
+ * If we expect input, loop that many times, each time,
+ * looking for the data register to have valid data
+ */
+ while (ocnt--) {
+ sts = inb(BT_CTRL_STAT_PORT);
+ for (i = wait; i; i--) {
+ sts = inb(BT_CTRL_STAT_PORT);
+ if (sts & BT_DF)
+ break;
+ DELAY(10);
+ }
+ if (i == 0) {
+ printf("bt%d: bt_cmd, cmd/data port empty %d\n",
+ unit, ocnt);
+ return (ENXIO);
+ }
+ oc = inb(BT_CMD_DATA_PORT);
+ if (retval)
+ *retval++ = oc;
+ }
+ /*
+ * Wait for the board to report a finised instruction
+ */
+ i = 100000; /* 1 sec? */
+ while (--i) {
+ sts = inb(BT_INTR_PORT);
+ if (sts & BT_HACC) {
+ break;
+ }
+ DELAY(10);
+ }
+ if (i == 0) {
+ printf("bt%d: bt_cmd, host not finished(0x%x)\n", unit, sts);
+ return (ENXIO);
+ }
+ outb(BT_CTRL_STAT_PORT, BT_IRST);
+ return (0);
+}
+
+/*
+ * Check if the device can be found at the port given
+ * and if so, set it up ready for further work
+ * as an argument, takes the isa_device structure from
+ * autoconf.c
+ */
+int
+btprobe(dev)
+ struct isa_device *dev;
+{
+ /*
+ * find unit and check we have that many defined
+ */
+ int unit = btunit;
+ struct bt_data *bt;
+
+ if (unit >= NBT) {
+ printf("bt%d: unit number too high\n", unit);
+ return 0;
+ }
+ /*
+ * Allocate a storage area for us
+ */
+ if (btdata[unit]) {
+ printf("bt%d: memory already allocated\n", unit);
+ return 0;
+ }
+ bt = malloc(sizeof(struct bt_data), M_TEMP, M_NOWAIT);
+ if (!bt) {
+ printf("bt%d: cannot malloc!\n", unit);
+ return 0;
+ }
+ bzero(bt, sizeof(struct bt_data));
+ btdata[unit] = bt;
+ bt->bt_base = dev->id_iobase;
+
+ /*
+ * Try initialise a unit at this location
+ * sets up dma and bus speed, loads bt->bt_int
+ */
+ if (bt_init(unit) != 0) {
+ btdata[unit] = NULL;
+ free(bt, M_TEMP);
+ return 0;
+ }
+ /*
+ * If it's there, put in it's interrupt vectors
+ */ dev->id_unit = unit;
+ dev->id_irq = (1 << bt->bt_int);
+ dev->id_drq = bt->bt_dma;
+
+ btunit++;
+ return 1;
+}
+
+/*
+ * Attach all the sub-devices we can find
+ */
+int
+btattach(dev)
+ struct isa_device *dev;
+{
+ int unit = dev->id_unit;
+ struct bt_data *bt = btdata[unit];
+
+ /*
+ * fill in the prototype scsi_link.
+ */
+ bt->sc_link.adapter_unit = unit;
+ bt->sc_link.adapter_targ = bt->bt_scsi_dev;
+ bt->sc_link.adapter = &bt_switch;
+ bt->sc_link.device = &bt_dev;
+ bt->sc_link.flags = SDEV_BOUNCE;
+
+ /*
+ * ask the adapter what subunits are present
+ */
+ scsi_attachdevs(&(bt->sc_link));
+ return 1;
+}
+
+/*
+ * Return some information to the caller about the adapter and its
+ * capabilities.
+ */
+u_int32
+bt_adapter_info(unit)
+ int unit;
+{
+ return (2); /* 2 outstanding requests at a time per device */
+}
+
+/*
+ * Catch an interrupt from the adaptor
+ */
+int
+btintr(unit)
+ int unit;
+{
+ struct bt_data *bt = btdata[unit];
+ BT_MBI *wmbi;
+ struct bt_mbx *wmbx;
+ struct bt_ccb *ccb;
+ unsigned char stat;
+ int i, wait;
+ int found = 0;
+
+#ifdef UTEST
+ printf("btintr ");
+#endif
+ /*
+ * First acknowlege the interrupt, Then if it's
+ * not telling about a completed operation
+ * just return.
+ */
+ stat = inb(BT_INTR_PORT);
+
+ /* Mail Box out empty ? */
+ if (stat & BT_MBOA) {
+ printf("bt%d: Available Free mbo post\n", unit);
+ /* Disable MBO available interrupt */
+ outb(BT_CMD_DATA_PORT, BT_MBO_INTR_EN);
+ wait = 100000; /* 1 sec enough? */
+ for (i = wait; i; i--) {
+ if (!(inb(BT_CTRL_STAT_PORT) & BT_CDF))
+ break;
+ DELAY(10);
+ }
+ if (i == 0) {
+ printf("bt%d: bt_intr, cmd/data port full\n", unit);
+ outb(BT_CTRL_STAT_PORT, BT_SRST);
+ return 1;
+ }
+ outb(BT_CMD_DATA_PORT, 0x00); /* Disable */
+ wakeup((caddr_t)&bt->bt_mbx);
+ outb(BT_CTRL_STAT_PORT, BT_IRST);
+ return 1;
+ }
+ if (!(stat & BT_MBIF)) {
+ outb(BT_CTRL_STAT_PORT, BT_IRST);
+ return 1;
+ }
+ /*
+ * If it IS then process the competed operation
+ */
+ wmbx = &bt->bt_mbx;
+ wmbi = wmbx->tmbi;
+ AGAIN:
+ while (wmbi->stat != BT_MBI_FREE) {
+ ccb = bt_ccb_phys_kv(bt, (wmbi->ccb_addr));
+ if (!ccb) {
+ wmbi->stat = BT_MBI_FREE;
+ printf("bt: BAD CCB ADDR!\n");
+ continue;
+ }
+ found++;
+ if ((stat = wmbi->stat) != BT_MBI_OK) {
+ switch (stat) {
+ case BT_MBI_ABORT:
+#ifdef UTEST
+ if (bt_debug & BT_SHOWMISC)
+ printf("abort ");
+#endif
+ ccb->host_stat = BT_ABORTED;
+ break;
+
+ case BT_MBI_UNKNOWN:
+ ccb = (struct bt_ccb *) 0;
+#ifdef UTEST
+ if (bt_debug & BT_SHOWMISC)
+ printf("unknown ccb for abort");
+#endif
+ break;
+
+ case BT_MBI_ERROR:
+ break;
+
+ default:
+ panic("Impossible mbxi status");
+
+ }
+#ifdef UTEST
+ if ((bt_debug & BT_SHOWCMDS) && ccb) {
+ u_char *cp;
+ cp = ccb->scsi_cmd;
+ printf("op=%x %x %x %x %x %x\n",
+ cp[0], cp[1], cp[2],
+ cp[3], cp[4], cp[5]);
+ printf("stat %x for mbi addr = 0x%08x\n"
+ ,wmbi->stat, wmbi);
+ printf("addr = 0x%x\n", ccb);
+ }
+#endif
+ }
+ wmbi->stat = BT_MBI_FREE;
+ if (ccb) {
+ untimeout(bt_timeout, (caddr_t)ccb);
+ bt_done(unit, ccb);
+ }
+ /* Set the IN mail Box pointer for next */ bt_nextmbx(wmbi, wmbx, mbi);
+ }
+ if (!found) {
+ for (i = 0; i < BT_MBX_SIZE; i++) {
+ if (wmbi->stat != BT_MBI_FREE) {
+ found++;
+ break;
+ }
+ bt_nextmbx(wmbi, wmbx, mbi);
+ }
+ if (!found) {
+ printf("bt%d: mbi at 0x%08x should be found, stat=%02x..resync\n",
+ unit, wmbi, stat);
+ } else {
+ found = 0;
+ goto AGAIN;
+ }
+ }
+ wmbx->tmbi = wmbi;
+ outb(BT_CTRL_STAT_PORT, BT_IRST);
+ return 1;
+}
+
+/*
+ * A ccb is put onto the free list.
+ */
+void
+bt_free_ccb(unit, ccb, flags)
+ int unit;
+ struct bt_ccb *ccb;
+ int flags;
+{
+ struct bt_data *bt = btdata[unit];
+ unsigned int opri = 0;
+
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+
+ ccb->next = bt->bt_ccb_free;
+ bt->bt_ccb_free = ccb;
+ ccb->flags = CCB_FREE;
+ /*
+ * If there were none, wake anybody waiting for one to come free,
+ * starting with queued entries.
+ */
+ if (!ccb->next) {
+ wakeup((caddr_t)&bt->bt_ccb_free);
+ }
+
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+}
+
+/*
+ * Get a free ccb
+ *
+ * If there are none, see if we can allocate a new one. If so, put it in
+ * the hash table too otherwise either return an error or sleep.
+ */
+struct bt_ccb *
+bt_get_ccb(unit, flags)
+ int unit;
+ int flags;
+{
+ struct bt_data *bt = btdata[unit];
+ unsigned opri = 0;
+ struct bt_ccb *ccbp;
+ struct bt_mbx *wmbx; /* Mail Box pointer specified unit */
+ BT_MBO *wmbo; /* Out Mail Box pointer */
+ int hashnum;
+
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+ /*
+ * If we can and have to, sleep waiting for one to come free
+ * but only if we can't allocate a new one.
+ */
+ while (!(ccbp = bt->bt_ccb_free)) {
+ if (bt->numccbs < BT_CCB_MAX) {
+ if (ccbp = (struct bt_ccb *) malloc(sizeof(struct bt_ccb),
+ M_TEMP,
+ M_NOWAIT)) {
+ bzero(ccbp, sizeof(struct bt_ccb));
+ bt->numccbs++;
+ ccbp->flags = CCB_ACTIVE;
+ /*
+ * put in the phystokv hash table
+ * Never gets taken out.
+ */
+ ccbp->hashkey = KVTOPHYS(ccbp);
+ hashnum = CCB_HASH(ccbp->hashkey);
+ ccbp->nexthash = bt->ccbhash[hashnum];
+ bt->ccbhash[hashnum] = ccbp;
+ } else {
+ printf("bt%d: Can't malloc CCB\n", unit);
+ }
+ goto gottit;
+ } else {
+ if (!(flags & SCSI_NOSLEEP)) {
+ tsleep((caddr_t)&bt->bt_ccb_free, PRIBIO,
+ "btccb", 0);
+ }
+ }
+ }
+ if (ccbp) {
+ /* Get CCB from from free list */
+ bt->bt_ccb_free = ccbp->next;
+ ccbp->flags = CCB_ACTIVE;
+ }
+ gottit:
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+
+ return (ccbp);
+}
+
+/*
+ * given a physical address, find the ccb that
+ * it corresponds to:
+ */
+struct bt_ccb *
+bt_ccb_phys_kv(bt, ccb_phys)
+ struct bt_data *bt;
+ physaddr ccb_phys;
+{
+ int hashnum = CCB_HASH(ccb_phys);
+ struct bt_ccb *ccbp = bt->ccbhash[hashnum];
+
+ while (ccbp) {
+ if (ccbp->hashkey == ccb_phys)
+ break;
+ ccbp = ccbp->nexthash;
+ }
+ return ccbp;
+}
+
+/*
+ * Get a MBO and then Send it
+ */
+BT_MBO *
+bt_send_mbo(int unit, int flags, int cmd, struct bt_ccb *ccb)
+{
+ struct bt_data *bt = btdata[unit];
+ unsigned opri = 0;
+ BT_MBO *wmbo; /* Mail Box Out pointer */
+ struct bt_mbx *wmbx; /* Mail Box pointer specified unit */
+ int i, wait;
+
+ wmbx = &bt->bt_mbx;
+
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+
+ /* Get the Target OUT mail Box pointer and move to Next */
+ wmbo = wmbx->tmbo;
+ wmbx->tmbo = (wmbo == &(wmbx->mbo[BT_MBX_SIZE - 1]) ?
+ &(wmbx->mbo[0]) : wmbo + 1);
+
+ /*
+ * Check the outmail box is free or not.
+ * Note: Under the normal operation, it shuld NOT happen to wait.
+ */
+ while (wmbo->cmd != BT_MBO_FREE) {
+ wait = 100000; /* 1 sec enough? */
+ /* Enable MBO available interrupt */
+ outb(BT_CMD_DATA_PORT, BT_MBO_INTR_EN);
+ for (i = wait; i; i--) {
+ if (!(inb(BT_CTRL_STAT_PORT) & BT_CDF))
+ break;
+ DELAY(10);
+ }
+ if (i == 0) {
+ printf("bt%d: bt_send_mbo, cmd/data port full\n", unit);
+ outb(BT_CTRL_STAT_PORT, BT_SRST);
+ return ((BT_MBO *) 0);
+ }
+ outb(BT_CMD_DATA_PORT, 0x01); /* Enable */
+ tsleep((caddr_t)wmbx, PRIBIO, "btsend", 0);
+ /* XXX */ /*can't do this! */
+ /* May be servicing an int */
+ }
+ /* Link CCB to the Mail Box */
+ wmbo->ccb_addr = KVTOPHYS(ccb);
+ ccb->mbx = wmbo;
+ wmbo->cmd = cmd;
+
+ /* Send it! */
+ outb(BT_CMD_DATA_PORT, BT_START_SCSI);
+
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+
+ return (wmbo);
+}
+
+/*
+ * We have a ccb which has been processed by the
+ * adaptor, now we look to see how the operation
+ * went. Wake up the owner if waiting
+ */
+void
+bt_done(unit, ccb)
+ int unit;
+ struct bt_ccb *ccb;
+{
+ struct bt_data *bt = btdata[unit];
+ struct scsi_sense_data *s1, *s2;
+ struct scsi_xfer *xs = ccb->xfer;
+
+ SC_DEBUG(xs->sc_link, SDEV_DB2, ("bt_done\n"));
+ /*
+ * Otherwise, put the results of the operation
+ * into the xfer and call whoever started it
+ */
+ if ((ccb->host_stat != BT_OK || ccb->target_stat != SCSI_OK)
+ && (!(xs->flags & SCSI_ERR_OK))) {
+
+ s1 = &(ccb->scsi_sense);
+ s2 = &(xs->sense);
+
+ if (ccb->host_stat) {
+ switch (ccb->host_stat) {
+ case BT_ABORTED: /* No response */
+ case BT_SEL_TIMEOUT: /* No response */
+ SC_DEBUG(xs->sc_link, SDEV_DB3,
+ ("timeout reported back\n"));
+ xs->error = XS_TIMEOUT;
+ break;
+ default: /* Other scsi protocol messes */
+ xs->error = XS_DRIVER_STUFFUP;
+ SC_DEBUG(xs->sc_link, SDEV_DB3,
+ ("unexpected host_stat: %x\n",
+ ccb->host_stat));
+ }
+ } else {
+ switch (ccb->target_stat) {
+ case 0x02:
+ *s2 = *s1;
+ xs->error = XS_SENSE;
+ break;
+ case 0x08:
+ xs->error = XS_BUSY;
+ break;
+ default:
+ SC_DEBUG(xs->sc_link, SDEV_DB3,
+ ("unexpected target_stat: %x\n",
+ ccb->target_stat));
+ xs->error = XS_DRIVER_STUFFUP;
+ }
+ }
+ } else { /* All went correctly OR errors expected */
+ xs->resid = 0;
+ }
+ xs->flags |= ITSDONE;
+ bt_free_ccb(unit, ccb, xs->flags);
+ scsi_done(xs);
+}
+
+/*
+ * Start the board, ready for normal operation
+ */
+int
+bt_init(unit)
+ int unit;
+{
+ struct bt_data *bt = btdata[unit];
+ unsigned char ad[4];
+ volatile int i, sts;
+ struct bt_config conf;
+
+ /*
+ * reset board, If it doesn't respond, assume
+ * that it's not there.. good for the probe
+ */
+
+ outb(BT_CTRL_STAT_PORT, BT_HRST | BT_SRST);
+
+ for (i = BT_RESET_TIMEOUT; i; i--) {
+ sts = inb(BT_CTRL_STAT_PORT);
+ if (sts == (BT_IDLE | BT_INIT))
+ break;
+ DELAY(1000);
+ }
+ if (i == 0) {
+#ifdef UTEST
+ printf("bt_init: No answer from bt742a board\n");
+#endif
+ return (ENXIO);
+ }
+ /*
+ * Assume we have a board at this stage
+ * setup dma channel from jumpers and save int
+ * level
+ */
+ printf("bt%d: reading board settings, ", unit);
+
+ bt_cmd(unit, 0, sizeof(conf), 0, &conf, BT_CONF_GET);
+ switch (conf.chan) {
+ case EISADMA:
+ bt->bt_dma = -1;
+ break;
+ case CHAN0:
+ outb(0x0b, 0x0c);
+ outb(0x0a, 0x00);
+ bt->bt_dma = 0;
+ break;
+ case CHAN5:
+ outb(0xd6, 0xc1);
+ outb(0xd4, 0x01);
+ bt->bt_dma = 5;
+ break;
+ case CHAN6:
+ outb(0xd6, 0xc2);
+ outb(0xd4, 0x02);
+ bt->bt_dma = 6;
+ break;
+ case CHAN7:
+ outb(0xd6, 0xc3);
+ outb(0xd4, 0x03);
+ bt->bt_dma = 7;
+ break;
+ default:
+ printf("illegal dma setting %x\n", conf.chan);
+ return (EIO);
+ }
+ if (bt->bt_dma == -1)
+ printf("eisa dma, ");
+ else
+ printf("dma=%d, ", bt->bt_dma);
+
+ switch (conf.intr) {
+ case INT9:
+ bt->bt_int = 9;
+ break;
+ case INT10:
+ bt->bt_int = 10;
+ break;
+ case INT11:
+ bt->bt_int = 11;
+ break;
+ case INT12:
+ bt->bt_int = 12;
+ break;
+ case INT14:
+ bt->bt_int = 14;
+ break;
+ case INT15:
+ bt->bt_int = 15;
+ break;
+ default:
+ printf("illegal int setting\n");
+ return (EIO);
+ }
+ printf("int=%d\n", bt->bt_int);
+
+ /* who are we on the scsi bus */
+ bt->bt_scsi_dev = conf.scsi_dev;
+ /*
+ * Initialize mail box
+ */
+ *((physaddr *) ad) = KVTOPHYS(&bt->bt_mbx);
+ bt_cmd(unit, 5, 0, 0, 0, BT_MBX_INIT_EXTENDED
+ ,BT_MBX_SIZE
+ ,ad[0]
+ ,ad[1]
+ ,ad[2]
+ ,ad[3]);
+
+ /*
+ * Set Pointer chain null for just in case
+ * Link the ccb's into a free-list W/O mbox
+ * Initialize mail box status to free
+ */
+ if (bt->bt_ccb_free != (struct bt_ccb *) 0) {
+ printf("bt%d: bt_ccb_free is NOT initialized but init here\n",
+ unit);
+ bt->bt_ccb_free = (struct bt_ccb *) 0;
+ }
+ for (i = 0; i < BT_MBX_SIZE; i++) {
+ bt->bt_mbx.mbo[i].cmd = BT_MBO_FREE;
+ bt->bt_mbx.mbi[i].stat = BT_MBI_FREE;
+ }
+ /*
+ * Set up initial mail box for round-robin operation.
+ */
+ bt->bt_mbx.tmbo = &bt->bt_mbx.mbo[0];
+ bt->bt_mbx.tmbi = &bt->bt_mbx.mbi[0];
+ bt_inquire_setup_information(unit);
+
+ /* Enable round-robin scheme - appeared at firmware rev. 3.31 */
+ bt_cmd(unit, 1, 0, 0, 0, BT_ROUND_ROBIN, BT_ENABLE);
+
+ /*
+ * Note that we are going and return (to probe)
+ */
+ return 0;
+}
+
+void
+bt_inquire_setup_information(unit)
+ int unit;
+{
+ struct bt_data *bt = btdata[unit];
+ struct bt_setup setup;
+ struct bt_boardID bID;
+ int i;
+
+ /* Inquire Board ID to Bt742 for firmware version */
+ bt_cmd(unit, 0, sizeof(bID), 0, &bID, BT_INQUIRE);
+ printf("bt%d: version %c.%c, ",
+ unit, bID.firm_revision, bID.firm_version);
+
+ /* Obtain setup information from Bt742. */
+ bt_cmd(unit, 1, sizeof(setup), 0, &setup, BT_SETUP_GET, sizeof(setup));
+
+ if (setup.sync_neg) {
+ printf("sync, ");
+ } else {
+ printf("async, ");
+ }
+ if (setup.parity) {
+ printf("parity, ");
+ } else {
+ printf("no parity, ");
+ }
+ printf("%d mbxs, %d ccbs\n", setup.num_mbx, bt->numccbs);
+
+ for (i = 0; i < 8; i++) {
+ if (!setup.sync[i].offset &&
+ !setup.sync[i].period &&
+ !setup.sync[i].valid)
+ continue;
+
+ printf("bt%d: dev%02d Offset=%d,Transfer period=%d, Synchronous? %s",
+ unit, i,
+ setup.sync[i].offset, setup.sync[i].period,
+ setup.sync[i].valid ? "Yes" : "No");
+ }
+}
+
+#ifndef min
+#define min(x,y) (x < y ? x : y)
+#endif /* min */
+
+void
+btminphys(bp)
+ struct buf *bp;
+{
+ if (bp->b_bcount > ((BT_NSEG - 1) * PAGESIZ)) {
+ bp->b_bcount = ((BT_NSEG - 1) * PAGESIZ);
+ }
+}
+
+/*
+ * start a scsi operation given the command and the data address. Also needs
+ * the unit, target and lu.
+ */
+int32
+bt_scsi_cmd(xs)
+ struct scsi_xfer *xs;
+{
+ struct scsi_sense_data *s1, *s2;
+ struct bt_ccb *ccb;
+ struct bt_scat_gath *sg;
+ int seg; /* scatter gather seg being worked on */
+ int i = 0;
+ int c = 0;
+ int thiskv;
+ physaddr thisphys, nextphys;
+ int unit = xs->sc_link->adapter_unit;
+ int bytes_this_seg, bytes_this_page, datalen, flags;
+ struct iovec *iovp;
+ struct bt_data *bt = btdata[unit];
+ BT_MBO *mbo;
+
+ SC_DEBUG(xs->sc_link, SDEV_DB2, ("bt_scsi_cmd\n"));
+ /*
+ * get a ccb (mbox-out) to use. If the transfer
+ * is from a buf (possibly from interrupt time)
+ * then we can't allow it to sleep
+ */
+ flags = xs->flags;
+ if (xs->bp)
+ flags |= (SCSI_NOSLEEP); /* just to be sure */
+ if (flags & ITSDONE) {
+ printf("bt%d: Already done?\n", unit);
+ xs->flags &= ~ITSDONE;
+ }
+ if (!(flags & INUSE)) {
+ printf("bt%d: Not in use?\n", unit);
+ xs->flags |= INUSE;
+ }
+ if (!(ccb = bt_get_ccb(unit, flags))) {
+ xs->error = XS_DRIVER_STUFFUP;
+ return (TRY_AGAIN_LATER);
+ }
+ SC_DEBUG(xs->sc_link, SDEV_DB3,
+ ("start ccb(%x)\n", ccb));
+ /*
+ * Put all the arguments for the xfer in the ccb
+ */
+ ccb->xfer = xs;
+ if (flags & SCSI_RESET) {
+ ccb->opcode = BT_RESET_CCB;
+ } else {
+ /* can't use S/G if zero length */
+ ccb->opcode = (xs->datalen ?
+ BT_INIT_SCAT_GATH_CCB
+ : BT_INITIATOR_CCB);
+ }
+ ccb->target = xs->sc_link->target;
+ ccb->data_out = 0;
+ ccb->data_in = 0;
+ ccb->lun = xs->sc_link->lun;
+ ccb->scsi_cmd_length = xs->cmdlen;
+ ccb->sense_ptr = KVTOPHYS(&(ccb->scsi_sense));
+ ccb->req_sense_length = sizeof(ccb->scsi_sense);
+
+ if ((xs->datalen) && (!(flags & SCSI_RESET))) { /* can use S/G only if not zero length */
+ ccb->data_addr = KVTOPHYS(ccb->scat_gath);
+ sg = ccb->scat_gath;
+ seg = 0;
+#ifdef TFS
+ if (flags & SCSI_DATA_UIO) {
+ iovp = ((struct uio *) xs->data)->uio_iov;
+ datalen = ((struct uio *) xs->data)->uio_iovcnt;
+ xs->datalen = 0;
+ while ((datalen) && (seg < BT_NSEG)) {
+ sg->seg_addr = (physaddr) iovp->iov_base;
+ xs->datalen += sg->seg_len = iovp->iov_len;
+ SC_DEBUGN(xs->sc_link, SDEV_DB4, ("(0x%x@0x%x)"
+ ,iovp->iov_len, iovp->iov_base));
+ sg++;
+ iovp++;
+ seg++;
+ datalen--;
+ }
+ } else
+#endif /* TFS */
+ {
+ /*
+ * Set up the scatter gather block
+ */
+
+ SC_DEBUG(xs->sc_link, SDEV_DB4,
+ ("%d @0x%x:- ", xs->datalen, xs->data));
+ datalen = xs->datalen;
+ thiskv = (int) xs->data;
+ thisphys = KVTOPHYS(thiskv);
+
+ while ((datalen) && (seg < BT_NSEG)) {
+ bytes_this_seg = 0;
+
+ /* put in the base address */
+ sg->seg_addr = thisphys;
+
+ SC_DEBUGN(xs->sc_link, SDEV_DB4,
+ ("0x%x", thisphys));
+
+ /* do it at least once */
+ nextphys = thisphys;
+ while ((datalen) && (thisphys == nextphys))
+ /*
+ * This page is contiguous (physically) with
+ * the the last, just extend the length
+ */
+ {
+
+ /* check it fits on the ISA bus */
+ if (thisphys > 0xFFFFFF)
+ {
+ printf("bt%d: DMA beyond"
+ " end Of ISA\n", unit);
+ xs->error = XS_DRIVER_STUFFUP;
+ bt_free_ccb(unit, ccb, flags);
+ return (HAD_ERROR);
+ }
+ /** how far to the end of the page ***/
+ /* how far to the end of the page */
+ nextphys = (thisphys & (~(PAGESIZ - 1)))
+ + PAGESIZ;
+ bytes_this_page = nextphys - thisphys;
+ /**** or the data ****/
+ bytes_this_page = min(bytes_this_page
+ ,datalen);
+ bytes_this_seg += bytes_this_page;
+ datalen -= bytes_this_page;
+
+ /* get more ready for the next page */
+ thiskv = (thiskv & (~(PAGESIZ - 1)))
+ + PAGESIZ;
+ if (datalen)
+ thisphys = KVTOPHYS(thiskv);
+ }
+ /*
+ * next page isn't contiguous, finish the seg
+ */
+ SC_DEBUGN(xs->sc_link, SDEV_DB4,
+ ("(0x%x)", bytes_this_seg));
+ sg->seg_len = bytes_this_seg;
+ sg++;
+ seg++;
+ }
+ }
+ /* end of iov/kv decision */
+ ccb->data_length = seg * sizeof(struct bt_scat_gath);
+ SC_DEBUGN(xs->sc_link, SDEV_DB4, ("\n"));
+ if (datalen) {
+ /*
+ * there's still data, must have run out of segs!
+ */
+ printf("bt%d: bt_scsi_cmd, more than %d DMA segs\n",
+ unit, BT_NSEG);
+ xs->error = XS_DRIVER_STUFFUP;
+ bt_free_ccb(unit, ccb, flags);
+ return (HAD_ERROR);
+ }
+ } else { /* No data xfer, use non S/G values */
+ ccb->data_addr = (physaddr) 0;
+ ccb->data_length = 0;
+ }
+ ccb->link_id = 0;
+ ccb->link_addr = (physaddr) 0;
+ /*
+ * Put the scsi command in the ccb and start it
+ */
+ if (!(flags & SCSI_RESET)) {
+ bcopy(xs->cmd, ccb->scsi_cmd, ccb->scsi_cmd_length);
+ }
+ if (bt_send_mbo(unit, flags, BT_MBO_START, ccb) == (BT_MBO *) 0) {
+ xs->error = XS_DRIVER_STUFFUP;
+ bt_free_ccb(unit, ccb, flags);
+ return (TRY_AGAIN_LATER);
+ }
+ /*
+ * Usually return SUCCESSFULLY QUEUED
+ */
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_sent\n"));
+ if (!(flags & SCSI_NOMASK)) {
+ timeout(bt_timeout, (caddr_t)ccb, (xs->timeout * hz) / 1000);
+ return (SUCCESSFULLY_QUEUED);
+ }
+ /*
+ * If we can't use interrupts, poll on completion
+ */
+ return (bt_poll(unit, xs, ccb));
+}
+
+/*
+ * Poll a particular unit, looking for a particular xs
+ */
+int
+bt_poll(unit, xs, ccb)
+ int unit;
+ struct scsi_xfer *xs;
+ struct bt_ccb *ccb;
+{
+ struct bt_data *bt = btdata[unit];
+ int done = 0;
+ int count = xs->timeout;
+ u_char stat;
+
+ /* timeouts are in msec, so we loop in 1000 usec cycles */
+ while (count) {
+ /*
+ * If we had interrupts enabled, would we
+ * have got an interrupt?
+ */
+ stat = inb(BT_INTR_PORT);
+ if (stat & BT_ANY_INTR) {
+ btintr(unit);
+ }
+ if (xs->flags & ITSDONE) {
+ break;
+ }
+ DELAY(1000); /* only happens in boot so ok */
+ count--;
+ }
+ if (count == 0) {
+ /*
+ * We timed out, so call the timeout handler manually,
+ * accounting for the fact that the clock is not running yet
+ * by taking out the clock queue entry it makes.
+ */
+ bt_timeout((caddr_t)ccb, 0);
+
+ /*
+ * because we are polling, take out the timeout entry
+ * bt_timeout made
+ */
+ untimeout(bt_timeout, (caddr_t)ccb);
+ count = 2000;
+ while (count) {
+ /*
+ * Once again, wait for the int bit
+ */
+ stat = inb(BT_INTR_PORT);
+ if (stat & BT_ANY_INTR) {
+ btintr(unit);
+ }
+ if (xs->flags & ITSDONE) {
+ break;
+ }
+ DELAY(1000); /* only happens in boot so ok */
+ count--;
+ }
+ if (count == 0) {
+ /*
+ * We timed out again... This is bad. Notice that
+ * this time there is no clock queue entry to remove.
+ */
+ bt_timeout((caddr_t)ccb, 0);
+ }
+ }
+ if (xs->error)
+ return (HAD_ERROR);
+ return (COMPLETE);
+}
+
+void
+bt_timeout(caddr_t arg1, int arg2)
+{
+ struct bt_ccb * ccb = (struct bt_ccb *)arg1;
+ int unit;
+ struct bt_data *bt;
+ int s = splbio();
+
+ unit = ccb->xfer->sc_link->adapter_unit;
+ bt = btdata[unit];
+ printf("bt%d:%d:%d (%s%d) timed out ", unit
+ ,ccb->xfer->sc_link->target
+ ,ccb->xfer->sc_link->lun
+ ,ccb->xfer->sc_link->device->name
+ ,ccb->xfer->sc_link->dev_unit);
+
+#ifdef UTEST
+ bt_print_active_ccbs(unit);
+#endif
+
+ /*
+ * If the ccb's mbx is not free, then the board has gone Far East?
+ */
+ if (bt_ccb_phys_kv(bt, ccb->mbx->ccb_addr) == ccb &&
+ ccb->mbx->cmd != BT_MBO_FREE) {
+ printf("bt%d: not taking commands!\n", unit);
+ Debugger("bt742a");
+ }
+ /*
+ * If it has been through before, then
+ * a previous abort has failed, don't
+ * try abort again
+ */
+ if (ccb->flags == CCB_ABORTED) {
+ /*
+ * abort timed out
+ */
+ printf("bt%d: Abort Operation has timed out\n", unit);
+ ccb->xfer->retries = 0; /* I MEAN IT ! */
+ ccb->host_stat = BT_ABORTED;
+ bt_done(unit, ccb);
+ } else { /* abort the operation that has timed out */
+ printf("bt%d: Try to abort\n", unit);
+ bt_send_mbo(unit, ~SCSI_NOMASK,
+ BT_MBO_ABORT, ccb);
+ /* 2 secs for the abort */
+ timeout(bt_timeout, (caddr_t)ccb, 2 * hz);
+ ccb->flags = CCB_ABORTED;
+ }
+ splx(s);
+}
+
+#ifdef UTEST
+void
+bt_print_ccb(ccb)
+ struct bt_ccb *ccb;
+{
+ printf("ccb:%x op:%x cmdlen:%d senlen:%d\n"
+ ,ccb
+ ,ccb->opcode
+ ,ccb->scsi_cmd_length
+ ,ccb->req_sense_length);
+ printf(" datlen:%d hstat:%x tstat:%x flags:%x\n"
+ ,ccb->data_length
+ ,ccb->host_stat
+ ,ccb->target_stat
+ ,ccb->flags);
+}
+
+void
+bt_print_active_ccbs(int unit)
+{
+ struct bt_data *bt = btdata[unit];
+ struct bt_ccb *ccb;
+ int i = 0;
+
+ while (i < CCB_HASH_SIZE) {
+ ccb = bt->ccbhash[i];
+ while (ccb) {
+ if (ccb->flags != CCB_FREE)
+ bt_print_ccb(ccb);
+ ccb = ccb->nexthash;
+ }
+ i++;
+ }
+}
+#endif /*UTEST */
+#endif /*KERNEL */
diff --git a/sys/i386/isa/clock.c b/sys/i386/isa/clock.c
new file mode 100644
index 0000000..d338cd5
--- /dev/null
+++ b/sys/i386/isa/clock.c
@@ -0,0 +1,430 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz and Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)clock.c 7.2 (Berkeley) 5/12/91
+ * $Id: clock.c,v 1.6 1994/02/06 22:48:13 davidg Exp $
+ */
+
+/*
+ * Primitive clock interrupt routines.
+ */
+#include "param.h"
+#include "systm.h"
+#include "time.h"
+#include "kernel.h"
+#include "machine/segments.h"
+#include "machine/frame.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/rtc.h"
+#include "i386/isa/timerreg.h"
+
+/* X-tals being what they are, it's nice to be able to fudge this one... */
+/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */
+#ifndef TIMER_FREQ
+#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
+#endif
+#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
+
+void hardclock();
+static int beeping;
+int timer0_divisor = TIMER_DIV(100); /* XXX should be hz */
+u_int timer0_prescale;
+static char timer0_state = 0, timer2_state = 0;
+static char timer0_reprogram = 0;
+static void (*timer_func)() = hardclock;
+static void (*new_function)();
+static u_int new_rate;
+static u_int hardclock_divisor;
+
+
+void
+timerintr(struct intrframe frame)
+{
+ timer_func(frame);
+ switch (timer0_state) {
+ case 0:
+ break;
+ case 1:
+ if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
+ hardclock(frame);
+ timer0_prescale = 0;
+ }
+ break;
+ case 2:
+ disable_intr();
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+ outb(TIMER_CNTR0, TIMER_DIV(new_rate)%256);
+ outb(TIMER_CNTR0, TIMER_DIV(new_rate)/256);
+ enable_intr();
+ timer0_divisor = TIMER_DIV(new_rate);
+ timer0_prescale = 0;
+ timer_func = new_function;
+ timer0_state = 1;
+ break;
+ case 3:
+ if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
+ hardclock(frame);
+ disable_intr();
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+ outb(TIMER_CNTR0, TIMER_DIV(hz)%256);
+ outb(TIMER_CNTR0, TIMER_DIV(hz)/256);
+ enable_intr();
+ timer0_divisor = TIMER_DIV(hz);
+ timer0_prescale = 0;
+ timer_func = hardclock;;
+ timer0_state = 0;
+ }
+ break;
+ }
+}
+
+
+int
+acquire_timer0(int rate, void (*function)() )
+{
+ if (timer0_state || !function)
+ return -1;
+
+ new_function = function;
+ new_rate = rate;
+ timer0_state = 2;
+ return 0;
+}
+
+
+int
+acquire_timer2(int mode)
+{
+ if (timer2_state)
+ return -1;
+ timer2_state = 1;
+ outb(TIMER_MODE, TIMER_SEL2 | (mode &0x3f));
+ return 0;
+}
+
+
+int
+release_timer0()
+{
+ if (!timer0_state)
+ return -1;
+ timer0_state = 3;
+ return 0;
+}
+
+
+int
+release_timer2()
+{
+ if (!timer2_state)
+ return -1;
+ timer2_state = 0;
+ outb(TIMER_MODE, TIMER_SEL2|TIMER_SQWAVE|TIMER_16BIT);
+ return 0;
+}
+
+
+static int
+getit()
+{
+ int high, low;
+
+ disable_intr();
+ /* select timer0 and latch counter value */
+ outb(TIMER_MODE, TIMER_SEL0);
+ low = inb(TIMER_CNTR0);
+ high = inb(TIMER_CNTR0);
+ enable_intr();
+ return ((high << 8) | low);
+}
+
+
+/*
+ * Wait "n" microseconds.
+ * Relies on timer 1 counting down from (TIMER_FREQ / hz)
+ * Note: timer had better have been programmed before this is first used!
+ */
+void
+DELAY(int n)
+{
+ int counter_limit, prev_tick, tick, ticks_left, sec, usec;
+
+#ifdef DELAYDEBUG
+ int getit_calls = 1;
+ int n1;
+ static int state = 0;
+
+ if (state == 0) {
+ state = 1;
+ for (n1 = 1; n1 <= 10000000; n1 *= 10)
+ DELAY(n1);
+ state = 2;
+ }
+ if (state == 1)
+ printf("DELAY(%d)...", n);
+#endif
+ /*
+ * Read the counter first, so that the rest of the setup overhead is
+ * counted. Guess the initial overhead is 20 usec (on most systems it
+ * takes about 1.5 usec for each of the i/o's in getit(). The loop
+ * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
+ * multiplications and divisions to scale the count take a while).
+ */
+ prev_tick = getit(0, 0);
+ n -= 20;
+ /*
+ * Calculate (n * (TIMER_FREQ / 1e6)) without using floating point
+ * and without any avoidable overflows.
+ */
+ sec = n / 1000000;
+ usec = n - sec * 1000000;
+ ticks_left = sec * TIMER_FREQ
+ + usec * (TIMER_FREQ / 1000000)
+ + usec * ((TIMER_FREQ % 1000000) / 1000) / 1000
+ + usec * (TIMER_FREQ % 1000) / 1000000;
+
+ while (ticks_left > 0) {
+ tick = getit(0, 0);
+#ifdef DELAYDEBUG
+ ++getit_calls;
+#endif
+ if (tick > prev_tick)
+ ticks_left -= prev_tick - (tick - timer0_divisor);
+ else
+ ticks_left -= prev_tick - tick;
+ prev_tick = tick;
+ }
+#ifdef DELAYDEBUG
+ if (state == 1)
+ printf(" %d calls to getit() at %d usec each\n",
+ getit_calls, (n + 5) / getit_calls);
+#endif
+}
+
+
+static void
+sysbeepstop()
+{
+ outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */
+ release_timer2();
+ beeping = 0;
+}
+
+
+int
+sysbeep(int pitch, int period)
+{
+
+ if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT))
+ return -1;
+ disable_intr();
+ outb(TIMER_CNTR2, pitch);
+ outb(TIMER_CNTR2, (pitch>>8));
+ enable_intr();
+ if (!beeping) {
+ outb(IO_PPI, inb(IO_PPI) | 3); /* enable counter2 output to speaker */
+ beeping = period;
+ timeout(sysbeepstop, 0, period);
+ }
+ return 0;
+}
+
+
+void
+startrtclock()
+{
+ int s;
+
+ /* initialize 8253 clock */
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+
+ /* Correct rounding will buy us a better precision in timekeeping */
+ outb (IO_TIMER1, TIMER_DIV(hz)%256);
+ outb (IO_TIMER1, TIMER_DIV(hz)/256);
+ timer0_divisor = hardclock_divisor = TIMER_DIV(hz);
+
+ /* initialize brain-dead battery powered clock */
+ outb (IO_RTC, RTC_STATUSA);
+ outb (IO_RTC+1, 0x26);
+ outb (IO_RTC, RTC_STATUSB);
+ outb (IO_RTC+1, 2);
+
+ outb (IO_RTC, RTC_DIAG);
+ if (s = inb (IO_RTC+1))
+ printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS);
+}
+
+
+/* convert 2 digit BCD number */
+int
+bcd(int i)
+{
+ return ((i/16)*10 + (i%16));
+}
+
+
+/* convert years to seconds (from 1970) */
+unsigned long
+ytos(int y)
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i = 1970; i < y; i++) {
+ if (i % 4) ret += 365*24*60*60;
+ else ret += 366*24*60*60;
+ }
+ return ret;
+}
+
+
+/* convert months to seconds */
+unsigned long
+mtos(int m, int leap)
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i=1; i<m; i++) {
+ switch(i){
+ case 1: case 3: case 5: case 7: case 8: case 10: case 12:
+ ret += 31*24*60*60; break;
+ case 4: case 6: case 9: case 11:
+ ret += 30*24*60*60; break;
+ case 2:
+ if (leap) ret += 29*24*60*60;
+ else ret += 28*24*60*60;
+ }
+ }
+ return ret;
+}
+
+
+/*
+ * Initialize the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+void
+inittodr(time_t base)
+{
+ unsigned long sec;
+ int leap, day_week, t, yd;
+ int sa,s;
+
+ /* do we have a realtime clock present? (otherwise we loop below) */
+ sa = rtcin(RTC_STATUSA);
+ if (sa == 0xff || sa == 0) return;
+
+ /* ready for a read? */
+ while ((sa&RTCSA_TUP) == RTCSA_TUP)
+ sa = rtcin(RTC_STATUSA);
+
+ sec = bcd(rtcin(RTC_YEAR)) + 1900;
+ if (sec < 1970)
+ sec += 100;
+
+ leap = !(sec % 4); sec = ytos(sec); /* year */
+ yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec+=yd; /* month */
+ t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec+=t; yd+=t; /* date */
+ day_week = rtcin(RTC_WDAY); /* day */
+ sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */
+ sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */
+ sec += bcd(rtcin(RTC_SEC)); /* seconds */
+ sec += tz.tz_minuteswest * 60;
+ time.tv_sec = sec;
+}
+
+
+#ifdef garbage
+/*
+ * Initialze the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+test_inittodr(time_t base)
+{
+
+ outb(IO_RTC,9); /* year */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,8); /* month */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,7); /* day */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,4); /* hour */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,2); /* minutes */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,0); /* seconds */
+ printf("%d\n",bcd(inb(IO_RTC+1)));
+
+ time.tv_sec = base;
+}
+#endif
+
+
+/*
+ * Restart the clock.
+ */
+void
+resettodr()
+{
+}
+
+
+/*
+ * Wire clock interrupt in.
+ */
+#define V(s) __CONCAT(V, s)
+extern void V(clk)();
+
+
+void
+enablertclock()
+{
+ setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL);
+ INTREN(IRQ0);
+}
+
+
+/*
+ * Delay for some number of milliseconds.
+ */
+void
+spinwait(int millisecs)
+{
+ DELAY(1000 * millisecs);
+}
diff --git a/sys/i386/isa/fd.c b/sys/i386/isa/fd.c
new file mode 100644
index 0000000..d05c361
--- /dev/null
+++ b/sys/i386/isa/fd.c
@@ -0,0 +1,1255 @@
+/*#define DEBUG 1*/
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)fd.c 7.4 (Berkeley) 5/25/91
+ * $Id: fd.c,v 1.24 1994/03/08 16:25:29 nate Exp $
+ *
+ */
+
+#include "ft.h"
+#if NFT < 1
+#undef NFDC
+#endif
+#include "fd.h"
+
+#if NFDC > 0
+
+#include <sys/param.h>
+#include <sys/dkbad.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <machine/ioctl_fd.h>
+#include <sys/disklabel.h>
+#include <sys/buf.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+#include <sys/syslog.h>
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/fdreg.h"
+#include "i386/isa/fdc.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/rtc.h"
+
+#if NFT > 0
+extern int ftopen(), ftintr(), ftattach(), ftclose(), ftioctl();
+#endif
+
+#define b_cylin b_resid
+#define FDBLK 512
+
+/* misuse a flag to identify format operation */
+#define B_FORMAT B_XXX
+
+#define NUMTYPES 14
+#define NUMDENS (NUMTYPES - 6)
+
+/* This defines (-1) must match index for fd_types */
+#define F_TAPE_TYPE 0x020 /* bit for fd_types to indicate tape */
+#define NO_TYPE 0 /* must match NO_TYPE in ft.c */
+#define FD_1720 1
+#define FD_1480 2
+#define FD_1440 3
+#define FD_1200 4
+#define FD_820 5
+#define FD_800 6
+#define FD_720 7
+#define FD_360 8
+
+#define FD_1480in5_25 9
+#define FD_1440in5_25 10
+#define FD_820in5_25 11
+#define FD_800in5_25 12
+#define FD_720in5_25 13
+#define FD_360in5_25 14
+
+
+struct fd_type fd_types[NUMTYPES] =
+{
+{ 21,2,0xFF,0x04,82,3444,1,FDC_500KBPS,2,0x0C,2 }, /* 1.72M in HD 3.5in */
+{ 18,2,0xFF,0x1B,82,2952,1,FDC_500KBPS,2,0x6C,1 }, /* 1.48M in HD 3.5in */
+{ 18,2,0xFF,0x1B,80,2880,1,FDC_500KBPS,2,0x6C,1 }, /* 1.44M in HD 3.5in */
+{ 15,2,0xFF,0x1B,80,2400,1,FDC_500KBPS,2,0x54,1 }, /* 1.2M in HD 5.25/3.5 */
+{ 10,2,0xFF,0x10,82,1640,1,FDC_250KBPS,2,0x2E,1 }, /* 820K in HD 3.5in */
+{ 10,2,0xFF,0x10,80,1600,1,FDC_250KBPS,2,0x2E,1 }, /* 800K in HD 3.5in */
+{ 9,2,0xFF,0x20,80,1440,1,FDC_250KBPS,2,0x50,1 }, /* 720K in HD 3.5in */
+{ 9,2,0xFF,0x2A,40, 720,1,FDC_250KBPS,2,0x50,1 }, /* 360K in DD 5.25in */
+
+{ 18,2,0xFF,0x02,82,2952,1,FDC_500KBPS,2,0x02,2 }, /* 1.48M in HD 5.25in */
+{ 18,2,0xFF,0x02,80,2880,1,FDC_500KBPS,2,0x02,2 }, /* 1.44M in HD 5.25in */
+{ 10,2,0xFF,0x10,82,1640,1,FDC_300KBPS,2,0x2E,1 }, /* 820K in HD 5.25in */
+{ 10,2,0xFF,0x10,80,1600,1,FDC_300KBPS,2,0x2E,1 }, /* 800K in HD 5.25in */
+{ 9,2,0xFF,0x20,80,1440,1,FDC_300KBPS,2,0x50,1 }, /* 720K in HD 5.25in */
+{ 9,2,0xFF,0x23,40, 720,2,FDC_300KBPS,2,0x50,1 }, /* 360K in HD 5.25in */
+};
+
+#define DRVS_PER_CTLR 2 /* 2 floppies */
+/***********************************************************************\
+* Per controller structure. *
+\***********************************************************************/
+struct fdc_data fdc_data[NFDC];
+
+/***********************************************************************\
+* Per drive structure. *
+* N per controller (DRVS_PER_CTLR) *
+\***********************************************************************/
+struct fd_data {
+ struct fdc_data *fdc; /* pointer to controller structure */
+ int fdsu; /* this units number on this controller */
+ int type; /* Drive type (HD, DD */
+ struct fd_type *ft; /* pointer to the type descriptor */
+ int flags;
+#define FD_OPEN 0x01 /* it's open */
+#define FD_ACTIVE 0x02 /* it's active */
+#define FD_MOTOR 0x04 /* motor should be on */
+#define FD_MOTOR_WAIT 0x08 /* motor coming up */
+ int skip;
+ int hddrv;
+ int track; /* where we think the head is */
+} fd_data[NFD];
+
+/***********************************************************************\
+* Throughout this file the following conventions will be used: *
+* fd is a pointer to the fd_data struct for the drive in question *
+* fdc is a pointer to the fdc_data struct for the controller *
+* fdu is the floppy drive unit number *
+* fdcu is the floppy controller unit number *
+* fdsu is the floppy drive unit number on that controller. (sub-unit) *
+\***********************************************************************/
+
+#define id_physid id_scsiid /* this biotab field doubles as a field */
+ /* for the physical unit number on the controller */
+
+static int retrier(fdcu_t);
+
+#define DEVIDLE 0
+#define FINDWORK 1
+#define DOSEEK 2
+#define SEEKCOMPLETE 3
+#define IOCOMPLETE 4
+#define RECALCOMPLETE 5
+#define STARTRECAL 6
+#define RESETCTLR 7
+#define SEEKWAIT 8
+#define RECALWAIT 9
+#define MOTORWAIT 10
+#define IOTIMEDOUT 11
+
+#ifdef DEBUG
+char *fdstates[] =
+{
+"DEVIDLE",
+"FINDWORK",
+"DOSEEK",
+"SEEKCOMPLETE",
+"IOCOMPLETE",
+"RECALCOMPLETE",
+"STARTRECAL",
+"RESETCTLR",
+"SEEKWAIT",
+"RECALWAIT",
+"MOTORWAIT",
+"IOTIMEDOUT"
+};
+
+
+int fd_debug = 1;
+#define TRACE0(arg) if(fd_debug) printf(arg)
+#define TRACE1(arg1,arg2) if(fd_debug) printf(arg1,arg2)
+#else /* DEBUG */
+#define TRACE0(arg)
+#define TRACE1(arg1,arg2)
+#endif /* DEBUG */
+
+static void fdstart(fdcu_t);
+void fdintr(fdcu_t);
+static void fd_turnoff(caddr_t, int);
+
+/****************************************************************************/
+/* autoconfiguration stuff */
+/****************************************************************************/
+static int fdprobe(struct isa_device *);
+static int fdattach(struct isa_device *);
+
+struct isa_driver fdcdriver = {
+ fdprobe, fdattach, "fdc",
+};
+
+/*
+ * probe for existance of controller
+ */
+int
+fdprobe(dev)
+ struct isa_device *dev;
+{
+ fdcu_t fdcu = dev->id_unit;
+ if(fdc_data[fdcu].flags & FDC_ATTACHED)
+ {
+ printf("fdc: same unit (%d) used multiple times\n",fdcu);
+ return 0;
+ }
+
+ fdc_data[fdcu].baseport = dev->id_iobase;
+
+ /* First - lets reset the floppy controller */
+
+ outb(dev->id_iobase+fdout,0);
+ DELAY(100);
+ outb(dev->id_iobase+fdout,FDO_FRST);
+
+ /* see if it can handle a command */
+ if (out_fdc(fdcu,NE7CMD_SPECIFY) < 0)
+ {
+ return(0);
+ }
+ out_fdc(fdcu,0xDF);
+ out_fdc(fdcu,2);
+ return (IO_FDCSIZE);
+}
+
+/*
+ * wire controller into system, look for floppy units
+ */
+int
+fdattach(dev)
+ struct isa_device *dev;
+{
+ unsigned fdt,st0, cyl;
+ int hdr;
+ fdu_t fdu;
+ fdcu_t fdcu = dev->id_unit;
+ fdc_p fdc = fdc_data + fdcu;
+ fd_p fd;
+ int fdsu;
+ struct isa_device *fdup;
+
+ fdc->fdcu = fdcu;
+ fdc->flags |= FDC_ATTACHED;
+ fdc->dmachan = dev->id_drq;
+ fdc->state = DEVIDLE;
+ hdr = 0;
+ printf("fdc%d:", fdcu);
+
+ /* check for each floppy drive */
+ for (fdup = isa_biotab_fdc; fdup->id_driver != 0; fdup++) {
+ if (fdup->id_iobase != dev->id_iobase)
+ continue;
+ fdu = fdup->id_unit;
+ fd = &fd_data[fdu];
+ if (fdu >= (NFD+NFT))
+ continue;
+ fdsu = fdup->id_physid;
+ /* look up what bios thinks we have */
+ switch (fdu) {
+ case 0: fdt = (rtcin(RTC_FDISKETTE) & 0xf0);
+ break;
+ case 1: fdt = ((rtcin(RTC_FDISKETTE) << 4) & 0xf0);
+ break;
+ default: fdt = RTCFDT_NONE;
+ break;
+ }
+ /* is there a unit? */
+ if ((fdt == RTCFDT_NONE)
+#if NFT > 0
+ || (fdsu >= DRVS_PER_CTLR)) {
+#else
+ ) {
+ fd->type = NO_TYPE;
+#endif
+#if NFT > 0
+ /* If BIOS says no floppy, or > 2nd device */
+ /* Probe for and attach a floppy tape. */
+ if (ftattach(dev, fdup))
+ continue;
+ if (fdsu < DRVS_PER_CTLR)
+ fd->type = NO_TYPE;
+#endif
+ continue;
+ }
+
+#ifdef notyet
+ /* select it */
+ fd_turnon1(fdu);
+ spinwait(1000); /* 1 sec */
+ out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
+ out_fdc(fdcu,fdsu);
+ spinwait(1000); /* 1 sec */
+
+ /* anything responding */
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (st0 & 0xd0)
+ continue;
+
+#endif
+ fd->track = -2;
+ fd->fdc = fdc;
+ fd->fdsu = fdsu;
+ printf(" [%d: fd%d: ", fdsu, fdu);
+
+ switch (fdt) {
+ case RTCFDT_12M:
+ printf("1.2MB 5.25in]");
+ fd->type = FD_1200;
+ break;
+ case RTCFDT_144M:
+ printf("1.44MB 3.5in]");
+ fd->type = FD_1440;
+ break;
+ case RTCFDT_360K:
+ printf("360KB 5.25in]");
+ fd->type = FD_360;
+ break;
+ case RTCFDT_720K:
+ printf("720KB 3.5in]");
+ fd->type = FD_720;
+ break;
+ default:
+ printf("unknown]");
+ fd->type = NO_TYPE;
+ break;
+ }
+
+ fd_turnoff((caddr_t)fdu, 0);
+ hdr = 1;
+ }
+ printf("\n");
+
+ /* Set transfer to 500kbps */
+ outb(fdc->baseport+fdctl,0); /*XXX*/
+ return 1;
+}
+
+int
+fdsize(dev)
+ dev_t dev;
+{
+ return(0);
+}
+
+/****************************************************************************/
+/* fdstrategy */
+/****************************************************************************/
+void fdstrategy(struct buf *bp)
+{
+ register struct buf *dp,*dp0,*dp1;
+ long nblocks,blknum;
+ int s;
+ fdcu_t fdcu;
+ fdu_t fdu;
+ fdc_p fdc;
+ fd_p fd;
+
+ fdu = FDUNIT(minor(bp->b_dev));
+ fd = &fd_data[fdu];
+ fdc = fd->fdc;
+ fdcu = fdc->fdcu;
+
+#if NFT > 0
+ /* check for controller already busy with tape */
+ if (fdc->flags & FDC_TAPE_BUSY) {
+ bp->b_error = EBUSY;
+ bp->b_flags |= B_ERROR;
+ return;
+ }
+#endif
+ if ((fdu >= NFD) || (bp->b_blkno < 0)) {
+ printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n",
+ fdu, bp->b_blkno, bp->b_bcount);
+ pg("fd:error in fdstrategy");
+ bp->b_error = EINVAL;
+ bp->b_flags |= B_ERROR;
+ goto bad;
+ }
+ /*
+ * Set up block calculations.
+ */
+ blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK;
+ nblocks = fd->ft->size;
+ if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
+ if (blknum == nblocks) {
+ bp->b_resid = bp->b_bcount;
+ } else {
+ bp->b_error = ENOSPC;
+ bp->b_flags |= B_ERROR;
+ }
+ goto bad;
+ }
+ bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads);
+ bp->b_pblkno = bp->b_blkno;
+ dp = &(fdc->head);
+ s = splbio();
+ disksort(dp, bp);
+ untimeout(fd_turnoff, (caddr_t)fdu); /* a good idea */
+ fdstart(fdcu);
+ splx(s);
+ return;
+
+bad:
+ biodone(bp);
+ return;
+}
+
+/****************************************************************************/
+/* motor control stuff */
+/* remember to not deselect the drive we're working on */
+/****************************************************************************/
+void
+set_motor(fdcu, fdu, reset)
+ fdcu_t fdcu;
+ fdu_t fdu;
+ int reset;
+{
+ int m0,m1;
+ int selunit;
+ fd_p fd;
+ if(fd = fdc_data[fdcu].fd)/* yes an assign! */
+ {
+ selunit = fd->fdsu;
+ }
+ else
+ {
+ selunit = 0;
+ }
+ m0 = fd_data[fdcu * DRVS_PER_CTLR + 0].flags & FD_MOTOR;
+ m1 = fd_data[fdcu * DRVS_PER_CTLR + 1].flags & FD_MOTOR;
+ outb(fdc_data[fdcu].baseport+fdout,
+ selunit
+ | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
+ | (m0 ? FDO_MOEN0 : 0)
+ | (m1 ? FDO_MOEN1 : 0));
+ TRACE1("[0x%x->fdout]",(
+ selunit
+ | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
+ | (m0 ? FDO_MOEN0 : 0)
+ | (m1 ? FDO_MOEN1 : 0)));
+}
+
+static void
+fd_turnoff(caddr_t arg1, int arg2)
+{
+ fdu_t fdu = (fdu_t)arg1;
+ int s;
+
+ fd_p fd = fd_data + fdu;
+ s = splbio();
+ fd->flags &= ~FD_MOTOR;
+ set_motor(fd->fdc->fdcu,fd->fdsu,0);
+ splx(s);
+}
+
+void
+fd_motor_on(caddr_t arg1, int arg2)
+{
+ fdu_t fdu = (fdu_t)arg1;
+ int s;
+
+ fd_p fd = fd_data + fdu;
+ s = splbio();
+ fd->flags &= ~FD_MOTOR_WAIT;
+ if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT))
+ {
+ fdintr(fd->fdc->fdcu);
+ }
+ splx(s);
+}
+
+static void fd_turnon1(fdu_t);
+
+void
+fd_turnon(fdu)
+ fdu_t fdu;
+{
+ fd_p fd = fd_data + fdu;
+ if(!(fd->flags & FD_MOTOR))
+ {
+ fd_turnon1(fdu);
+ fd->flags |= FD_MOTOR_WAIT;
+ timeout(fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */
+ }
+}
+
+static void
+fd_turnon1(fdu_t fdu)
+{
+ fd_p fd = fd_data + fdu;
+ fd->flags |= FD_MOTOR;
+ set_motor(fd->fdc->fdcu,fd->fdsu,0);
+}
+
+/****************************************************************************/
+/* fdc in/out */
+/****************************************************************************/
+int
+in_fdc(fdcu)
+ fdcu_t fdcu;
+{
+ int baseport = fdc_data[fdcu].baseport;
+ int i, j = 100000;
+ while ((i = inb(baseport+fdsts) & (NE7_DIO|NE7_RQM))
+ != (NE7_DIO|NE7_RQM) && j-- > 0)
+ if (i == NE7_RQM) return -1;
+ if (j <= 0)
+ return(-1);
+#ifdef DEBUG
+ i = inb(baseport+fddata);
+ TRACE1("[fddata->0x%x]",(unsigned char)i);
+ return(i);
+#else
+ return inb(baseport+fddata);
+#endif
+}
+
+int
+out_fdc(fdcu, x)
+ fdcu_t fdcu;
+ int x;
+{
+ int baseport = fdc_data[fdcu].baseport;
+ int i;
+
+ /* Check that the direction bit is set */
+ i = 100000;
+ while ((inb(baseport+fdsts) & NE7_DIO) && i-- > 0);
+ if (i <= 0) return (-1); /* Floppy timed out */
+
+ /* Check that the floppy controller is ready for a command */
+ i = 100000;
+ while ((inb(baseport+fdsts) & NE7_RQM) == 0 && i-- > 0);
+ if (i <= 0) return (-1); /* Floppy timed out */
+
+ /* Send the command and return */
+ outb(baseport+fddata,x);
+ TRACE1("[0x%x->fddata]",x);
+ return (0);
+}
+
+/****************************************************************************/
+/* fdopen/fdclose */
+/****************************************************************************/
+int
+Fdopen(dev, flags)
+ dev_t dev;
+ int flags;
+{
+ fdu_t fdu = FDUNIT(minor(dev));
+ int type = FDTYPE(minor(dev));
+ fdc_p fdc;
+
+#if NFT > 0
+ /* check for a tape open */
+ if (type & F_TAPE_TYPE)
+ return(ftopen(dev, flags));
+#endif
+ /* check bounds */
+ if (fdu >= NFD)
+ return(ENXIO);
+ fdc = fd_data[fdu].fdc;
+ if ((fdc == NULL) || (fd_data[fdu].type == NO_TYPE))
+ return(ENXIO);
+ if (type > NUMDENS)
+ return(ENXIO);
+ if (type == 0)
+ type = fd_data[fdu].type;
+ else {
+ if (type != fd_data[fdu].type) {
+ switch (fd_data[fdu].type) {
+ case FD_360:
+ return(ENXIO);
+ case FD_720:
+ if ( type != FD_820
+ && type != FD_800
+ )
+ return(ENXIO);
+ break;
+ case FD_1200:
+ switch (type) {
+ case FD_1480:
+ type = FD_1480in5_25;
+ break;
+ case FD_1440:
+ type = FD_1440in5_25;
+ break;
+ case FD_820:
+ type = FD_820in5_25;
+ break;
+ case FD_800:
+ type = FD_800in5_25;
+ break;
+ case FD_720:
+ type = FD_720in5_25;
+ break;
+ case FD_360:
+ type = FD_360in5_25;
+ break;
+ default:
+ return(ENXIO);
+ }
+ break;
+ case FD_1440:
+ if ( type != FD_1720
+ && type != FD_1480
+ && type != FD_1200
+ && type != FD_820
+ && type != FD_800
+ && type != FD_720
+ )
+ return(ENXIO);
+ break;
+ }
+ }
+ }
+ fd_data[fdu].ft = fd_types + type - 1;
+ fd_data[fdu].flags |= FD_OPEN;
+
+ return 0;
+}
+
+int
+fdclose(dev, flags)
+ dev_t dev;
+ int flags;
+{
+ fdu_t fdu = FDUNIT(minor(dev));
+ int type = FDTYPE(minor(dev));
+
+#if NFT > 0
+ if (type & F_TAPE_TYPE)
+ return ftclose(0);
+#endif
+ fd_data[fdu].flags &= ~FD_OPEN;
+ return(0);
+}
+
+
+/***************************************************************\
+* fdstart *
+* We have just queued something.. if the controller is not busy *
+* then simulate the case where it has just finished a command *
+* So that it (the interrupt routine) looks on the queue for more*
+* work to do and picks up what we just added. *
+* If the controller is already busy, we need do nothing, as it *
+* will pick up our work when the present work completes *
+\***************************************************************/
+static void
+fdstart(fdcu)
+ fdcu_t fdcu;
+{
+ register struct buf *dp,*bp;
+ int s;
+ fdu_t fdu;
+
+ s = splbio();
+ if(fdc_data[fdcu].state == DEVIDLE)
+ {
+ fdintr(fdcu);
+ }
+ splx(s);
+}
+
+static void
+fd_timeout(caddr_t arg1, int arg2)
+{
+ fdcu_t fdcu = (fdcu_t)arg1;
+ fdu_t fdu = fdc_data[fdcu].fdu;
+ int st0, st3, cyl;
+ struct buf *dp,*bp;
+ int s;
+
+ dp = &fdc_data[fdcu].head;
+ s = splbio();
+ bp = dp->b_actf;
+
+ out_fdc(fdcu,NE7CMD_SENSED);
+ out_fdc(fdcu,fd_data[fdu].hddrv);
+ st3 = in_fdc(fdcu);
+
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ printf("fd%d: Operation timeout ST0 %b cyl %d ST3 %b\n",
+ fdu,
+ st0,
+ NE7_ST0BITS,
+ cyl,
+ st3,
+ NE7_ST3BITS);
+
+ if (bp)
+ {
+ retrier(fdcu);
+ fdc_data[fdcu].status[0] = 0xc0;
+ fdc_data[fdcu].state = IOTIMEDOUT;
+ if( fdc_data[fdcu].retry < 6)
+ fdc_data[fdcu].retry = 6;
+ }
+ else
+ {
+ fdc_data[fdcu].fd = (fd_p) 0;
+ fdc_data[fdcu].fdu = -1;
+ fdc_data[fdcu].state = DEVIDLE;
+ }
+ fdintr(fdcu);
+ splx(s);
+}
+
+/* just ensure it has the right spl */
+static void
+fd_pseudointr(caddr_t arg1, int arg2)
+{
+ fdcu_t fdcu = (fdcu_t)arg1;
+ int s;
+ s = splbio();
+ fdintr(fdcu);
+ splx(s);
+}
+
+/***********************************************************************\
+* fdintr *
+* keep calling the state machine until it returns a 0 *
+* ALWAYS called at SPLBIO *
+\***********************************************************************/
+void
+fdintr(fdcu_t fdcu)
+{
+ fdc_p fdc = fdc_data + fdcu;
+#if NFT > 0
+ fdu_t fdu = fdc->fdu;
+
+ if (fdc->flags & FDC_TAPE_BUSY)
+ (ftintr(fdu));
+ else
+#endif
+ while(fdstate(fdcu, fdc))
+ ;
+}
+
+/***********************************************************************\
+* The controller state machine. *
+* if it returns a non zero value, it should be called again immediatly *
+\***********************************************************************/
+int
+fdstate(fdcu, fdc)
+ fdcu_t fdcu;
+ fdc_p fdc;
+{
+ int read, format, head, trac, sec = 0, i = 0, s, sectrac, cyl, st0;
+ unsigned long blknum;
+ fdu_t fdu = fdc->fdu;
+ fd_p fd;
+ register struct buf *dp,*bp;
+ struct fd_formb *finfo = NULL;
+
+ dp = &(fdc->head);
+ bp = dp->b_actf;
+ if(!bp)
+ {
+ /***********************************************\
+ * nothing left for this controller to do *
+ * Force into the IDLE state, *
+ \***********************************************/
+ fdc->state = DEVIDLE;
+ if(fdc->fd)
+ {
+ printf("unexpected valid fd pointer (fdu = %d)\n"
+ ,fdc->fdu);
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ }
+ TRACE1("[fdc%d IDLE]",fdcu);
+ return(0);
+ }
+ fdu = FDUNIT(minor(bp->b_dev));
+ fd = fd_data + fdu;
+ if (fdc->fd && (fd != fdc->fd))
+ {
+ printf("confused fd pointers\n");
+ }
+ read = bp->b_flags & B_READ;
+ format = bp->b_flags & B_FORMAT;
+ if(format)
+ finfo = (struct fd_formb *)bp->b_un.b_addr;
+ TRACE1("fd%d",fdu);
+ TRACE1("[%s]",fdstates[fdc->state]);
+ TRACE1("(0x%x)",fd->flags);
+ untimeout(fd_turnoff, (caddr_t)fdu);
+ timeout(fd_turnoff, (caddr_t)fdu, 4 * hz);
+ switch (fdc->state)
+ {
+ case DEVIDLE:
+ case FINDWORK: /* we have found new work */
+ fdc->retry = 0;
+ fd->skip = 0;
+ fdc->fd = fd;
+ fdc->fdu = fdu;
+ outb(fdc->baseport+fdctl, fd->ft->trans);
+ /*******************************************************\
+ * If the next drive has a motor startup pending, then *
+ * it will start up in it's own good time *
+ \*******************************************************/
+ if(fd->flags & FD_MOTOR_WAIT)
+ {
+ fdc->state = MOTORWAIT;
+ return(0); /* come back later */
+ }
+ /*******************************************************\
+ * Maybe if it's not starting, it SHOULD be starting *
+ \*******************************************************/
+ if (!(fd->flags & FD_MOTOR))
+ {
+ fdc->state = MOTORWAIT;
+ fd_turnon(fdu);
+ return(0);
+ }
+ else /* at least make sure we are selected */
+ {
+ set_motor(fdcu,fd->fdsu,0);
+ }
+ fdc->state = DOSEEK;
+ break;
+ case DOSEEK:
+ if (bp->b_cylin == fd->track)
+ {
+ fdc->state = SEEKCOMPLETE;
+ break;
+ }
+ out_fdc(fdcu,NE7CMD_SEEK); /* Seek function */
+ out_fdc(fdcu,fd->fdsu); /* Drive number */
+ out_fdc(fdcu,bp->b_cylin * fd->ft->steptrac);
+ fd->track = -2;
+ fdc->state = SEEKWAIT;
+ timeout(fd_timeout, (caddr_t)fdcu, 2 * hz);
+ return(0); /* will return later */
+ case SEEKWAIT:
+ untimeout(fd_timeout, (caddr_t)fdcu);
+ /* allow heads to settle */
+ timeout(fd_pseudointr, (caddr_t)fdcu, hz / 50);
+ fdc->state = SEEKCOMPLETE;
+ return(0); /* will return later */
+ break;
+
+ case SEEKCOMPLETE : /* SEEK DONE, START DMA */
+ /* Make sure seek really happened*/
+ if(fd->track == -2)
+ {
+ int descyl = bp->b_cylin * fd->ft->steptrac;
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ i = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (cyl != descyl)
+ {
+ printf("fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n",
+ fdu, descyl, cyl, i, NE7_ST0BITS);
+ return(retrier(fdcu));
+ }
+ }
+
+ fd->track = bp->b_cylin;
+ if(format)
+ fd->skip = (char *)&(finfo->fd_formb_cylno(0))
+ - (char *)finfo;
+ isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip,
+ format ? bp->b_bcount : FDBLK, fdc->dmachan);
+ blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
+ + fd->skip/FDBLK;
+ sectrac = fd->ft->sectrac;
+ sec = blknum % (sectrac * fd->ft->heads);
+ head = sec / sectrac;
+ sec = sec % sectrac + 1;
+/*XXX*/ fd->hddrv = ((head&1)<<2)+fdu;
+
+ if(format)
+ {
+ /* formatting */
+ out_fdc(fdcu,/* NE7CMD_FORMAT */ 0x4d);
+ out_fdc(fdcu,head << 2 | fdu);
+ out_fdc(fdcu,finfo->fd_formb_secshift);
+ out_fdc(fdcu,finfo->fd_formb_nsecs);
+ out_fdc(fdcu,finfo->fd_formb_gaplen);
+ out_fdc(fdcu,finfo->fd_formb_fillbyte);
+ }
+ else
+ {
+ if (read)
+ {
+ out_fdc(fdcu,NE7CMD_READ); /* READ */
+ }
+ else
+ {
+ out_fdc(fdcu,NE7CMD_WRITE); /* WRITE */
+ }
+ out_fdc(fdcu,head << 2 | fdu); /* head & unit */
+ out_fdc(fdcu,fd->track); /* track */
+ out_fdc(fdcu,head);
+ out_fdc(fdcu,sec); /* sector XXX +1? */
+ out_fdc(fdcu,fd->ft->secsize); /* sector size */
+ out_fdc(fdcu,sectrac); /* sectors/track */
+ out_fdc(fdcu,fd->ft->gap); /* gap size */
+ out_fdc(fdcu,fd->ft->datalen); /* data length */
+ }
+ fdc->state = IOCOMPLETE;
+ timeout(fd_timeout, (caddr_t)fdcu, 2 * hz);
+ return(0); /* will return later */
+ case IOCOMPLETE: /* IO DONE, post-analyze */
+ untimeout(fd_timeout, (caddr_t)fdcu);
+ for(i=0;i<7;i++)
+ {
+ fdc->status[i] = in_fdc(fdcu);
+ }
+ case IOTIMEDOUT: /*XXX*/
+ isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip,
+ format ? bp->b_bcount : FDBLK, fdc->dmachan);
+ if (fdc->status[0]&0xF8)
+ {
+ if (fdc->status[1] & 0x10) {
+ /*
+ * Operation not completed in reasonable time.
+ * Just restart it, don't increment retry count.
+ * (vak)
+ */
+ fdc->state = SEEKCOMPLETE;
+ return (1);
+ }
+ return(retrier(fdcu));
+ }
+ /* All OK */
+ fd->skip += FDBLK;
+ if (!format && fd->skip < bp->b_bcount)
+ {
+ /* set up next transfer */
+ blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
+ + fd->skip/FDBLK;
+ bp->b_cylin = (blknum / (fd->ft->sectrac * fd->ft->heads));
+ fdc->state = DOSEEK;
+ }
+ else
+ {
+ /* ALL DONE */
+ fd->skip = 0;
+ bp->b_resid = 0;
+ dp->b_actf = bp->av_forw;
+ biodone(bp);
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ fdc->state = FINDWORK;
+ }
+ return(1);
+ case RESETCTLR:
+ /* Try a reset, keep motor on */
+ set_motor(fdcu,fd->fdsu,1);
+ DELAY(100);
+ set_motor(fdcu,fd->fdsu,0);
+ outb(fdc->baseport+fdctl,fd->ft->trans);
+ TRACE1("[0x%x->fdctl]",fd->ft->trans);
+ fdc->retry++;
+ fdc->state = STARTRECAL;
+ break;
+ case STARTRECAL:
+ out_fdc(fdcu,NE7CMD_SPECIFY); /* specify command */
+ out_fdc(fdcu,0xDF);
+ out_fdc(fdcu,2);
+ out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
+ out_fdc(fdcu,fdu);
+ fdc->state = RECALWAIT;
+ return(0); /* will return later */
+ case RECALWAIT:
+ /* allow heads to settle */
+ timeout(fd_pseudointr, (caddr_t)fdcu, hz / 30);
+ fdc->state = RECALCOMPLETE;
+ return(0); /* will return later */
+ case RECALCOMPLETE:
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (cyl != 0)
+ {
+ printf("fd%d: recal failed ST0 %b cyl %d\n", fdu,
+ st0, NE7_ST0BITS, cyl);
+ return(retrier(fdcu));
+ }
+ fd->track = 0;
+ /* Seek (probably) necessary */
+ fdc->state = DOSEEK;
+ return(1); /* will return immediatly */
+ case MOTORWAIT:
+ if(fd->flags & FD_MOTOR_WAIT)
+ {
+ return(0); /* time's not up yet */
+ }
+ fdc->state = DOSEEK;
+ return(1); /* will return immediatly */
+ default:
+ printf("Unexpected FD int->");
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ printf("ST0 = %lx, PCN = %lx\n",i,sec);
+ out_fdc(fdcu,0x4A);
+ out_fdc(fdcu,fd->fdsu);
+ for(i=0;i<7;i++) {
+ fdc->status[i] = in_fdc(fdcu);
+ }
+ printf("intr status :%lx %lx %lx %lx %lx %lx %lx ",
+ fdc->status[0],
+ fdc->status[1],
+ fdc->status[2],
+ fdc->status[3],
+ fdc->status[4],
+ fdc->status[5],
+ fdc->status[6] );
+ return(0);
+ }
+ return(1); /* Come back immediatly to new state */
+}
+
+static int
+retrier(fdcu)
+ fdcu_t fdcu;
+{
+ fdc_p fdc = fdc_data + fdcu;
+ register struct buf *dp,*bp;
+
+ dp = &(fdc->head);
+ bp = dp->b_actf;
+
+ switch(fdc->retry)
+ {
+ case 0: case 1: case 2:
+ fdc->state = SEEKCOMPLETE;
+ break;
+ case 3: case 4: case 5:
+ fdc->state = STARTRECAL;
+ break;
+ case 6:
+ fdc->state = RESETCTLR;
+ break;
+ case 7:
+ break;
+ default:
+ {
+ dev_t sav_b_dev = bp->b_dev;
+ /* Trick diskerr */
+ bp->b_dev = makedev(major(bp->b_dev), (FDUNIT(minor(bp->b_dev))<<3)|3);
+ diskerr(bp, "fd", "hard error", LOG_PRINTF,
+ fdc->fd->skip, (struct disklabel *)NULL);
+ bp->b_dev = sav_b_dev;
+ printf(" (ST0 %b ", fdc->status[0], NE7_ST0BITS);
+ printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS);
+ printf(" ST2 %b ", fdc->status[2], NE7_ST2BITS);
+ printf("cyl %d hd %d sec %d)\n",
+ fdc->status[3], fdc->status[4], fdc->status[5]);
+ }
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ bp->b_resid = bp->b_bcount - fdc->fd->skip;
+ dp->b_actf = bp->av_forw;
+ fdc->fd->skip = 0;
+ biodone(bp);
+ fdc->state = FINDWORK;
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ /* XXX abort current command, if any. */
+ return(1);
+ }
+ fdc->retry++;
+ return(1);
+}
+
+static int
+fdformat(dev, finfo, p)
+ dev_t dev;
+ struct fd_formb *finfo;
+ struct proc *p;
+{
+ fdu_t fdu;
+ fd_p fd;
+
+ struct buf *bp;
+ int rv = 0, s;
+
+ fdu = FDUNIT(minor(dev));
+ fd = &fd_data[fdu];
+
+ /* set up a buffer header for fdstrategy() */
+ bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
+ if(bp == 0)
+ return ENOBUFS;
+ bzero((void *)bp, sizeof(struct buf));
+ bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
+ bp->b_proc = p;
+ bp->b_dev = dev;
+
+ /*
+ * calculate a fake blkno, so fdstrategy() would initiate a
+ * seek to the requested cylinder
+ */
+ bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads)
+ + finfo->head * fd->ft->sectrac) * FDBLK / DEV_BSIZE;
+
+ bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
+ bp->b_un.b_addr = (caddr_t)finfo;
+
+ /* now do the format */
+ fdstrategy(bp);
+
+ /* ...and wait for it to complete */
+ s = splbio();
+ while(!(bp->b_flags & B_DONE))
+ {
+ rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
+ if(rv == EWOULDBLOCK)
+ break;
+ }
+ splx(s);
+
+ if(rv == EWOULDBLOCK)
+ {
+ /* timed out */
+ biodone(bp);
+ rv = EIO;
+ }
+ free(bp, M_TEMP);
+ return rv;
+}
+
+/*
+ * fdioctl() from jc@irbs.UUCP (John Capo)
+ * i386/i386/conf.c needs to have fdioctl() declared and remove the line that
+ * defines fdioctl to be enxio.
+ *
+ * TODO: Reformat.
+ * Think about allocating buffer off stack.
+ * Don't pass uncast 0's and NULL's to read/write/setdisklabel().
+ * Watch out for NetBSD's different *disklabel() interface.
+ *
+ * Added functionality for floppy formatting
+ * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
+ */
+
+int
+fdioctl (dev, cmd, addr, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t addr;
+ int flag;
+ struct proc *p;
+{
+ struct fd_type *fdt;
+ struct disklabel *dl;
+ char buffer[DEV_BSIZE];
+ int error;
+
+#if NFT > 0
+ int type = FDTYPE(minor(dev));
+
+ /* check for a tape ioctl */
+ if (type & F_TAPE_TYPE)
+ return ftioctl(dev, cmd, addr, flag, p);
+#endif
+
+ error = 0;
+
+ switch (cmd)
+ {
+ case DIOCGDINFO:
+ bzero(buffer, sizeof (buffer));
+ dl = (struct disklabel *)buffer;
+ dl->d_secsize = FDBLK;
+ fdt = fd_data[FDUNIT(minor(dev))].ft;
+ dl->d_secpercyl = fdt->size / fdt->tracks;
+ dl->d_type = DTYPE_FLOPPY;
+
+ if (readdisklabel(dev, fdstrategy, dl, NULL, 0, 0) == NULL)
+ error = 0;
+ else
+ error = EINVAL;
+
+ *(struct disklabel *)addr = *dl;
+ break;
+
+ case DIOCSDINFO:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ break;
+
+ case DIOCWLABEL:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ break;
+
+ case DIOCWDINFO:
+ if ((flag & FWRITE) == 0)
+ {
+ error = EBADF;
+ break;
+ }
+
+ dl = (struct disklabel *)addr;
+
+ if (error = setdisklabel ((struct disklabel *)buffer,
+ dl, 0, NULL))
+ break;
+
+ error = writedisklabel(dev, fdstrategy,
+ (struct disklabel *)buffer, NULL);
+ break;
+
+ case FD_FORM:
+ if((flag & FWRITE) == 0)
+ error = EBADF; /* must be opened for writing */
+ else if(((struct fd_formb *)addr)->format_version !=
+ FD_FORMAT_VERSION)
+ error = EINVAL; /* wrong version of formatting prog */
+ else
+ error = fdformat(dev, (struct fd_formb *)addr, p);
+ break;
+
+ case FD_GTYPE: /* get drive type */
+ *(struct fd_type *)addr = *fd_data[FDUNIT(minor(dev))].ft;
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ return (error);
+}
+
+#endif
diff --git a/sys/i386/isa/fdc.h b/sys/i386/isa/fdc.h
new file mode 100644
index 0000000..1542f0e
--- /dev/null
+++ b/sys/i386/isa/fdc.h
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)fd.c 7.4 (Berkeley) 5/25/91
+ * $Id:$
+ *
+ */
+
+
+/***********************************************************************\
+* Per controller structure. *
+\***********************************************************************/
+struct fdc_data
+{
+ int fdcu; /* our unit number */
+ int baseport;
+ int dmachan;
+ int flags;
+#define FDC_ATTACHED 0x01
+#define FDC_HASFTAPE 0x02
+#define FDC_TAPE_BUSY 0x04
+ struct fd_data *fd;
+ int fdu; /* the active drive */
+ struct buf head; /* Head of buf chain */
+ struct buf rhead; /* Raw head of buf chain */
+ int state;
+ int retry;
+ int status[7]; /* copy of the registers */
+};
+
+/***********************************************************************\
+* Throughout this file the following conventions will be used: *
+* fd is a pointer to the fd_data struct for the drive in question *
+* fdc is a pointer to the fdc_data struct for the controller *
+* fdu is the floppy drive unit number *
+* fdcu is the floppy controller unit number *
+* fdsu is the floppy drive unit number on that controller. (sub-unit) *
+\***********************************************************************/
+typedef int fdu_t;
+typedef int fdcu_t;
+typedef int fdsu_t;
+typedef struct fd_data *fd_p;
+typedef struct fdc_data *fdc_p;
+
+#define FDUNIT(s) (((s)>>6)&03)
+#define FDTYPE(s) ((s)&077)
diff --git a/sys/i386/isa/fdreg.h b/sys/i386/isa/fdreg.h
new file mode 100644
index 0000000..5deb02c
--- /dev/null
+++ b/sys/i386/isa/fdreg.h
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)fdreg.h 7.1 (Berkeley) 5/9/91
+ * $Id: fdreg.h,v 1.3 1994/02/07 04:27:10 alm Exp $
+ */
+
+/*
+ * AT floppy controller registers and bitfields
+ */
+
+/* uses NEC765 controller */
+#include "../i386/isa/ic/nec765.h"
+
+/* registers */
+#define fdout 2 /* Digital Output Register (W) */
+#define FDO_FDSEL 0x03 /* floppy device select */
+#define FDO_FRST 0x04 /* floppy controller reset */
+#define FDO_FDMAEN 0x08 /* enable floppy DMA and Interrupt */
+#define FDO_MOEN0 0x10 /* motor enable drive 0 */
+#define FDO_MOEN1 0x20 /* motor enable drive 1 */
+#define FDO_MOEN2 0x30 /* motor enable drive 2 */
+#define FDO_MOEN3 0x40 /* motor enable drive 3 */
+
+#define fdsts 4 /* NEC 765 Main Status Register (R) */
+#define fddata 5 /* NEC 765 Data Register (R/W) */
+
+#define fdctl 7 /* Control Register (W) */
+#define FDC_500KBPS 0x00 /* 500KBPS MFM drive transfer rate */
+#define FDC_300KBPS 0x01 /* 300KBPS MFM drive transfer rate */
+#define FDC_250KBPS 0x02 /* 250KBPS MFM drive transfer rate */
+#define FDC_125KBPS 0x03 /* 125KBPS FM drive transfer rate */
+
+#define fdin 7 /* Digital Input Register (R) */
+#define FDI_DCHG 0x80 /* diskette has been changed */
+
diff --git a/sys/i386/isa/ft.c b/sys/i386/isa/ft.c
new file mode 100644
index 0000000..4022b20
--- /dev/null
+++ b/sys/i386/isa/ft.c
@@ -0,0 +1,2129 @@
+/*
+ * Copyright (c) 1993 Steve Gerakines
+ *
+ * This is freely redistributable software. You may do anything you
+ * wish with it, so long as the above notice stays intact.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ft.c - QIC-40/80 floppy tape driver
+ * $Id: ft.c,v 1.4 1994/02/14 22:24:28 nate Exp $
+ *
+ *
+ * 01/26/94 v0.3b - Jim Babb
+ * Got rid of the hard coded device selection. Moved (some of) the
+ * static variables into a structure for support of multiple devices.
+ * ( still has a way to go for 2 controllers - but closer )
+ * Changed the interface with fd.c so we no longer 'steal' it's
+ * driver routine vectors.
+ *
+ * 10/30/93 v0.3
+ * Fixed a couple more bugs. Reading was sometimes looping when an
+ * an error such as address-mark-missing was encountered. Both
+ * reading and writing was having more backup-and-retries than was
+ * necessary. Added support to get hardware info. Updated for use
+ * with FreeBSD.
+ *
+ * 09/15/93 v0.2 pl01
+ * Fixed a bunch of bugs: extra isa_dmadone() in async_write() (shouldn't
+ * matter), fixed double buffering in async_req(), changed tape_end() in
+ * set_fdcmode() to reduce unexpected interrupts, changed end of track
+ * processing in async_req(), protected more of ftreq_rw() with an
+ * splbio(). Changed some of the ftreq_*() functions so that they wait
+ * for inactivity and then go, instead of aborting immediately.
+ *
+ * 08/07/93 v0.2 release
+ * Shifted from ftstrat to ioctl support for I/O. Streaming is now much
+ * more reliable. Added internal support for error correction, QIC-40,
+ * and variable length tapes. Random access of segments greatly
+ * improved. Formatting and verification support is close but still
+ * incomplete.
+ *
+ * 06/03/93 v0.1 Alpha release
+ * Hopefully the last re-write. Many bugs fixed, many remain.
+ */
+
+#include "ft.h"
+#if NFT > 0
+#include "fd.h"
+
+#include <sys/param.h>
+#include <sys/dkbad.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/uio.h>
+#include <sys/ftape.h>
+#include <machine/pio.h>
+#include "i386/isa/isa_device.h"
+#include "i386/isa/fdreg.h"
+#include "i386/isa/fdc.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/rtc.h"
+#include "ftreg.h"
+
+/* Enable or disable debugging messages. */
+#define FTDBGALL 0 /* everything */
+/* #define DPRT(a) printf a */
+#define DPRT(a)
+
+/* Constants private to the driver */
+#define FTPRI (PRIBIO) /* sleep priority */
+
+/* The following items are needed from the fd driver. */
+extern int in_fdc(int); /* read fdc registers */
+extern int out_fdc(int, int); /* write fdc registers */
+
+extern int hz; /* system clock rate */
+
+/* Type of tape attached */
+/* use numbers that don't interfere with the possible floppy types */
+#define NO_TYPE 0 /* (same as NO_TYPE in fd.c) */
+ /* F_TAPE_TYPE must match value in fd.c */
+#define F_TAPE_TYPE 0x020 /* bit for ft->types to indicate tape */
+#define FT_MOUNTAIN (F_TAPE_TYPE | 1)
+#define FT_COLORADO (F_TAPE_TYPE | 2)
+
+
+/* Mode FDC is currently in: tape or disk */
+enum { FDC_TAPE_MODE, FDC_DISK_MODE };
+
+/* Command we are awaiting completion of */
+enum { FTCMD_NONE, FTCMD_RESET, FTCMD_RECAL, FTCMD_SEEK, FTCMD_READID };
+
+/* Tape interrupt status of current request */
+enum { FTSTS_NONE, FTSTS_SNOOZE, FTSTS_INTERRUPT, FTSTS_TIMEOUT };
+
+/* Tape I/O status */
+enum {
+ FTIO_READY, /* No I/O activity */
+ FTIO_READING, /* Currently reading blocks */
+ FTIO_RDAHEAD, /* Currently reading ahead */
+ FTIO_WRITING /* Buffers are being written */
+};
+
+/* Current tape mode */
+enum {
+ FTM_PRIMARY, /* Primary mode */
+ FTM_VERIFY, /* Verify mode */
+ FTM_FORMAT, /* Format mode */
+ FTM_DIAG1, /* Diagnostic mode 1 */
+ FTM_DIAG2 /* Diagnostic mode 2 */
+};
+
+/* Tape geometries table */
+QIC_Geom ftgtbl[] = {
+ { 0, 0, "Unformatted", "Unknown", 0, 0, 0, 0, 0 }, /* XXX */
+ { 1, 1, "QIC-40", "205/550", 20, 68, 2176, 128, 21760 },
+ { 1, 2, "QIC-40", "307.5/550", 20, 102, 3264, 128, 32640 },
+ { 1, 3, "QIC-40", "295/900", 0, 0, 0, 0, 0 }, /* ??? */
+ { 1, 4, "QIC-40", "1100/550", 20, 365, 11680, 128, 32512 },
+ { 1, 5, "QIC-40", "1100/900", 0, 0, 0, 0, 0 }, /* ??? */
+ { 2, 1, "QIC-80", "205/550", 28, 100, 3200, 128, 19200 },
+ { 2, 2, "QIC-80", "307.5/550", 28, 150, 4800, 128, 19200 },
+ { 2, 3, "QIC-80", "295/900", 0, 0, 0, 0, 0 }, /* ??? */
+ { 2, 4, "QIC-80", "1100/550", 28, 537, 17184, 128, 32512 },
+ { 2, 5, "QIC-80", "1100/900", 0, 0, 0, 0, 0 }, /* ??? */
+ { 3, 1, "QIC-500", "205/550", 0, 0, 0, 0, 0 }, /* ??? */
+ { 3, 2, "QIC-500", "307.5/550", 0, 0, 0, 0, 0 }, /* ??? */
+ { 3, 3, "QIC-500", "295/900", 0, 0, 0, 0, 0 }, /* ??? */
+ { 3, 4, "QIC-500", "1100/550", 0, 0, 0, 0, 0 }, /* ??? */
+ { 3, 5, "QIC-500", "1100/900", 0, 0, 0, 0, 0 } /* ??? */
+};
+#define NGEOM (sizeof(ftgtbl) / sizeof(QIC_Geom))
+
+QIC_Geom *ftg = NULL; /* Current tape's geometry */
+
+/*
+ * things relating to asynchronous commands
+ */
+static int astk_depth; /* async_cmd stack depth */
+static int awr_state; /* state of async write */
+static int ard_state; /* state of async read */
+static int arq_state; /* state of async request */
+static int async_retries; /* retries, one per invocation */
+static int async_func; /* function to perform */
+static int async_state; /* state current function is at */
+static int async_arg[5]; /* up to 5 arguments for async cmds */
+static int async_ret; /* return value */
+
+/* List of valid async (interrupt driven) tape support functions. */
+enum {
+ ACMD_NONE, /* no command */
+ ACMD_SEEK, /* command seek */
+ ACMD_STATUS, /* report status */
+ ACMD_STATE, /* wait for state bits to be true */
+ ACMD_SEEKSTS, /* perform command and wait for status */
+ ACMD_READID, /* read id */
+ ACMD_RUNBLK /* ready tape for I/O on the given block */
+};
+
+/* Call another asyncronous command from within async_cmd(). */
+#define CALL_ACMD(r,f,a,b,c,d,e) \
+ astk[astk_depth].over_retries = async_retries; \
+ astk[astk_depth].over_func = async_func; \
+ astk[astk_depth].over_state = (r); \
+ for (i = 0; i < 5; i++) \
+ astk[astk_depth].over_arg[i] = async_arg[i]; \
+ async_func = (f); async_state = 0; async_retries = 0; \
+ async_arg[0]=(a); async_arg[1]=(b); async_arg[2]=(c); \
+ async_arg[3]=(d); async_arg[4]=(e); \
+ astk_depth++; \
+ goto restate
+
+/* Perform an asyncronous command from outside async_cmd(). */
+#define ACMD_FUNC(r,f,a,b,c,d,e) over_async = (r); astk_depth = 0; \
+ async_func = (f); async_state = 0; async_retries = 0; \
+ async_arg[0]=(a); async_arg[1]=(b); async_arg[2]=(c); \
+ async_arg[3]=(d); async_arg[4]=(e); \
+ async_cmd(ftu); \
+ return
+
+/* Various wait channels */
+static struct {
+ int buff_avail;
+ int iosts_change;
+ int long_delay;
+ int intr_wait;
+} ftsem;
+
+/***********************************************************************\
+* Per controller structure. *
+\***********************************************************************/
+extern struct fdc_data fdc_data[NFDC];
+
+/***********************************************************************\
+* Per tape drive structure. *
+\***********************************************************************/
+struct ft_data {
+ struct fdc_data *fdc; /* pointer to controller structure */
+ int ftsu; /* this units number on this controller */
+ int type; /* Drive type (Mountain, Colorado) */
+/* QIC_Geom *ftg; */ /* pointer to Current tape's geometry */
+ int flags;
+ int cmd_wait; /* Command we are awaiting completion of */
+ int sts_wait; /* Tape interrupt status of current request */
+ int io_sts; /* Tape I/O status */
+ int mode;
+ int pcn; /* present cylinder number */
+ int attaching; /* true when ft is attaching */
+ unsigned char *xptr; /* pointer to buffer blk to xfer */
+ int xcnt; /* transfer count */
+ int xblk; /* block number to transfer */
+ SegReq *curseg; /* Current segment to do I/O on */
+ SegReq *bufseg; /* Buffered segment to r/w ahead */
+ /* the next 3 should be defines in 'flags' */
+ int active; /* TRUE if transfer is active */
+ int rdonly; /* TRUE if tape is read-only */
+ int newcart; /* TRUE if new cartridge detected */
+ int laststs; /* last reported status code */
+ int lastcfg; /* last reported QIC config */
+ int lasterr; /* last QIC error code */
+ int lastpos; /* last known segment number */
+ int moving; /* TRUE if tape is moving */
+ int rid[7]; /* read_id return values */
+
+} ft_data[NFT];
+
+/***********************************************************************\
+* Throughout this file the following conventions will be used: *
+* ft is a pointer to the ft_data struct for the drive in question *
+* fdc is a pointer to the fdc_data struct for the controller *
+* ftu is the tape drive unit number *
+* fdcu is the floppy controller unit number *
+* ftsu is the tape drive unit number on that controller. (sub-unit) *
+\***********************************************************************/
+
+
+typedef int ftu_t;
+typedef int ftsu_t;
+typedef struct ft_data *ft_p;
+
+#define id_physid id_scsiid /* this biotab field doubles as a field */
+ /* for the physical unit number on the controller */
+
+int ftopen(dev_t, int);
+int ftclose(dev_t, int);
+void ftstrategy(struct buf *);
+int ftioctl(dev_t, int, caddr_t, int, struct proc *);
+int ftdump(dev_t);
+int ftsize(dev_t);
+static void ft_timeout(caddr_t arg1, int arg2);
+void async_cmd(ftu_t);
+void async_req(ftu_t, int);
+void async_read(ftu_t, int);
+void async_write(ftu_t, int);
+void tape_start(ftu_t);
+void tape_end(ftu_t);
+void tape_inactive(ftu_t);
+
+
+
+
+
+/*
+ * Probe/attach floppy tapes.
+ */
+int ftattach(isadev, fdup)
+ struct isa_device *isadev, *fdup;
+{
+ fdcu_t fdcu = isadev->id_unit; /* fdc active unit */
+ fdc_p fdc = fdc_data + fdcu; /* pointer to controller structure */
+ ftu_t ftu = fdup->id_unit;
+ ft_p ft;
+ ftsu_t ftsu = fdup->id_physid;
+
+ if (ftu >= NFT)
+ return 0;
+ ft = &ft_data[ftu];
+ /* Probe for tape */
+ ft->attaching = 1;
+ ft->type = NO_TYPE;
+ ft->fdc = fdc;
+ ft->ftsu = ftsu;
+
+ tape_start(ftu); /* ready controller for tape */
+ tape_cmd(ftu, QC_COL_ENABLE1);
+ tape_cmd(ftu, QC_COL_ENABLE2);
+ if (tape_status(ftu) >= 0) {
+ ft->type = FT_COLORADO;
+ fdc->flags |= FDC_HASFTAPE;
+ printf(" [%d: ft%d: Colorado tape]",
+ fdup->id_physid, fdup->id_unit );
+ tape_cmd(ftu, QC_COL_DISABLE);
+ goto out;
+ }
+
+ tape_start(ftu); /* ready controller for tape */
+ tape_cmd(ftu, QC_MTN_ENABLE1);
+ tape_cmd(ftu, QC_MTN_ENABLE2);
+ if (tape_status(ftu) >= 0) {
+ ft->type = FT_MOUNTAIN;
+ fdc->flags |= FDC_HASFTAPE;
+ printf(" [%d: ft%d: Mountain tape]",
+ fdup->id_physid, fdup->id_unit );
+ tape_cmd(ftu, QC_MTN_DISABLE);
+ goto out;
+ }
+
+out:
+ tape_end(ftu);
+ ft->attaching = 0;
+ return(ft->type);
+}
+
+
+/*
+ * Perform common commands asynchronously.
+ */
+void async_cmd(ftu_t ftu) {
+ ft_p ft = &ft_data[ftu];
+ fdcu_t fdcu = ft->fdc->fdcu;
+ int cmd, i, st0, st3, pcn;
+ static int bitn, retval, retpos, nbits, newcn;
+ static struct {
+ int over_func;
+ int over_state;
+ int over_retries;
+ int over_arg[5];
+ } astk[15];
+ static int wanttrk, wantblk, wantdir;
+ static int curpos, curtrk, curblk, curdir, curdiff;
+ static int errcnt = 0;
+
+restate:
+#if FTDBGALL
+ DPRT(("async_cmd state: func: %d state: %d\n", async_func, async_state));
+#endif
+ switch(async_func) {
+ case ACMD_SEEK:
+ /*
+ * Arguments:
+ * 0 - command to perform
+ */
+ switch (async_state) {
+ case 0:
+ cmd = async_arg[0];
+#if FTDBGALL
+ DPRT(("===>async_seek cmd = %d\n", cmd));
+#endif
+ newcn = (cmd <= ft->pcn) ? ft->pcn - cmd : ft->pcn + cmd;
+ async_state = 1;
+ i = 0;
+ if (out_fdc(fdcu, NE7CMD_SEEK) < 0) i = 1;
+ if (!i && out_fdc(fdcu, 0x00) < 0) i = 1;
+ if (!i && out_fdc(fdcu, newcn) < 0) i = 1;
+ if (i) {
+ if (++async_retries >= 10) {
+ DPRT(("ft%d: async_cmd command seek failed!!\n", ftu));
+ goto complete;
+ }
+ DPRT(("ft%d: async_cmd command seek retry...\n",ftu));
+ async_state = 0;
+ goto restate;
+ }
+ break;
+ case 1:
+ out_fdc(fdcu, NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ pcn = in_fdc(fdcu);
+ if (st0 < 0 || pcn < 0 || newcn != pcn) {
+ if (++async_retries >= 10) {
+ DPRT(("ft%d: async_cmd seek retries exceeded\n",ftu));
+ goto complete;
+ }
+ DPRT(("ft%d: async_cmd command bad st0=$%02x pcn=$%02x\n",
+ ftu, st0, pcn));
+ async_state = 0;
+ timeout(ft_timeout, (caddr_t)ftu, hz/10);
+ break;
+ }
+ if (st0 & 0x20) { /* seek done */
+ ft->pcn = pcn;
+ }
+#if FTDBGALL
+ else
+ DPRT(("ft%d: async_seek error st0 = $%02x pcn = %d\n",
+ ftu, st0, pcn));
+#endif
+ if (async_arg[1]) goto complete;
+ async_state = 2;
+ timeout(ft_timeout, (caddr_t)ftu, hz/50);
+ break;
+ case 2:
+ goto complete;
+ /* NOTREACHED */
+ }
+ break;
+
+ case ACMD_STATUS:
+ /*
+ * Arguments:
+ * 0 - command to issue report from
+ * 1 - number of bits
+ * modifies: bitn, retval, st3
+ */
+ switch (async_state) {
+ case 0:
+ bitn = 0;
+ retval = 0;
+ cmd = async_arg[0];
+ nbits = async_arg[1];
+ DPRT(("async_status got cmd = %d nbits = %d\n", cmd,nbits));
+ CALL_ACMD(5, ACMD_SEEK, QC_NEXTBIT, 0, 0, 0, 0);
+ /* NOTREACHED */
+ case 1:
+ out_fdc(fdcu, NE7CMD_SENSED);
+ out_fdc(fdcu, 0x00);
+ st3 = in_fdc(fdcu);
+ if (st3 < 0) {
+ DPRT(("ft%d: async_status timed out on bit %d r=$%02x\n",
+ ftu,bitn,retval));
+ async_ret = -1;
+ goto complete;
+ }
+ if ((st3 & 0x10) != 0) retval |= (1 << bitn);
+ bitn++;
+ if (bitn >= (nbits+2)) {
+ if ((retval & 1) && (retval & (1 << (nbits+1)))) {
+ async_ret = (retval & ~(1<<(nbits+1))) >> 1;
+ if (async_arg[0] == QC_STATUS && async_arg[2] == 0 &&
+ (async_ret & (QS_ERROR|QS_NEWCART))) {
+ async_state = 2;
+ goto restate;
+ }
+ DPRT(("async status got $%04x ($%04x)\n", async_ret,retval));
+ } else {
+ DPRT(("ft%d: async_status failed: retval=$%04x nbits=%d\n",
+ ftu, retval,nbits));
+ async_ret = -2;
+ }
+ goto complete;
+ }
+ CALL_ACMD(1, ACMD_SEEK, QC_NEXTBIT, 0, 0, 0, 0);
+ /* NOTREACHED */
+ case 2:
+ if (async_ret & QS_NEWCART) ft->newcart = 1;
+ CALL_ACMD(3, ACMD_STATUS, QC_ERRCODE, 16, 1, 0, 0);
+ case 3:
+ ft->lasterr = async_ret;
+ if ((ft->lasterr & QS_NEWCART) == 0 && ft->lasterr) {
+ DPRT(("ft%d: QIC error %d occurred on cmd %d\n",
+ ftu, ft->lasterr & 0xff, ft->lasterr >> 8));
+ }
+ cmd = async_arg[0];
+ nbits = async_arg[1];
+ CALL_ACMD(4, ACMD_STATUS, QC_STATUS, 8, 1, 0, 0);
+ case 4:
+ goto complete;
+ case 5:
+ CALL_ACMD(6, ACMD_SEEK, QC_NEXTBIT, 0, 0, 0, 0);
+ case 6:
+ CALL_ACMD(7, ACMD_SEEK, QC_NEXTBIT, 0, 0, 0, 0);
+ case 7:
+ CALL_ACMD(8, ACMD_SEEK, QC_NEXTBIT, 0, 0, 0, 0);
+ case 8:
+ cmd = async_arg[0];
+ CALL_ACMD(1, ACMD_SEEK, cmd, 0, 0, 0, 0);
+ }
+ break;
+
+ case ACMD_STATE:
+ /*
+ * Arguments:
+ * 0 - status bits to check
+ */
+ switch(async_state) {
+ case 0:
+ CALL_ACMD(1, ACMD_STATUS, QC_STATUS, 8, 0, 0, 0);
+ case 1:
+ if ((async_ret & async_arg[0]) != 0) goto complete;
+ async_state = 0;
+ if (++async_retries == 360) { /* 90 secs. */
+ DPRT(("ft%d: acmd_state exceeded retry count\n", ftu));
+ goto complete;
+ }
+ timeout(ft_timeout, (caddr_t)ftu, hz/4);
+ break;
+ }
+ break;
+
+ case ACMD_SEEKSTS:
+ /*
+ * Arguments:
+ * 0 - command to perform
+ * 1 - status bits to check
+ * 2 - (optional) seconds to wait until completion
+ */
+ switch(async_state) {
+ case 0:
+ cmd = async_arg[0];
+ async_retries = (async_arg[2]) ? (async_arg[2]*4) : 10;
+ CALL_ACMD(1, ACMD_SEEK, cmd, 0, 0, 0, 0);
+ case 1:
+ CALL_ACMD(2, ACMD_STATUS, QC_STATUS, 8, 0, 0, 0);
+ case 2:
+ if ((async_ret & async_arg[1]) != 0) goto complete;
+ if (--async_retries == 0) {
+ DPRT(("ft%d: acmd_seeksts retries exceeded\n", ftu));
+ goto complete;
+ }
+ async_state = 1;
+ timeout(ft_timeout, (caddr_t)ftu, hz/4);
+ break;
+ }
+ break;
+
+ case ACMD_READID:
+ /*
+ * Arguments: (none)
+ */
+ switch(async_state) {
+ case 0:
+ if (!ft->moving) {
+ CALL_ACMD(4, ACMD_SEEKSTS, QC_STOP, QS_READY, 0, 0, 0);
+ /* NOTREACHED */
+ }
+ async_state = 1;
+ out_fdc(fdcu, 0x4a); /* READ_ID */
+ out_fdc(fdcu, 0);
+ break;
+ case 1:
+ for (i = 0; i < 7; i++) ft->rid[i] = in_fdc(fdcu);
+ async_ret = (ft->rid[3]*ftg->g_fdtrk) +
+ (ft->rid[4]*ftg->g_fdside) + ft->rid[5] - 1;
+ DPRT(("readid st0:%02x st1:%02x st2:%02x c:%d h:%d s:%d pos:%d\n",
+ ft->rid[0], ft->rid[1], ft->rid[2], ft->rid[3],
+ ft->rid[4], ft->rid[5], async_ret));
+ if ((ft->rid[0] & 0xc0) == 0x40) {
+ if (++errcnt >= 10) {
+ DPRT(("ft%d: acmd_readid errcnt exceeded\n", fdcu));
+ async_ret = ft->lastpos;
+ errcnt = 0;
+ goto complete;
+ }
+ if (errcnt > 2) {
+ ft->moving = 0;
+ CALL_ACMD(4, ACMD_SEEKSTS, QC_STOP, QS_READY, 0, 0, 0);
+ }
+ DPRT(("readid retry...\n"));
+ async_state = 0;
+ goto restate;
+ }
+ if ((async_ret % ftg->g_blktrk) == (ftg->g_blktrk-1)) {
+ DPRT(("acmd_readid detected last block on track\n"));
+ retpos = async_ret;
+ CALL_ACMD(2, ACMD_STATE, QS_BOT|QS_EOT, 0, 0, 0, 0);
+ /* NOTREACHED */
+ }
+ ft->lastpos = async_ret;
+ errcnt = 0;
+ goto complete;
+ /* NOTREACHED */
+ case 2:
+ CALL_ACMD(3, ACMD_STATE, QS_READY, 0, 0, 0, 0);
+ case 3:
+ ft->moving = 0;
+ async_ret = retpos+1;
+ goto complete;
+ case 4:
+ CALL_ACMD(5, ACMD_SEEK, QC_FORWARD, 0, 0, 0, 0);
+ case 5:
+ ft->moving = 1;
+ async_state = 0;
+ timeout(ft_timeout, (caddr_t)ftu, hz/10); /* XXX */
+ break;
+ }
+ break;
+
+ case ACMD_RUNBLK:
+ /*
+ * Arguments:
+ * 0 - block number I/O will be performed on
+ *
+ * modifies: curpos
+ */
+ switch (async_state) {
+ case 0:
+ wanttrk = async_arg[0] / ftg->g_blktrk;
+ wantblk = async_arg[0] % ftg->g_blktrk;
+ wantdir = wanttrk & 1;
+ ft->moving = 0;
+ CALL_ACMD(1, ACMD_SEEKSTS, QC_STOP, QS_READY, 0, 0, 0);
+ case 1:
+ curtrk = wanttrk;
+ curdir = curtrk & 1;
+ DPRT(("Changing to track %d\n", wanttrk));
+ CALL_ACMD(2, ACMD_SEEK, QC_SEEKTRACK, 0, 0, 0, 0);
+ case 2:
+ cmd = wanttrk+2;
+ CALL_ACMD(3, ACMD_SEEKSTS, cmd, QS_READY, 0, 0, 0);
+ case 3:
+ CALL_ACMD(4, ACMD_STATUS, QC_STATUS, 8, 0, 0, 0);
+ case 4:
+ ft->laststs = async_ret;
+ if (wantblk == 0) {
+ curblk = 0;
+ cmd = (wantdir) ? QC_SEEKEND : QC_SEEKSTART;
+ CALL_ACMD(6, ACMD_SEEKSTS, cmd, QS_READY, 90, 0, 0);
+ }
+ if (ft->laststs & QS_BOT) {
+ DPRT(("Tape is at BOT\n"));
+ curblk = (wantdir) ? 4800 : 0;
+ async_state = 6;
+ goto restate;
+ }
+ if (ft->laststs & QS_EOT) {
+ DPRT(("Tape is at EOT\n"));
+ curblk = (wantdir) ? 0 : 4800;
+ async_state = 6;
+ goto restate;
+ }
+ CALL_ACMD(5, ACMD_READID, 0, 0, 0, 0, 0);
+ case 5:
+ curtrk = (async_ret+1) / ftg->g_blktrk;
+ curblk = (async_ret+1) % ftg->g_blktrk;
+ DPRT(("gotid: curtrk=%d wanttrk=%d curblk=%d wantblk=%d\n",
+ curtrk, wanttrk, curblk, wantblk));
+ if (curtrk != wanttrk) { /* oops! */
+ DPRT(("oops!! wrong track!\n"));
+ CALL_ACMD(1, ACMD_SEEKSTS, QC_STOP, QS_READY, 0, 0, 0);
+ }
+ async_state = 6;
+ goto restate;
+ case 6:
+ DPRT(("curtrk = %d nextblk = %d\n", curtrk, curblk));
+ if (curblk == wantblk) {
+ ft->lastpos = curblk - 1;
+ async_ret = ft->lastpos;
+ if (ft->moving) goto complete;
+ CALL_ACMD(7, ACMD_STATE, QS_READY, 0, 0, 0, 0);
+ }
+ if (curblk > wantblk) { /* passed it */
+ ft->moving = 0;
+ CALL_ACMD(10, ACMD_SEEKSTS, QC_STOP, QS_READY, 0, 0, 0);
+ }
+ if ((wantblk - curblk) <= 96) { /* approaching it */
+ CALL_ACMD(5, ACMD_READID, 0, 0, 0, 0, 0);
+ }
+ /* way up ahead */
+ ft->moving = 0;
+ CALL_ACMD(14, ACMD_SEEKSTS, QC_STOP, QS_READY, 0, 0, 0);
+ break;
+ case 7:
+ ft->moving = 1;
+ CALL_ACMD(8, ACMD_SEEK, QC_FORWARD, 0, 0, 0, 0);
+ break;
+ case 8:
+ async_state = 9;
+ timeout(ft_timeout, (caddr_t)ftu, hz/10); /* XXX */
+ break;
+ case 9:
+ goto complete;
+ case 10:
+ curdiff = ((curblk - wantblk) / QCV_BLKSEG) + 2;
+ if (curdiff >= ftg->g_segtrk) curdiff = ftg->g_segtrk - 1;
+ DPRT(("pos %d past %d, reverse %d\n", curblk, wantblk, curdiff));
+ CALL_ACMD(11, ACMD_SEEK, QC_SEEKREV, 0, 0, 0, 0);
+ case 11:
+ DPRT(("reverse 1 done\n"));
+ CALL_ACMD(12, ACMD_SEEK, (curdiff & 0xf)+2, 0, 0, 0, 0);
+ case 12:
+ DPRT(("reverse 2 done\n"));
+ CALL_ACMD(13, ACMD_SEEKSTS, ((curdiff>>4)&0xf)+2, QS_READY, 90, 0, 0);
+ case 13:
+ CALL_ACMD(5, ACMD_READID, 0, 0, 0, 0, 0);
+ case 14:
+ curdiff = ((wantblk - curblk) / QCV_BLKSEG) - 2;
+ if (curdiff < 0) curdiff = 0;
+ DPRT(("pos %d before %d, forward %d\n", curblk, wantblk, curdiff));
+ CALL_ACMD(15, ACMD_SEEK, QC_SEEKFWD, 0, 0, 0, 0);
+ case 15:
+ DPRT(("forward 1 done\n"));
+ CALL_ACMD(16, ACMD_SEEK, (curdiff & 0xf)+2, 0, 0, 0, 0);
+ case 16:
+ DPRT(("forward 2 done\n"));
+ CALL_ACMD(13, ACMD_SEEKSTS, ((curdiff>>4)&0xf)+2, QS_READY, 90, 0, 0);
+ }
+ break;
+ }
+
+ return;
+
+complete:
+ if (astk_depth) {
+ astk_depth--;
+ async_retries = astk[astk_depth].over_retries;
+ async_func = astk[astk_depth].over_func;
+ async_state = astk[astk_depth].over_state;
+ for(i = 0; i < 5; i++)
+ async_arg[i] = astk[astk_depth].over_arg[i];
+ goto restate;
+ }
+ async_func = ACMD_NONE;
+ async_state = 0;
+ switch (ft->io_sts) {
+ case FTIO_READY:
+ async_req(ftu, 2);
+ break;
+ case FTIO_READING:
+ async_read(ftu, 2);
+ break;
+ case FTIO_WRITING:
+ async_write(ftu, 2);
+ break;
+ default:
+ DPRT(("ft%d: bad async_cmd ending I/O state!\n", ftu));
+ break;
+ }
+}
+
+
+/*
+ * Entry point for the async request processor.
+ */
+void async_req(ftu_t ftu, int from)
+{
+ ft_p ft = &ft_data[ftu];
+ SegReq *sp;
+ static int over_async, lastreq, domore;
+ int cmd;
+
+ if (from == 2) arq_state = over_async;
+
+restate:
+ switch (arq_state) {
+ case 0: /* Process segment */
+ ft->io_sts = ft->curseg->reqtype;
+ if (ft->io_sts == FTIO_WRITING)
+ async_write(ftu, from);
+ else
+ async_read(ftu, from);
+ if (ft->io_sts != FTIO_READY) return;
+
+ /* Swap buffered and current segment */
+ lastreq = ft->curseg->reqtype;
+ ft->curseg->reqtype = FTIO_READY;
+ sp = ft->curseg;
+ ft->curseg = ft->bufseg;
+ ft->bufseg = sp;
+
+ wakeup((caddr_t)&ftsem.buff_avail);
+
+ /* Detect end of track */
+ if (((ft->xblk / QCV_BLKSEG) % ftg->g_segtrk) == 0) {
+ domore = (ft->curseg->reqtype != FTIO_READY);
+ ACMD_FUNC(2, ACMD_STATE, QS_BOT|QS_EOT, 0, 0, 0, 0);
+ }
+ arq_state = 1;
+ goto restate;
+
+ case 1: /* Next request */
+ if (ft->curseg->reqtype != FTIO_READY) {
+ ft->curseg->reqcrc = 0;
+ arq_state = ard_state = awr_state = 0;
+ ft->xblk = ft->curseg->reqblk;
+ ft->xcnt = 0;
+ ft->xptr = ft->curseg->buff;
+ DPRT(("I/O reqblk = %d\n", ft->curseg->reqblk));
+ goto restate;
+ }
+ if (lastreq == FTIO_READING) {
+ ft->curseg->reqtype = FTIO_RDAHEAD;
+ ft->curseg->reqblk = ft->xblk;
+ ft->curseg->reqcrc = 0;
+ ft->curseg->reqcan = 0;
+ bzero(ft->curseg->buff, QCV_SEGSIZE);
+ arq_state = ard_state = awr_state = 0;
+ ft->xblk = ft->curseg->reqblk;
+ ft->xcnt = 0;
+ ft->xptr = ft->curseg->buff;
+ DPRT(("Processing readahead reqblk = %d\n", ft->curseg->reqblk));
+ goto restate;
+ }
+ if (ft->moving) {
+ DPRT(("No more I/O.. Stopping.\n"));
+ ACMD_FUNC(7, ACMD_SEEKSTS, QC_STOP, QS_READY, 0, 0, 0);
+ break;
+ }
+ arq_state = 7;
+ goto restate;
+
+ case 2: /* End of track */
+ ft->moving = 0;
+ ACMD_FUNC(3, ACMD_STATE, QS_READY, 0, 0, 0, 0);
+ break;
+
+ case 3:
+ DPRT(("async_req seek head to track %d\n", ft->xblk / ftg->g_blktrk));
+ ACMD_FUNC(4, ACMD_SEEK, QC_SEEKTRACK, 0, 0, 0, 0);
+ break;
+
+ case 4:
+ cmd = (ft->xblk / ftg->g_blktrk) + 2;
+ if (domore) {
+ ACMD_FUNC(5, ACMD_SEEKSTS, cmd, QS_READY, 0, 0, 0);
+ } else {
+ ACMD_FUNC(7, ACMD_SEEKSTS, cmd, QS_READY, 0, 0, 0);
+ }
+ break;
+
+ case 5:
+ ft->moving = 1;
+ ACMD_FUNC(6, ACMD_SEEK, QC_FORWARD, 0, 0, 0, 0);
+ break;
+
+ case 6:
+ arq_state = 1;
+ timeout(ft_timeout, (caddr_t)ftu, hz/10); /* XXX */
+ break;
+
+ case 7:
+ ft->moving = 0;
+
+ /* Check one last time to see if a request came in. */
+ if (ft->curseg->reqtype != FTIO_READY) {
+ DPRT(("async_req: Never say no!\n"));
+ arq_state = 1;
+ goto restate;
+ }
+
+ /* Time to rest. */
+ ft->active = 0;
+ wakeup((caddr_t)&ftsem.iosts_change); /* wakeup those who want an i/o chg */
+ break;
+ }
+}
+
+/*
+ * Entry for async read.
+ */
+void async_read(ftu_t ftu, int from)
+{
+ ft_p ft = &ft_data[ftu];
+ fdcu_t fdcu = ft->fdc->fdcu; /* fdc active unit */
+ unsigned long paddr;
+ int i, cmd, newcn, rddta[7];
+ int st0, pcn, where;
+ static int over_async;
+
+ if (from == 2) ard_state = over_async;
+
+restate:
+#if FTDBGALL
+ DPRT(("async_read: state: %d from = %d\n", ard_state, from));
+#endif
+ switch (ard_state) {
+ case 0: /* Start off */
+ /* If tape is not at desired position, stop and locate */
+ if (ft->lastpos != (ft->xblk-1)) {
+ DPRT(("ft%d: position unknown: lastpos:%d ft->xblk:%d\n",
+ ftu, ft->lastpos, ft->xblk));
+ ACMD_FUNC(1, ACMD_RUNBLK, ft->xblk, 0, 0, 0, 0);
+ }
+
+ /* Tape is in position but stopped. */
+ if (!ft->moving) {
+ DPRT(("async_read ******STARTING TAPE\n"));
+ ACMD_FUNC(3, ACMD_STATE, QS_READY, 0, 0, 0, 0);
+ }
+ ard_state = 1;
+ goto restate;
+
+ case 1: /* Start DMA */
+ /* Tape is now moving and in position-- start DMA now! */
+ isa_dmastart(B_READ, ft->xptr, QCV_BLKSIZE, 2);
+ out_fdc(fdcu, 0x66); /* read */
+ out_fdc(fdcu, 0x00); /* unit */
+ out_fdc(fdcu, (ft->xblk % ftg->g_fdside) / ftg->g_fdtrk); /* cylinder */
+ out_fdc(fdcu, ft->xblk / ftg->g_fdside); /* head */
+ out_fdc(fdcu, (ft->xblk % ftg->g_fdtrk) + 1); /* sector */
+ out_fdc(fdcu, 0x03); /* 1K sectors */
+ out_fdc(fdcu, (ft->xblk % ftg->g_fdtrk) + 1); /* count */
+ out_fdc(fdcu, 0x74); /* gap length */
+ out_fdc(fdcu, 0xff); /* transfer size */
+ ard_state = 2;
+ break;
+
+ case 2: /* DMA completed */
+ /* Transfer complete, get status */
+ for (i = 0; i < 7; i++) rddta[i] = in_fdc(fdcu);
+ isa_dmadone(B_READ, ft->xptr, QCV_BLKSIZE, 2);
+
+#if FTDBGALL
+ /* Compute where the controller thinks we are */
+ where = (rddta[3]*ftg->g_fdtrk) + (rddta[4]*ftg->g_fdside) + rddta[5]-1;
+ DPRT(("xfer done: st0:%02x st1:%02x st2:%02x c:%d h:%d s:%d pos:%d want:%d\n",
+ rddta[0], rddta[1], rddta[2], rddta[3], rddta[4], rddta[5],
+ where, ft->xblk));
+#endif
+
+ /* Check for errors */
+ if ((rddta[0] & 0xc0) != 0x00) {
+ if (rddta[1] & 0x04) {
+ /* Probably wrong position */
+ ft->lastpos = ft->xblk;
+ ard_state = 0;
+ goto restate;
+ } else {
+ /* CRC/Address-mark/Data-mark, et. al. */
+ DPRT(("ft%d: CRC error on block %d\n", fdcu, ft->xblk));
+ ft->curseg->reqcrc |= (1 << ft->xcnt);
+ }
+ }
+
+ /* Otherwise, transfer completed okay. */
+ ft->lastpos = ft->xblk;
+ ft->xblk++;
+ ft->xcnt++;
+ ft->xptr += QCV_BLKSIZE;
+ if (ft->xcnt < QCV_BLKSEG && ft->curseg->reqcan == 0) {
+ ard_state = 0;
+ goto restate;
+ }
+ DPRT(("Read done.. Cancel = %d\n", ft->curseg->reqcan));
+ ft->io_sts = FTIO_READY;
+ break;
+
+ case 3:
+ ft->moving = 1;
+ ACMD_FUNC(4, ACMD_SEEK, QC_FORWARD, 0, 0, 0, 0);
+ break;
+
+ case 4:
+ ard_state = 1;
+ timeout(ft_timeout, (caddr_t)ftu, hz/10); /* XXX */
+ break;
+
+ default:
+ DPRT(("ft%d: bad async_read state %d!!\n", ftu, ard_state));
+ break;
+ }
+}
+
+
+/*
+ * Entry for async write. If from is 0, this came from the interrupt
+ * routine, if it's 1 then it was a timeout, if it's 2, then an
+ * async_cmd completed.
+ */
+void async_write(ftu_t ftu, int from)
+{
+ ft_p ft = &ft_data[ftu];
+ fdcu_t fdcu = ft->fdc->fdcu; /* fdc active unit */
+ unsigned long paddr;
+ int i, cmd, newcn, rddta[7];
+ int st0, pcn, where;
+ static int over_async;
+ static int retries = 0;
+
+ if (from == 2) awr_state = over_async;
+
+restate:
+#if FTDBGALL
+ DPRT(("async_write: state: %d from = %d\n", awr_state, from));
+#endif
+ switch (awr_state) {
+ case 0: /* Start off */
+ /* If tape is not at desired position, stop and locate */
+ if (ft->lastpos != (ft->xblk-1)) {
+ DPRT(("ft%d: position unknown: lastpos:%d ft->xblk:%d\n",
+ ftu, ft->lastpos, ft->xblk));
+ ACMD_FUNC(1, ACMD_RUNBLK, ft->xblk, 0, 0, 0, 0);
+ }
+
+ /* Tape is in position but stopped. */
+ if (!ft->moving) {
+ DPRT(("async_write ******STARTING TAPE\n"));
+ ACMD_FUNC(3, ACMD_STATE, QS_READY, 0, 0, 0, 0);
+ }
+ awr_state = 1;
+ goto restate;
+
+ case 1: /* Start DMA */
+ /* Tape is now moving and in position-- start DMA now! */
+ isa_dmastart(B_WRITE, ft->xptr, QCV_BLKSIZE, 2);
+ out_fdc(fdcu, 0x45); /* write */
+ out_fdc(fdcu, 0x00); /* unit */
+ out_fdc(fdcu, (ft->xblk % ftg->g_fdside) / ftg->g_fdtrk); /* cylinder */
+ out_fdc(fdcu, ft->xblk / ftg->g_fdside); /* head */
+ out_fdc(fdcu, (ft->xblk % ftg->g_fdtrk) + 1); /* sector */
+ out_fdc(fdcu, 0x03); /* 1K sectors */
+ out_fdc(fdcu, (ft->xblk % ftg->g_fdtrk) + 1); /* count */
+ out_fdc(fdcu, 0x74); /* gap length */
+ out_fdc(fdcu, 0xff); /* transfer size */
+ awr_state = 2;
+ break;
+
+ case 2: /* DMA completed */
+ /* Transfer complete, get status */
+ for (i = 0; i < 7; i++) rddta[i] = in_fdc(fdcu);
+ isa_dmadone(B_WRITE, ft->xptr, QCV_BLKSIZE, 2);
+
+#if FTDBGALL
+ /* Compute where the controller thinks we are */
+ where = (rddta[3]*ftg->g_fdtrk) + (rddta[4]*ftg->g_fdside) + rddta[5]-1;
+ DPRT(("xfer done: st0:%02x st1:%02x st2:%02x c:%d h:%d s:%d pos:%d want:%d\n",
+ rddta[0], rddta[1], rddta[2], rddta[3], rddta[4], rddta[5],
+ where, ft->xblk));
+#endif
+
+ /* Check for errors */
+ if ((rddta[0] & 0xc0) != 0x00) {
+ if (rddta[1] & 0x04) {
+ /* Probably wrong position */
+ ft->lastpos = ft->xblk;
+ awr_state = 0;
+ goto restate;
+ } else if (retries < 5) {
+ /* Something happened -- try again */
+ ft->lastpos = ft->xblk;
+ awr_state = 0;
+ retries++;
+ goto restate;
+ } else {
+ /*
+ * Retries failed. Note the unrecoverable error.
+ * Marking the block as bad is fairly useless.
+ */
+ printf("ft%d: unrecoverable write error on block %d\n",
+ ftu, ft->xblk);
+ ft->curseg->reqcrc |= (1 << ft->xcnt);
+ }
+ }
+
+ /* Otherwise, transfer completed okay. */
+ retries = 0;
+ ft->lastpos = ft->xblk;
+ ft->xblk++;
+ ft->xcnt++;
+ ft->xptr += QCV_BLKSIZE;
+ if (ft->xcnt < QCV_BLKSEG) {
+ awr_state = 0; /* next block */
+ goto restate;
+ }
+#if FTDBGALL
+ DPRT(("Write done.\n"));
+#endif
+ ft->io_sts = FTIO_READY;
+ break;
+
+ case 3:
+ ft->moving = 1;
+ ACMD_FUNC(4, ACMD_SEEK, QC_FORWARD, 0, 0, 0, 0);
+ break;
+
+ case 4:
+ awr_state = 1;
+ timeout(ft_timeout, (caddr_t)ftu, hz/10); /* XXX */
+ break;
+
+ default:
+ DPRT(("ft%d: bad async_write state %d!!\n", ftu, awr_state));
+ break;
+ }
+}
+
+
+/*
+ * Interrupt handler for active tape. Bounced off of fdintr().
+ */
+int ftintr(ftu_t ftu)
+{
+ int st0, pcn, i;
+ ft_p ft = &ft_data[ftu];
+ fdcu_t fdcu = ft->fdc->fdcu; /* fdc active unit */
+ st0 = 0;
+ pcn = 0;
+
+ /* I/O segment transfer completed */
+ if (ft->active) {
+ if (async_func != ACMD_NONE) {
+ async_cmd(ftu);
+ return(1);
+ }
+#if FTDBGALL
+ DPRT(("Got request interrupt\n"));
+#endif
+ async_req(ftu, 0);
+ return(1);
+ }
+
+ /* Get interrupt status */
+ if (ft->cmd_wait != FTCMD_READID) {
+ out_fdc(fdcu, NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ pcn = in_fdc(fdcu);
+ }
+
+ if (ft->cmd_wait == FTCMD_NONE || ft->sts_wait != FTSTS_SNOOZE) {
+huh_what:
+ printf("ft%d: unexpected interrupt; st0 = $%02x pcn = %d\n",
+ ftu, st0, pcn);
+ return(1);
+ }
+
+ switch (ft->cmd_wait) {
+ case FTCMD_RESET:
+ ft->sts_wait = FTSTS_INTERRUPT;
+ wakeup((caddr_t)&ftsem.intr_wait);
+ break;
+ case FTCMD_RECAL:
+ case FTCMD_SEEK:
+ if (st0 & 0x20) { /* seek done */
+ ft->sts_wait = FTSTS_INTERRUPT;
+ ft->pcn = pcn;
+ wakeup((caddr_t)&ftsem.intr_wait);
+ }
+#if FTDBGALL
+ else
+ DPRT(("ft%d: seek error st0 = $%02x pcn = %d\n",
+ ftu, st0, pcn));
+#endif
+ break;
+ case FTCMD_READID:
+ for (i = 0; i < 7; i++) ft->rid[i] = in_fdc(fdcu);
+ ft->sts_wait = FTSTS_INTERRUPT;
+ wakeup((caddr_t)&ftsem.intr_wait);
+ break;
+
+ default:
+ goto huh_what;
+ }
+
+ return(1);
+}
+
+/*
+ * Interrupt timeout routine.
+ */
+static void ft_timeout(caddr_t arg1, int arg2)
+{
+ int s;
+ ftu_t ftu = (ftu_t)arg1;
+ ft_p ft = &ft_data[ftu];
+
+ s = splbio();
+ if (ft->active) {
+ if (async_func != ACMD_NONE) {
+ async_cmd(ftu);
+ splx(s);
+ return;
+ }
+ async_req(ftu, 1);
+ } else {
+ ft->sts_wait = FTSTS_TIMEOUT;
+ wakeup((caddr_t)&ftsem.intr_wait);
+ }
+ splx(s);
+}
+
+/*
+ * Wait for a particular interrupt to occur. ftintr() will wake us up
+ * if it sees what we want. Otherwise, time out and return error.
+ * Should always disable ints before trigger is sent and calling here.
+ */
+int ftintr_wait(ftu_t ftu, int cmd, int ticks)
+{
+ int retries, st0, pcn;
+ ft_p ft = &ft_data[ftu];
+ fdcu_t fdcu = ft->fdc->fdcu; /* fdc active unit */
+
+ ft->cmd_wait = cmd;
+ ft->sts_wait = FTSTS_SNOOZE;
+
+ /* At attach time, we can't rely on having interrupts serviced */
+ if (ft->attaching) {
+ switch (cmd) {
+ case FTCMD_RESET:
+ DELAY(100);
+ ft->sts_wait = FTSTS_INTERRUPT;
+ goto intrdone;
+ case FTCMD_RECAL:
+ case FTCMD_SEEK:
+ for (retries = 0; retries < 10000; retries++) {
+ out_fdc(fdcu, NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ pcn = in_fdc(fdcu);
+ if (st0 & 0x20) {
+ ft->sts_wait = FTSTS_INTERRUPT;
+ ft->pcn = pcn;
+ goto intrdone;
+ }
+ DELAY(100);
+ }
+ break;
+ }
+ ft->sts_wait = FTSTS_TIMEOUT;
+ goto intrdone;
+ }
+
+ if (ticks) timeout(ft_timeout, (caddr_t)ftu, ticks);
+ tsleep((caddr_t)&ftsem.intr_wait, FTPRI, "ftwait", 0);
+
+intrdone:
+ if (ft->sts_wait == FTSTS_TIMEOUT) { /* timeout */
+ if (ft->cmd_wait != FTCMD_RESET)
+ DPRT(("ft%d: timeout on command %d\n", ftu, ft->cmd_wait));
+ ft->cmd_wait = FTCMD_NONE;
+ ft->sts_wait = FTSTS_NONE;
+ return(1);
+ }
+
+ /* got interrupt */
+ if (ft->attaching == 0 && ticks) untimeout(ft_timeout, (caddr_t)ftu);
+ ft->cmd_wait = FTCMD_NONE;
+ ft->sts_wait = FTSTS_NONE;
+ return(0);
+}
+
+/*
+ * Recalibrate tape drive. Parameter totape is true, if we should
+ * recalibrate to tape drive settings.
+ */
+int tape_recal(ftu_t ftu, int totape)
+{
+ int s;
+ ft_p ft = &ft_data[ftu];
+ fdcu_t fdcu = ft->fdc->fdcu; /* fdc active unit */
+
+ DPRT(("tape_recal start\n"));
+
+ out_fdc(fdcu, NE7CMD_SPECIFY);
+ out_fdc(fdcu, (totape) ? 0xAD : 0xDF);
+ out_fdc(fdcu, 0x02);
+
+ s = splbio();
+ out_fdc(fdcu, NE7CMD_RECAL);
+ out_fdc(fdcu, 0x00);
+
+ if (ftintr_wait(ftu, FTCMD_RECAL, hz)) {
+ splx(s);
+ DPRT(("ft%d: recalibrate timeout\n", ftu));
+ return(1);
+ }
+ splx(s);
+
+ out_fdc(fdcu, NE7CMD_SPECIFY);
+ out_fdc(fdcu, (totape) ? 0xFD : 0xDF);
+ out_fdc(fdcu, 0x02);
+
+ DPRT(("tape_recal end\n"));
+ return(0);
+}
+
+static void state_timeout(caddr_t arg1, int arg2)
+{
+ ftu_t ftu = (ftu_t)arg1;
+
+ wakeup((caddr_t)&ftsem.long_delay);
+}
+
+/*
+ * Wait for a particular tape status to be met. If all is TRUE, then
+ * all states must be met, otherwise any state can be met.
+ */
+int tape_state(ftu_t ftu, int all, int mask, int seconds)
+{
+ int r, tries, maxtries;
+
+ maxtries = (seconds) ? (4 * seconds) : 1;
+ for (tries = 0; tries < maxtries; tries++) {
+ r = tape_status(ftu);
+ if (r >= 0) {
+ if (all && (r & mask) == mask) return(r);
+ if ((r & mask) != 0) return(r);
+ }
+ if (seconds) {
+ timeout(state_timeout, (caddr_t)ftu, hz/4);
+ tsleep((caddr_t)&ftsem.long_delay, FTPRI, "ftstate", 0);
+ }
+ }
+ DPRT(("ft%d: tape_state failed on mask=$%02x maxtries=%d\n",
+ ftu, mask, maxtries));
+ return(-1);
+}
+
+/*
+ * Send a QIC command to tape drive, wait for completion.
+ */
+int tape_cmd(ftu_t ftu, int cmd)
+{
+ int newcn;
+ int retries = 0;
+ int s;
+ ft_p ft = &ft_data[ftu];
+ fdcu_t fdcu = ft->fdc->fdcu; /* fdc active unit */
+
+ DPRT(("===> tape_cmd: %d\n",cmd));
+ newcn = (cmd <= ft->pcn) ? ft->pcn - cmd : ft->pcn + cmd;
+
+retry:
+
+ /* Perform seek */
+ s = splbio();
+ out_fdc(fdcu, NE7CMD_SEEK);
+ out_fdc(fdcu, 0x00);
+ out_fdc(fdcu, newcn);
+
+ if (ftintr_wait(ftu, FTCMD_SEEK, hz)) {
+ DPRT(("ft%d: tape_cmd seek timeout\n", ftu));
+redo:
+ splx(s);
+ if (++retries < 5) goto retry;
+ DPRT(("ft%d: tape_cmd seek failed!\n", ftu));
+ return(1);
+ }
+ splx(s);
+
+ if (ft->pcn != newcn) {
+ DPRT(("ft%d: bad seek in tape_cmd; pcn = %d newcn = %d\n",
+ ftu, ft->pcn, newcn));
+ goto redo;
+ }
+ DELAY(2500);
+ return(0);
+}
+
+/*
+ * Return status of tape drive
+ */
+int tape_status(ftu_t ftu)
+{
+ int r, err, tries;
+ ft_p ft = &ft_data[ftu];
+
+ for (r = -1, tries = 0; r < 0 && tries < 3; tries++)
+ r = qic_status(ftu, QC_STATUS, 8);
+ if (tries == 3) return(-1);
+ DPRT(("tape_status got $%04x\n",r));
+ ft->laststs = r;
+
+ if (r & (QS_ERROR|QS_NEWCART)) {
+ if (r & QS_NEWCART) ft->newcart = 1;
+ err = qic_status(ftu, QC_ERRCODE, 16);
+ ft->lasterr = err;
+ if ((r & QS_NEWCART) == 0 && err && ft->attaching == 0) {
+ DPRT(("ft%d: QIC error %d occurred on cmd %d\n",
+ ftu, err & 0xff, err >> 8));
+ }
+ r = qic_status(ftu, QC_STATUS, 8);
+ ft->laststs = r;
+ DPRT(("tape_status got error code $%04x new sts = $%02x\n",err,r));
+ }
+ ft->rdonly = (r & QS_RDONLY);
+ return(r);
+}
+
+/*
+ * Transfer control to tape drive.
+ */
+void tape_start(ftu_t ftu)
+{
+ ft_p ft = &ft_data[ftu];
+ fdc_p fdc = ft->fdc;
+ int s;
+
+ DPRT(("tape_start start\n"));
+
+ s = splbio();
+
+ /* reset, dma disable */
+ outb(fdc->baseport+fdout, 0x00);
+ (void)ftintr_wait(ftu, FTCMD_RESET, hz/10);
+
+ /* raise reset, enable DMA */
+ outb(fdc->baseport+fdout, FDO_FRST | FDO_FDMAEN);
+ (void)ftintr_wait(ftu, FTCMD_RESET, hz/10);
+
+ splx(s);
+
+ tape_recal(ftu, 1);
+
+ /* set transfer speed */
+ outb(fdc->baseport+fdctl, FDC_500KBPS);
+ DELAY(10);
+
+ DPRT(("tape_start end\n"));
+}
+
+/*
+ * Transfer control back to floppy disks.
+ */
+void tape_end(ftu_t ftu)
+{
+ ft_p ft = &ft_data[ftu];
+ fdc_p fdc = ft->fdc;
+ int s;
+
+ DPRT(("tape_end start\n"));
+ tape_recal(ftu, 0);
+
+ s = splbio();
+
+ /* reset, dma disable */
+ outb(fdc->baseport+fdout, 0x00);
+ (void)ftintr_wait(ftu, FTCMD_RESET, hz/10);
+
+ /* raise reset, enable DMA */
+ outb(fdc->baseport+fdout, FDO_FRST | FDO_FDMAEN);
+ (void)ftintr_wait(ftu, FTCMD_RESET, hz/10);
+
+ splx(s);
+
+ /* set transfer speed */
+ outb(fdc->baseport+fdctl, FDC_500KBPS);
+ DELAY(10);
+ fdc->flags &= ~FDC_TAPE_BUSY;
+
+ DPRT(("tape_end end\n"));
+}
+
+/*
+ * Wait for the driver to go inactive, cancel readahead if necessary.
+ */
+void tape_inactive(ftu_t ftu)
+{
+ ft_p ft = &ft_data[ftu];
+
+ if (ft->curseg->reqtype == FTIO_RDAHEAD) {
+ ft->curseg->reqcan = 1; /* XXX cancel rdahead */
+ while (ft->active)
+ tsleep((caddr_t)&ftsem.iosts_change, FTPRI, "ftinact", 0);
+ }
+ while (ft->active)
+ tsleep((caddr_t)&ftsem.iosts_change, FTPRI, "ftinact", 0);
+}
+
+/*
+ * Get the geometry of the tape currently in the drive.
+ */
+int ftgetgeom(ftu_t ftu)
+{
+ int r, i, tries;
+ int cfg, qic80, ext;
+ int sts, fmt, len;
+ ft_p ft = &ft_data[ftu];
+
+ r = tape_status(ftu);
+
+ /* XXX fix me when format mode is finished */
+ if ((r & QS_CART) == 0 || (r & QS_FMTOK) == 0) {
+ DPRT(("ftgetgeom: no cart or not formatted 0x%04x\n",r));
+ ftg = NULL;
+ ft->newcart = 1;
+ return(0);
+ }
+
+ /* Report drive configuration */
+ for (cfg = -1, tries = 0; cfg < 0 && tries < 3; tries++)
+ cfg = qic_status(ftu, QC_CONFIG, 8);
+ if (tries == 3) {
+ DPRT(("ftgetgeom report config failed\n"));
+ ftg = NULL;
+ return(-1);
+ }
+ DPRT(("ftgetgeom report config got $%04x\n", cfg));
+ ft->lastcfg = cfg;
+
+ qic80 = cfg & QCF_QIC80;
+ ext = cfg & QCF_EXTRA;
+
+/*
+ * XXX - This doesn't seem to work on my Colorado Jumbo 250...
+ * if it works on your drive, I'd sure like to hear about it.
+ */
+#if 0
+ /* Report drive status */
+ for (sts = -1, tries = 0; sts < 0 && tries < 3; tries++)
+ sts = qic_status(ftu, QC_TSTATUS, 8);
+ if (tries == 3) {
+ DPRT(("ftgetgeom report tape status failed\n"));
+ ftg = NULL;
+ return(-1);
+ }
+ DPRT(("ftgetgeom report tape status got $%04x\n", sts));
+#else
+ /*
+ * XXX - Forge a fake tape status based upon the returned
+ * configuration, since the above command or code is broken
+ * for my drive and probably other older drives.
+ */
+ sts = 0;
+ sts = (qic80) ? QTS_QIC80 : QTS_QIC40;
+ sts |= (ext) ? QTS_LEN2 : QTS_LEN1;
+#endif
+
+ fmt = sts & QTS_FMMASK;
+ len = (sts & QTS_LNMASK) >> 4;
+
+ if (fmt > QCV_NFMT) {
+ ftg = NULL;
+ printf("ft%d: unsupported tape format\n", ftu);
+ return(-1);
+ }
+ if (len > QCV_NLEN) {
+ ftg = NULL;
+ printf("ft%d: unsupported tape length\n", ftu);
+ return(-1);
+ }
+
+ /* Look up geometry in the table */
+ for (i = 1; i < NGEOM; i++)
+ if (ftgtbl[i].g_fmtno == fmt && ftgtbl[i].g_lenno == len) break;
+ if (i == NGEOM) {
+ printf("ft%d: unknown tape geometry\n", ftu);
+ ftg = NULL;
+ return(-1);
+ }
+ ftg = &ftgtbl[i];
+ if (!ftg->g_trktape) {
+ printf("ft%d: unsupported format %s w/len %s\n",
+ ftu, ftg->g_fmtdesc, ftg->g_lendesc);
+ ftg = NULL;
+ return(-1);
+ }
+ DPRT(("Tape format is %s, length is %s\n", ftg->g_fmtdesc, ftg->g_lendesc));
+ ft->newcart = 0;
+ return(0);
+}
+
+/*
+ * Switch between tape/floppy. This will send the tape enable/disable
+ * codes for this drive's manufacturer.
+ */
+int set_fdcmode(dev_t dev, int newmode)
+{
+ ftu_t ftu = FDUNIT(minor(dev));
+ ft_p ft = &ft_data[ftu];
+ fdc_p fdc = ft->fdc;
+
+ static int havebufs = 0;
+ void *buf;
+ int r, s, i;
+ SegReq *sp;
+
+ if (newmode == FDC_TAPE_MODE) {
+ /* Wake up the tape drive */
+ switch (ft->type) {
+ case NO_TYPE:
+ fdc->flags &= ~FDC_TAPE_BUSY;
+ return(ENXIO);
+ case FT_COLORADO:
+ tape_start(ftu);
+ if (tape_cmd(ftu, QC_COL_ENABLE1)) {
+ tape_end(ftu);
+ return(EIO);
+ }
+ if (tape_cmd(ftu, QC_COL_ENABLE2)) {
+ tape_end(ftu);
+ return(EIO);
+ }
+ break;
+ case FT_MOUNTAIN:
+ tape_start(ftu);
+ if (tape_cmd(ftu, QC_MTN_ENABLE1)) {
+ tape_end(ftu);
+ return(EIO);
+ }
+ if (tape_cmd(ftu, QC_MTN_ENABLE2)) {
+ tape_end(ftu);
+ return(EIO);
+ }
+ break;
+ default:
+ DPRT(("ft%d: bad tape type\n", ftu));
+ return(ENXIO);
+ }
+ if (tape_status(ftu) < 0) {
+ tape_cmd(ftu, (ft->type == FT_COLORADO) ? QC_COL_DISABLE : QC_MTN_DISABLE);
+ tape_end(ftu);
+ return(EIO);
+ }
+
+ /* Grab buffers from memory. */
+ if (!havebufs) {
+ ft->curseg = malloc(sizeof(SegReq), M_DEVBUF, M_NOWAIT);
+ if (ft->curseg == NULL) {
+ printf("ft%d: not enough memory for buffers\n", ftu);
+ return(ENOMEM);
+ }
+ ft->bufseg = malloc(sizeof(SegReq), M_DEVBUF, M_NOWAIT);
+ if (ft->bufseg == NULL) {
+ free(ft->curseg, M_DEVBUF);
+ printf("ft%d: not enough memory for buffers\n", ftu);
+ return(ENOMEM);
+ }
+ havebufs = 1;
+ }
+ ft->curseg->reqtype = FTIO_READY;
+ ft->bufseg->reqtype = FTIO_READY;
+ ft->io_sts = FTIO_READY; /* tape drive is ready */
+ ft->active = 0; /* interrupt driver not active */
+ ft->moving = 0; /* tape not moving */
+ ft->rdonly = 0; /* tape read only */
+ ft->newcart = 0; /* a new cart was inserted */
+ ft->lastpos = -1; /* tape is rewound */
+ tape_state(ftu, 0, QS_READY, 60);
+ tape_cmd(ftu, QC_RATE);
+ tape_cmd(ftu, QCF_RT500+2); /* 500K bps */
+ tape_state(ftu, 0, QS_READY, 60);
+ ft->mode = FTM_PRIMARY;
+ tape_cmd(ftu, QC_PRIMARY); /* Make sure we're in primary mode */
+ tape_state(ftu, 0, QS_READY, 60);
+ ftg = NULL; /* No geometry yet */
+ ftgetgeom(ftu); /* Get tape geometry */
+ ftreq_rewind(ftu); /* Make sure tape is rewound */
+ } else {
+ tape_cmd(ftu, (ft->type == FT_COLORADO) ? QC_COL_DISABLE : QC_MTN_DISABLE);
+ tape_end(ftu);
+ ft->newcart = 0; /* clear new cartridge */
+ havebufs = 0;
+ free(ft->curseg, M_DEVBUF);
+ free(ft->bufseg, M_DEVBUF);
+ }
+ return(0);
+}
+
+
+/*
+ * Perform a QIC status function.
+ */
+int qic_status(ftu_t ftu, int cmd, int nbits)
+{
+ int st3, val, r, i;
+ ft_p ft = &ft_data[ftu];
+ fdcu_t fdcu = ft->fdc->fdcu; /* fdc active unit */
+
+ if (tape_cmd(ftu, cmd)) {
+ DPRT(("ft%d: QIC status timeout\n", ftu));
+ return(-1);
+ }
+
+ /* Sense drive status */
+ out_fdc(fdcu, NE7CMD_SENSED);
+ out_fdc(fdcu, 0x00);
+ st3 = in_fdc(fdcu);
+
+ if ((st3 & 0x10) == 0) { /* track 0 */
+ DPRT(("qic_status has dead drive... st3 = $%02x\n", st3));
+ return(-1);
+ }
+
+ for (i = r = 0; i <= nbits; i++) {
+ if (tape_cmd(ftu, QC_NEXTBIT)) {
+ DPRT(("ft%d: QIC status bit timed out on %d\n", ftu, i));
+ return(-1);
+ }
+
+ out_fdc(fdcu, NE7CMD_SENSED);
+ out_fdc(fdcu, 0x00);
+ st3 = in_fdc(fdcu);
+ if (st3 < 0) {
+ DPRT(("ft%d: controller timed out on bit %d r=$%02x\n",
+ ftu, i, r));
+ return(-1);
+ }
+
+ r >>= 1;
+ if (i < nbits)
+ r |= ((st3 & 0x10) ? 1 : 0) << nbits;
+ else if ((st3 & 0x10) == 0) {
+ DPRT(("ft%d: qic status stop bit missing at %d, st3=$%02x r=$%04x\n",
+ ftu,i,st3,r));
+ return(-1);
+ }
+ }
+
+ DPRT(("qic_status returned $%02x\n", r));
+ return(r);
+}
+
+/*
+ * Open tape drive for use. Bounced off of Fdopen if tape minor is
+ * detected.
+ */
+int ftopen(dev_t dev, int arg2) {
+ ftu_t ftu = FDUNIT(minor(dev));
+ int type = FDTYPE(minor(dev));
+ fdc_p fdc;
+
+ /* check bounds */
+ if (ftu >= NFT)
+ return(ENXIO);
+ fdc = ft_data[ftu].fdc;
+ /* check for controller already busy with tape */
+ if (fdc->flags & FDC_TAPE_BUSY)
+ return(EBUSY);
+ /* make sure we found a tape when probed */
+ if (!(fdc->flags & FDC_HASFTAPE))
+ return(ENODEV);
+ fdc->fdu = ftu;
+ fdc->flags |= FDC_TAPE_BUSY;
+ return(set_fdcmode(dev, FDC_TAPE_MODE)); /* try to switch to tape */
+}
+
+/*
+ * Close tape and return floppy controller to disk mode.
+ */
+int ftclose(dev_t dev, int flags)
+{
+ int s;
+ SegReq *sp;
+ ftu_t ftu = FDUNIT(minor(dev));
+ ft_p ft = &ft_data[ftu];
+
+ /* Wait for any remaining I/O activity to complete. */
+ if (ft->curseg->reqtype == FTIO_RDAHEAD) ft->curseg->reqcan = 1;
+ while (ft->active)
+ tsleep((caddr_t)&ftsem.iosts_change, FTPRI, "ftclose", 0);
+
+ ft->mode = FTM_PRIMARY;
+ tape_cmd(ftu, QC_PRIMARY);
+ tape_state(ftu, 0, QS_READY, 60);
+ ftreq_rewind(ftu);
+ return(set_fdcmode(dev, FDC_DISK_MODE)); /* Otherwise, close tape */
+}
+
+/*
+ * Perform strategy on a given buffer (not!). The driver was not
+ * performing very efficiently using the buffering routines. After
+ * support for error correction was added, this routine became
+ * obsolete in favor of doing ioctl's. Ugly, yes.
+ */
+void ftstrategy(struct buf *bp)
+{
+ return;
+}
+
+/* Read or write a segment. */
+int ftreq_rw(ftu_t ftu, int cmd, QIC_Segment *sr, struct proc *p)
+{
+ int r, i, j;
+ SegReq *sp;
+ int s;
+ long blk, bad;
+ unsigned char *cp, *cp2;
+ ft_p ft = &ft_data[ftu];
+
+ if (!ft->active) {
+ r = tape_status(ftu);
+ if ((r & QS_CART) == 0) {
+ return(ENXIO); /* No cartridge */
+ }
+ if ((r & QS_FMTOK) == 0) {
+ return(ENXIO); /* Not formatted */
+ }
+ tape_state(ftu, 0, QS_READY, 90);
+ }
+
+ if (ftg == NULL || ft->newcart) {
+ while (ft->active)
+ tsleep((caddr_t)&ftsem.iosts_change, FTPRI, "ftrw", 0);
+ tape_state(ftu, 0, QS_READY, 90);
+ if (ftgetgeom(ftu) < 0) {
+ return(ENXIO);
+ }
+ }
+
+ /* Write not allowed on a read-only tape. */
+ if (cmd == QIOWRITE && ft->rdonly) {
+ return(EROFS);
+ }
+ /* Quick check of request and buffer. */
+ if (sr == NULL || sr->sg_data == NULL) {
+ return(EINVAL);
+ }
+ if (sr->sg_trk >= ftg->g_trktape ||
+ sr->sg_seg >= ftg->g_segtrk) {
+ return(EINVAL);
+ }
+ blk = sr->sg_trk * ftg->g_blktrk + sr->sg_seg * QCV_BLKSEG;
+
+ s = splbio();
+ if (cmd == QIOREAD) {
+ if (ft->curseg->reqtype == FTIO_RDAHEAD) {
+ if (blk == ft->curseg->reqblk) {
+ sp = ft->curseg;
+ sp->reqtype = FTIO_READING;
+ sp->reqbad = sr->sg_badmap;
+ goto rdwait;
+ } else
+ ft->curseg->reqcan = 1; /* XXX cancel rdahead */
+ }
+
+ /* Wait until we're ready. */
+ while (ft->active)
+ tsleep((caddr_t)&ftsem.iosts_change, FTPRI, "ftrw", 0);
+
+ /* Set up a new read request. */
+ sp = ft->curseg;
+ sp->reqcrc = 0;
+ sp->reqbad = sr->sg_badmap;
+ sp->reqblk = blk;
+ sp->reqcan = 0;
+ sp->reqtype = FTIO_READING;
+
+ /* Start the read request off. */
+ DPRT(("Starting read I/O chain\n"));
+ arq_state = ard_state = awr_state = 0;
+ ft->xblk = sp->reqblk;
+ ft->xcnt = 0;
+ ft->xptr = sp->buff;
+ ft->active = 1;
+ timeout(ft_timeout, (caddr_t)ftu, 1);
+
+rdwait:
+ tsleep((caddr_t)&ftsem.buff_avail, FTPRI, "ftrw", 0);
+ bad = sp->reqbad;
+ sr->sg_crcmap = sp->reqcrc & ~bad;
+
+ /* Copy out segment and discard bad mapped blocks. */
+ cp = sp->buff; cp2 = sr->sg_data;
+ for (i = 0; i < QCV_BLKSEG; cp += QCV_BLKSIZE, i++) {
+ if (bad & (1 << i)) continue;
+ copyout(cp, cp2, QCV_BLKSIZE);
+ cp2 += QCV_BLKSIZE;
+ }
+ } else {
+ if (ft->curseg->reqtype == FTIO_RDAHEAD) {
+ ft->curseg->reqcan = 1; /* XXX cancel rdahead */
+ while (ft->active)
+ tsleep((caddr_t)&ftsem.iosts_change, FTPRI, "ftrw", 0);
+ }
+
+ /* Sleep until a buffer becomes available. */
+ while (ft->bufseg->reqtype != FTIO_READY)
+ tsleep((caddr_t)&ftsem.buff_avail, FTPRI, "ftrwbuf", 0);
+ sp = (ft->curseg->reqtype == FTIO_READY) ? ft->curseg : ft->bufseg;
+
+ /* Copy in segment and expand bad blocks. */
+ bad = sr->sg_badmap;
+ cp = sr->sg_data; cp2 = sp->buff;
+ for (i = 0; i < QCV_BLKSEG; cp2 += QCV_BLKSIZE, i++) {
+ if (bad & (1 << i)) continue;
+ copyin(cp, cp2, QCV_BLKSIZE);
+ cp += QCV_BLKSIZE;
+ }
+
+ sp->reqblk = blk;
+ sp->reqcan = 0;
+ sp->reqtype = FTIO_WRITING;
+
+ if (!ft->active) {
+ DPRT(("Starting write I/O chain\n"));
+ arq_state = ard_state = awr_state = 0;
+ ft->xblk = sp->reqblk;
+ ft->xcnt = 0;
+ ft->xptr = sp->buff;
+ ft->active = 1;
+ timeout(ft_timeout, (caddr_t)ftu, 1);
+ }
+ }
+ splx(s);
+ return(0);
+}
+
+
+/* Rewind to beginning of tape */
+int ftreq_rewind(ftu_t ftu)
+{
+ ft_p ft = &ft_data[ftu];
+
+ tape_inactive(ftu);
+ tape_cmd(ftu, QC_STOP);
+ tape_state(ftu, 0, QS_READY, 90);
+ tape_cmd(ftu, QC_SEEKSTART);
+ tape_state(ftu, 0, QS_READY, 90);
+ tape_cmd(ftu, QC_SEEKTRACK);
+ tape_cmd(ftu, 2);
+ tape_state(ftu, 0, QS_READY, 90);
+ ft->lastpos = -1;
+ ft->moving = 0;
+ return(0);
+}
+
+/* Move to logical beginning or end of track */
+int ftreq_trkpos(ftu_t ftu, int req)
+{
+ int curtrk, r, cmd;
+ ft_p ft = &ft_data[ftu];
+
+ tape_inactive(ftu);
+ tape_cmd(ftu, QC_STOP);
+ tape_state(ftu, 0, QS_READY, 90);
+
+ r = tape_status(ftu);
+ if ((r & QS_CART) == 0) return(ENXIO); /* No cartridge */
+ if ((r & QS_FMTOK) == 0) return(ENXIO); /* Not formatted */
+
+ if (ftg == NULL || ft->newcart) {
+ if (ftgetgeom(ftu) < 0) return(ENXIO);
+ }
+
+ curtrk = (ft->lastpos < 0) ? 0 : ft->lastpos / ftg->g_blktrk;
+ if (req == QIOBOT)
+ cmd = (curtrk & 1) ? QC_SEEKEND : QC_SEEKSTART;
+ else
+ cmd = (curtrk & 1) ? QC_SEEKSTART : QC_SEEKEND;
+ tape_cmd(ftu, cmd);
+ tape_state(ftu, 0, QS_READY, 90);
+ return(0);
+}
+
+/* Seek tape head to a particular track. */
+int ftreq_trkset(ftu_t ftu, int *trk)
+{
+ int curtrk, r, cmd;
+ ft_p ft = &ft_data[ftu];
+
+ tape_inactive(ftu);
+ tape_cmd(ftu, QC_STOP);
+ tape_state(ftu, 0, QS_READY, 90);
+
+ r = tape_status(ftu);
+ if ((r & QS_CART) == 0) return(ENXIO); /* No cartridge */
+ if ((r & QS_FMTOK) == 0) return(ENXIO); /* Not formatted */
+ if (ftg == NULL || ft->newcart) {
+ if (ftgetgeom(ftu) < 0) return(ENXIO);
+ }
+
+ tape_cmd(ftu, QC_SEEKTRACK);
+ tape_cmd(ftu, *trk + 2);
+ tape_state(ftu, 0, QS_READY, 90);
+ return(0);
+}
+
+/* Start tape moving forward. */
+int ftreq_lfwd(ftu_t ftu)
+{
+ tape_inactive(ftu);
+ tape_cmd(ftu, QC_STOP);
+ tape_state(ftu, 0, QS_READY, 90);
+ tape_cmd(ftu, QC_FORWARD);
+ return(0);
+}
+
+/* Stop the tape */
+int ftreq_stop(ftu_t ftu)
+{
+ tape_inactive(ftu);
+ tape_cmd(ftu, QC_STOP);
+ tape_state(ftu, 0, QS_READY, 90);
+ return(0);
+}
+
+/* Set the particular mode the drive should be in. */
+int ftreq_setmode(ftu_t ftu, int cmd)
+{
+ int r;
+ ft_p ft = &ft_data[ftu];
+
+ tape_inactive(ftu);
+ r = tape_status(ftu);
+
+ switch(cmd) {
+ case QIOPRIMARY:
+ ft->mode = FTM_PRIMARY;
+ tape_cmd(ftu, QC_PRIMARY);
+ break;
+ case QIOFORMAT:
+ if (r & QS_RDONLY) return(ENXIO);
+ if ((r & QS_BOT) == 0) return(ENXIO);
+ tape_cmd(ftu, QC_FORMAT);
+ break;
+ case QIOVERIFY:
+ if ((r & QS_FMTOK) == 0) return(ENXIO); /* Not formatted */
+ tape_cmd(ftu, QC_VERIFY);
+ break;
+ }
+ tape_state(ftu, 0, QS_READY, 60);
+ return(0);
+}
+
+/* Return drive status bits */
+int ftreq_status(ftu_t ftu, int cmd, int *sts, struct proc *p)
+{
+ ft_p ft = &ft_data[ftu];
+
+ if (ft->active)
+ *sts = ft->laststs & ~QS_READY;
+ else
+ *sts = tape_status(ftu);
+ return(0);
+}
+
+/* Return drive configuration bits */
+int ftreq_config(ftu_t ftu, int cmd, int *cfg, struct proc *p)
+{
+ int r, tries;
+ ft_p ft = &ft_data[ftu];
+
+ if (ft->active)
+ r = ft->lastcfg;
+ else {
+ for (r = -1, tries = 0; r < 0 && tries < 3; tries++)
+ r = qic_status(ftu, QC_CONFIG, 8);
+ if (tries == 3) return(ENXIO);
+ }
+ *cfg = r;
+ return(0);
+}
+
+/* Return current tape's geometry. */
+int ftreq_geom(ftu_t ftu, QIC_Geom *g)
+{
+ tape_inactive(ftu);
+ if (ftg == NULL && ftgetgeom(ftu) < 0) return(ENXIO);
+ bcopy(ftg, g, sizeof(QIC_Geom));
+ return(0);
+}
+
+/* Return drive hardware information */
+int ftreq_hwinfo(ftu_t ftu, QIC_HWInfo *hwp)
+{
+ int r, tries;
+ int rom, vend;
+
+ tape_inactive(ftu);
+ bzero(hwp, sizeof(QIC_HWInfo));
+
+ for (rom = -1, tries = 0; rom < 0 && tries < 3; tries++)
+ rom = qic_status(ftu, QC_VERSION, 8);
+ if (rom > 0) {
+ hwp->hw_rombeta = (rom >> 7) & 0x01;
+ hwp->hw_romid = rom & 0x7f;
+ }
+
+ for (vend = -1, tries = 0; vend < 0 && tries < 3; tries++)
+ vend = qic_status(ftu, QC_VENDORID, 16);
+ if (vend > 0) {
+ hwp->hw_make = (vend >> 6) & 0x3ff;
+ hwp->hw_model = vend & 0x3f;
+ }
+
+ return(0);
+}
+
+/*
+ * I/O functions.
+ */
+int ftioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
+{
+ ftu_t ftu = FDUNIT(minor(dev));
+ ft_p ft = &ft_data[ftu];
+
+ switch(cmd) {
+ case QIOREAD: /* Request reading a segment from tape. */
+ case QIOWRITE: /* Request writing a segment to tape. */
+ return(ftreq_rw(ftu, cmd, (QIC_Segment *)data, p));
+
+ case QIOREWIND: /* Rewind tape. */
+ return(ftreq_rewind(ftu));
+
+ case QIOBOT: /* Seek to logical beginning of track. */
+ case QIOEOT: /* Seek to logical end of track. */
+ return(ftreq_trkpos(ftu, cmd));
+
+ case QIOTRACK: /* Seek tape head to specified track. */
+ return(ftreq_trkset(ftu, (int *)data));
+
+ case QIOSEEKLP: /* Seek load point. */
+ goto badreq;
+
+ case QIOFORWARD: /* Move tape in logical forward direction. */
+ return(ftreq_lfwd(ftu));
+
+ case QIOSTOP: /* Causes tape to stop. */
+ return(ftreq_stop(ftu));
+
+ case QIOPRIMARY: /* Enter primary mode. */
+ case QIOFORMAT: /* Enter format mode. */
+ case QIOVERIFY: /* Enter verify mode. */
+ return(ftreq_setmode(ftu, cmd));
+
+ case QIOWRREF: /* Write reference burst. */
+ goto badreq;
+
+ case QIOSTATUS: /* Get drive status. */
+ return(ftreq_status(ftu, cmd, (int *)data, p));
+
+ case QIOCONFIG: /* Get tape configuration. */
+ return(ftreq_config(ftu, cmd, (int *)data, p));
+
+ case QIOGEOM:
+ return(ftreq_geom(ftu, (QIC_Geom *)data));
+
+ case QIOHWINFO:
+ return(ftreq_hwinfo(ftu, (QIC_HWInfo *)data));
+ }
+badreq:
+ DPRT(("ft%d: unknown ioctl(%d) request\n", ftu, cmd));
+ return(ENXIO);
+}
+
+/* Not implemented */
+int ftdump(dev_t dev)
+{
+ return(EINVAL);
+}
+
+/* Not implemented */
+int ftsize(dev_t dev)
+{
+ return(EINVAL);
+}
+#endif
diff --git a/sys/i386/isa/ftreg.h b/sys/i386/isa/ftreg.h
new file mode 100644
index 0000000..7b4ca6a
--- /dev/null
+++ b/sys/i386/isa/ftreg.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1993 Steve Gerakines
+ *
+ * This is freely redistributable software. You may do anything you
+ * wish with it, so long as the above notice stays intact.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ftreg.h - QIC-40/80 floppy tape driver header
+ * 10/30/93 v0.3
+ * More things will end up here. QC_VENDORID and QC_VERSION now used.
+ *
+ * 08/07/93 v0.2 release
+ * Things that should've been here in the first place were moved.
+ * Tape geometry and segment request types were added.
+ *
+ * 06/03/93 v0.1 Alpha release
+ * Initial revision. Many more things should be moved here.
+ */
+
+/* QIC-117 command set. */
+#define QC_RESET 1 /* reset */
+#define QC_NEXTBIT 2 /* report next bit */
+#define QC_PAUSE 3 /* pause */
+#define QC_STPAUSE 4 /* step pause */
+#define QC_TIMEOUT 5 /* alt timeout */
+#define QC_STATUS 6 /* report status */
+#define QC_ERRCODE 7 /* report error code */
+#define QC_CONFIG 8 /* report config */
+#define QC_VERSION 9 /* report version */
+#define QC_FORWARD 10 /* logical forward */
+#define QC_SEEKSTART 11 /* seek to track start */
+#define QC_SEEKEND 12 /* seek to track end */
+#define QC_SEEKTRACK 13 /* seek head to track */
+#define QC_SEEKLOAD 14 /* seek load point */
+#define QC_FORMAT 15 /* format mode */
+#define QC_WRITEREF 16 /* write reference */
+#define QC_VERIFY 17 /* verify mode */
+#define QC_STOP 18 /* stop tape */
+#define QC_STEPUP 21 /* step head up */
+#define QC_STEPDOWN 22 /* step head down */
+#define QC_SEEKREV 25 /* seek reverse */
+#define QC_SEEKFWD 26 /* seek forward */
+#define QC_RATE 27 /* select data rate */
+#define QC_DIAG1 28 /* diagnostic mode 1 */
+#define QC_DIAG2 29 /* diagnostic mode 2 */
+#define QC_PRIMARY 30 /* primary mode */
+#define QC_VENDORID 32 /* vendor id */
+#define QC_TSTATUS 33 /* report tape status */
+#define QC_EXTREV 34 /* extended skip reverse */
+#define QC_EXTFWD 35 /* extended skip forward */
+
+/* Colorado enable/disable. */
+#define QC_COL_ENABLE1 46 /* enable */
+#define QC_COL_ENABLE2 2 /* null-op */
+#define QC_COL_DISABLE 47 /* disable */
+
+/* Mountain enable/disable. */
+#define QC_MTN_ENABLE1 23 /* enable 1 */
+#define QC_MTN_ENABLE2 20 /* enable 2 */
+#define QC_MTN_DISABLE 24 /* disable */
+
+/* Segment I/O request. */
+typedef struct segq {
+ unsigned char buff[QCV_SEGSIZE];/* Segment data; first for alignment */
+ int reqtype; /* Request type */
+ long reqcrc; /* CRC Errors found */
+ long reqbad; /* Bad sector map */
+ long reqblk; /* Block request starts at */
+ int reqcan; /* Cancel read-ahead */
+} SegReq;
diff --git a/sys/i386/isa/ic/i8042.h b/sys/i386/isa/ic/i8042.h
new file mode 100644
index 0000000..84ee90f
--- /dev/null
+++ b/sys/i386/isa/ic/i8042.h
@@ -0,0 +1,27 @@
+/*
+ * $Id$
+ */
+
+#define KBSTATP 0x64 /* kbd controller status port (I) */
+#define KBS_DIB 0x01 /* kbd data in buffer */
+#define KBS_IBF 0x02 /* kbd input buffer low */
+#define KBS_WARM 0x04 /* kbd input buffer low */
+#define KBS_OCMD 0x08 /* kbd output buffer has command */
+#define KBS_NOSEC 0x10 /* kbd security lock not engaged */
+#define KBS_TERR 0x20 /* kbd transmission error */
+#define KBS_RERR 0x40 /* kbd receive error */
+#define KBS_PERR 0x80 /* kbd parity error */
+
+#define KBCMDP 0x64 /* kbd controller port (O) */
+#define KBDATAP 0x60 /* kbd data port (I) */
+#define KBOUTP 0x60 /* kbd data port (O) */
+
+#define K_LDCMDBYTE 0x60
+
+#define KC8_TRANS 0x40 /* convert to old scan codes */
+#define KC8_OLDPC 0x20 /* old 9bit codes instead of new 11bit */
+#define KC8_DISABLE 0x10 /* disable keyboard */
+#define KC8_IGNSEC 0x08 /* ignore security lock */
+#define KC8_CPU 0x04 /* exit from protected mode reset */
+#define KC8_IEN 0x01 /* enable interrupt */
+#define CMDBYTE (KC8_TRANS|KC8_IGNSEC|KC8_CPU|KC8_IEN)
diff --git a/sys/i386/isa/ic/i8237.h b/sys/i386/isa/ic/i8237.h
new file mode 100644
index 0000000..2199e73
--- /dev/null
+++ b/sys/i386/isa/ic/i8237.h
@@ -0,0 +1,11 @@
+/*
+ * Intel 8237 DMA Controller
+ *
+ * $Id$
+ */
+
+#define DMA37MD_SINGLE 0x40 /* single pass mode */
+#define DMA37MD_CASCADE 0xc0 /* cascade mode */
+#define DMA37MD_WRITE 0x04 /* read the device, write memory operation */
+#define DMA37MD_READ 0x08 /* write the device, read memory operation */
+
diff --git a/sys/i386/isa/ic/i82586.h b/sys/i386/isa/ic/i82586.h
new file mode 100644
index 0000000..577313d
--- /dev/null
+++ b/sys/i386/isa/ic/i82586.h
@@ -0,0 +1,325 @@
+/*-
+ * Copyright (c) 1992, University of Vermont and State Agricultural College.
+ * Copyright (c) 1992, Garrett A. Wollman.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * Vermont and State Agricultural College and Garrett A. Wollman.
+ * 4. Neither the name of the University nor the name of the author
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR AUTHOR BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+/*
+ * Intel 82586 Ethernet chip
+ * Register, bit, and structure definitions.
+ *
+ * Written by GAW with reference to the Clarkson Packet Driver code for this
+ * chip written by Russ Nelson and others.
+ */
+
+struct ie_en_addr {
+ u_char data[6];
+};
+
+/*
+ * This is the master configuration block. It tells the hardware where all
+ * the rest of the stuff is.
+ */
+struct ie_sys_conf_ptr {
+ u_short mbz; /* must be zero */
+ u_char ie_bus_use; /* true if 8-bit only */
+ u_char mbz2[5]; /* must be zero */
+ caddr_t ie_iscp_ptr; /* 24-bit physaddr of ISCP */
+};
+
+/*
+ * Note that this is wired in hardware; the SCP is always located here, no
+ * matter what.
+ */
+#define IE_SCP_ADDR 0xfffff4
+
+/*
+ * The tells the hardware where all the rest of the stuff is, too.
+ * FIXME: some of these should be re-commented after we figure out their
+ * REAL function.
+ */
+struct ie_int_sys_conf_ptr {
+ u_char ie_busy; /* zeroed after init */
+ u_char mbz;
+ u_short ie_scb_offset; /* 16-bit physaddr of next struct */
+ caddr_t ie_base; /* 24-bit physaddr for all 16-bit vars */
+};
+
+/*
+ * This FINALLY tells the hardware what to do and where to put it.
+ */
+struct ie_sys_ctl_block {
+ u_short ie_status; /* status word */
+ u_short ie_command; /* command word */
+ u_short ie_command_list; /* 16-pointer to command block list */
+ u_short ie_recv_list; /* 16-pointer to receive frame list */
+ u_short ie_err_crc; /* CRC errors */
+ u_short ie_err_align; /* Alignment errors */
+ u_short ie_err_resource; /* Resource errors */
+ u_short ie_err_overrun; /* Overrun errors */
+};
+
+/* Command values */
+#define IE_RU_COMMAND 0x0070 /* mask for RU command */
+#define IE_RU_NOP 0 /* for completeness */
+#define IE_RU_START 0x0010 /* start receive unit command */
+#define IE_RU_ENABLE 0x0020 /* enable receiver command */
+#define IE_RU_DISABLE 0x0030 /* disable receiver command */
+#define IE_RU_ABORT 0x0040 /* abort current receive operation */
+
+#define IE_CU_COMMAND 0x0700 /* mask for CU command */
+#define IE_CU_NOP 0 /* included for completeness */
+#define IE_CU_START 0x0100 /* do-command command */
+#define IE_CU_RESUME 0x0200 /* resume a suspended cmd list */
+#define IE_CU_STOP 0x0300 /* SUSPEND was already taken */
+#define IE_CU_ABORT 0x0400 /* abort current command */
+
+#define IE_ACK_COMMAND 0xf000 /* mask for ACK command */
+#define IE_ACK_CX 0x8000 /* ack IE_ST_DONE */
+#define IE_ACK_FR 0x4000 /* ack IE_ST_RECV */
+#define IE_ACK_CNA 0x2000 /* ack IE_ST_ALLDONE */
+#define IE_ACK_RNR 0x1000 /* ack IE_ST_RNR */
+
+#define IE_ACTION_COMMAND(x) (((x) & IE_CU_COMMAND) == IE_CU_START)
+ /* is this command an action command? */
+
+/* Status values */
+#define IE_ST_WHENCE 0xf000 /* mask for cause of interrupt */
+#define IE_ST_DONE 0x8000 /* command with I bit completed */
+#define IE_ST_RECV 0x4000 /* frame received */
+#define IE_ST_ALLDONE 0x2000 /* all commands completed */
+#define IE_ST_RNR 0x1000 /* receive not ready */
+
+#define IE_CU_STATUS 0x700 /* mask for command unit status */
+#define IE_CU_ACTIVE 0x200 /* command unit is active */
+#define IE_CU_SUSPEND 0x100 /* command unit is suspended */
+
+#define IE_RU_STATUS 0x70 /* mask for receiver unit status */
+#define IE_RU_SUSPEND 0x10 /* receiver is suspended */
+#define IE_RU_NOSPACE 0x20 /* receiver has no resources */
+#define IE_RU_READY 0x40 /* reveiver is ready */
+
+/*
+ * This is filled in partially by the chip, partially by us.
+ */
+struct ie_recv_frame_desc {
+ u_short ie_fd_status; /* status for this frame */
+ u_short ie_fd_last; /* end of frame list flag */
+ u_short ie_fd_next; /* 16-pointer to next RFD */
+ u_short ie_fd_buf_desc; /* 16-pointer to list of buffer desc's */
+ struct ie_en_addr dest; /* destination ether */
+ struct ie_en_addr src; /* source ether */
+ u_short ie_length; /* 802 length/Ether type */
+ u_short mbz; /* must be zero */
+};
+
+#define IE_FD_LAST 0x8000 /* last rfd in list */
+#define IE_FD_SUSP 0x4000 /* suspend RU after receipt */
+
+#define IE_FD_COMPLETE 0x8000 /* frame is complete */
+#define IE_FD_BUSY 0x4000 /* frame is busy */
+#define IE_FD_OK 0x2000 /* frame is bad */
+#define IE_FD_RNR 0x0200 /* receiver out of resources here */
+
+/*
+ * linked list of buffers...
+ */
+struct ie_recv_buf_desc {
+ u_short ie_rbd_actual; /* status for this buffer */
+ u_short ie_rbd_next; /* 16-pointer to next RBD */
+ caddr_t ie_rbd_buffer; /* 24-pointer to buffer for this RBD */
+ u_short ie_rbd_length; /* length of the buffer */
+ u_short mbz; /* must be zero */
+};
+
+#define IE_RBD_LAST 0x8000 /* last buffer */
+#define IE_RBD_USED 0x4000 /* this buffer has data */
+/*
+ * All commands share this in common.
+ */
+struct ie_cmd_common {
+ u_short ie_cmd_status; /* status of this command */
+ u_short ie_cmd_cmd; /* command word */
+ u_short ie_cmd_link; /* link to next command */
+};
+
+#define IE_STAT_COMPL 0x8000 /* command is completed */
+#define IE_STAT_BUSY 0x4000 /* command is running now */
+#define IE_STAT_OK 0x2000 /* command completed successfully */
+
+#define IE_CMD_NOP 0x0000 /* NOP */
+#define IE_CMD_IASETUP 0x0001 /* initial address setup */
+#define IE_CMD_CONFIG 0x0002 /* configure command */
+#define IE_CMD_MCAST 0x0003 /* multicast setup command */
+#define IE_CMD_XMIT 0x0004 /* transmit command */
+#define IE_CMD_TDR 0x0005 /* time-domain reflectometer command */
+#define IE_CMD_DUMP 0x0006 /* dump command */
+#define IE_CMD_DIAGNOSE 0x0007 /* diagnostics command */
+
+#define IE_CMD_LAST 0x8000 /* this is the last command in the list */
+#define IE_CMD_SUSPEND 0x4000 /* suspend CU after this command */
+#define IE_CMD_INTR 0x2000 /* post an interrupt after completion */
+
+/*
+ * This is the command to transmit a frame.
+ */
+struct ie_xmit_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_xmit_status com.ie_cmd_status
+
+ u_short ie_xmit_desc; /* 16-pointer to buffer descriptor */
+ struct ie_en_addr ie_xmit_addr; /* destination address */
+
+ u_short ie_xmit_length; /* 802.3 length/Ether type field */
+};
+
+#define IE_XS_MAXCOLL 0x000f /* number of collisions during transmit */
+#define IE_XS_EXCMAX 0x0020 /* exceeded maximum number of collisions */
+#define IE_XS_SQE 0x0040 /* SQE positive */
+#define IE_XS_DEFERRED 0x0080 /* transmission deferred */
+#define IE_XS_UNDERRUN 0x0100 /* DMA underrun */
+#define IE_XS_LOSTCTS 0x0200 /* Lost CTS */
+#define IE_XS_NOCARRIER 0x0400 /* No Carrier */
+#define IE_XS_LATECOLL 0x0800 /* Late collision */
+
+/*
+ * This is a buffer descriptor for a frame to be transmitted.
+ */
+
+struct ie_xmit_buf {
+ u_short ie_xmit_flags; /* see below */
+ u_short ie_xmit_next; /* 16-pointer to next desc. */
+ caddr_t ie_xmit_buf; /* 24-pointer to the actual buffer */
+};
+
+#define IE_XMIT_LAST 0x8000 /* this TBD is the last one */
+/* The rest of the `flags' word is actually the length. */
+
+/*
+ * Multicast setup command.
+ */
+
+#define MAXMCAST 50 /* must fit in transmit buffer */
+
+struct ie_mcast_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_mcast_status com.ie_cmd_status
+
+ u_short ie_mcast_bytes; /* size (in bytes) of multicast addresses */
+ struct ie_en_addr ie_mcast_addrs[MAXMCAST + 1]; /* space for them */
+};
+
+/*
+ * Time Domain Reflectometer command.
+ */
+
+struct ie_tdr_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_tdr_status com.ie_cmd_status
+
+ u_short ie_tdr_time; /* error bits and time */
+};
+
+#define IE_TDR_SUCCESS 0x8000 /* TDR succeeded without error */
+#define IE_TDR_XCVR 0x4000 /* detected a transceiver problem */
+#define IE_TDR_OPEN 0x2000 /* detected an open */
+#define IE_TDR_SHORT 0x1000 /* TDR detected a short */
+#define IE_TDR_TIME 0x07ff /* mask for reflection time */
+
+/*
+ * Initial Address Setup command
+ */
+struct ie_iasetup_cmd {
+ struct ie_cmd_common com;
+#define ie_iasetup_status com.ie_cmd_status
+
+ struct ie_en_addr ie_address;
+};
+
+/*
+ * Configuration command
+ */
+struct ie_config_cmd {
+ struct ie_cmd_common com; /* common part */
+#define ie_config_status com.ie_cmd_status
+
+ u_char ie_config_count; /* byte count (0x0c) */
+ u_char ie_fifo; /* fifo (8) */
+ u_char ie_save_bad; /* save bad frames (0x40) */
+ u_char ie_addr_len; /* address length (0x2e) (AL-LOC == 1) */
+ u_char ie_priority; /* priority and backoff (0x0) */
+ u_char ie_ifs; /* inter-frame spacing (0x60) */
+ u_char ie_slot_low; /* slot time, LSB (0x0) */
+ u_char ie_slot_high; /* slot time, MSN, and retries (0xf2) */
+ u_char ie_promisc; /* 1 if promiscuous, else 0 */
+ u_char ie_crs_cdt; /* CSMA/CD parameters (0x0) */
+ u_char ie_min_len; /* min frame length (0x40) */
+ u_char ie_junk; /* stuff for 82596 (0xff) */
+};
+
+/*
+ * Here are a few useful functions. We could have done these as macros,
+ * but since we have the inline facility, it makes sense to use that
+ * instead.
+ */
+inline void
+ie_setup_config(volatile struct ie_config_cmd *cmd,
+ int promiscuous, int manchester) {
+ cmd->ie_config_count = 0x0c;
+ cmd->ie_fifo = 8;
+ cmd->ie_save_bad = 0x40;
+ cmd->ie_addr_len = 0x2e;
+ cmd->ie_priority = 0;
+ cmd->ie_ifs = 0x60;
+ cmd->ie_slot_low = 0;
+ cmd->ie_slot_high = 0xf2;
+ cmd->ie_promisc = !!promiscuous | manchester << 2;
+ cmd->ie_crs_cdt = 0;
+ cmd->ie_min_len = 64;
+ cmd->ie_junk = 0xff;
+}
+
+inline caddr_t
+Align(caddr_t ptr) {
+ unsigned long l = (unsigned long)ptr;
+ l = (l + 3) & ~3L;
+ return (caddr_t)l;
+}
+
+inline void
+ie_ack(volatile struct ie_sys_ctl_block *scb,
+ u_int mask, int unit,
+ void (*ca)(int)) {
+ scb->ie_command = scb->ie_status & mask;
+ (*ca)(unit);
+}
diff --git a/sys/i386/isa/ic/nec765.h b/sys/i386/isa/ic/nec765.h
new file mode 100644
index 0000000..1895db7
--- /dev/null
+++ b/sys/i386/isa/ic/nec765.h
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)nec765.h 7.1 (Berkeley) 5/9/91
+ * $Id$
+ */
+
+/*
+ * Nec 765 floppy disc controller definitions
+ */
+
+/* Main status register */
+#define NE7_DAB 0x01 /* Diskette drive A is seeking, thus busy */
+#define NE7_DBB 0x02 /* Diskette drive B is seeking, thus busy */
+#define NE7_CB 0x10 /* Diskette Controller Busy */
+#define NE7_NDM 0x20 /* Diskette Controller in Non Dma Mode */
+#define NE7_DIO 0x40 /* Diskette Controller Data register I/O */
+#define NE7_RQM 0x80 /* Diskette Controller ReQuest for Master */
+
+/* Status register ST0 */
+#define NE7_ST0BITS "\020\010invld\007abnrml\006seek_cmplt\005drv_chck\004drive_rdy\003top_head"
+
+/* Status register ST1 */
+#define NE7_ST1BITS "\020\010end_of_cyl\006bad_crc\005data_overrun\003sec_not_fnd\002write_protect\001no_am"
+
+/* Status register ST2 */
+#define NE7_ST2BITS "\020\007ctrl_mrk\006bad_crc\005wrong_cyl\004scn_eq\003scn_not_fnd\002bad_cyl\001no_dam"
+
+/* Status register ST3 */
+#define NE7_ST3BITS "\020\010fault\007write_protect\006drdy\005tk0\004two_side\003side_sel\002"
+
+/* Commands */
+#define NE7CMD_SPECIFY 3 /* specify drive parameters - requires unit
+ parameters byte */
+#define NE7CMD_SENSED 4 /* sense drive - requires unit select byte */
+#define NE7CMD_WRITE 0xc5 /* write - requires eight additional bytes */
+#define NE7CMD_READ 0xe6 /* read - requires eight additional bytes */
+#define NE7CMD_FORMAT 0x4c /* format - requires five additional bytes */
+#define NE7CMD_RECAL 7 /* recalibrate drive - requires
+ unit select byte */
+#define NE7CMD_SENSEI 8 /* sense controller interrupt status */
+#define NE7CMD_SEEK 15 /* seek drive - requires unit select byte
+ and new cyl byte */
diff --git a/sys/i386/isa/ic/ns16450.h b/sys/i386/isa/ic/ns16450.h
new file mode 100644
index 0000000..aa6280d
--- /dev/null
+++ b/sys/i386/isa/ic/ns16450.h
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)ns16450.h 7.1 (Berkeley) 5/9/91
+ * $Id$
+ */
+
+/*
+ * NS16450 UART registers
+ */
+
+#define com_data 0 /* data register (R/W) */
+#define com_dlbl 0 /* divisor latch low (W) */
+#define com_dlbh 1 /* divisor latch high (W) */
+#define com_ier 1 /* interrupt enable (W) */
+#define com_iir 2 /* interrupt identification (R) */
+#define com_lctl 3 /* line control register (R/W) */
+#define com_cfcr 3 /* line control register (R/W) */
+#define com_mcr 4 /* modem control register (R/W) */
+#define com_lsr 5 /* line status register (R/W) */
+#define com_msr 6 /* modem status register (R/W) */
diff --git a/sys/i386/isa/ic/ns16550.h b/sys/i386/isa/ic/ns16550.h
new file mode 100644
index 0000000..ff59757
--- /dev/null
+++ b/sys/i386/isa/ic/ns16550.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)ns16550.h 7.1 (Berkeley) 5/9/91
+ * $Id$
+ */
+
+/*
+ * NS16550 UART registers
+ */
+
+#define com_data 0 /* data register (R/W) */
+#define com_dlbl 0 /* divisor latch low (W) */
+#define com_dlbh 1 /* divisor latch high (W) */
+#define com_ier 1 /* interrupt enable (W) */
+#define com_iir 2 /* interrupt identification (R) */
+#define com_fifo 2 /* FIFO control (W) */
+#define com_lctl 3 /* line control register (R/W) */
+#define com_cfcr 3 /* line control register (R/W) */
+#define com_mcr 4 /* modem control register (R/W) */
+#define com_lsr 5 /* line status register (R/W) */
+#define com_msr 6 /* modem status register (R/W) */
diff --git a/sys/i386/isa/icu.h b/sys/i386/isa/icu.h
new file mode 100644
index 0000000..13216b0
--- /dev/null
+++ b/sys/i386/isa/icu.h
@@ -0,0 +1,97 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)icu.h 5.6 (Berkeley) 5/9/91
+ * $Id: icu.h,v 1.2 1993/10/16 13:45:51 rgrimes Exp $
+ */
+
+/*
+ * AT/386 Interrupt Control constants
+ * W. Jolitz 8/89
+ */
+
+#ifndef __ICU__
+#define __ICU__
+
+#ifndef LOCORE
+
+/*
+ * Interrupt "level" mechanism variables, masks, and macros
+ */
+extern unsigned imen; /* interrupt mask enable */
+
+#define INTREN(s) (imen &= ~(s), SET_ICUS())
+#define INTRDIS(s) (imen |= (s), SET_ICUS())
+#define INTRMASK(msk,s) (msk |= (s))
+#if 0
+#define SET_ICUS() (outb(IO_ICU1 + 1, imen), outb(IU_ICU2 + 1, imen >> 8))
+#else
+/*
+ * XXX - IO_ICU* are defined in isa.h, not icu.h, and nothing much bothers to
+ * include isa.h, while too many things include icu.h.
+ */
+#define SET_ICUS() (outb(0x21, imen), outb(0xa1, imen >> 8))
+#endif
+
+#endif
+
+/*
+ * Interrupt enable bits - in normal order of priority (which we change)
+ */
+#define IRQ0 0x0001 /* highest priority - timer */
+#define IRQ1 0x0002
+#define IRQ_SLAVE 0x0004
+#define IRQ8 0x0100
+#define IRQ9 0x0200
+#define IRQ2 IRQ9
+#define IRQ10 0x0400
+#define IRQ11 0x0800
+#define IRQ12 0x1000
+#define IRQ13 0x2000
+#define IRQ14 0x4000
+#define IRQ15 0x8000
+#define IRQ3 0x0008 /* this is highest after rotation */
+#define IRQ4 0x0010
+#define IRQ5 0x0020
+#define IRQ6 0x0040
+#define IRQ7 0x0080 /* lowest - parallel printer */
+
+/*
+ * Interrupt Control offset into Interrupt descriptor table (IDT)
+ */
+#define ICU_OFFSET 32 /* 0-31 are processor exceptions */
+#define ICU_LEN 16 /* 32-47 are ISA interrupts */
+
+#endif __ICU__
diff --git a/sys/i386/isa/icu.s b/sys/i386/isa/icu.s
new file mode 100644
index 0000000..b8bf1a8
--- /dev/null
+++ b/sys/i386/isa/icu.s
@@ -0,0 +1,328 @@
+/*-
+ * Copyright (c) 1989, 1990 William F. Jolitz.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)icu.s 7.2 (Berkeley) 5/21/91
+ *
+ * $Id: icu.s,v 1.7 1993/12/20 14:58:21 wollman Exp $
+ */
+
+/*
+ * AT/386
+ * Vector interrupt control section
+ */
+
+/*
+ * XXX this file should be named ipl.s. All spls are now soft and the
+ * only thing related to the hardware icu is that the h/w interrupt
+ * numbers are used without translation in the masks.
+ */
+
+#include "../net/netisr.h"
+
+ .data
+ .globl _cpl
+_cpl: .long HWI_MASK | SWI_MASK /* current priority (all off) */
+ .globl _imen
+_imen: .long HWI_MASK /* interrupt mask enable (all h/w off) */
+_high_imask: .long HWI_MASK | SWI_MASK
+ .globl _tty_imask
+_tty_imask: .long 0
+ .globl _bio_imask
+_bio_imask: .long 0
+ .globl _net_imask
+_net_imask: .long 0
+ .globl _ipending
+_ipending: .long 0
+ .globl _astpending
+_astpending: .long 0 /* tells us an AST needs to be taken */
+ .globl _netisr
+_netisr: .long 0 /* set with bits for which queue to service */
+vec:
+ .long vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7
+ .long vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15
+
+ .text
+
+/*
+ * Handle return from interrupts, traps and syscalls.
+ */
+ SUPERALIGN_TEXT
+_doreti:
+ FAKE_MCOUNT(_bintr) /* init "from" _bintr -> _doreti */
+ addl $4,%esp /* discard unit number */
+ popl %eax /* cpl to restore */
+doreti_next:
+ /*
+ * Check for pending HWIs and SWIs atomically with restoring cpl
+ * and exiting. The check has to be atomic with exiting to stop
+ * (ipending & ~cpl) changing from zero to nonzero while we're
+ * looking at it (this wouldn't be fatal but it would increase
+ * interrupt latency). Restoring cpl has to be atomic with exiting
+ * so that the stack cannot pile up (the nesting level of interrupt
+ * handlers is limited by the number of bits in cpl).
+ */
+ movl %eax,%ecx
+ notl %ecx
+ cli
+ andl _ipending,%ecx
+ jne doreti_unpend
+doreti_exit:
+ movl %eax,_cpl
+ MEXITCOUNT
+ popl %es
+ popl %ds
+ popal
+ addl $8,%esp
+ iret
+
+ ALIGN_TEXT
+doreti_unpend:
+ /*
+ * Enabling interrupts is safe because we haven't restored cpl yet.
+ * The locking from the "btrl" test is probably no longer necessary.
+ * We won't miss any new pending interrupts because we will check
+ * for them again.
+ */
+ sti
+ bsfl %ecx,%ecx /* slow, but not worth optimizing */
+ btrl %ecx,_ipending
+ jnc doreti_next /* some intr cleared memory copy */
+ movl ihandlers(,%ecx,4),%edx
+ testl %edx,%edx
+ je doreti_next /* "can't happen" */
+ cmpl $NHWI,%ecx
+ jae doreti_swi
+ cli
+ movl %eax,_cpl
+ MEXITCOUNT
+ jmp %edx
+
+ ALIGN_TEXT
+doreti_swi:
+ pushl %eax
+ /*
+ * The SWI_AST handler has to run at cpl = SWI_AST_MASK and the
+ * SWI_CLOCK handler at cpl = SWI_CLOCK_MASK, so we have to restore
+ * all the h/w bits in cpl now and have to worry about stack growth.
+ * The worst case is currently (30 Jan 1994) 2 SWI handlers nested
+ * in dying interrupt frames and about 12 HWIs nested in active
+ * interrupt frames. There are only 4 different SWIs and the HWI
+ * and SWI masks limit the nesting further.
+ */
+ orl imasks(,%ecx,4),%eax
+ movl %eax,_cpl
+ call %edx
+ popl %eax
+ jmp doreti_next
+
+ ALIGN_TEXT
+swi_ast:
+ addl $8,%esp /* discard raddr & cpl to get trap frame */
+ testb $SEL_RPL_MASK,TRAPF_CS_OFF(%esp)
+ je swi_ast_phantom
+ movl $T_ASTFLT,(2+8+0)*4(%esp)
+ call _trap
+ subl %eax,%eax /* recover cpl */
+ jmp doreti_next
+
+ ALIGN_TEXT
+swi_ast_phantom:
+ /*
+ * These happen when there is an interrupt in a trap handler before
+ * ASTs can be masked or in an lcall handler before they can be
+ * masked or after they are unmasked. They could be avoided for
+ * trap entries by using interrupt gates, and for lcall exits by
+ * using by using cli, but they are unavoidable for lcall entries.
+ */
+ cli
+ orl $SWI_AST_PENDING,_ipending
+ jmp doreti_exit /* SWI_AST is highest so we must be done */
+
+/*
+ * Interrupt priority mechanism
+ * -- soft splXX masks with group mechanism (cpl)
+ * -- h/w masks for currently active or unused interrupts (imen)
+ * -- ipending = active interrupts currently masked by cpl
+ */
+
+ENTRY(splz)
+ /*
+ * The caller has restored cpl and checked that (ipending & ~cpl)
+ * is nonzero. We have to repeat the check since if there is an
+ * interrupt while we're looking, _doreti processing for the
+ * interrupt will handle all the unmasked pending interrupts
+ * because we restored early. We're repeating the calculation
+ * of (ipending & ~cpl) anyway so that the caller doesn't have
+ * to pass it, so this only costs one "jne". "bsfl %ecx,%ecx"
+ * is undefined when %ecx is 0 so we can't rely on the secondary
+ * btrl tests.
+ */
+ movl _cpl,%eax
+splz_next:
+ /*
+ * We don't need any locking here. (ipending & ~cpl) cannot grow
+ * while we're looking at it - any interrupt will shrink it to 0.
+ */
+ movl %eax,%ecx
+ notl %ecx
+ andl _ipending,%ecx
+ jne splz_unpend
+ ret
+
+ ALIGN_TEXT
+splz_unpend:
+ bsfl %ecx,%ecx
+ btrl %ecx,_ipending
+ jnc splz_next
+ movl ihandlers(,%ecx,4),%edx
+ testl %edx,%edx
+ je splz_next /* "can't happen" */
+ cmpl $NHWI,%ecx
+ jae splz_swi
+ /*
+ * We would prefer to call the intr handler directly here but that
+ * doesn't work for badly behaved handlers that want the interrupt
+ * frame. Also, there's a problem determining the unit number.
+ * We should change the interface so that the unit number is not
+ * determined at config time.
+ */
+ jmp *vec(,%ecx,4)
+
+ ALIGN_TEXT
+splz_swi:
+ cmpl $SWI_AST,%ecx
+ je splz_next /* "can't happen" */
+ pushl %eax
+ orl imasks(,%ecx,4),%eax
+ movl %eax,_cpl
+ call %edx
+ popl %eax
+ movl %eax,_cpl
+ jmp splz_next
+
+/*
+ * Fake clock IRQ so that it appears to come from our caller and not from
+ * vec0, so that kernel profiling works.
+ * XXX do this more generally (for all vectors; look up the C entry point).
+ * XXX frame bogusness stops us from just jumping to the C entry point.
+ */
+ ALIGN_TEXT
+vec0:
+ popl %eax /* return address */
+ pushfl
+#define KCSEL 8
+ pushl $KCSEL
+ pushl %eax
+ cli
+ MEXITCOUNT
+ jmp _Vclk
+
+#define BUILD_VEC(irq_num) \
+ ALIGN_TEXT ; \
+vec/**/irq_num: ; \
+ int $ICU_OFFSET + (irq_num) ; \
+ ret
+
+ BUILD_VEC(1)
+ BUILD_VEC(2)
+ BUILD_VEC(3)
+ BUILD_VEC(4)
+ BUILD_VEC(5)
+ BUILD_VEC(6)
+ BUILD_VEC(7)
+ BUILD_VEC(8)
+ BUILD_VEC(9)
+ BUILD_VEC(10)
+ BUILD_VEC(11)
+ BUILD_VEC(12)
+ BUILD_VEC(13)
+ BUILD_VEC(14)
+ BUILD_VEC(15)
+
+ ALIGN_TEXT
+swi_clock:
+ MCOUNT
+ subl %eax,%eax
+ cmpl $_splz,(%esp) /* XXX call from splz()? */
+ jae 1f /* yes, usermode = 0 */
+ movl 4+4+TRAPF_CS_OFF(%esp),%eax /* no, check trap frame */
+ andl $SEL_RPL_MASK,%eax
+1:
+ pushl %eax
+ call _softclock
+ addl $4,%esp
+ ret
+
+#define DONET(s, c, event) ; \
+ .globl c ; \
+ btrl $s,_netisr ; \
+ jnc 9f ; \
+ call c ; \
+9:
+
+ ALIGN_TEXT
+swi_net:
+ MCOUNT
+#if 0
+ DONET(NETISR_RAW, _rawintr,netisr_raw)
+#endif
+#ifdef INET
+ DONET(NETISR_IP, _ipintr,netisr_ip)
+#endif
+#ifdef IMP
+ DONET(NETISR_IMP, _impintr,netisr_imp)
+#endif
+#ifdef NS
+ DONET(NETISR_NS, _nsintr,netisr_ns)
+#endif
+#ifdef ISO
+ DONET(NETISR_ISO, _clnlintr,netisr_iso)
+#endif
+#ifdef CCITT
+ DONET(NETISR_X25, _pkintr, 29)
+ DONET(NETISR_HDLC, _hdintr, 30)
+#endif
+ ret
+
+ ALIGN_TEXT
+swi_tty:
+ MCOUNT
+#include "sio.h"
+#if NSIO > 0
+ jmp _siopoll
+#else
+ ret
+#endif
diff --git a/sys/i386/isa/if_ed.c b/sys/i386/isa/if_ed.c
new file mode 100644
index 0000000..84047e2
--- /dev/null
+++ b/sys/i386/isa/if_ed.c
@@ -0,0 +1,2488 @@
+/*
+ * Device driver for National Semiconductor DS8390/WD83C690 based ethernet
+ * adapters. By David Greenman, 29-April-1993
+ *
+ * Copyright (C) 1993, David Greenman. This software may be used, modified,
+ * copied, distributed, and sold, in both source and binary form provided
+ * that the above copyright and these terms are retained. Under no
+ * circumstances is the author responsible for the proper functioning
+ * of this software, nor does the author assume any responsibility
+ * for damages incurred with its use.
+ *
+ * Currently supports the Western Digital/SMC 8003 and 8013 series,
+ * the SMC Elite Ultra (8216), the 3Com 3c503, the NE1000 and NE2000,
+ * and a variety of similar clones.
+ *
+ */
+
+/*
+ * $Id: if_ed.c,v 1.36 1994/04/10 20:06:26 davidg Exp $
+ */
+
+#include "ed.h"
+#if NED > 0
+/* bpfilter included here in case it is needed in future net includes */
+#include "bpfilter.h"
+
+#include "param.h"
+#include "systm.h"
+#include "errno.h"
+#include "ioctl.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "syslog.h"
+
+#include "net/if.h"
+#include "net/if_dl.h"
+#include "net/if_types.h"
+
+#ifdef INET
+#include "netinet/in.h"
+#include "netinet/in_systm.h"
+#include "netinet/in_var.h"
+#include "netinet/ip.h"
+#include "netinet/if_ether.h"
+#endif
+
+#ifdef NS
+#include "netns/ns.h"
+#include "netns/ns_if.h"
+#endif
+
+#if NBPFILTER > 0
+#include "net/bpf.h"
+#include "net/bpfdesc.h"
+#endif
+
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/if_edreg.h"
+
+#include "i386/include/pio.h"
+
+/* For backwards compatibility */
+#ifndef IFF_ALTPHYS
+#define IFF_ALTPHYS IFF_LLC0
+#endif
+
+/*
+ * ed_softc: per line info and status
+ */
+struct ed_softc {
+ struct arpcom arpcom; /* ethernet common */
+
+ char *type_str; /* pointer to type string */
+ u_char vendor; /* interface vendor */
+ u_char type; /* interface type code */
+
+ u_short asic_addr; /* ASIC I/O bus address */
+ u_short nic_addr; /* NIC (DS8390) I/O bus address */
+
+/*
+ * The following 'proto' variable is part of a work-around for 8013EBT asics
+ * being write-only. It's sort of a prototype/shadow of the real thing.
+ */
+ u_char wd_laar_proto;
+ u_char isa16bit; /* width of access to card 0=8 or 1=16 */
+ int is790; /* set by the probe code if the card is 790 based */
+
+ caddr_t bpf; /* BPF "magic cookie" */
+ caddr_t mem_start; /* NIC memory start address */
+ caddr_t mem_end; /* NIC memory end address */
+ u_long mem_size; /* total NIC memory size */
+ caddr_t mem_ring; /* start of RX ring-buffer (in NIC mem) */
+
+ u_char mem_shared; /* NIC memory is shared with host */
+ u_char xmit_busy; /* transmitter is busy */
+ u_char txb_cnt; /* number of transmit buffers */
+ u_char txb_inuse; /* number of TX buffers currently in-use*/
+
+ u_char txb_new; /* pointer to where new buffer will be added */
+ u_char txb_next_tx; /* pointer to next buffer ready to xmit */
+ u_short txb_len[8]; /* buffered xmit buffer lengths */
+ u_char tx_page_start; /* first page of TX buffer area */
+ u_char rec_page_start; /* first page of RX ring-buffer */
+ u_char rec_page_stop; /* last page of RX ring-buffer */
+ u_char next_packet; /* pointer to next unread RX packet */
+} ed_softc[NED];
+
+int ed_attach(struct isa_device *);
+void ed_init(int);
+void edintr(int);
+int ed_ioctl(struct ifnet *, int, caddr_t);
+int ed_probe(struct isa_device *);
+void ed_start(struct ifnet *);
+void ed_reset(int, int);
+void ed_watchdog(int);
+
+static void ed_get_packet(struct ed_softc *, char *, int /*u_short*/);
+static void ed_stop(int);
+
+static inline void ed_rint();
+static inline void ed_xmit();
+static inline char *ed_ring_copy();
+
+void ed_pio_readmem(), ed_pio_writemem();
+u_short ed_pio_write_mbufs();
+
+extern int ether_output();
+
+struct trailer_header {
+ u_short ether_type;
+ u_short ether_residual;
+};
+
+struct isa_driver eddriver = {
+ ed_probe,
+ ed_attach,
+ "ed"
+};
+/*
+ * Interrupt conversion table for WD/SMC ASIC
+ * (IRQ* are defined in icu.h)
+ */
+static unsigned short ed_intr_mask[] = {
+ IRQ9,
+ IRQ3,
+ IRQ5,
+ IRQ7,
+ IRQ10,
+ IRQ11,
+ IRQ15,
+ IRQ4
+};
+
+/*
+ * Interrupt conversion table for 585/790 Combo
+ */
+static unsigned short ed_790_intr_mask[] = {
+ 0,
+ IRQ9,
+ IRQ3,
+ IRQ5,
+ IRQ7,
+ IRQ10,
+ IRQ11,
+ IRQ15
+};
+#define ETHER_MIN_LEN 64
+#define ETHER_MAX_LEN 1518
+#define ETHER_ADDR_LEN 6
+#define ETHER_HDR_SIZE 14
+
+/*
+ * Determine if the device is present
+ *
+ * on entry:
+ * a pointer to an isa_device struct
+ * on exit:
+ * NULL if device not found
+ * or # of i/o addresses used (if found)
+ */
+int
+ed_probe(isa_dev)
+ struct isa_device *isa_dev;
+{
+ struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
+ int nports;
+
+ if (nports = ed_probe_WD80x3(isa_dev))
+ return (nports);
+
+ if (nports = ed_probe_3Com(isa_dev))
+ return (nports);
+
+ if (nports = ed_probe_Novell(isa_dev))
+ return (nports);
+
+ return(0);
+}
+
+/*
+ * Generic probe routine for testing for the existance of a DS8390.
+ * Must be called after the NIC has just been reset. This routine
+ * works by looking at certain register values that are gauranteed
+ * to be initialized a certain way after power-up or reset. Seems
+ * not to currently work on the 83C690.
+ *
+ * Specifically:
+ *
+ * Register reset bits set bits
+ * Command Register (CR) TXP, STA RD2, STP
+ * Interrupt Status (ISR) RST
+ * Interrupt Mask (IMR) All bits
+ * Data Control (DCR) LAS
+ * Transmit Config. (TCR) LB1, LB0
+ *
+ * We only look at the CR and ISR registers, however, because looking at
+ * the others would require changing register pages (which would be
+ * intrusive if this isn't an 8390).
+ *
+ * Return 1 if 8390 was found, 0 if not.
+ */
+
+int
+ed_probe_generic8390(sc)
+ struct ed_softc *sc;
+{
+ if ((inb(sc->nic_addr + ED_P0_CR) &
+ (ED_CR_RD2|ED_CR_TXP|ED_CR_STA|ED_CR_STP)) !=
+ (ED_CR_RD2|ED_CR_STP))
+ return (0);
+ if ((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RST) != ED_ISR_RST)
+ return (0);
+
+ return(1);
+}
+
+/*
+ * Probe and vendor-specific initialization routine for SMC/WD80x3 boards
+ */
+int
+ed_probe_WD80x3(isa_dev)
+ struct isa_device *isa_dev;
+{
+ struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
+ int i;
+ u_int memsize;
+ u_char iptr, isa16bit, sum;
+
+ sc->asic_addr = isa_dev->id_iobase;
+ sc->nic_addr = sc->asic_addr + ED_WD_NIC_OFFSET;
+ sc->is790 = 0;
+
+#ifdef TOSH_ETHER
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_POW);
+ DELAY(10000);
+#endif
+ /*
+ * Attempt to do a checksum over the station address PROM.
+ * If it fails, it's probably not a SMC/WD board. There
+ * is a problem with this, though: some clone WD boards
+ * don't pass the checksum test. Danpex boards for one.
+ */
+ for (sum = 0, i = 0; i < 8; ++i)
+ sum += inb(sc->asic_addr + ED_WD_PROM + i);
+
+ if (sum != ED_WD_ROM_CHECKSUM_TOTAL) {
+ /*
+ * Checksum is invalid. This often happens with cheap
+ * WD8003E clones. In this case, the checksum byte
+ * (the eighth byte) seems to always be zero.
+ */
+ if (inb(sc->asic_addr + ED_WD_CARD_ID) != ED_TYPE_WD8003E ||
+ inb(sc->asic_addr + ED_WD_PROM + 7) != 0)
+ return(0);
+ }
+
+ /* reset card to force it into a known state. */
+#ifdef TOSH_ETHER
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_RST | ED_WD_MSR_POW);
+#else
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_RST);
+#endif
+ DELAY(100);
+ outb(sc->asic_addr + ED_WD_MSR, inb(sc->asic_addr + ED_WD_MSR) & ~ED_WD_MSR_RST);
+ /* wait in the case this card is reading it's EEROM */
+ DELAY(5000);
+
+ sc->vendor = ED_VENDOR_WD_SMC;
+ sc->type = inb(sc->asic_addr + ED_WD_CARD_ID);
+
+ /*
+ * Set initial values for width/size.
+ */
+ memsize = 8192;
+ isa16bit = 0;
+ switch (sc->type) {
+ case ED_TYPE_WD8003S:
+ sc->type_str = "WD8003S";
+ break;
+ case ED_TYPE_WD8003E:
+ sc->type_str = "WD8003E";
+ break;
+ case ED_TYPE_WD8003EB:
+ sc->type_str = "WD8003EB";
+ break;
+ case ED_TYPE_WD8003W:
+ sc->type_str = "WD8003W";
+ break;
+ case ED_TYPE_WD8013EBT:
+ sc->type_str = "WD8013EBT";
+ memsize = 16384;
+ isa16bit = 1;
+ break;
+ case ED_TYPE_WD8013W:
+ sc->type_str = "WD8013W";
+ memsize = 16384;
+ isa16bit = 1;
+ break;
+ case ED_TYPE_WD8013EP: /* also WD8003EP */
+ if (inb(sc->asic_addr + ED_WD_ICR)
+ & ED_WD_ICR_16BIT) {
+ isa16bit = 1;
+ memsize = 16384;
+ sc->type_str = "WD8013EP";
+ } else {
+ sc->type_str = "WD8003EP";
+ }
+ break;
+ case ED_TYPE_WD8013WC:
+ sc->type_str = "WD8013WC";
+ memsize = 16384;
+ isa16bit = 1;
+ break;
+ case ED_TYPE_WD8013EBP:
+ sc->type_str = "WD8013EBP";
+ memsize = 16384;
+ isa16bit = 1;
+ break;
+ case ED_TYPE_WD8013EPC:
+ sc->type_str = "WD8013EPC";
+ memsize = 16384;
+ isa16bit = 1;
+ break;
+ case ED_TYPE_SMC8216C:
+ sc->type_str = "SMC8216/SMC8216C";
+ memsize = 16384;
+ isa16bit = 1;
+ sc->is790 = 1;
+ break;
+ case ED_TYPE_SMC8216T:
+ sc->type_str = "SMC8216T";
+ memsize = 16384;
+ isa16bit = 1;
+ sc->is790 = 1;
+ break;
+#ifdef TOSH_ETHER
+ case ED_TYPE_TOSHIBA1:
+ sc->type_str = "Toshiba1";
+ memsize = 32768;
+ isa16bit = 1;
+ break;
+ case ED_TYPE_TOSHIBA4:
+ sc->type_str = "Toshiba4";
+ memsize = 32768;
+ isa16bit = 1;
+ break;
+#endif
+ default:
+ sc->type_str = "";
+ break;
+ }
+ /*
+ * Make some adjustments to initial values depending on what is
+ * found in the ICR.
+ */
+ if (isa16bit && (sc->type != ED_TYPE_WD8013EBT)
+#ifdef TOSH_ETHER
+ && (sc->type != ED_TYPE_TOSHIBA1) && (sc->type != ED_TYPE_TOSHIBA4)
+#endif
+ && ((inb(sc->asic_addr + ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) {
+ isa16bit = 0;
+ memsize = 8192;
+ }
+
+#if ED_DEBUG
+ printf("type = %x type_str=%s isa16bit=%d memsize=%d id_msize=%d\n",
+ sc->type,sc->type_str,isa16bit,memsize,isa_dev->id_msize);
+ for (i=0; i<8; i++)
+ printf("%x -> %x\n", i, inb(sc->asic_addr + i));
+#endif
+ /*
+ * Allow the user to override the autoconfiguration
+ */
+ if (isa_dev->id_msize)
+ memsize = isa_dev->id_msize;
+ /*
+ * (note that if the user specifies both of the following flags
+ * that '8bit' mode intentionally has precedence)
+ */
+ if (isa_dev->id_flags & ED_FLAGS_FORCE_16BIT_MODE)
+ isa16bit = 1;
+ if (isa_dev->id_flags & ED_FLAGS_FORCE_8BIT_MODE)
+ isa16bit = 0;
+
+ /*
+ * Check 83C584 interrupt configuration register if this board has one
+ * XXX - we could also check the IO address register. But why
+ * bother...if we get past this, it *has* to be correct.
+ */
+ if ((sc->type & ED_WD_SOFTCONFIG) && (!sc->is790)) {
+ /*
+ * Assemble together the encoded interrupt number.
+ */
+ iptr = (inb(isa_dev->id_iobase + ED_WD_ICR) & ED_WD_ICR_IR2) |
+ ((inb(isa_dev->id_iobase + ED_WD_IRR) &
+ (ED_WD_IRR_IR0 | ED_WD_IRR_IR1)) >> 5);
+ /*
+ * Translate it using translation table, and check for correctness.
+ */
+ if (ed_intr_mask[iptr] != isa_dev->id_irq) {
+ printf("ed%d: kernel configured irq %d doesn't match board configured irq %d\n",
+ isa_dev->id_unit, ffs(isa_dev->id_irq) - 1,
+ ffs(ed_intr_mask[iptr]) - 1);
+ return(0);
+ }
+ /*
+ * Enable the interrupt.
+ */
+ outb(isa_dev->id_iobase + ED_WD_IRR,
+ inb(isa_dev->id_iobase + ED_WD_IRR) | ED_WD_IRR_IEN);
+ }
+ if (sc->is790) {
+ outb(isa_dev->id_iobase + ED_WD790_HWR,
+ inb(isa_dev->id_iobase + ED_WD790_HWR) | ED_WD790_HWR_SWH);
+ iptr = (((inb(isa_dev->id_iobase + ED_WD790_GCR) & ED_WD790_GCR_IR2) >> 4) |
+ (inb(isa_dev->id_iobase + ED_WD790_GCR) &
+ (ED_WD790_GCR_IR1|ED_WD790_GCR_IR0)) >> 2);
+ outb(isa_dev->id_iobase + ED_WD790_HWR,
+ inb(isa_dev->id_iobase + ED_WD790_HWR) & ~ED_WD790_HWR_SWH);
+
+ if (ed_790_intr_mask[iptr] != isa_dev->id_irq) {
+ printf("ed%d: kernel configured irq %d doesn't match board configured irq %d %d\n",
+ isa_dev->id_unit, ffs(isa_dev->id_irq) - 1,
+ ffs(ed_790_intr_mask[iptr]) - 1, iptr);
+ return 0;
+ }
+ /*
+ * Enable interrupts.
+ */
+ outb(isa_dev->id_iobase + ED_WD790_ICR,
+ inb(isa_dev->id_iobase + ED_WD790_ICR) | ED_WD790_ICR_EIL);
+ }
+
+ sc->isa16bit = isa16bit;
+
+#ifdef notyet /* XXX - I'm not sure if PIO mode is even possible on WD/SMC boards */
+ /*
+ * The following allows the WD/SMC boards to be used in Programmed I/O
+ * mode - without mapping the NIC memory shared. ...Not the prefered
+ * way, but it might be the only way.
+ */
+ if (isa_dev->id_flags & ED_FLAGS_FORCE_PIO) {
+ sc->mem_shared = 0;
+ isa_dev->id_maddr = 0;
+ } else {
+ sc->mem_shared = 1;
+ }
+#else
+ sc->mem_shared = 1;
+#endif
+ isa_dev->id_msize = memsize;
+
+ sc->mem_start = (caddr_t)isa_dev->id_maddr;
+
+ /*
+ * allocate one xmit buffer if < 16k, two buffers otherwise
+ */
+ if ((memsize < 16384) || (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING)) {
+ sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE);
+ sc->txb_cnt = 1;
+ sc->rec_page_start = ED_TXBUF_SIZE;
+ } else {
+ sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE * 2);
+ sc->txb_cnt = 2;
+ sc->rec_page_start = ED_TXBUF_SIZE * 2;
+ }
+ sc->mem_size = memsize;
+ sc->mem_end = sc->mem_start + memsize;
+ sc->rec_page_stop = memsize / ED_PAGE_SIZE;
+ sc->tx_page_start = ED_WD_PAGE_OFFSET;
+
+ /*
+ * Get station address from on-board ROM
+ */
+ for (i = 0; i < ETHER_ADDR_LEN; ++i)
+ sc->arpcom.ac_enaddr[i] = inb(sc->asic_addr + ED_WD_PROM + i);
+
+ if (sc->mem_shared) {
+ /*
+ * Set address and enable interface shared memory.
+ */
+ if(!sc->is790) {
+#ifdef TOSH_ETHER
+ outb(sc->asic_addr + ED_WD_MSR + 1, ((kvtop(sc->mem_start) >> 8) & 0xe0) | 4);
+ outb(sc->asic_addr + ED_WD_MSR + 2, ((kvtop(sc->mem_start) >> 16) & 0x0f));
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB | ED_WD_MSR_POW);
+
+#else
+ outb(sc->asic_addr + ED_WD_MSR, ((kvtop(sc->mem_start) >> 13) &
+ ED_WD_MSR_ADDR) | ED_WD_MSR_MENB);
+#endif
+ } else {
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB);
+ outb(sc->asic_addr + 0x04, (inb(sc->asic_addr + 0x04) | 0x80));
+ outb(sc->asic_addr + 0x0b, ((kvtop(sc->mem_start) >> 13) & 0x0f) |
+ ((kvtop(sc->mem_start) >> 11) & 0x40) |
+ (inb(sc->asic_addr + 0x0b) & 0xb0));
+ outb(sc->asic_addr + 0x04, (inb(sc->asic_addr + 0x04) & ~0x80));
+ }
+
+ /*
+ * Set upper address bits and 8/16 bit access to shared memory
+ */
+ if (isa16bit) {
+ if (sc->is790) {
+ sc->wd_laar_proto = inb(sc->asic_addr + ED_WD_LAAR);
+ outb(sc->asic_addr + ED_WD_LAAR, ED_WD_LAAR_M16EN);
+ (void) inb(0x84);
+ } else {
+ outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto =
+ ED_WD_LAAR_L16EN | ED_WD_LAAR_M16EN |
+ ((kvtop(sc->mem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
+ }
+ } else {
+ if ((sc->type & ED_WD_SOFTCONFIG) ||
+#ifdef TOSH_ETHER
+ (sc->type == ED_TYPE_TOSHIBA1) || (sc->type == ED_TYPE_TOSHIBA4) ||
+#endif
+ (sc->type == ED_TYPE_WD8013EBT) && (!sc->is790)) {
+ outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto =
+ ((kvtop(sc->mem_start) >> 19) & ED_WD_LAAR_ADDRHI)));
+ }
+ }
+
+ /*
+ * Now zero memory and verify that it is clear
+ */
+ bzero(sc->mem_start, memsize);
+
+ for (i = 0; i < memsize; ++i)
+ if (sc->mem_start[i]) {
+ printf("ed%d: failed to clear shared memory at %x - check configuration\n",
+ isa_dev->id_unit, kvtop(sc->mem_start + i));
+
+ /*
+ * Disable 16 bit access to shared memory
+ */
+ if (isa16bit) {
+ outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto &=
+ ~ED_WD_LAAR_M16EN));
+ (void) inb(0x84);
+ }
+
+ return(0);
+ }
+
+ /*
+ * Disable 16bit access to shared memory - we leave it disabled so
+ * that 1) machines reboot properly when the board is set
+ * 16 bit mode and there are conflicting 8bit devices/ROMS
+ * in the same 128k address space as this boards shared
+ * memory. and 2) so that other 8 bit devices with shared
+ * memory can be used in this 128k region, too.
+ */
+ if (isa16bit) {
+ outb(sc->asic_addr + ED_WD_LAAR, (sc->wd_laar_proto &=
+ ~ED_WD_LAAR_M16EN));
+ (void) inb(0x84);
+ }
+ }
+
+ return (ED_WD_IO_PORTS);
+}
+
+/*
+ * Probe and vendor-specific initialization routine for 3Com 3c503 boards
+ */
+int
+ed_probe_3Com(isa_dev)
+ struct isa_device *isa_dev;
+{
+ struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
+ int i;
+ u_int memsize;
+ u_char isa16bit, sum;
+
+ sc->asic_addr = isa_dev->id_iobase + ED_3COM_ASIC_OFFSET;
+ sc->nic_addr = isa_dev->id_iobase + ED_3COM_NIC_OFFSET;
+
+ /*
+ * Verify that the kernel configured I/O address matches the board
+ * configured address
+ */
+ switch (inb(sc->asic_addr + ED_3COM_BCFR)) {
+ case ED_3COM_BCFR_300:
+ if (isa_dev->id_iobase != 0x300)
+ return(0);
+ break;
+ case ED_3COM_BCFR_310:
+ if (isa_dev->id_iobase != 0x310)
+ return(0);
+ break;
+ case ED_3COM_BCFR_330:
+ if (isa_dev->id_iobase != 0x330)
+ return(0);
+ break;
+ case ED_3COM_BCFR_350:
+ if (isa_dev->id_iobase != 0x350)
+ return(0);
+ break;
+ case ED_3COM_BCFR_250:
+ if (isa_dev->id_iobase != 0x250)
+ return(0);
+ break;
+ case ED_3COM_BCFR_280:
+ if (isa_dev->id_iobase != 0x280)
+ return(0);
+ break;
+ case ED_3COM_BCFR_2A0:
+ if (isa_dev->id_iobase != 0x2a0)
+ return(0);
+ break;
+ case ED_3COM_BCFR_2E0:
+ if (isa_dev->id_iobase != 0x2e0)
+ return(0);
+ break;
+ default:
+ return(0);
+ }
+
+ /*
+ * Verify that the kernel shared memory address matches the
+ * board configured address.
+ */
+ switch (inb(sc->asic_addr + ED_3COM_PCFR)) {
+ case ED_3COM_PCFR_DC000:
+ if (kvtop(isa_dev->id_maddr) != 0xdc000)
+ return(0);
+ break;
+ case ED_3COM_PCFR_D8000:
+ if (kvtop(isa_dev->id_maddr) != 0xd8000)
+ return(0);
+ break;
+ case ED_3COM_PCFR_CC000:
+ if (kvtop(isa_dev->id_maddr) != 0xcc000)
+ return(0);
+ break;
+ case ED_3COM_PCFR_C8000:
+ if (kvtop(isa_dev->id_maddr) != 0xc8000)
+ return(0);
+ break;
+ default:
+ return(0);
+ }
+
+
+ /*
+ * Reset NIC and ASIC. Enable on-board transceiver throughout reset
+ * sequence because it'll lock up if the cable isn't connected
+ * if we don't.
+ */
+ outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_RST | ED_3COM_CR_XSEL);
+
+ /*
+ * Wait for a while, then un-reset it
+ */
+ DELAY(50);
+ /*
+ * The 3Com ASIC defaults to rather strange settings for the CR after
+ * a reset - it's important to set it again after the following
+ * outb (this is done when we map the PROM below).
+ */
+ outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
+
+ /*
+ * Wait a bit for the NIC to recover from the reset
+ */
+ DELAY(5000);
+
+ sc->vendor = ED_VENDOR_3COM;
+ sc->type_str = "3c503";
+
+ sc->mem_shared = 1;
+
+ /*
+ * Hmmm...a 16bit 3Com board has 16k of memory, but only an 8k
+ * window to it.
+ */
+ memsize = 8192;
+
+ /*
+ * Get station address from on-board ROM
+ */
+ /*
+ * First, map ethernet address PROM over the top of where the NIC
+ * registers normally appear.
+ */
+ outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_EALO | ED_3COM_CR_XSEL);
+
+ for (i = 0; i < ETHER_ADDR_LEN; ++i)
+ sc->arpcom.ac_enaddr[i] = inb(sc->nic_addr + i);
+
+ /*
+ * Unmap PROM - select NIC registers. The proper setting of the
+ * tranceiver is set in ed_init so that the attach code
+ * is given a chance to set the default based on a compile-time
+ * config option
+ */
+ outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
+
+ /*
+ * Determine if this is an 8bit or 16bit board
+ */
+
+ /*
+ * select page 0 registers
+ */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
+
+ /*
+ * Attempt to clear WTS bit. If it doesn't clear, then this is a
+ * 16bit board.
+ */
+ outb(sc->nic_addr + ED_P0_DCR, 0);
+
+ /*
+ * select page 2 registers
+ */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_2|ED_CR_RD2|ED_CR_STP);
+
+ /*
+ * The 3c503 forces the WTS bit to a one if this is a 16bit board
+ */
+ if (inb(sc->nic_addr + ED_P2_DCR) & ED_DCR_WTS)
+ isa16bit = 1;
+ else
+ isa16bit = 0;
+
+ /*
+ * select page 0 registers
+ */
+ outb(sc->nic_addr + ED_P2_CR, ED_CR_RD2|ED_CR_STP);
+
+ sc->mem_start = (caddr_t)isa_dev->id_maddr;
+ sc->mem_size = memsize;
+ sc->mem_end = sc->mem_start + memsize;
+
+ /*
+ * We have an entire 8k window to put the transmit buffers on the
+ * 16bit boards. But since the 16bit 3c503's shared memory
+ * is only fast enough to overlap the loading of one full-size
+ * packet, trying to load more than 2 buffers can actually
+ * leave the transmitter idle during the load. So 2 seems
+ * the best value. (Although a mix of variable-sized packets
+ * might change this assumption. Nonetheless, we optimize for
+ * linear transfers of same-size packets.)
+ */
+ if (isa16bit) {
+ if (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING)
+ sc->txb_cnt = 1;
+ else
+ sc->txb_cnt = 2;
+
+ sc->tx_page_start = ED_3COM_TX_PAGE_OFFSET_16BIT;
+ sc->rec_page_start = ED_3COM_RX_PAGE_OFFSET_16BIT;
+ sc->rec_page_stop = memsize / ED_PAGE_SIZE +
+ ED_3COM_RX_PAGE_OFFSET_16BIT;
+ sc->mem_ring = sc->mem_start;
+ } else {
+ sc->txb_cnt = 1;
+ sc->tx_page_start = ED_3COM_TX_PAGE_OFFSET_8BIT;
+ sc->rec_page_start = ED_TXBUF_SIZE + ED_3COM_TX_PAGE_OFFSET_8BIT;
+ sc->rec_page_stop = memsize / ED_PAGE_SIZE +
+ ED_3COM_TX_PAGE_OFFSET_8BIT;
+ sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE);
+ }
+
+ sc->isa16bit = isa16bit;
+
+ /*
+ * Initialize GA page start/stop registers. Probably only needed
+ * if doing DMA, but what the hell.
+ */
+ outb(sc->asic_addr + ED_3COM_PSTR, sc->rec_page_start);
+ outb(sc->asic_addr + ED_3COM_PSPR, sc->rec_page_stop);
+
+ /*
+ * Set IRQ. 3c503 only allows a choice of irq 2-5.
+ */
+ switch (isa_dev->id_irq) {
+ case IRQ2:
+ outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ2);
+ break;
+ case IRQ3:
+ outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ3);
+ break;
+ case IRQ4:
+ outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ4);
+ break;
+ case IRQ5:
+ outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ5);
+ break;
+ default:
+ printf("ed%d: Invalid irq configuration (%d) must be 2-5 for 3c503\n",
+ isa_dev->id_unit, ffs(isa_dev->id_irq) - 1);
+ return(0);
+ }
+
+ /*
+ * Initialize GA configuration register. Set bank and enable shared mem.
+ */
+ outb(sc->asic_addr + ED_3COM_GACFR, ED_3COM_GACFR_RSEL |
+ ED_3COM_GACFR_MBS0);
+
+ /*
+ * Initialize "Vector Pointer" registers. These gawd-awful things
+ * are compared to 20 bits of the address on ISA, and if they
+ * match, the shared memory is disabled. We set them to
+ * 0xffff0...allegedly the reset vector.
+ */
+ outb(sc->asic_addr + ED_3COM_VPTR2, 0xff);
+ outb(sc->asic_addr + ED_3COM_VPTR1, 0xff);
+ outb(sc->asic_addr + ED_3COM_VPTR0, 0x00);
+
+ /*
+ * Zero memory and verify that it is clear
+ */
+ bzero(sc->mem_start, memsize);
+
+ for (i = 0; i < memsize; ++i)
+ if (sc->mem_start[i]) {
+ printf("ed%d: failed to clear shared memory at %x - check configuration\n",
+ isa_dev->id_unit, kvtop(sc->mem_start + i));
+ return(0);
+ }
+
+ isa_dev->id_msize = memsize;
+ return(ED_3COM_IO_PORTS);
+}
+
+/*
+ * Probe and vendor-specific initialization routine for NE1000/2000 boards
+ */
+int
+ed_probe_Novell(isa_dev)
+ struct isa_device *isa_dev;
+{
+ struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
+ u_int memsize, n;
+ u_char romdata[16], isa16bit = 0, tmp;
+ static char test_pattern[32] = "THIS is A memory TEST pattern";
+ char test_buffer[32];
+
+ sc->asic_addr = isa_dev->id_iobase + ED_NOVELL_ASIC_OFFSET;
+ sc->nic_addr = isa_dev->id_iobase + ED_NOVELL_NIC_OFFSET;
+
+ /* XXX - do Novell-specific probe here */
+
+ /* Reset the board */
+ tmp = inb(sc->asic_addr + ED_NOVELL_RESET);
+
+ /*
+ * I don't know if this is necessary; probably cruft leftover from
+ * Clarkson packet driver code. Doesn't do a thing on the boards
+ * I've tested. -DG [note that a outb(0x84, 0) seems to work
+ * here, and is non-invasive...but some boards don't seem to reset
+ * and I don't have complete documentation on what the 'right'
+ * thing to do is...so we do the invasive thing for now. Yuck.]
+ */
+ outb(sc->asic_addr + ED_NOVELL_RESET, tmp);
+ DELAY(5000);
+
+ /*
+ * This is needed because some NE clones apparently don't reset the
+ * NIC properly (or the NIC chip doesn't reset fully on power-up)
+ * XXX - this makes the probe invasive! ...Done against my better
+ * judgement. -DLG
+ */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
+
+ DELAY(5000);
+
+ /* Make sure that we really have an 8390 based board */
+ if (!ed_probe_generic8390(sc))
+ return(0);
+
+ sc->vendor = ED_VENDOR_NOVELL;
+ sc->mem_shared = 0;
+ isa_dev->id_maddr = 0;
+
+ /*
+ * Test the ability to read and write to the NIC memory. This has
+ * the side affect of determining if this is an NE1000 or an NE2000.
+ */
+
+ /*
+ * This prevents packets from being stored in the NIC memory when
+ * the readmem routine turns on the start bit in the CR.
+ */
+ outb(sc->nic_addr + ED_P0_RCR, ED_RCR_MON);
+
+ /* Temporarily initialize DCR for byte operations */
+ outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1|ED_DCR_LS);
+
+ outb(sc->nic_addr + ED_P0_PSTART, 8192 / ED_PAGE_SIZE);
+ outb(sc->nic_addr + ED_P0_PSTOP, 16384 / ED_PAGE_SIZE);
+
+ sc->isa16bit = 0;
+
+ /*
+ * Write a test pattern in byte mode. If this fails, then there
+ * probably isn't any memory at 8k - which likely means
+ * that the board is an NE2000.
+ */
+ ed_pio_writemem(sc, test_pattern, 8192, sizeof(test_pattern));
+ ed_pio_readmem(sc, 8192, test_buffer, sizeof(test_pattern));
+
+ if (bcmp(test_pattern, test_buffer, sizeof(test_pattern))) {
+ /* not an NE1000 - try NE2000 */
+
+ outb(sc->nic_addr + ED_P0_DCR, ED_DCR_WTS|ED_DCR_FT1|ED_DCR_LS);
+ outb(sc->nic_addr + ED_P0_PSTART, 16384 / ED_PAGE_SIZE);
+ outb(sc->nic_addr + ED_P0_PSTOP, 32768 / ED_PAGE_SIZE);
+
+ sc->isa16bit = 1;
+ /*
+ * Write a test pattern in word mode. If this also fails, then
+ * we don't know what this board is.
+ */
+ ed_pio_writemem(sc, test_pattern, 16384, sizeof(test_pattern));
+ ed_pio_readmem(sc, 16384, test_buffer, sizeof(test_pattern));
+
+ if (bcmp(test_pattern, test_buffer, sizeof(test_pattern)))
+ return(0); /* not an NE2000 either */
+
+ sc->type = ED_TYPE_NE2000;
+ sc->type_str = "NE2000";
+ } else {
+ sc->type = ED_TYPE_NE1000;
+ sc->type_str = "NE1000";
+ }
+
+ /* 8k of memory plus an additional 8k if 16bit */
+ memsize = 8192 + sc->isa16bit * 8192;
+
+#if 0 /* probably not useful - NE boards only come two ways */
+ /* allow kernel config file overrides */
+ if (isa_dev->id_msize)
+ memsize = isa_dev->id_msize;
+#endif
+
+ sc->mem_size = memsize;
+
+ /* NIC memory doesn't start at zero on an NE board */
+ /* The start address is tied to the bus width */
+ sc->mem_start = (char *) 8192 + sc->isa16bit * 8192;
+ sc->mem_end = sc->mem_start + memsize;
+ sc->tx_page_start = memsize / ED_PAGE_SIZE;
+
+ /*
+ * Use one xmit buffer if < 16k, two buffers otherwise (if not told
+ * otherwise).
+ */
+ if ((memsize < 16384) || (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING))
+ sc->txb_cnt = 1;
+ else
+ sc->txb_cnt = 2;
+
+ sc->rec_page_start = sc->tx_page_start + sc->txb_cnt * ED_TXBUF_SIZE;
+ sc->rec_page_stop = sc->tx_page_start + memsize / ED_PAGE_SIZE;
+
+ sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE;
+
+ ed_pio_readmem(sc, 0, romdata, 16);
+ for (n = 0; n < ETHER_ADDR_LEN; n++)
+ sc->arpcom.ac_enaddr[n] = romdata[n*(sc->isa16bit+1)];
+
+ /* clear any pending interrupts that might have occurred above */
+ outb(sc->nic_addr + ED_P0_ISR, 0xff);
+
+ return(ED_NOVELL_IO_PORTS);
+}
+
+/*
+ * Install interface into kernel networking data structures
+ */
+int
+ed_attach(isa_dev)
+ struct isa_device *isa_dev;
+{
+ struct ed_softc *sc = &ed_softc[isa_dev->id_unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct ifaddr *ifa;
+ struct sockaddr_dl *sdl;
+
+ /*
+ * Set interface to stopped condition (reset)
+ */
+ ed_stop(isa_dev->id_unit);
+
+ /*
+ * Initialize ifnet structure
+ */
+ ifp->if_unit = isa_dev->id_unit;
+ ifp->if_name = "ed" ;
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_init = ed_init;
+ ifp->if_output = ether_output;
+ ifp->if_start = ed_start;
+ ifp->if_ioctl = ed_ioctl;
+ ifp->if_reset = ed_reset;
+ ifp->if_watchdog = ed_watchdog;
+
+ /*
+ * Set default state for ALTPHYS flag (used to disable the tranceiver
+ * for AUI operation), based on compile-time config option.
+ */
+ if (isa_dev->id_flags & ED_FLAGS_DISABLE_TRANCEIVER)
+ ifp->if_flags =
+ (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_ALTPHYS);
+ else
+ ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS);
+
+ /*
+ * Attach the interface
+ */
+ if_attach(ifp);
+
+ /*
+ * Search down the ifa address list looking for the AF_LINK type entry
+ */
+ ifa = ifp->if_addrlist;
+ while ((ifa != 0) && (ifa->ifa_addr != 0) &&
+ (ifa->ifa_addr->sa_family != AF_LINK))
+ ifa = ifa->ifa_next;
+ /*
+ * If we find an AF_LINK type entry we fill in the hardware address.
+ * This is useful for netstat(1) to keep track of which interface
+ * is which.
+ */
+ if ((ifa != 0) && (ifa->ifa_addr != 0)) {
+ /*
+ * Fill in the link-level address for this interface
+ */
+ sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ sdl->sdl_type = IFT_ETHER;
+ sdl->sdl_alen = ETHER_ADDR_LEN;
+ sdl->sdl_slen = 0;
+ bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN);
+ }
+
+ /*
+ * Print additional info when attached
+ */
+ printf("ed%d: address %s, ", isa_dev->id_unit,
+ ether_sprintf(sc->arpcom.ac_enaddr));
+
+ if (sc->type_str && (*sc->type_str != 0))
+ printf("type %s ", sc->type_str);
+ else
+ printf("type unknown (0x%x) ", sc->type);
+
+ printf("%s ",sc->isa16bit ? "(16 bit)" : "(8 bit)");
+
+ printf("%s\n", ((sc->vendor == ED_VENDOR_3COM) &&
+ (ifp->if_flags & IFF_ALTPHYS)) ? " tranceiver disabled" : "");
+
+ /*
+ * If BPF is in the kernel, call the attach for it
+ */
+#if NBPFILTER > 0
+ bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+ return 1;
+}
+
+/*
+ * Reset interface.
+ */
+void
+ed_reset(unit, uban)
+ int unit;
+ int uban; /* XXX */
+{
+ int s;
+
+ s = splimp();
+
+ /*
+ * Stop interface and re-initialize.
+ */
+ ed_stop(unit);
+ ed_init(unit);
+
+ (void) splx(s);
+}
+
+/*
+ * Take interface offline.
+ */
+void
+ed_stop(unit)
+ int unit;
+{
+ struct ed_softc *sc = &ed_softc[unit];
+ int n = 5000;
+
+ /*
+ * Stop everything on the interface, and select page 0 registers.
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_STP);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
+ }
+ /*
+ * Wait for interface to enter stopped state, but limit # of checks
+ * to 'n' (about 5ms). It shouldn't even take 5us on modern
+ * DS8390's, but just in case it's an old one.
+ */
+ while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RST) == 0) && --n);
+
+}
+
+/*
+ * Device timeout/watchdog routine. Entered if the device neglects to
+ * generate an interrupt after a transmit has been started on it.
+ */
+void
+ed_watchdog(unit)
+ int unit;
+{
+ struct ed_softc *sc = &ed_softc[unit];
+
+ log(LOG_ERR, "ed%d: device timeout\n", unit);
+ ++sc->arpcom.ac_if.if_oerrors;
+
+ ed_reset(unit, 0);
+}
+
+/*
+ * Initialize device.
+ */
+void
+ed_init(unit)
+ int unit;
+{
+ struct ed_softc *sc = &ed_softc[unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ int i, s;
+ u_char command;
+
+
+ /* address not known */
+ if (ifp->if_addrlist == (struct ifaddr *)0) return;
+
+ /*
+ * Initialize the NIC in the exact order outlined in the NS manual.
+ * This init procedure is "mandatory"...don't change what or when
+ * things happen.
+ */
+ s = splimp();
+
+ /* reset transmitter flags */
+ sc->xmit_busy = 0;
+ sc->arpcom.ac_if.if_timer = 0;
+
+ sc->txb_inuse = 0;
+ sc->txb_new = 0;
+ sc->txb_next_tx = 0;
+
+ /* This variable is used below - don't move this assignment */
+ sc->next_packet = sc->rec_page_start + 1;
+
+ /*
+ * Set interface for page 0, Remote DMA complete, Stopped
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_STP);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP);
+ }
+ if (sc->isa16bit) {
+ /*
+ * Set FIFO threshold to 8, No auto-init Remote DMA,
+ * byte order=80x86, word-wide DMA xfers,
+ */
+ outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1|ED_DCR_WTS|ED_DCR_LS);
+ } else {
+ /*
+ * Same as above, but byte-wide DMA xfers
+ */
+ outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1|ED_DCR_LS);
+ }
+
+ /*
+ * Clear Remote Byte Count Registers
+ */
+ outb(sc->nic_addr + ED_P0_RBCR0, 0);
+ outb(sc->nic_addr + ED_P0_RBCR1, 0);
+
+ /*
+ * Enable reception of broadcast packets
+ */
+ outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB);
+
+ /*
+ * Place NIC in internal loopback mode
+ */
+ outb(sc->nic_addr + ED_P0_TCR, ED_TCR_LB0);
+
+ /*
+ * Initialize transmit/receive (ring-buffer) Page Start
+ */
+ outb(sc->nic_addr + ED_P0_TPSR, sc->tx_page_start);
+ outb(sc->nic_addr + ED_P0_PSTART, sc->rec_page_start);
+ /* Set lower bits of byte addressable framing to 0 */
+ if (sc->is790)
+ outb(sc->nic_addr + 0x09, 0);
+
+ /*
+ * Initialize Receiver (ring-buffer) Page Stop and Boundry
+ */
+ outb(sc->nic_addr + ED_P0_PSTOP, sc->rec_page_stop);
+ outb(sc->nic_addr + ED_P0_BNRY, sc->rec_page_start);
+
+ /*
+ * Clear all interrupts. A '1' in each bit position clears the
+ * corresponding flag.
+ */
+ outb(sc->nic_addr + ED_P0_ISR, 0xff);
+
+ /*
+ * Enable the following interrupts: receive/transmit complete,
+ * receive/transmit error, and Receiver OverWrite.
+ *
+ * Counter overflow and Remote DMA complete are *not* enabled.
+ */
+ outb(sc->nic_addr + ED_P0_IMR,
+ ED_IMR_PRXE|ED_IMR_PTXE|ED_IMR_RXEE|ED_IMR_TXEE|ED_IMR_OVWE);
+
+ /*
+ * Program Command Register for page 1
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_STP);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STP);
+ }
+ /*
+ * Copy out our station address
+ */
+ for (i = 0; i < ETHER_ADDR_LEN; ++i)
+ outb(sc->nic_addr + ED_P1_PAR0 + i, sc->arpcom.ac_enaddr[i]);
+
+#if NBPFILTER > 0
+ /*
+ * Initialize multicast address hashing registers to accept
+ * all multicasts (only used when in promiscuous mode)
+ */
+ for (i = 0; i < 8; ++i)
+ outb(sc->nic_addr + ED_P1_MAR0 + i, 0xff);
+#endif
+
+ /*
+ * Set Current Page pointer to next_packet (initialized above)
+ */
+ outb(sc->nic_addr + ED_P1_CURR, sc->next_packet);
+
+ /*
+ * Set Command Register for page 0, Remote DMA complete,
+ * and interface Start.
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P1_CR, ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P1_CR, ED_CR_RD2|ED_CR_STA);
+ }
+ /*
+ * Take interface out of loopback
+ */
+ outb(sc->nic_addr + ED_P0_TCR, 0);
+
+ /*
+ * If this is a 3Com board, the tranceiver must be software enabled
+ * (there is no settable hardware default).
+ */
+ if (sc->vendor == ED_VENDOR_3COM) {
+ if (ifp->if_flags & IFF_ALTPHYS) {
+ outb(sc->asic_addr + ED_3COM_CR, 0);
+ } else {
+ outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
+ }
+ }
+
+ /*
+ * Set 'running' flag, and clear output active flag.
+ */
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ /*
+ * ...and attempt to start output
+ */
+ ed_start(ifp);
+
+ (void) splx(s);
+}
+
+/*
+ * This routine actually starts the transmission on the interface
+ */
+static inline void ed_xmit(ifp)
+ struct ifnet *ifp;
+{
+ struct ed_softc *sc = &ed_softc[ifp->if_unit];
+ unsigned short len;
+
+ len = sc->txb_len[sc->txb_next_tx];
+
+ /*
+ * Set NIC for page 0 register access
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ }
+ /*
+ * Set TX buffer start page
+ */
+ outb(sc->nic_addr + ED_P0_TPSR, sc->tx_page_start +
+ sc->txb_next_tx * ED_TXBUF_SIZE);
+
+ /*
+ * Set TX length
+ */
+ outb(sc->nic_addr + ED_P0_TBCR0, len);
+ outb(sc->nic_addr + ED_P0_TBCR1, len >> 8);
+
+ /*
+ * Set page 0, Remote DMA complete, Transmit Packet, and *Start*
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_TXP | ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_TXP|ED_CR_STA);
+ }
+ sc->xmit_busy = 1;
+
+ /*
+ * Point to next transmit buffer slot and wrap if necessary.
+ */
+ sc->txb_next_tx++;
+ if (sc->txb_next_tx == sc->txb_cnt)
+ sc->txb_next_tx = 0;
+
+ /*
+ * Set a timer just in case we never hear from the board again
+ */
+ ifp->if_timer = 2;
+}
+
+/*
+ * Start output on interface.
+ * We make two assumptions here:
+ * 1) that the current priority is set to splimp _before_ this code
+ * is called *and* is returned to the appropriate priority after
+ * return
+ * 2) that the IFF_OACTIVE flag is checked before this code is called
+ * (i.e. that the output part of the interface is idle)
+ */
+void
+ed_start(ifp)
+ struct ifnet *ifp;
+{
+ struct ed_softc *sc = &ed_softc[ifp->if_unit];
+ struct mbuf *m0, *m;
+ caddr_t buffer;
+ int len;
+
+outloop:
+ /*
+ * First, see if there are buffered packets and an idle
+ * transmitter - should never happen at this point.
+ */
+ if (sc->txb_inuse && (sc->xmit_busy == 0)) {
+ printf("ed: packets buffers, but transmitter idle\n");
+ ed_xmit(ifp);
+ }
+
+ /*
+ * See if there is room to put another packet in the buffer.
+ */
+ if (sc->txb_inuse == sc->txb_cnt) {
+ /*
+ * No room. Indicate this to the outside world
+ * and exit.
+ */
+ ifp->if_flags |= IFF_OACTIVE;
+ return;
+ }
+
+ IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
+ if (m == 0) {
+ /*
+ * We are using the !OACTIVE flag to indicate to the outside
+ * world that we can accept an additional packet rather than
+ * that the transmitter is _actually_ active. Indeed, the
+ * transmitter may be active, but if we haven't filled all
+ * the buffers with data then we still want to accept more.
+ */
+ ifp->if_flags &= ~IFF_OACTIVE;
+ return;
+ }
+
+ /*
+ * Copy the mbuf chain into the transmit buffer
+ */
+
+ m0 = m;
+
+ /* txb_new points to next open buffer slot */
+ buffer = sc->mem_start + (sc->txb_new * ED_TXBUF_SIZE * ED_PAGE_SIZE);
+
+ if (sc->mem_shared) {
+ /*
+ * Special case setup for 16 bit boards...
+ */
+ if (sc->isa16bit) {
+ switch (sc->vendor) {
+ /*
+ * For 16bit 3Com boards (which have 16k of memory),
+ * we have the xmit buffers in a different page
+ * of memory ('page 0') - so change pages.
+ */
+ case ED_VENDOR_3COM:
+ outb(sc->asic_addr + ED_3COM_GACFR,
+ ED_3COM_GACFR_RSEL);
+ break;
+ /*
+ * Enable 16bit access to shared memory on WD/SMC boards
+ * Don't update wd_laar_proto because we want to restore the
+ * previous state (because an arp reply in the input code
+ * may cause a call-back to ed_start)
+ * XXX - the call-back to 'start' is a bug, IMHO.
+ */
+ case ED_VENDOR_WD_SMC: {
+ outb(sc->asic_addr + ED_WD_LAAR,
+ (sc->wd_laar_proto | ED_WD_LAAR_M16EN));
+ (void) inb(0x84);
+ if (sc->is790) {
+ outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_MENB);
+ (void) inb(0x84);
+ }
+ (void) inb(0x84);
+ break;
+ }
+ }
+ }
+
+ for (len = 0; m != 0; m = m->m_next) {
+ bcopy(mtod(m, caddr_t), buffer, m->m_len);
+ buffer += m->m_len;
+ len += m->m_len;
+ }
+
+ /*
+ * Restore previous shared memory access
+ */
+ if (sc->isa16bit) {
+ switch (sc->vendor) {
+ case ED_VENDOR_3COM:
+ outb(sc->asic_addr + ED_3COM_GACFR,
+ ED_3COM_GACFR_RSEL | ED_3COM_GACFR_MBS0);
+ break;
+ case ED_VENDOR_WD_SMC: {
+ outb(sc->asic_addr + ED_WD_LAAR, sc->wd_laar_proto);
+ (void) inb(0x84);
+ if (sc->is790) {
+ outb(sc->asic_addr + ED_WD_MSR, 0x00);
+ (void) inb(0x84);
+ }
+ break;
+ }
+ }
+ }
+ } else {
+ len = ed_pio_write_mbufs(sc, m, buffer);
+ }
+
+ sc->txb_len[sc->txb_new] = MAX(len, ETHER_MIN_LEN);
+
+ sc->txb_inuse++;
+
+ /*
+ * Point to next buffer slot and wrap if necessary.
+ */
+ sc->txb_new++;
+ if (sc->txb_new == sc->txb_cnt)
+ sc->txb_new = 0;
+
+ if (sc->xmit_busy == 0)
+ ed_xmit(ifp);
+ /*
+ * If there is BPF support in the configuration, tap off here.
+ * The following has support for converting trailer packets
+ * back to normal.
+ * XXX - support for trailer packets in BPF should be moved into
+ * the bpf code proper to avoid code duplication in all of
+ * the drivers.
+ */
+#if NBPFILTER > 0
+ if (sc->bpf) {
+ u_short etype;
+ int off, datasize, resid;
+ struct ether_header *eh;
+ struct trailer_header trailer_header;
+ char ether_packet[ETHER_MAX_LEN];
+ char *ep;
+
+ ep = ether_packet;
+
+ /*
+ * We handle trailers below:
+ * Copy ether header first, then residual data,
+ * then data. Put all this in a temporary buffer
+ * 'ether_packet' and send off to bpf. Since the
+ * system has generated this packet, we assume
+ * that all of the offsets in the packet are
+ * correct; if they're not, the system will almost
+ * certainly crash in m_copydata.
+ * We make no assumptions about how the data is
+ * arranged in the mbuf chain (i.e. how much
+ * data is in each mbuf, if mbuf clusters are
+ * used, etc.), which is why we use m_copydata
+ * to get the ether header rather than assume
+ * that this is located in the first mbuf.
+ */
+ /* copy ether header */
+ m_copydata(m0, 0, sizeof(struct ether_header), ep);
+ eh = (struct ether_header *) ep;
+ ep += sizeof(struct ether_header);
+ etype = ntohs(eh->ether_type);
+ if (etype >= ETHERTYPE_TRAIL &&
+ etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+ datasize = ((etype - ETHERTYPE_TRAIL) << 9);
+ off = datasize + sizeof(struct ether_header);
+
+ /* copy trailer_header into a data structure */
+ m_copydata(m0, off, sizeof(struct trailer_header),
+ (caddr_t)&trailer_header.ether_type);
+
+ /* copy residual data */
+ m_copydata(m0, off+sizeof(struct trailer_header),
+ resid = ntohs(trailer_header.ether_residual) -
+ sizeof(struct trailer_header), ep);
+ ep += resid;
+
+ /* copy data */
+ m_copydata(m0, sizeof(struct ether_header),
+ datasize, ep);
+ ep += datasize;
+
+ /* restore original ether packet type */
+ eh->ether_type = trailer_header.ether_type;
+
+ bpf_tap(sc->bpf, ether_packet, ep - ether_packet);
+ } else
+ bpf_mtap(sc->bpf, m0);
+ }
+#endif
+
+ m_freem(m0);
+
+ /*
+ * Loop back to the top to possibly buffer more packets
+ */
+ goto outloop;
+}
+
+/*
+ * Ethernet interface receiver interrupt.
+ */
+static inline void
+ed_rint(unit)
+ int unit;
+{
+ register struct ed_softc *sc = &ed_softc[unit];
+ u_char boundry, current;
+ u_short len;
+ struct ed_ring packet_hdr;
+ char *packet_ptr;
+
+ /*
+ * Set NIC to page 1 registers to get 'current' pointer
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STA);
+ }
+ /*
+ * 'sc->next_packet' is the logical beginning of the ring-buffer - i.e.
+ * it points to where new data has been buffered. The 'CURR'
+ * (current) register points to the logical end of the ring-buffer
+ * - i.e. it points to where additional new data will be added.
+ * We loop here until the logical beginning equals the logical
+ * end (or in other words, until the ring-buffer is empty).
+ */
+ while (sc->next_packet != inb(sc->nic_addr + ED_P1_CURR)) {
+
+ /* get pointer to this buffer's header structure */
+ packet_ptr = sc->mem_ring +
+ (sc->next_packet - sc->rec_page_start) * ED_PAGE_SIZE;
+
+ /*
+ * The byte count includes the FCS - Frame Check Sequence (a
+ * 32 bit CRC).
+ */
+ if (sc->mem_shared)
+ packet_hdr = *(struct ed_ring *)packet_ptr;
+ else
+ ed_pio_readmem(sc, packet_ptr, (char *) &packet_hdr,
+ sizeof(packet_hdr));
+ len = packet_hdr.count;
+ if ((len >= ETHER_MIN_LEN) && (len <= ETHER_MAX_LEN)) {
+ /*
+ * Go get packet. len - 4 removes CRC from length.
+ */
+ ed_get_packet(sc, packet_ptr + 4, len - 4);
+ ++sc->arpcom.ac_if.if_ipackets;
+ } else {
+ /*
+ * Really BAD...probably indicates that the ring pointers
+ * are corrupted. Also seen on early rev chips under
+ * high load - the byte order of the length gets switched.
+ */
+ log(LOG_ERR,
+ "ed%d: NIC memory corrupt - invalid packet length %d\n",
+ unit, len);
+ ++sc->arpcom.ac_if.if_ierrors;
+ ed_reset(unit, 0);
+ return;
+ }
+
+ /*
+ * Update next packet pointer
+ */
+ sc->next_packet = packet_hdr.next_packet;
+
+ /*
+ * Update NIC boundry pointer - being careful to keep it
+ * one buffer behind. (as recommended by NS databook)
+ */
+ boundry = sc->next_packet - 1;
+ if (boundry < sc->rec_page_start)
+ boundry = sc->rec_page_stop - 1;
+
+ /*
+ * Set NIC to page 0 registers to update boundry register
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ }
+ outb(sc->nic_addr + ED_P0_BNRY, boundry);
+
+ /*
+ * Set NIC to page 1 registers before looping to top (prepare to
+ * get 'CURR' current pointer)
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STA);
+ }
+ }
+}
+
+/*
+ * Ethernet interface interrupt processor
+ */
+void
+edintr(unit)
+ int unit;
+{
+ struct ed_softc *sc = &ed_softc[unit];
+ u_char isr;
+
+ /*
+ * Set NIC to page 0 registers
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ }
+ /*
+ * loop until there are no more new interrupts
+ */
+ while (isr = inb(sc->nic_addr + ED_P0_ISR)) {
+
+ /*
+ * reset all the bits that we are 'acknowledging'
+ * by writing a '1' to each bit position that was set
+ * (writing a '1' *clears* the bit)
+ */
+ outb(sc->nic_addr + ED_P0_ISR, isr);
+
+ /*
+ * Handle transmitter interrupts. Handle these first
+ * because the receiver will reset the board under
+ * some conditions.
+ */
+ if (isr & (ED_ISR_PTX|ED_ISR_TXE)) {
+ u_char collisions = inb(sc->nic_addr + ED_P0_NCR) & 0x0f;
+
+ /*
+ * Check for transmit error. If a TX completed with an
+ * error, we end up throwing the packet away. Really
+ * the only error that is possible is excessive
+ * collisions, and in this case it is best to allow the
+ * automatic mechanisms of TCP to backoff the flow. Of
+ * course, with UDP we're screwed, but this is expected
+ * when a network is heavily loaded.
+ */
+ (void) inb(sc->nic_addr + ED_P0_TSR);
+ if (isr & ED_ISR_TXE) {
+
+ /*
+ * Excessive collisions (16)
+ */
+ if ((inb(sc->nic_addr + ED_P0_TSR) & ED_TSR_ABT)
+ && (collisions == 0)) {
+ /*
+ * When collisions total 16, the
+ * P0_NCR will indicate 0, and the
+ * TSR_ABT is set.
+ */
+ collisions = 16;
+ }
+
+ /*
+ * update output errors counter
+ */
+ ++sc->arpcom.ac_if.if_oerrors;
+ } else {
+ /*
+ * Update total number of successfully
+ * transmitted packets.
+ */
+ ++sc->arpcom.ac_if.if_opackets;
+ }
+
+ /*
+ * reset tx busy and output active flags
+ */
+ sc->xmit_busy = 0;
+ sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+
+ /*
+ * clear watchdog timer
+ */
+ sc->arpcom.ac_if.if_timer = 0;
+
+ /*
+ * Add in total number of collisions on last
+ * transmission.
+ */
+ sc->arpcom.ac_if.if_collisions += collisions;
+
+ /*
+ * Decrement buffer in-use count if not zero (can only
+ * be zero if a transmitter interrupt occured while
+ * not actually transmitting).
+ * If data is ready to transmit, start it transmitting,
+ * otherwise defer until after handling receiver
+ */
+ if (sc->txb_inuse && --sc->txb_inuse)
+ ed_xmit(&sc->arpcom.ac_if);
+ }
+
+ /*
+ * Handle receiver interrupts
+ */
+ if (isr & (ED_ISR_PRX|ED_ISR_RXE|ED_ISR_OVW)) {
+ /*
+ * Overwrite warning. In order to make sure that a lockup
+ * of the local DMA hasn't occurred, we reset and
+ * re-init the NIC. The NSC manual suggests only a
+ * partial reset/re-init is necessary - but some
+ * chips seem to want more. The DMA lockup has been
+ * seen only with early rev chips - Methinks this
+ * bug was fixed in later revs. -DG
+ */
+ if (isr & ED_ISR_OVW) {
+ ++sc->arpcom.ac_if.if_ierrors;
+#ifdef DIAGNOSTIC
+ log(LOG_WARNING,
+ "ed%d: warning - receiver ring buffer overrun\n",
+ unit);
+#endif
+ /*
+ * Stop/reset/re-init NIC
+ */
+ ed_reset(unit, 0);
+ } else {
+
+ /*
+ * Receiver Error. One or more of: CRC error, frame
+ * alignment error FIFO overrun, or missed packet.
+ */
+ if (isr & ED_ISR_RXE) {
+ ++sc->arpcom.ac_if.if_ierrors;
+#ifdef ED_DEBUG
+ printf("ed%d: receive error %x\n", unit,
+ inb(sc->nic_addr + ED_P0_RSR));
+#endif
+ }
+
+ /*
+ * Go get the packet(s)
+ * XXX - Doing this on an error is dubious
+ * because there shouldn't be any data to
+ * get (we've configured the interface to
+ * not accept packets with errors).
+ */
+
+ /*
+ * Enable 16bit access to shared memory first
+ * on WD/SMC boards.
+ */
+ if (sc->isa16bit &&
+ (sc->vendor == ED_VENDOR_WD_SMC)) {
+
+ outb(sc->asic_addr + ED_WD_LAAR,
+ (sc->wd_laar_proto |=
+ ED_WD_LAAR_M16EN));
+ (void) inb(0x84);
+ if (sc->is790) {
+ outb(sc->asic_addr + ED_WD_MSR,
+ ED_WD_MSR_MENB);
+ (void) inb(0x84);
+ }
+ }
+
+ ed_rint (unit);
+
+ /* disable 16bit access */
+ if (sc->isa16bit &&
+ (sc->vendor == ED_VENDOR_WD_SMC)) {
+
+ outb(sc->asic_addr + ED_WD_LAAR,
+ (sc->wd_laar_proto &=
+ ~ED_WD_LAAR_M16EN));
+ (void) inb(0x84);
+ if (sc->is790) {
+ outb(sc->asic_addr + ED_WD_MSR, 0x00);
+ (void) inb(0x84);
+ }
+ }
+ }
+ }
+
+ /*
+ * If it looks like the transmitter can take more data,
+ * attempt to start output on the interface.
+ * This is done after handling the receiver to
+ * give the receiver priority.
+ */
+ if ((sc->arpcom.ac_if.if_flags & IFF_OACTIVE) == 0)
+ ed_start(&sc->arpcom.ac_if);
+
+ /*
+ * return NIC CR to standard state: page 0, remote DMA complete,
+ * start (toggling the TXP bit off, even if was just set
+ * in the transmit routine, is *okay* - it is 'edge'
+ * triggered from low to high)
+ */
+ if (sc->is790) {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_STA);
+ } else {
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+ }
+ /*
+ * If the Network Talley Counters overflow, read them to
+ * reset them. It appears that old 8390's won't
+ * clear the ISR flag otherwise - resulting in an
+ * infinite loop.
+ */
+ if (isr & ED_ISR_CNT) {
+ (void) inb(sc->nic_addr + ED_P0_CNTR0);
+ (void) inb(sc->nic_addr + ED_P0_CNTR1);
+ (void) inb(sc->nic_addr + ED_P0_CNTR2);
+ }
+ }
+}
+
+/*
+ * Process an ioctl request. This code needs some work - it looks
+ * pretty ugly.
+ */
+int
+ed_ioctl(ifp, command, data)
+ register struct ifnet *ifp;
+ int command;
+ caddr_t data;
+{
+ register struct ifaddr *ifa = (struct ifaddr *)data;
+ struct ed_softc *sc = &ed_softc[ifp->if_unit];
+ struct ifreq *ifr = (struct ifreq *)data;
+ int s, error = 0;
+
+ s = splimp();
+
+ switch (command) {
+
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ ed_init(ifp->if_unit); /* before arpwhohas */
+ /*
+ * See if another station has *our* IP address.
+ * i.e.: There is an address conflict! If a
+ * conflict exists, a message is sent to the
+ * console.
+ */
+ ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
+ arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
+ break;
+#endif
+#ifdef NS
+ /*
+ * XXX - This code is probably wrong
+ */
+ case AF_NS:
+ {
+ register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+
+ if (ns_nullhost(*ina))
+ ina->x_host =
+ *(union ns_host *)(sc->arpcom.ac_enaddr);
+ else {
+ /*
+ *
+ */
+ bcopy((caddr_t)ina->x_host.c_host,
+ (caddr_t)sc->arpcom.ac_enaddr,
+ sizeof(sc->arpcom.ac_enaddr));
+ }
+ /*
+ * Set new address
+ */
+ ed_init(ifp->if_unit);
+ break;
+ }
+#endif
+ default:
+ ed_init(ifp->if_unit);
+ break;
+ }
+ break;
+
+ case SIOCGIFADDR:
+ {
+ struct sockaddr *sa;
+ sa = (struct sockaddr *)&ifr->ifr_data;
+ bcopy((caddr_t)sc->arpcom.ac_enaddr,
+ (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
+ }
+ break;
+
+ case SIOCSIFFLAGS:
+ /*
+ * If interface is marked down and it is running, then stop it
+ */
+ if (((ifp->if_flags & IFF_UP) == 0) &&
+ (ifp->if_flags & IFF_RUNNING)) {
+ ed_stop(ifp->if_unit);
+ ifp->if_flags &= ~IFF_RUNNING;
+ } else {
+ /*
+ * If interface is marked up and it is stopped, then start it
+ */
+ if ((ifp->if_flags & IFF_UP) &&
+ ((ifp->if_flags & IFF_RUNNING) == 0))
+ ed_init(ifp->if_unit);
+ }
+#if NBPFILTER > 0
+ if (ifp->if_flags & IFF_PROMISC) {
+ /*
+ * Set promiscuous mode on interface.
+ * XXX - for multicasts to work, we would need to
+ * write 1's in all bits of multicast
+ * hashing array. For now we assume that
+ * this was done in ed_init().
+ */
+ outb(sc->nic_addr + ED_P0_RCR,
+ ED_RCR_PRO|ED_RCR_AM|ED_RCR_AB);
+ } else {
+ /*
+ * XXX - for multicasts to work, we would need to
+ * rewrite the multicast hashing array with the
+ * proper hash (would have been destroyed above).
+ */
+ outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB);
+ }
+#endif
+ /*
+ * An unfortunate hack to provide the (required) software control
+ * of the tranceiver for 3Com boards. The ALTPHYS flag disables
+ * the tranceiver if set.
+ */
+ if (sc->vendor == ED_VENDOR_3COM) {
+ if (ifp->if_flags & IFF_ALTPHYS) {
+ outb(sc->asic_addr + ED_3COM_CR, 0);
+ } else {
+ outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
+ }
+ }
+
+ break;
+
+ default:
+ error = EINVAL;
+ }
+ (void) splx(s);
+ return (error);
+}
+
+/*
+ * Macro to calculate a new address within shared memory when given an offset
+ * from an address, taking into account ring-wrap.
+ */
+#define ringoffset(sc, start, off, type) \
+ ((type)( ((caddr_t)(start)+(off) >= (sc)->mem_end) ? \
+ (((caddr_t)(start)+(off))) - (sc)->mem_end \
+ + (sc)->mem_ring: \
+ ((caddr_t)(start)+(off)) ))
+
+/*
+ * Retreive packet from shared memory and send to the next level up via
+ * ether_input(). If there is a BPF listener, give a copy to BPF, too.
+ */
+static void
+ed_get_packet(sc, buf, len)
+ struct ed_softc *sc;
+ char *buf;
+ u_short len;
+{
+ struct ether_header *eh;
+ struct mbuf *m, *head = 0, *ed_ring_to_mbuf();
+ u_short off;
+ int resid;
+ u_short etype;
+ struct trailer_header trailer_header;
+
+ /* Allocate a header mbuf */
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ goto bad;
+ m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
+ m->m_pkthdr.len = len;
+ m->m_len = 0;
+ head = m;
+
+ /* The following sillines is to make NFS happy */
+#define EROUND ((sizeof(struct ether_header) + 3) & ~3)
+#define EOFF (EROUND - sizeof(struct ether_header))
+
+ /*
+ * The following assumes there is room for
+ * the ether header in the header mbuf
+ */
+ head->m_data += EOFF;
+ eh = mtod(head, struct ether_header *);
+
+ if (sc->mem_shared)
+ bcopy(buf, mtod(head, caddr_t), sizeof(struct ether_header));
+ else
+ ed_pio_readmem(sc, buf, mtod(head, caddr_t),
+ sizeof(struct ether_header));
+ buf += sizeof(struct ether_header);
+ head->m_len += sizeof(struct ether_header);
+ len -= sizeof(struct ether_header);
+
+ etype = ntohs((u_short)eh->ether_type);
+
+ /*
+ * Deal with trailer protocol:
+ * If trailer protocol, calculate the datasize as 'off',
+ * which is also the offset to the trailer header.
+ * Set resid to the amount of packet data following the
+ * trailer header.
+ * Finally, copy residual data into mbuf chain.
+ */
+ if (etype >= ETHERTYPE_TRAIL &&
+ etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+
+ off = (etype - ETHERTYPE_TRAIL) << 9;
+ if ((off + sizeof(struct trailer_header)) > len)
+ goto bad; /* insanity */
+
+ /*
+ * If we have shared memory, we can get info directly from the
+ * stored packet, otherwise we must get a local copy
+ * of the trailer header using PIO.
+ */
+ if (sc->mem_shared) {
+ eh->ether_type = *ringoffset(sc, buf, off, u_short *);
+ resid = ntohs(*ringoffset(sc, buf, off+2, u_short *));
+ } else {
+ struct trailer_header trailer_header;
+ ed_pio_readmem(sc,
+ ringoffset(sc, buf, off, caddr_t),
+ (char *) &trailer_header,
+ sizeof(trailer_header));
+ eh->ether_type = trailer_header.ether_type;
+ resid = trailer_header.ether_residual;
+ }
+
+ if ((off + resid) > len) goto bad; /* insanity */
+
+ resid -= sizeof(struct trailer_header);
+ if (resid < 0) goto bad; /* insanity */
+
+ m = ed_ring_to_mbuf(sc, ringoffset(sc, buf, off+4, char *),
+ head, resid);
+ if (m == 0) goto bad;
+
+ len = off;
+ head->m_pkthdr.len -= 4; /* subtract trailer header */
+ }
+
+ /*
+ * Pull packet off interface. Or if this was a trailer packet,
+ * the data portion is appended.
+ */
+ m = ed_ring_to_mbuf(sc, buf, m, len);
+ if (m == 0) goto bad;
+
+#if NBPFILTER > 0
+ /*
+ * Check if there's a BPF listener on this interface.
+ * If so, hand off the raw packet to bpf.
+ */
+ if (sc->bpf) {
+ bpf_mtap(sc->bpf, head);
+
+ /*
+ * Note that the interface cannot be in promiscuous mode if
+ * there are no BPF listeners. And if we are in promiscuous
+ * mode, we have to check if this packet is really ours.
+ *
+ * XXX This test does not support multicasts.
+ */
+ if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) &&
+ bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
+ sizeof(eh->ether_dhost)) != 0 &&
+ bcmp(eh->ether_dhost, etherbroadcastaddr,
+ sizeof(eh->ether_dhost)) != 0) {
+
+ m_freem(head);
+ return;
+ }
+ }
+#endif
+
+ /*
+ * Fix up data start offset in mbuf to point past ether header
+ */
+ m_adj(head, sizeof(struct ether_header));
+
+ /*
+ * silly ether_input routine needs 'type' in host byte order
+ */
+ eh->ether_type = ntohs(eh->ether_type);
+
+ ether_input(&sc->arpcom.ac_if, eh, head);
+ return;
+
+bad: if (head)
+ m_freem(head);
+ return;
+}
+
+/*
+ * Supporting routines
+ */
+
+/*
+ * Given a NIC memory source address and a host memory destination
+ * address, copy 'amount' from NIC to host using Programmed I/O.
+ * The 'amount' is rounded up to a word - okay as long as mbufs
+ * are word sized.
+ * This routine is currently Novell-specific.
+ */
+void
+ed_pio_readmem(sc,src,dst,amount)
+ struct ed_softc *sc;
+ unsigned short src;
+ unsigned char *dst;
+ unsigned short amount;
+{
+ unsigned short tmp_amount;
+
+ /* select page 0 registers */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+
+ /* round up to a word */
+ tmp_amount = amount;
+ if (amount & 1) ++amount;
+
+ /* set up DMA byte count */
+ outb(sc->nic_addr + ED_P0_RBCR0, amount);
+ outb(sc->nic_addr + ED_P0_RBCR1, amount>>8);
+
+ /* set up source address in NIC mem */
+ outb(sc->nic_addr + ED_P0_RSAR0, src);
+ outb(sc->nic_addr + ED_P0_RSAR1, src>>8);
+
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD0 | ED_CR_STA);
+
+ if (sc->isa16bit) {
+ insw(sc->asic_addr + ED_NOVELL_DATA, dst, amount/2);
+ } else
+ insb(sc->asic_addr + ED_NOVELL_DATA, dst, amount);
+
+}
+
+/*
+ * Stripped down routine for writing a linear buffer to NIC memory.
+ * Only used in the probe routine to test the memory. 'len' must
+ * be even.
+ */
+void
+ed_pio_writemem(sc,src,dst,len)
+ struct ed_softc *sc;
+ char *src;
+ unsigned short dst;
+ unsigned short len;
+{
+ int maxwait=100; /* about 120us */
+
+ /* select page 0 registers */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+
+ /* reset remote DMA complete flag */
+ outb(sc->nic_addr + ED_P0_ISR, ED_ISR_RDC);
+
+ /* set up DMA byte count */
+ outb(sc->nic_addr + ED_P0_RBCR0, len);
+ outb(sc->nic_addr + ED_P0_RBCR1, len>>8);
+
+ /* set up destination address in NIC mem */
+ outb(sc->nic_addr + ED_P0_RSAR0, dst);
+ outb(sc->nic_addr + ED_P0_RSAR1, dst>>8);
+
+ /* set remote DMA write */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD1 | ED_CR_STA);
+
+ if (sc->isa16bit)
+ outsw(sc->asic_addr + ED_NOVELL_DATA, src, len/2);
+ else
+ outsb(sc->asic_addr + ED_NOVELL_DATA, src, len);
+ /*
+ * Wait for remote DMA complete. This is necessary because on the
+ * transmit side, data is handled internally by the NIC in bursts
+ * and we can't start another remote DMA until this one completes.
+ * Not waiting causes really bad things to happen - like the NIC
+ * irrecoverably jamming the ISA bus.
+ */
+ while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RDC) != ED_ISR_RDC) && --maxwait);
+}
+
+/*
+ * Write an mbuf chain to the destination NIC memory address using
+ * programmed I/O.
+ */
+u_short
+ed_pio_write_mbufs(sc,m,dst)
+ struct ed_softc *sc;
+ struct mbuf *m;
+ unsigned short dst;
+{
+ unsigned short len, mb_offset;
+ struct mbuf *mp;
+ unsigned char residual[2];
+ int maxwait=100; /* about 120us */
+
+ /* First, count up the total number of bytes to copy */
+ for (len = 0, mp = m; mp; mp = mp->m_next)
+ len += mp->m_len;
+
+ /* select page 0 registers */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA);
+
+ /* reset remote DMA complete flag */
+ outb(sc->nic_addr + ED_P0_ISR, ED_ISR_RDC);
+
+ /* set up DMA byte count */
+ outb(sc->nic_addr + ED_P0_RBCR0, len);
+ outb(sc->nic_addr + ED_P0_RBCR1, len>>8);
+
+ /* set up destination address in NIC mem */
+ outb(sc->nic_addr + ED_P0_RSAR0, dst);
+ outb(sc->nic_addr + ED_P0_RSAR1, dst>>8);
+
+ /* set remote DMA write */
+ outb(sc->nic_addr + ED_P0_CR, ED_CR_RD1 | ED_CR_STA);
+
+ mb_offset = 0;
+ /*
+ * Transfer the mbuf chain to the NIC memory.
+ * The following code isn't too pretty. The problem is that we can only
+ * transfer words to the board, and if an mbuf has an odd number
+ * of bytes in it, this is a problem. It's not a simple matter of
+ * just removing a byte from the next mbuf (adjusting data++ and
+ * len--) because this will hose-over the mbuf chain which might
+ * be needed later for BPF. Instead, we maintain an offset
+ * (mb_offset) which let's us skip over the first byte in the
+ * following mbuf.
+ */
+ while (m) {
+ if (m->m_len - mb_offset) {
+ if (sc->isa16bit) {
+ if ((m->m_len - mb_offset) > 1)
+ outsw(sc->asic_addr + ED_NOVELL_DATA,
+ mtod(m, caddr_t) + mb_offset,
+ (m->m_len - mb_offset) / 2);
+
+ /*
+ * if odd number of bytes, get the odd byte from
+ * the next mbuf with data
+ */
+ if ((m->m_len - mb_offset) & 1) {
+ /* first the last byte in current mbuf */
+ residual[0] = *(mtod(m, caddr_t) +
+ m->m_len - 1);
+
+ /* advance past any empty mbufs */
+ while (m->m_next && (m->m_next->m_len == 0))
+ m = m->m_next;
+
+ if (m->m_next) {
+ /* remove first byte in next mbuf */
+ residual[1] = *(mtod(m->m_next, caddr_t));
+ mb_offset = 1;
+ }
+
+ outw(sc->asic_addr + ED_NOVELL_DATA,
+ *((unsigned short *) residual));
+ } else
+ mb_offset = 0;
+ } else
+ outsb(sc->asic_addr + ED_NOVELL_DATA, m->m_data, m->m_len);
+
+ }
+ m = m->m_next;
+ }
+
+ /*
+ * Wait for remote DMA complete. This is necessary because on the
+ * transmit side, data is handled internally by the NIC in bursts
+ * and we can't start another remote DMA until this one completes.
+ * Not waiting causes really bad things to happen - like the NIC
+ * irrecoverably jamming the ISA bus.
+ */
+ while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RDC) != ED_ISR_RDC) && --maxwait);
+
+ if (!maxwait) {
+ log(LOG_WARNING, "ed%d: remote transmit DMA failed to complete\n",
+ sc->arpcom.ac_if.if_unit);
+ ed_reset(sc->arpcom.ac_if.if_unit, 0);
+ }
+
+ return(len);
+}
+
+/*
+ * Given a source and destination address, copy 'amount' of a packet from
+ * the ring buffer into a linear destination buffer. Takes into account
+ * ring-wrap.
+ */
+static inline char *
+ed_ring_copy(sc,src,dst,amount)
+ struct ed_softc *sc;
+ char *src;
+ char *dst;
+ u_short amount;
+{
+ u_short tmp_amount;
+
+ /* does copy wrap to lower addr in ring buffer? */
+ if (src + amount > sc->mem_end) {
+ tmp_amount = sc->mem_end - src;
+
+ /* copy amount up to end of NIC memory */
+ if (sc->mem_shared)
+ bcopy(src,dst,tmp_amount);
+ else
+ ed_pio_readmem(sc,src,dst,tmp_amount);
+
+ amount -= tmp_amount;
+ src = sc->mem_ring;
+ dst += tmp_amount;
+ }
+
+ if (sc->mem_shared)
+ bcopy(src, dst, amount);
+ else
+ ed_pio_readmem(sc, src, dst, amount);
+
+ return(src + amount);
+}
+
+/*
+ * Copy data from receive buffer to end of mbuf chain
+ * allocate additional mbufs as needed. return pointer
+ * to last mbuf in chain.
+ * sc = ed info (softc)
+ * src = pointer in ed ring buffer
+ * dst = pointer to last mbuf in mbuf chain to copy to
+ * amount = amount of data to copy
+ */
+struct mbuf *
+ed_ring_to_mbuf(sc,src,dst,total_len)
+ struct ed_softc *sc;
+ char *src;
+ struct mbuf *dst;
+ u_short total_len;
+{
+ register struct mbuf *m = dst;
+
+ while (total_len) {
+ register u_short amount = min(total_len, M_TRAILINGSPACE(m));
+
+ if (amount == 0) { /* no more data in this mbuf, alloc another */
+ /*
+ * If there is enough data for an mbuf cluster, attempt
+ * to allocate one of those, otherwise, a regular
+ * mbuf will do.
+ * Note that a regular mbuf is always required, even if
+ * we get a cluster - getting a cluster does not
+ * allocate any mbufs, and one is needed to assign
+ * the cluster to. The mbuf that has a cluster
+ * extension can not be used to contain data - only
+ * the cluster can contain data.
+ */
+ dst = m;
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ return (0);
+
+ if (total_len >= MINCLSIZE)
+ MCLGET(m, M_DONTWAIT);
+
+ m->m_len = 0;
+ dst->m_next = m;
+ amount = min(total_len, M_TRAILINGSPACE(m));
+ }
+
+ src = ed_ring_copy(sc, src, mtod(m, caddr_t) + m->m_len, amount);
+
+ m->m_len += amount;
+ total_len -= amount;
+
+ }
+ return (m);
+}
+#endif
diff --git a/sys/i386/isa/if_edreg.h b/sys/i386/isa/if_edreg.h
new file mode 100644
index 0000000..f75e261
--- /dev/null
+++ b/sys/i386/isa/if_edreg.h
@@ -0,0 +1,962 @@
+/*
+ * National Semiconductor DS8390 NIC register definitions
+ *
+ * $Id: if_edreg.h,v 1.13 1994/02/02 14:05:58 davidg Exp $
+ *
+ * Modification history
+ *
+ * Revision 2.2 1993/11/29 16:33:39 davidg
+ * From Thomas Sandford <t.d.g.sandford@comp.brad.ac.uk>
+ * Add support for the 8013W board type
+ *
+ * Revision 2.1 1993/11/22 10:52:33 davidg
+ * patch to add support for SMC8216 (Elite-Ultra) boards
+ * from Glen H. Lowe
+ *
+ * Revision 2.0 93/09/29 00:37:15 davidg
+ * changed double buffering flag to multi buffering
+ * made changes/additions for 3c503 multi-buffering
+ * ...companion to Rev. 2.0 of 'ed' driver.
+ *
+ * Revision 1.1 93/06/23 03:01:07 davidg
+ * Initial revision
+ *
+ */
+
+/*
+ * Page 0 register offsets
+ */
+#define ED_P0_CR 0x00 /* Command Register */
+
+#define ED_P0_CLDA0 0x01 /* Current Local DMA Addr low (read) */
+#define ED_P0_PSTART 0x01 /* Page Start register (write) */
+
+#define ED_P0_CLDA1 0x02 /* Current Local DMA Addr high (read) */
+#define ED_P0_PSTOP 0x02 /* Page Stop register (write) */
+
+#define ED_P0_BNRY 0x03 /* Boundary Pointer */
+
+#define ED_P0_TSR 0x04 /* Transmit Status Register (read) */
+#define ED_P0_TPSR 0x04 /* Transmit Page Start (write) */
+
+#define ED_P0_NCR 0x05 /* Number of Collisions Reg (read) */
+#define ED_P0_TBCR0 0x05 /* Transmit Byte count, low (write) */
+
+#define ED_P0_FIFO 0x06 /* FIFO register (read) */
+#define ED_P0_TBCR1 0x06 /* Transmit Byte count, high (write) */
+
+#define ED_P0_ISR 0x07 /* Interrupt Status Register */
+
+#define ED_P0_CRDA0 0x08 /* Current Remote DMA Addr low (read) */
+#define ED_P0_RSAR0 0x08 /* Remote Start Address low (write) */
+
+#define ED_P0_CRDA1 0x09 /* Current Remote DMA Addr high (read) */
+#define ED_P0_RSAR1 0x09 /* Remote Start Address high (write) */
+
+#define ED_P0_RBCR0 0x0a /* Remote Byte Count low (write) */
+
+#define ED_P0_RBCR1 0x0b /* Remote Byte Count high (write) */
+
+#define ED_P0_RSR 0x0c /* Receive Status (read) */
+#define ED_P0_RCR 0x0c /* Receive Configuration Reg (write) */
+
+#define ED_P0_CNTR0 0x0d /* frame alignment error counter (read) */
+#define ED_P0_TCR 0x0d /* Transmit Configuration Reg (write) */
+
+#define ED_P0_CNTR1 0x0e /* CRC error counter (read) */
+#define ED_P0_DCR 0x0e /* Data Configuration Reg (write) */
+
+#define ED_P0_CNTR2 0x0f /* missed packet counter (read) */
+#define ED_P0_IMR 0x0f /* Interrupt Mask Register (write) */
+
+/*
+ * Page 1 register offsets
+ */
+#define ED_P1_CR 0x00 /* Command Register */
+#define ED_P1_PAR0 0x01 /* Physical Address Register 0 */
+#define ED_P1_PAR1 0x02 /* Physical Address Register 1 */
+#define ED_P1_PAR2 0x03 /* Physical Address Register 2 */
+#define ED_P1_PAR3 0x04 /* Physical Address Register 3 */
+#define ED_P1_PAR4 0x05 /* Physical Address Register 4 */
+#define ED_P1_PAR5 0x06 /* Physical Address Register 5 */
+#define ED_P1_CURR 0x07 /* Current RX ring-buffer page */
+#define ED_P1_MAR0 0x08 /* Multicast Address Register 0 */
+#define ED_P1_MAR1 0x09 /* Multicast Address Register 1 */
+#define ED_P1_MAR2 0x0a /* Multicast Address Register 2 */
+#define ED_P1_MAR3 0x0b /* Multicast Address Register 3 */
+#define ED_P1_MAR4 0x0c /* Multicast Address Register 4 */
+#define ED_P1_MAR5 0x0d /* Multicast Address Register 5 */
+#define ED_P1_MAR6 0x0e /* Multicast Address Register 6 */
+#define ED_P1_MAR7 0x0f /* Multicast Address Register 7 */
+
+/*
+ * Page 2 register offsets
+ */
+#define ED_P2_CR 0x00 /* Command Register */
+#define ED_P2_PSTART 0x01 /* Page Start (read) */
+#define ED_P2_CLDA0 0x01 /* Current Local DMA Addr 0 (write) */
+#define ED_P2_PSTOP 0x02 /* Page Stop (read) */
+#define ED_P2_CLDA1 0x02 /* Current Local DMA Addr 1 (write) */
+#define ED_P2_RNPP 0x03 /* Remote Next Packet Pointer */
+#define ED_P2_TPSR 0x04 /* Transmit Page Start (read) */
+#define ED_P2_LNPP 0x05 /* Local Next Packet Pointer */
+#define ED_P2_ACU 0x06 /* Address Counter Upper */
+#define ED_P2_ACL 0x07 /* Address Counter Lower */
+#define ED_P2_RCR 0x0c /* Receive Configuration Register (read) */
+#define ED_P2_TCR 0x0d /* Transmit Configuration Register (read) */
+#define ED_P2_DCR 0x0e /* Data Configuration Register (read) */
+#define ED_P2_IMR 0x0f /* Interrupt Mask Register (read) */
+
+/*
+ * Command Register (CR) definitions
+ */
+
+/*
+ * STP: SToP. Software reset command. Takes the controller offline. No
+ * packets will be received or transmitted. Any reception or
+ * transmission in progress will continue to completion before
+ * entering reset state. To exit this state, the STP bit must
+ * reset and the STA bit must be set. The software reset has
+ * executed only when indicated by the RST bit in the ISR being
+ * set.
+ */
+#define ED_CR_STP 0x01
+
+/*
+ * STA: STArt. This bit is used to activate the NIC after either power-up,
+ * or when the NIC has been put in reset mode by software command
+ * or error.
+ */
+#define ED_CR_STA 0x02
+
+/*
+ * TXP: Transmit Packet. This bit must be set to indicate transmission of
+ * a packet. TXP is internally reset either after the transmission is
+ * completed or aborted. This bit should be set only after the Transmit
+ * Byte Count and Transmit Page Start register have been programmed.
+ */
+#define ED_CR_TXP 0x04
+
+/*
+ * RD0, RD1, RD2: Remote DMA Command. These three bits control the operation
+ * of the remote DMA channel. RD2 can be set to abort any remote DMA
+ * command in progress. The Remote Byte Count registers should be cleared
+ * when a remote DMA has been aborted. The Remote Start Addresses are not
+ * restored to the starting address if the remote DMA is aborted.
+ *
+ * RD2 RD1 RD0 function
+ * 0 0 0 not allowed
+ * 0 0 1 remote read
+ * 0 1 0 remote write
+ * 0 1 1 send packet
+ * 1 X X abort
+ */
+#define ED_CR_RD0 0x08
+#define ED_CR_RD1 0x10
+#define ED_CR_RD2 0x20
+
+/*
+ * PS0, PS1: Page Select. The two bits select which register set or 'page' to
+ * access.
+ *
+ * PS1 PS0 page
+ * 0 0 0
+ * 0 1 1
+ * 1 0 2
+ * 1 1 reserved
+ */
+#define ED_CR_PS0 0x40
+#define ED_CR_PS1 0x80
+/* bit encoded aliases */
+#define ED_CR_PAGE_0 0x00 /* (for consistency) */
+#define ED_CR_PAGE_1 0x40
+#define ED_CR_PAGE_2 0x80
+
+/*
+ * Interrupt Status Register (ISR) definitions
+ */
+
+/*
+ * PRX: Packet Received. Indicates packet received with no errors.
+ */
+#define ED_ISR_PRX 0x01
+
+/*
+ * PTX: Packet Transmitted. Indicates packet transmitted with no errors.
+ */
+#define ED_ISR_PTX 0x02
+
+/*
+ * RXE: Receive Error. Indicates that a packet was received with one or more
+ * the following errors: CRC error, frame alignment error, FIFO overrun,
+ * missed packet.
+ */
+#define ED_ISR_RXE 0x04
+
+/*
+ * TXE: Transmission Error. Indicates that an attempt to transmit a packet
+ * resulted in one or more of the following errors: excessive
+ * collisions, FIFO underrun.
+ */
+#define ED_ISR_TXE 0x08
+
+/*
+ * OVW: OverWrite. Indicates a receive ring-buffer overrun. Incoming network
+ * would exceed (has exceeded?) the boundry pointer, resulting in data
+ * that was previously received and not yet read from the buffer to be
+ * overwritten.
+ */
+#define ED_ISR_OVW 0x10
+
+/*
+ * CNT: Counter Overflow. Set when the MSB of one or more of the Network Talley
+ * Counters has been set.
+ */
+#define ED_ISR_CNT 0x20
+
+/*
+ * RDC: Remote Data Complete. Indicates that a Remote DMA operation has completed.
+ */
+#define ED_ISR_RDC 0x40
+
+/*
+ * RST: Reset status. Set when the NIC enters the reset state and cleared when a
+ * Start Command is issued to the CR. This bit is also set when a receive
+ * ring-buffer overrun (OverWrite) occurs and is cleared when one or more
+ * packets have been removed from the ring. This is a read-only bit.
+ */
+#define ED_ISR_RST 0x80
+
+/*
+ * Interrupt Mask Register (IMR) definitions
+ */
+
+/*
+ * PRXE: Packet Received interrupt Enable. If set, a received packet will cause
+ * an interrupt.
+ */
+#define ED_IMR_PRXE 0x01
+
+/*
+ * PTXE: Packet Transmit interrupt Enable. If set, an interrupt is generated when
+ * a packet transmission completes.
+ */
+#define ED_IMR_PTXE 0x02
+
+/*
+ * RXEE: Receive Error interrupt Enable. If set, an interrupt will occur whenever a
+ * packet is received with an error.
+ */
+#define ED_IMR_RXEE 0x04
+
+/*
+ * TXEE: Transmit Error interrupt Enable. If set, an interrupt will occur whenever
+ * a transmission results in an error.
+ */
+#define ED_IMR_TXEE 0x08
+
+/*
+ * OVWE: OverWrite error interrupt Enable. If set, an interrupt is generated whenever
+ * the receive ring-buffer is overrun. i.e. when the boundry pointer is exceeded.
+ */
+#define ED_IMR_OVWE 0x10
+
+/*
+ * CNTE: Counter overflow interrupt Enable. If set, an interrupt is generated whenever
+ * the MSB of one or more of the Network Statistics counters has been set.
+ */
+#define ED_IMR_CNTE 0x20
+
+/*
+ * RDCE: Remote DMA Complete interrupt Enable. If set, an interrupt is generated
+ * when a remote DMA transfer has completed.
+ */
+#define ED_IMR_RDCE 0x40
+
+/*
+ * bit 7 is unused/reserved
+ */
+
+/*
+ * Data Configuration Register (DCR) definitions
+ */
+
+/*
+ * WTS: Word Transfer Select. WTS establishes byte or word transfers for
+ * both remote and local DMA transfers
+ */
+#define ED_DCR_WTS 0x01
+
+/*
+ * BOS: Byte Order Select. BOS sets the byte order for the host.
+ * Should be 0 for 80x86, and 1 for 68000 series processors
+ */
+#define ED_DCR_BOS 0x02
+
+/*
+ * LAS: Long Address Select. When LAS is 1, the contents of the remote
+ * DMA registers RSAR0 and RSAR1 are used to provide A16-A31
+ */
+#define ED_DCR_LAS 0x04
+
+/*
+ * LS: Loopback Select. When 0, loopback mode is selected. Bits D1 and D2
+ * of the TCR must also be programmed for loopback operation.
+ * When 1, normal operation is selected.
+ */
+#define ED_DCR_LS 0x08
+
+/*
+ * AR: Auto-initialize Remote. When 0, data must be removed from ring-buffer
+ * under program control. When 1, remote DMA is automatically initiated
+ * and the boundry pointer is automatically updated
+ */
+#define ED_DCR_AR 0x10
+
+/*
+ * FT0, FT1: Fifo Threshold select.
+ * FT1 FT0 Word-width Byte-width
+ * 0 0 1 word 2 bytes
+ * 0 1 2 words 4 bytes
+ * 1 0 4 words 8 bytes
+ * 1 1 8 words 12 bytes
+ *
+ * During transmission, the FIFO threshold indicates the number of bytes
+ * or words that the FIFO has filled from the local DMA before BREQ is
+ * asserted. The transmission threshold is 16 bytes minus the receiver
+ * threshold.
+ */
+#define ED_DCR_FT0 0x20
+#define ED_DCR_FT1 0x40
+
+/*
+ * bit 7 (0x80) is unused/reserved
+ */
+
+/*
+ * Transmit Configuration Register (TCR) definitions
+ */
+
+/*
+ * CRC: Inhibit CRC. If 0, CRC will be appended by the transmitter, if 0, CRC
+ * is not appended by the transmitter.
+ */
+#define ED_TCR_CRC 0x01
+
+/*
+ * LB0, LB1: Loopback control. These two bits set the type of loopback that is
+ * to be performed.
+ *
+ * LB1 LB0 mode
+ * 0 0 0 - normal operation (DCR_LS = 0)
+ * 0 1 1 - internal loopback (DCR_LS = 0)
+ * 1 0 2 - external loopback (DCR_LS = 1)
+ * 1 1 3 - external loopback (DCR_LS = 0)
+ */
+#define ED_TCR_LB0 0x02
+#define ED_TCR_LB1 0x04
+
+/*
+ * ATD: Auto Transmit Disable. Clear for normal operation. When set, allows
+ * another station to disable the NIC's transmitter by transmitting to
+ * a multicast address hashing to bit 62. Reception of a multicast address
+ * hashing to bit 63 enables the transmitter.
+ */
+#define ED_TCR_ATD 0x08
+
+/*
+ * OFST: Collision Offset enable. This bit when set modifies the backoff
+ * algorithm to allow prioritization of nodes.
+ */
+#define ED_TCR_OFST 0x10
+
+/*
+ * bits 5, 6, and 7 are unused/reserved
+ */
+
+/*
+ * Transmit Status Register (TSR) definitions
+ */
+
+/*
+ * PTX: Packet Transmitted. Indicates successful transmission of packet.
+ */
+#define ED_TSR_PTX 0x01
+
+/*
+ * bit 1 (0x02) is unused/reserved
+ */
+
+/*
+ * COL: Transmit Collided. Indicates that the transmission collided at least
+ * once with another station on the network.
+ */
+#define ED_TSR_COL 0x04
+
+/*
+ * ABT: Transmit aborted. Indicates that the transmission was aborted due to
+ * excessive collisions.
+ */
+#define ED_TSR_ABT 0x08
+
+/*
+ * CRS: Carrier Sense Lost. Indicates that carrier was lost during the
+ * transmission of the packet. (Transmission is not aborted because
+ * of a loss of carrier)
+ */
+#define ED_TSR_CRS 0x10
+
+/*
+ * FU: FIFO Underrun. Indicates that the NIC wasn't able to access bus/
+ * transmission memory before the FIFO emptied. Transmission of the
+ * packet was aborted.
+ */
+#define ED_TSR_FU 0x20
+
+/*
+ * CDH: CD Heartbeat. Indicates that the collision detection circuitry
+ * isn't working correctly during a collision heartbeat test.
+ */
+#define ED_TSR_CDH 0x40
+
+/*
+ * OWC: Out of Window Collision: Indicates that a collision occurred after
+ * a slot time (51.2us). The transmission is rescheduled just as in
+ * normal collisions.
+ */
+#define ED_TSR_OWC 0x80
+
+/*
+ * Receiver Configuration Register (RCR) definitions
+ */
+
+/*
+ * SEP: Save Errored Packets. If 0, error packets are discarded. If set to 1,
+ * packets with CRC and frame errors are not discarded.
+ */
+#define ED_RCR_SEP 0x01
+
+/*
+ * AR: Accept Runt packet. If 0, packet with less than 64 byte are discarded.
+ * If set to 1, packets with less than 64 byte are not discarded.
+ */
+#define ED_RCR_AR 0x02
+
+/*
+ * AB: Accept Broadcast. If set, packets sent to the broadcast address will be
+ * accepted.
+ */
+#define ED_RCR_AB 0x04
+
+/*
+ * AM: Accept Multicast. If set, packets sent to a multicast address are checked
+ * for a match in the hashing array. If clear, multicast packets are ignored.
+ */
+#define ED_RCR_AM 0x08
+
+/*
+ * PRO: Promiscuous Physical. If set, all packets with a physical addresses are
+ * accepted. If clear, a physical destination address must match this
+ * station's address. Note: for full promiscuous mode, RCR_AB and RCR_AM
+ * must also be set. In addition, the multicast hashing array must be set
+ * to all 1's so that all multicast addresses are accepted.
+ */
+#define ED_RCR_PRO 0x10
+
+/*
+ * MON: Monitor Mode. If set, packets will be checked for good CRC and framing,
+ * but are not stored in the ring-buffer. If clear, packets are stored (normal
+ * operation).
+ */
+#define ED_RCR_MON 0x20
+
+/*
+ * bits 6 and 7 are unused/reserved.
+ */
+
+/*
+ * Receiver Status Register (RSR) definitions
+ */
+
+/*
+ * PRX: Packet Received without error.
+ */
+#define ED_RSR_PRX 0x01
+
+/*
+ * CRC: CRC error. Indicates that a packet has a CRC error. Also set for frame
+ * alignment errors.
+ */
+#define ED_RSR_CRC 0x02
+
+/*
+ * FAE: Frame Alignment Error. Indicates that the incoming packet did not end on
+ * a byte boundry and the CRC did not match at the last byte boundry.
+ */
+#define ED_RSR_FAE 0x04
+
+/*
+ * FO: FIFO Overrun. Indicates that the FIFO was not serviced (during local DMA)
+ * causing it to overrun. Reception of the packet is aborted.
+ */
+#define ED_RSR_FO 0x08
+
+/*
+ * MPA: Missed Packet. Indicates that the received packet couldn't be stored in
+ * the ring-buffer because of insufficient buffer space (exceeding the
+ * boundry pointer), or because the transfer to the ring-buffer was inhibited
+ * by RCR_MON - monitor mode.
+ */
+#define ED_RSR_MPA 0x10
+
+/*
+ * PHY: Physical address. If 0, the packet received was sent to a physical address.
+ * If 1, the packet was accepted because of a multicast/broadcast address
+ * match.
+ */
+#define ED_RSR_PHY 0x20
+
+/*
+ * DIS: Receiver Disabled. Set to indicate that the receiver has enetered monitor
+ * mode. Cleared when the receiver exits monitor mode.
+ */
+#define ED_RSR_DIS 0x40
+
+/*
+ * DFR: Deferring. Set to indicate a 'jabber' condition. The CRS and COL inputs
+ * are active, and the transceiver has set the CD line as a result of the
+ * jabber.
+ */
+#define ED_RSR_DFR 0x80
+
+/*
+ * receive ring discriptor
+ *
+ * The National Semiconductor DS8390 Network interface controller uses
+ * the following receive ring headers. The way this works is that the
+ * memory on the interface card is chopped up into 256 bytes blocks.
+ * A contiguous portion of those blocks are marked for receive packets
+ * by setting start and end block #'s in the NIC. For each packet that
+ * is put into the receive ring, one of these headers (4 bytes each) is
+ * tacked onto the front.
+ */
+struct ed_ring {
+ struct edr_status { /* received packet status */
+ u_char rs_prx:1, /* packet received intack */
+ rs_crc:1, /* crc error */
+ rs_fae:1, /* frame alignment error */
+ rs_fo:1, /* fifo overrun */
+ rs_mpa:1, /* packet received intack */
+ rs_phy:1, /* packet received intack */
+ rs_dis:1, /* packet received intack */
+ rs_dfr:1; /* packet received intack */
+ } ed_rcv_status; /* received packet status */
+ u_char next_packet; /* pointer to next packet */
+ u_short count; /* bytes in packet (length + 4) */
+};
+
+/*
+ * Common constants
+ */
+#define ED_PAGE_SIZE 256 /* Size of RAM pages in bytes */
+#define ED_TXBUF_SIZE 6 /* Size of TX buffer in pages */
+
+/*
+ * Vendor types
+ */
+#define ED_VENDOR_WD_SMC 0x00 /* Western Digital/SMC */
+#define ED_VENDOR_3COM 0x01 /* 3Com */
+#define ED_VENDOR_NOVELL 0x02 /* Novell */
+
+/*
+ * Compile-time config flags
+ */
+/*
+ * this sets the default for enabling/disablng the tranceiver
+ */
+#define ED_FLAGS_DISABLE_TRANCEIVER 0x0001
+
+/*
+ * This forces the board to be used in 8/16bit mode even if it
+ * autoconfigs differently
+ */
+#define ED_FLAGS_FORCE_8BIT_MODE 0x0002
+#define ED_FLAGS_FORCE_16BIT_MODE 0x0004
+
+/*
+ * This disables the use of double transmit buffers.
+ */
+#define ED_FLAGS_NO_MULTI_BUFFERING 0x0008
+
+/*
+ * This forces all operations with the NIC memory to use Programmed
+ * I/O (i.e. not via shared memory)
+ */
+#define ED_FLAGS_FORCE_PIO 0x0010
+
+/*
+ * Definitions for Western digital/SMC WD80x3 series ASIC
+ */
+/*
+ * Memory Select Register (MSR)
+ */
+#define ED_WD_MSR 0
+
+/* next three definitions for Toshiba */
+#define ED_WD_MSR_POW 0x02 /* 0 = power save, 1 = normal (R/W) */
+#define ED_WD_MSR_BSY 0x04 /* gate array busy (R) */
+#define ED_WD_MSR_LEN 0x20 /* data bus width, 0 = 16 bits,
+ 1 = 8 bits (R/W) */
+#define ED_WD_MSR_ADDR 0x3f /* Memory decode bits 18-13 */
+#define ED_WD_MSR_MENB 0x40 /* Memory enable */
+#define ED_WD_MSR_RST 0x80 /* Reset board */
+
+/*
+ * Interface Configuration Register (ICR)
+ */
+#define ED_WD_ICR 1
+
+#define ED_WD_ICR_16BIT 0x01 /* 16-bit interface */
+#define ED_WD_ICR_OAR 0x02 /* select register. 0=BIO 1=EAR */
+#define ED_WD_ICR_IR2 0x04 /* high order bit of encoded IRQ */
+#define ED_WD_ICR_MSZ 0x08 /* memory size (0=8k 1=32k) */
+#define ED_WD_ICR_RLA 0x10 /* recall LAN address */
+#define ED_WD_ICR_RX7 0x20 /* recall all but i/o and LAN address */
+#define ED_WD_ICR_RIO 0x40 /* recall i/o address */
+#define ED_WD_ICR_STO 0x80 /* store to non-volatile memory */
+#ifdef TOSH_ETHER
+#define ED_WD_ICR_MEM 0xe0 /* shared mem address A15-A13 (R/W) */
+#define ED_WD_ICR_MSZ1 0x0f /* memory size, 0x08 = 64K, 0x04 = 32K,
+ 0x02 = 16K, 0x01 = 8K */
+ /* 64K can only be used if mem address
+ above 1Mb */
+ /* IAR holds address A23-A16 (R/W) */
+#endif
+
+/*
+ * IO Address Register (IAR)
+ */
+#define ED_WD_IAR 2
+
+/*
+ * EEROM Address Register
+ */
+#define ED_WD_EAR 3
+
+/*
+ * Interrupt Request Register (IRR)
+ */
+#define ED_WD_IRR 4
+
+#define ED_WD_IRR_0WS 0x01 /* use 0 wait-states on 8 bit bus */
+#define ED_WD_IRR_OUT1 0x02 /* WD83C584 pin 1 output */
+#define ED_WD_IRR_OUT2 0x04 /* WD83C584 pin 2 output */
+#define ED_WD_IRR_OUT3 0x08 /* WD83C584 pin 3 output */
+#define ED_WD_IRR_FLASH 0x10 /* Flash RAM is in the ROM socket */
+
+/*
+ * The three bits of the encoded IRQ are decoded as follows:
+ *
+ * IR2 IR1 IR0 IRQ
+ * 0 0 0 2/9
+ * 0 0 1 3
+ * 0 1 0 5
+ * 0 1 1 7
+ * 1 0 0 10
+ * 1 0 1 11
+ * 1 1 0 15
+ * 1 1 1 4
+ */
+#define ED_WD_IRR_IR0 0x20 /* bit 0 of encoded IRQ */
+#define ED_WD_IRR_IR1 0x40 /* bit 1 of encoded IRQ */
+#define ED_WD_IRR_IEN 0x80 /* Interrupt enable */
+
+/*
+ * LA Address Register (LAAR)
+ */
+#define ED_WD_LAAR 5
+
+#define ED_WD_LAAR_ADDRHI 0x1f /* bits 23-19 of RAM address */
+#define ED_WD_LAAR_0WS16 0x20 /* enable 0 wait-states on 16 bit bus */
+#define ED_WD_LAAR_L16EN 0x40 /* enable 16-bit operation */
+#define ED_WD_LAAR_M16EN 0x80 /* enable 16-bit memory access */
+
+/* i/o base offset to station address/card-ID PROM */
+#define ED_WD_PROM 8
+
+/*
+ * 83C790 specific registers
+ */
+/*
+ * Hardware Support Register (HWR) ('790)
+ */
+#define ED_WD790_HWR 4
+
+#define WD_WD790_HWR_NUKE 0x10 /* hardware reset */
+#define ED_WD790_HWR_LPRM 0x40 /* LAN PROM select */
+#define ED_WD790_HWR_SWH 0x80 /* switch register set */
+
+/*
+ * ICR790 Interrupt Control Register for the 83C790
+ */
+#define ED_WD790_ICR 6
+
+#define ED_WD790_ICR_EIL 0x01 /* enable interrupts */
+
+/*
+ * General Control Register (GCR)
+ * Enabled with SWH bit=1 in HWR register
+ */
+#define ED_WD790_GCR 0x0d
+
+#define ED_WD790_GCR_IR0 0x04 /* bit 0 of encoded IRQ */
+#define ED_WD790_GCR_IR1 0x08 /* bit 1 of encoded IRQ */
+#define ED_WD790_GCR_ZWSEN 0x20 /* zero wait state enable */
+#define ED_WD790_GCR_IR2 0x40 /* bit 2 of encoded IRQ */
+/*
+ * The three bits of the encoded IRQ are decoded as follows:
+ *
+ * IR2 IR1 IR0 IRQ
+ * 0 0 0 none
+ * 0 0 1 9
+ * 0 1 0 3
+ * 0 1 1 5
+ * 1 0 0 7
+ * 1 0 1 10
+ * 1 1 0 11
+ * 1 1 1 15
+ */
+
+/* i/o base offset to CARD ID */
+#define ED_WD_CARD_ID ED_WD_PROM+6
+
+/* Board type codes in card ID */
+#define ED_TYPE_WD8003S 0x02
+#define ED_TYPE_WD8003E 0x03
+#define ED_TYPE_WD8013EBT 0x05
+#define ED_TYPE_TOSHIBA1 0x11 /* named PCETA1 */
+#define ED_TYPE_TOSHIBA2 0x12 /* named PCETA2 */
+#define ED_TYPE_TOSHIBA3 0x13 /* named PCETB */
+#define ED_TYPE_TOSHIBA4 0x14 /* named PCETC */
+#define ED_TYPE_WD8003W 0x24
+#define ED_TYPE_WD8003EB 0x25
+#define ED_TYPE_WD8013W 0x26
+#define ED_TYPE_WD8013EP 0x27
+#define ED_TYPE_WD8013WC 0x28
+#define ED_TYPE_WD8013EPC 0x29
+#define ED_TYPE_SMC8216T 0x2a
+#define ED_TYPE_SMC8216C 0x2b
+#define ED_TYPE_WD8013EBP 0x2c
+
+/* Bit definitions in card ID */
+#define ED_WD_REV_MASK 0x1f /* Revision mask */
+#define ED_WD_SOFTCONFIG 0x20 /* Soft config */
+#define ED_WD_LARGERAM 0x40 /* Large RAM */
+#define ED_MICROCHANEL 0x80 /* Microchannel bus (vs. isa) */
+
+/*
+ * Checksum total. All 8 bytes in station address PROM will add up to this
+ */
+#ifdef TOSH_ETHER
+#define ED_WD_ROM_CHECKSUM_TOTAL 0xA5
+#else
+#define ED_WD_ROM_CHECKSUM_TOTAL 0xFF
+#endif
+
+#define ED_WD_NIC_OFFSET 0x10 /* I/O base offset to NIC */
+#define ED_WD_ASIC_OFFSET 0 /* I/O base offset to ASIC */
+#define ED_WD_IO_PORTS 32 /* # of i/o addresses used */
+
+#define ED_WD_PAGE_OFFSET 0 /* page offset for NIC access to mem */
+
+/*
+ * Definitions for 3Com 3c503
+ */
+#define ED_3COM_NIC_OFFSET 0
+#define ED_3COM_ASIC_OFFSET 0x400 /* offset to nic i/o regs */
+
+/*
+ * XXX - The I/O address range is fragmented in the 3c503; this is the
+ * number of regs at iobase.
+ */
+#define ED_3COM_IO_PORTS 16 /* # of i/o addresses used */
+
+/* tx memory starts in second bank on 8bit cards */
+#define ED_3COM_TX_PAGE_OFFSET_8BIT 0x20
+
+/* tx memory starts in first bank on 16bit cards */
+#define ED_3COM_TX_PAGE_OFFSET_16BIT 0x0
+
+/* ...and rx memory starts in second bank */
+#define ED_3COM_RX_PAGE_OFFSET_16BIT 0x20
+
+
+/*
+ * Page Start Register. Must match PSTART in NIC
+ */
+#define ED_3COM_PSTR 0
+
+/*
+ * Page Stop Register. Must match PSTOP in NIC
+ */
+#define ED_3COM_PSPR 1
+
+/*
+ * Drq Timer Register. Determines number of bytes to be transfered during
+ * a DMA burst.
+ */
+#define ED_3COM_DQTR 2
+
+/*
+ * Base Configuration Register. Read-only register which contains the
+ * board-configured I/O base address of the adapter. Bit encoded.
+ */
+#define ED_3COM_BCFR 3
+
+#define ED_3COM_BCFR_2E0 0x01
+#define ED_3COM_BCFR_2A0 0x02
+#define ED_3COM_BCFR_280 0x04
+#define ED_3COM_BCFR_250 0x08
+#define ED_3COM_BCFR_350 0x10
+#define ED_3COM_BCFR_330 0x20
+#define ED_3COM_BCFR_310 0x40
+#define ED_3COM_BCFR_300 0x80
+
+/*
+ * EPROM Configuration Register. Read-only register which contains the
+ * board-configured memory base address. Bit encoded.
+ */
+#define ED_3COM_PCFR 4
+
+#define ED_3COM_PCFR_C8000 0x10
+#define ED_3COM_PCFR_CC000 0x20
+#define ED_3COM_PCFR_D8000 0x40
+#define ED_3COM_PCFR_DC000 0x80
+
+/*
+ * GA Configuration Register. Gate-Array Configuration Register.
+ */
+#define ED_3COM_GACFR 5
+
+/*
+ * mbs2 mbs1 mbs0 start address
+ * 0 0 0 0x0000
+ * 0 0 1 0x2000
+ * 0 1 0 0x4000
+ * 0 1 1 0x6000
+ *
+ * Note that with adapters with only 8K, the setting for 0x2000 must
+ * always be used.
+ */
+#define ED_3COM_GACFR_MBS0 0x01
+#define ED_3COM_GACFR_MBS1 0x02
+#define ED_3COM_GACFR_MBS2 0x04
+
+#define ED_3COM_GACFR_RSEL 0x08 /* enable shared memory */
+#define ED_3COM_GACFR_TEST 0x10 /* for GA testing */
+#define ED_3COM_GACFR_OWS 0x20 /* select 0WS access to GA */
+#define ED_3COM_GACFR_TCM 0x40 /* Mask DMA interrupts */
+#define ED_3COM_GACFR_NIM 0x80 /* Mask NIC interrupts */
+
+/*
+ * Control Register. Miscellaneous control functions.
+ */
+#define ED_3COM_CR 6
+
+#define ED_3COM_CR_RST 0x01 /* Reset GA and NIC */
+#define ED_3COM_CR_XSEL 0x02 /* Transceiver select. BNC=1(def) AUI=0 */
+#define ED_3COM_CR_EALO 0x04 /* window EA PROM 0-15 to I/O base */
+#define ED_3COM_CR_EAHI 0x08 /* window EA PROM 16-31 to I/O base */
+#define ED_3COM_CR_SHARE 0x10 /* select interrupt sharing option */
+#define ED_3COM_CR_DBSEL 0x20 /* Double buffer select */
+#define ED_3COM_CR_DDIR 0x40 /* DMA direction select */
+#define ED_3COM_CR_START 0x80 /* Start DMA controller */
+
+/*
+ * Status Register. Miscellaneous status information.
+ */
+#define ED_3COM_STREG 7
+
+#define ED_3COM_STREG_REV 0x07 /* GA revision */
+#define ED_3COM_STREG_DIP 0x08 /* DMA in progress */
+#define ED_3COM_STREG_DTC 0x10 /* DMA terminal count */
+#define ED_3COM_STREG_OFLW 0x20 /* Overflow */
+#define ED_3COM_STREG_UFLW 0x40 /* Underflow */
+#define ED_3COM_STREG_DPRDY 0x80 /* Data port ready */
+
+/*
+ * Interrupt/DMA Configuration Register
+ */
+#define ED_3COM_IDCFR 8
+
+#define ED_3COM_IDCFR_DRQ0 0x01 /* DMA request 1 select */
+#define ED_3COM_IDCFR_DRQ1 0x02 /* DMA request 2 select */
+#define ED_3COM_IDCFR_DRQ2 0x04 /* DMA request 3 select */
+#define ED_3COM_IDCFR_UNUSED 0x08 /* not used */
+#define ED_3COM_IDCFR_IRQ2 0x10 /* Interrupt request 2 select */
+#define ED_3COM_IDCFR_IRQ3 0x20 /* Interrupt request 3 select */
+#define ED_3COM_IDCFR_IRQ4 0x40 /* Interrupt request 4 select */
+#define ED_3COM_IDCFR_IRQ5 0x80 /* Interrupt request 5 select */
+
+/*
+ * DMA Address Register MSB
+ */
+#define ED_3COM_DAMSB 9
+
+/*
+ * DMA Address Register LSB
+ */
+#define ED_3COM_DALSB 0x0a
+
+/*
+ * Vector Pointer Register 2
+ */
+#define ED_3COM_VPTR2 0x0b
+
+/*
+ * Vector Pointer Register 1
+ */
+#define ED_3COM_VPTR1 0x0c
+
+/*
+ * Vector Pointer Register 0
+ */
+#define ED_3COM_VPTR0 0x0d
+
+/*
+ * Register File Access MSB
+ */
+#define ED_3COM_RFMSB 0x0e
+
+/*
+ * Register File Access LSB
+ */
+#define ED_3COM_RFLSB 0x0f
+
+/*
+ * Definitions for Novell NE1000/2000 boards
+ */
+
+/*
+ * Board type codes
+ */
+#define ED_TYPE_NE1000 0x01
+#define ED_TYPE_NE2000 0x02
+
+/*
+ * Register offsets/total
+ */
+#define ED_NOVELL_NIC_OFFSET 0x00
+#define ED_NOVELL_ASIC_OFFSET 0x10
+#define ED_NOVELL_IO_PORTS 32
+
+/*
+ * Remote DMA data register; for reading or writing to the NIC mem
+ * via programmed I/O (offset from ASIC base)
+ */
+#define ED_NOVELL_DATA 0x00
+
+/*
+ * Reset register; reading from this register causes a board reset
+ */
+#define ED_NOVELL_RESET 0x0f
diff --git a/sys/i386/isa/if_el.c b/sys/i386/isa/if_el.c
new file mode 100644
index 0000000..d0de274
--- /dev/null
+++ b/sys/i386/isa/if_el.c
@@ -0,0 +1,800 @@
+/* Copyright (c) 1994, Matthew E. Kimmel. Permission is hereby granted
+ * to use, copy, modify and distribute this software provided that both
+ * the copyright notice and this permission notice appear in all copies
+ * of the software, derivative works or modified versions, and any
+ * portions thereof.
+ *
+ * Questions, comments, bug reports and fixes to kimmel@cs.umass.edu.
+ */
+/* Except of course for the portions of code lifted from other FreeBSD
+ * drivers (mainly elread, elget and el_ioctl)
+ */
+/* 3COM Etherlink 3C501 device driver for FreeBSD */
+/* Yeah, I know these cards suck, but you can also get them for free
+ * really easily...
+ */
+/* Bugs/possible improvements:
+ * - Does not currently support DMA
+ * - Does not currently support multicasts
+ */
+#include "el.h"
+#if NEL > 0
+#include "bpfilter.h"
+
+#include "param.h"
+#include "systm.h"
+#include "errno.h"
+#include "ioctl.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "syslog.h"
+
+#include "net/if.h"
+#include "net/if_dl.h"
+#include "net/if_types.h"
+
+#ifdef INET
+#include "netinet/in.h"
+#include "netinet/in_systm.h"
+#include "netinet/in_var.h"
+#include "netinet/ip.h"
+#include "netinet/if_ether.h"
+#endif
+
+#ifdef NS
+#include "netns/ns.h"
+#include "netns/ns_if.h"
+#endif
+
+#if NBPFILTER > 0
+#include "net/bpf.h"
+#include "net/bpfdesc.h"
+#endif
+
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/if_elreg.h"
+
+#define ETHER_MIN_LEN 64
+#define ETHER_MAX_LEN 1518
+
+/* For debugging convenience */
+#ifdef EL_DEBUG
+#define dprintf(x) printf x
+#else
+#define dprintf(x)
+#endif
+
+/* el_softc: per line info and status */
+struct el_softc {
+ struct arpcom arpcom; /* Ethernet common */
+ u_short el_base; /* Base I/O addr */
+ caddr_t bpf; /* BPF magic cookie */
+ char el_pktbuf[EL_BUFSIZ]; /* Frame buffer */
+} el_softc[NEL];
+
+/* Prototypes */
+int el_attach(struct isa_device *);
+void el_init(int);
+void elintr(int);
+int el_ioctl(struct ifnet *,int,caddr_t);
+int el_probe(struct isa_device *);
+void el_start(struct ifnet *);
+void el_reset(int,int);
+void el_watchdog(int);
+
+static void el_stop(int);
+static int el_xmit(struct el_softc *,int);
+static inline void elread(struct el_softc *,caddr_t,int);
+static struct mbuf *elget(caddr_t,int,int,struct ifnet *);
+static inline void el_hardreset(int);
+
+/* isa_driver structure for autoconf */
+struct isa_driver eldriver = {
+ el_probe, el_attach, "el"
+};
+
+/* Probe routine. See if the card is there and at the right place. */
+int el_probe(struct isa_device *idev)
+{
+ struct el_softc *sc;
+ u_short base; /* Just for convenience */
+ u_char station_addr[ETHER_ADDR_LEN];
+ int i;
+
+ /* Grab some info for our structure */
+ sc = &el_softc[idev->id_unit];
+ sc->el_base = idev->id_iobase;
+ base = sc->el_base;
+
+ /* First check the base */
+ if((base < 0x280) || (base > 0x3f0)) {
+ printf("el%d: ioaddr must be between 0x280 and 0x3f0\n",
+ idev->id_unit);
+ return(0);
+ }
+
+ /* Now attempt to grab the station address from the PROM
+ * and see if it contains the 3com vendor code.
+ */
+ dprintf(("Probing 3c501 at 0x%x...\n",base));
+
+ /* Reset the board */
+ dprintf(("Resetting board...\n"));
+ outb(base+EL_AC,EL_AC_RESET);
+ DELAY(5);
+ outb(base+EL_AC,0);
+ dprintf(("Reading station address...\n"));
+ /* Now read the address */
+ for(i=0;i<ETHER_ADDR_LEN;i++) {
+ outb(base+EL_GPBL,i);
+ station_addr[i] = inb(base+EL_EAW);
+ }
+ dprintf(("Address is %s\n",ether_sprintf(station_addr)));
+
+ /* If the vendor code is ok, return a 1. We'll assume that
+ * whoever configured this system is right about the IRQ.
+ */
+ if((station_addr[0] != 0x02) || (station_addr[1] != 0x60)
+ || (station_addr[2] != 0x8c)) {
+ dprintf(("Bad vendor code.\n"));
+ return(0);
+ } else {
+ dprintf(("Vendor code ok.\n"));
+ /* Copy the station address into the arpcom structure */
+ bcopy(station_addr,sc->arpcom.ac_enaddr,ETHER_ADDR_LEN);
+ return(1);
+ }
+}
+
+/* Attach the interface to the kernel data structures. By the time
+ * this is called, we know that the card exists at the given I/O address.
+ * We still assume that the IRQ given is correct.
+ */
+int el_attach(struct isa_device *idev)
+{
+ struct el_softc *sc;
+ struct ifnet *ifp;
+ struct ifaddr *ifa;
+ struct sockaddr_dl *sdl;
+ u_short base;
+ int t;
+
+ dprintf(("Attaching el%d...\n",idev->id_unit));
+
+ /* Get things pointing to the right places. */
+ sc = &el_softc[idev->id_unit];
+ ifp = &sc->arpcom.ac_if;
+ base = sc->el_base;
+
+ /* Now reset the board */
+ dprintf(("Resetting board...\n"));
+ el_hardreset(idev->id_unit);
+
+ /* Initialize ifnet structure */
+ ifp->if_unit = idev->id_unit;
+ ifp->if_name = "el";
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_init = el_init;
+ ifp->if_output = ether_output;
+ ifp->if_start = el_start;
+ ifp->if_ioctl = el_ioctl;
+ ifp->if_reset = el_reset;
+ ifp->if_watchdog = el_watchdog;
+ ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS);
+
+ /* Now we can attach the interface */
+ dprintf(("Attaching interface...\n"));
+ if_attach(ifp);
+
+ /* Put the station address in the ifa address list's AF_LINK
+ * entry, if any.
+ */
+ ifa = ifp->if_addrlist;
+ while ((ifa != NULL) && (ifa->ifa_addr != NULL) &&
+ (ifa->ifa_addr->sa_family != AF_LINK))
+ ifa = ifa->ifa_next;
+ if((ifa != NULL) && (ifa->ifa_addr != NULL)) {
+ sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ sdl->sdl_type = IFT_ETHER;
+ sdl->sdl_alen = ETHER_ADDR_LEN;
+ sdl->sdl_slen = 0;
+ bcopy(sc->arpcom.ac_enaddr,LLADDR(sdl),ETHER_ADDR_LEN);
+ }
+
+ /* Print out some information for the user */
+ printf("el%d: 3c501 address %s\n",idev->id_unit,
+ ether_sprintf(sc->arpcom.ac_enaddr));
+
+ /* Finally, attach to bpf filter if it is present. */
+#if NBPFILTER > 0
+ dprintf(("Attaching to BPF...\n"));
+ bpfattach(&sc->bpf,ifp,DLT_EN10MB,sizeof(struct ether_header));
+#endif
+
+ dprintf(("el_attach() finished.\n"));
+ return(1);
+}
+
+/* This routine resets the interface. */
+void el_reset(int unit,int uban)
+{
+ int s;
+
+ dprintf(("elreset()\n"));
+ s = splimp();
+ el_stop(unit);
+ el_init(unit);
+ splx(s);
+}
+
+static void el_stop(int unit)
+{
+ struct el_softc *sc;
+
+ sc = &el_softc[unit];
+ outb(sc->el_base+EL_AC,0);
+}
+
+/* Do a hardware reset of the 3c501. Do not call until after el_probe()! */
+static inline void el_hardreset(int unit)
+{
+ register struct el_softc *sc;
+ register int base;
+ register int j;
+
+ sc = &el_softc[unit];
+ base = sc->el_base;
+
+ /* First reset the board */
+ outb(base+EL_AC,EL_AC_RESET);
+ DELAY(5);
+ outb(base+EL_AC,0);
+
+ /* Then give it back its ethernet address. Thanks to the mach
+ * source code for this undocumented goodie...
+ */
+ for(j=0;j<ETHER_ADDR_LEN;j++)
+ outb(base+j,sc->arpcom.ac_enaddr[j]);
+}
+
+/* Initialize interface. */
+void el_init(int unit)
+{
+ struct el_softc *sc;
+ struct ifnet *ifp;
+ int s;
+ u_short base;
+
+ /* Set up pointers */
+ sc = &el_softc[unit];
+ ifp = &sc->arpcom.ac_if;
+ base = sc->el_base;
+
+ /* If address not known, do nothing. */
+ if(ifp->if_addrlist == (struct ifaddr *)0)
+ return;
+
+ s = splimp();
+
+ /* First, reset the board. */
+ dprintf(("Resetting board...\n"));
+ el_hardreset(unit);
+
+ /* Configure rx */
+ dprintf(("Configuring rx...\n"));
+ if(ifp->if_flags & IFF_PROMISC)
+ outb(base+EL_RXC,(EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
+ else
+ outb(base+EL_RXC,(EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
+ outb(base+EL_RBC,0);
+
+ /* Configure TX */
+ dprintf(("Configuring tx...\n"));
+ outb(base+EL_TXC,0);
+
+ /* Start reception */
+ dprintf(("Starting reception...\n"));
+ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
+
+ /* Set flags appropriately */
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ /* And start output. */
+ el_start(ifp);
+
+ splx(s);
+}
+
+/* Start output on interface. Get datagrams from the queue and output
+ * them, giving the receiver a chance between datagrams. Call only
+ * from splimp or interrupt level!
+ */
+void el_start(struct ifnet *ifp)
+{
+ struct el_softc *sc;
+ u_short base;
+ struct mbuf *m, *m0;
+ int s, i, len, retries, done;
+
+ /* Get things pointing in the right directions */
+ sc = &el_softc[ifp->if_unit];
+ base = sc->el_base;
+
+ dprintf(("el_start()...\n"));
+ s = splimp();
+
+ /* Don't do anything if output is active */
+ if(sc->arpcom.ac_if.if_flags & IFF_OACTIVE)
+ return;
+ sc->arpcom.ac_if.if_flags |= IFF_OACTIVE;
+
+ /* The main loop. They warned me against endless loops, but
+ * would I listen? NOOO....
+ */
+ while(1) {
+ /* Dequeue the next datagram */
+ IF_DEQUEUE(&sc->arpcom.ac_if.if_snd,m0);
+
+ /* If there's nothing to send, return. */
+ if(m0 == NULL) {
+ sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+ splx(s);
+ return;
+ }
+
+ /* Disable the receiver */
+ outb(base+EL_AC,EL_AC_HOST);
+ outb(base+EL_RBC,0);
+
+ /* Copy the datagram to the buffer. */
+ len = 0;
+ for(m = m0; m != NULL; m = m->m_next) {
+ if(m->m_len == 0)
+ continue;
+ bcopy(mtod(m,caddr_t),sc->el_pktbuf+len,m->m_len);
+ len += m->m_len;
+ }
+ m_freem(m0);
+
+ len = MAX(len,ETHER_MIN_LEN);
+
+ /* Give the packet to the bpf, if any */
+#if NBPFILTER > 0
+ if(sc->bpf)
+ bpf_tap(sc->bpf,sc->el_pktbuf,len);
+#endif
+
+ /* Transfer datagram to board */
+ dprintf(("el: xfr pkt length=%d...\n",len));
+ i = EL_BUFSIZ - len;
+ outb(base+EL_GPBL,(i & 0xff));
+ outb(base+EL_GPBH,((i>>8)&0xff));
+ outsb(base+EL_BUF,sc->el_pktbuf,len);
+
+ /* Now transmit the datagram */
+ retries=0;
+ done=0;
+ while(!done) {
+ if(el_xmit(sc,len)) { /* Something went wrong */
+ done = -1;
+ break;
+ }
+ /* Check out status */
+ i = inb(base+EL_TXS);
+ dprintf(("tx status=0x%x\n",i));
+ if(!(i & EL_TXS_READY)) {
+ dprintf(("el: err txs=%x\n",i));
+ sc->arpcom.ac_if.if_oerrors++;
+ if(i & (EL_TXS_COLL|EL_TXS_COLL16)) {
+ if((!(i & EL_TXC_DCOLL16)) && retries < 15) {
+ retries++;
+ outb(base+EL_AC,EL_AC_HOST);
+ }
+ }
+ else
+ done = 1;
+ }
+ else {
+ sc->arpcom.ac_if.if_opackets++;
+ done = 1;
+ }
+ }
+ if(done == -1) /* Packet not transmitted */
+ continue;
+
+ /* Now give the card a chance to receive.
+ * Gotta love 3c501s...
+ */
+ (void)inb(base+EL_AS);
+ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
+ splx(s);
+ /* Interrupt here */
+ s = splimp();
+ }
+}
+
+/* This function actually attempts to transmit a datagram downloaded
+ * to the board. Call at splimp or interrupt, after downloading data!
+ * Returns 0 on success, non-0 on failure
+ */
+static int el_xmit(struct el_softc *sc,int len)
+{
+ int gpl;
+ int i;
+
+ gpl = EL_BUFSIZ - len;
+ dprintf(("el: xmit..."));
+ outb((sc->el_base)+EL_GPBL,(gpl & 0xff));
+ outb((sc->el_base)+EL_GPBH,((gpl>>8)&0xff));
+ outb((sc->el_base)+EL_AC,EL_AC_TXFRX);
+ i = 20000;
+ while((inb((sc->el_base)+EL_AS) & EL_AS_TXBUSY) && (i>0))
+ i--;
+ if(i == 0) {
+ dprintf(("tx not ready\n"));
+ sc->arpcom.ac_if.if_oerrors++;
+ return(-1);
+ }
+ dprintf(("%d cycles.\n",(20000-i)));
+ return(0);
+}
+
+/* controller interrupt */
+void elintr(int unit)
+{
+ register struct el_softc *sc;
+ register base;
+ int stat, rxstat, len, done;
+
+ /* Get things pointing properly */
+ sc = &el_softc[unit];
+ base = sc->el_base;
+
+ dprintf(("elintr: "));
+
+ /* Check board status */
+ stat = inb(base+EL_AS);
+ if(stat & EL_AS_RXBUSY) {
+ (void)inb(base+EL_RXC);
+ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
+ return;
+ }
+
+ done = 0;
+ while(!done) {
+ rxstat = inb(base+EL_RXS);
+ if(rxstat & EL_RXS_STALE) {
+ (void)inb(base+EL_RXC);
+ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
+ return;
+ }
+
+ /* If there's an overflow, reinit the board. */
+ if(!(rxstat & EL_RXS_NOFLOW)) {
+ dprintf(("overflow.\n"));
+ el_hardreset(unit);
+ /* Put board back into receive mode */
+ if(sc->arpcom.ac_if.if_flags & IFF_PROMISC)
+ outb(base+EL_RXC,(EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
+ else
+ outb(base+EL_RXC,(EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
+ (void)inb(base+EL_AS);
+ outb(base+EL_RBC,0);
+ (void)inb(base+EL_RXC);
+ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
+ return;
+ }
+
+ /* Incoming packet */
+ len = inb(base+EL_RBL);
+ len |= inb(base+EL_RBH) << 8;
+ dprintf(("receive len=%d rxstat=%x ",len,rxstat));
+ outb(base+EL_AC,EL_AC_HOST);
+
+ /* If packet too short or too long, restore rx mode and return
+ */
+ if((len <= sizeof(struct ether_header)) || (len > ETHER_MAX_LEN)) {
+ if(sc->arpcom.ac_if.if_flags & IFF_PROMISC)
+ outb(base+EL_RXC,(EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
+ else
+ outb(base+EL_RXC,(EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
+ (void)inb(base+EL_AS);
+ outb(base+EL_RBC,0);
+ (void)inb(base+EL_RXC);
+ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
+ return;
+ }
+
+ sc->arpcom.ac_if.if_ipackets++;
+
+ /* Copy the data into our buffer */
+ outb(base+EL_GPBL,0);
+ outb(base+EL_GPBH,0);
+ insb(base+EL_BUF,sc->el_pktbuf,len);
+ outb(base+EL_RBC,0);
+ outb(base+EL_AC,EL_AC_RX);
+ dprintf(("%s-->",ether_sprintf(sc->el_pktbuf+6)));
+ dprintf(("%s\n",ether_sprintf(sc->el_pktbuf)));
+
+ /* Pass data up to upper levels */
+ len -= sizeof(struct ether_header);
+ elread(sc,(caddr_t)(sc->el_pktbuf),len);
+
+ /* Is there another packet? */
+ stat = inb(base+EL_AS);
+
+ /* If so, do it all again (i.e. don't set done to 1) */
+ if(!(stat & EL_AS_RXBUSY))
+ dprintf(("<rescan> "));
+ else
+ done = 1;
+ }
+
+ (void)inb(base+EL_RXC);
+ outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));
+ return;
+}
+
+/* Pass a packet up to the higher levels. Deal with trailer protocol. */
+static inline void elread(struct el_softc *sc,caddr_t buf,int len)
+{
+ register struct ether_header *eh;
+ struct mbuf *m;
+ int off, resid;
+
+ /* Deal with trailer protocol: if type is trailer type
+ * get true type from first 16-bit word past data.
+ * Remember that type was trailer by setting off.
+ */
+ eh = (struct ether_header *)buf;
+ eh->ether_type = ntohs((u_short)eh->ether_type);
+#define eldataaddr(eh,off,type) ((type)(((caddr_t)((eh)+1)+(off))))
+ if(eh->ether_type >= ETHERTYPE_TRAIL &&
+ eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+ off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
+ if(off >= ETHERMTU)
+ return;
+ eh->ether_type = ntohs(*eldataaddr(eh,off,u_short *));
+ resid = ntohs(*(eldataaddr(eh,off+2,u_short *)));
+ if((off+resid) > len)
+ return;
+ len = off + resid;
+ }
+ else
+ off = 0;
+
+ if(len <= 0)
+ return;
+
+#if NBPFILTER > 0
+ /*
+ * Check if there's a bpf filter listening on this interface.
+ * If so, hand off the raw packet to bpf, which must deal with
+ * trailers in its own way.
+ */
+ if(sc->bpf) {
+ eh->ether_type = htons((u_short)eh->ether_type);
+ bpf_tap(sc->bpf,buf,len+sizeof(struct ether_header));
+ eh->ether_type = ntohs((u_short)eh->ether_type);
+
+ /*
+ * Note that the interface cannot be in promiscuous mode if
+ * there are no bpf listeners. And if el are in promiscuous
+ * mode, el have to check if this packet is really ours.
+ *
+ * This test does not support multicasts.
+ */
+ if((sc->arpcom.ac_if.if_flags & IFF_PROMISC)
+ && bcmp(eh->ether_dhost,sc->arpcom.ac_enaddr,
+ sizeof(eh->ether_dhost)) != 0
+ && bcmp(eh->ether_dhost,etherbroadcastaddr,
+ sizeof(eh->ether_dhost)) != 0)
+ return;
+ }
+#endif
+
+ /*
+ * Pull packet off interface. Off is nonzero if packet
+ * has trailing header; neget will then force this header
+ * information to be at the front, but we still have to drop
+ * the type and length which are at the front of any trailer data.
+ */
+ m = elget(buf,len,off,&sc->arpcom.ac_if);
+ if(m == 0)
+ return;
+
+ ether_input(&sc->arpcom.ac_if,eh,m);
+}
+
+/*
+ * Pull read data off a interface.
+ * Len is length of data, with local net header stripped.
+ * Off is non-zero if a trailer protocol was used, and
+ * gives the offset of the trailer information.
+ * We copy the trailer information and then all the normal
+ * data into mbufs. When full cluster sized units are present
+ * we copy into clusters.
+ */
+struct mbuf *
+elget(buf, totlen, off0, ifp)
+ caddr_t buf;
+ int totlen, off0;
+ struct ifnet *ifp;
+{
+ struct mbuf *top, **mp, *m, *p;
+ int off = off0, len;
+ register caddr_t cp = buf;
+ char *epkt;
+
+ buf += sizeof(struct ether_header);
+ cp = buf;
+ epkt = cp + totlen;
+
+
+ if (off) {
+ cp += off + 2 * sizeof(u_short);
+ totlen -= 2 * sizeof(u_short);
+ }
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ return (0);
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = totlen;
+ m->m_len = MHLEN;
+ top = 0;
+ mp = &top;
+ while (totlen > 0) {
+ if (top) {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == 0) {
+ m_freem(top);
+ return (0);
+ }
+ m->m_len = MLEN;
+ }
+ len = min(totlen, epkt - cp);
+ if (len >= MINCLSIZE) {
+ MCLGET(m, M_DONTWAIT);
+ if (m->m_flags & M_EXT)
+ m->m_len = len = min(len, MCLBYTES);
+ else
+ len = m->m_len;
+ } else {
+ /*
+ * Place initial small packet/header at end of mbuf.
+ */
+ if (len < m->m_len) {
+ if (top == 0 && len + max_linkhdr <= m->m_len)
+ m->m_data += max_linkhdr;
+ m->m_len = len;
+ } else
+ len = m->m_len;
+ }
+ bcopy(cp, mtod(m, caddr_t), (unsigned)len);
+ cp += len;
+ *mp = m;
+ mp = &m->m_next;
+ totlen -= len;
+ if (cp == epkt)
+ cp = buf;
+ }
+ return (top);
+}
+
+/*
+ * Process an ioctl request. This code needs some work - it looks
+ * pretty ugly.
+ */
+int
+el_ioctl(ifp, command, data)
+ register struct ifnet *ifp;
+ int command;
+ caddr_t data;
+{
+ register struct ifaddr *ifa = (struct ifaddr *)data;
+ struct el_softc *sc = &el_softc[ifp->if_unit];
+ struct ifreq *ifr = (struct ifreq *)data;
+ int s, error = 0;
+
+ s = splimp();
+
+ switch (command) {
+
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ el_init(ifp->if_unit); /* before arpwhohas */
+ /*
+ * See if another station has *our* IP address.
+ * i.e.: There is an address conflict! If a
+ * conflict exists, a message is sent to the
+ * console.
+ */
+ ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
+ arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
+ break;
+#endif
+#ifdef NS
+ /*
+ * XXX - This code is probably wrong
+ */
+ case AF_NS:
+ {
+ register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+
+ if (ns_nullhost(*ina))
+ ina->x_host =
+ *(union ns_host *)(sc->arpcom.ac_enaddr);
+ else {
+ /*
+ *
+ */
+ bcopy((caddr_t)ina->x_host.c_host,
+ (caddr_t)sc->arpcom.ac_enaddr,
+ sizeof(sc->arpcom.ac_enaddr));
+ }
+ /*
+ * Set new address
+ */
+ el_init(ifp->if_unit);
+ break;
+ }
+#endif
+ default:
+ el_init(ifp->if_unit);
+ break;
+ }
+ break;
+
+ case SIOCGIFADDR:
+ {
+ struct sockaddr *sa;
+ sa = (struct sockaddr *)&ifr->ifr_data;
+ bcopy((caddr_t)sc->arpcom.ac_enaddr,
+ (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
+ }
+ break;
+
+ case SIOCSIFFLAGS:
+ /*
+ * If interface is marked down and it is running, then stop it
+ */
+ if (((ifp->if_flags & IFF_UP) == 0) &&
+ (ifp->if_flags & IFF_RUNNING)) {
+ el_stop(ifp->if_unit);
+ ifp->if_flags &= ~IFF_RUNNING;
+ } else {
+ /*
+ * If interface is marked up and it is stopped, then start it
+ */
+ if ((ifp->if_flags & IFF_UP) &&
+ ((ifp->if_flags & IFF_RUNNING) == 0))
+ el_init(ifp->if_unit);
+ }
+
+ default:
+ error = EINVAL;
+ }
+ (void) splx(s);
+ return (error);
+}
+
+/* Device timeout routine */
+void el_watchdog(int unit)
+{
+ struct el_softc *sc;
+
+ sc = &el_softc[unit];
+
+ log(LOG_ERR,"el%d: device timeout\n",unit);
+ sc->arpcom.ac_if.if_oerrors++;
+ el_reset(unit,0);
+}
+#endif
diff --git a/sys/i386/isa/if_elreg.h b/sys/i386/isa/if_elreg.h
new file mode 100644
index 0000000..806d6ff
--- /dev/null
+++ b/sys/i386/isa/if_elreg.h
@@ -0,0 +1,76 @@
+/* Copyright (c) 1994, Matthew E. Kimmel. Permission is hereby granted
+ * to use, copy, modify and distribute this software provided that both
+ * the copyright notice and this permission notice appear in all copies
+ * of the software, derivative works or modified versions, and any
+ * portions thereof.
+ */
+/* 3COM Etherlink 3C501 Register Definitions */
+
+/* I/O Ports */
+#define EL_RXS 0x6 /* Receive status register */
+#define EL_RXC 0x6 /* Receive command register */
+#define EL_TXS 0x7 /* Transmit status register */
+#define EL_TXC 0x7 /* Transmit command register */
+#define EL_GPBL 0x8 /* GP buffer ptr low byte */
+#define EL_GPBH 0x9 /* GP buffer ptr high byte */
+#define EL_RBL 0xa /* Receive buffer ptr low byte */
+#define EL_RBC 0xa /* Receive buffer clear */
+#define EL_RBH 0xb /* Receive buffer ptr high byte */
+#define EL_EAW 0xc /* Ethernet address window */
+#define EL_AS 0xe /* Auxillary status register */
+#define EL_AC 0xe /* Auxillary command register */
+#define EL_BUF 0xf /* Data buffer */
+
+/* Receive status register bits */
+#define EL_RXS_OFLOW 0x01 /* Overflow error */
+#define EL_RXS_FCS 0x02 /* FCS error */
+#define EL_RXS_DRIB 0x04 /* Dribble error */
+#define EL_RXS_SHORT 0x08 /* Short frame */
+#define EL_RXS_NOFLOW 0x10 /* No overflow */
+#define EL_RXS_GOOD 0x20 /* Received good frame */
+#define EL_RXS_STALE 0x80 /* Stale receive status */
+
+/* Receive command register bits */
+#define EL_RXC_DISABLE 0x00 /* Receiver disabled */
+#define EL_RXC_DOFLOW 0x01 /* Detect overflow */
+#define EL_RXC_DFCS 0x02 /* Detect FCS errs */
+#define EL_RXC_DDRIB 0x04 /* Detect dribble errors */
+#define EL_RXC_DSHORT 0x08 /* Detect short frames */
+#define EL_RXC_DNOFLOW 0x10 /* Detect frames w/o overflow ??? */
+#define EL_RXC_AGF 0x20 /* Accept Good Frames */
+#define EL_RXC_PROMISC 0x40 /* Promiscuous mode */
+#define EL_RXC_ABROAD 0x80 /* Accept address, broadcast */
+#define EL_RXC_AMULTI 0xc0 /* Accept address, multicast */
+
+/* Transmit status register bits */
+#define EL_TXS_UFLOW 0x01 /* Underflow */
+#define EL_TXS_COLL 0x02 /* Collision */
+#define EL_TXS_COLL16 0x04 /* Collision 16 */
+#define EL_TXS_READY 0x08 /* Ready for new frame */
+
+/* Transmit command register bits */
+#define EL_TXC_DUFLOW 0x01 /* Detect underflow */
+#define EL_TXC_DCOLL 0x02 /* Detect collisions */
+#define EL_TXC_DCOLL16 0x04 /* Detect collision 16 */
+#define EL_TXC_DSUCCESS 0x08 /* Detect success */
+
+/* Auxillary status register bits */
+#define EL_AS_RXBUSY 0x01 /* Receive busy */
+#define EL_AS_DMADONE 0x10 /* DMA finished */
+#define EL_AS_TXBUSY 0x80 /* Transmit busy */
+
+/* Auxillary command register bits */
+#define EL_AC_HOST 0x00 /* System bus can access buffer */
+#define EL_AC_IRQE 0x01 /* IRQ enable */
+#define EL_AC_TXBAD 0x02 /* Transmit frames with bad FCS */
+#define EL_AC_TXFRX 0x04 /* Transmit followed by receive */
+#define EL_AC_RX 0x08 /* Receive */
+#define EL_AC_LB 0x0c /* Loopback */
+#define EL_AC_DRQ 0x20 /* DMA request */
+#define EL_AC_RIDE 0x40 /* DRQ and IRQ enabled */
+#define EL_AC_RESET 0x80 /* Reset */
+
+/* Packet buffer size */
+#define EL_BUFSIZ 2048
+
+#define ETHER_ADDR_LEN 6
diff --git a/sys/i386/isa/if_ep.c b/sys/i386/isa/if_ep.c
new file mode 100644
index 0000000..e8d3112
--- /dev/null
+++ b/sys/i386/isa/if_ep.c
@@ -0,0 +1,994 @@
+/*
+ * Copyright (c) 1993 Herb Peyerl <hpeyerl@novatel.ca>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * From: if_ep.c,v 1.9 1994/01/25 10:46:29 deraadt Exp $
+ * $Id: if_ep.c,v 1.8 1994/03/15 01:58:22 wollman Exp $
+ */
+
+#include "ep.h"
+#if NEP > 0
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#if defined(__FreeBSD__)
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#endif
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+#if defined(__NetBSD__)
+#include <sys/select.h>
+#endif
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#endif
+
+#ifdef NS
+#include <netns/ns.h>
+#include <netns/ns_if.h>
+#endif
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+#include <machine/pio.h>
+
+#include <i386/isa/isa.h>
+#include <i386/isa/isa_device.h>
+#include <i386/isa/icu.h>
+#include <i386/isa/if_epreg.h>
+
+#define ETHER_MIN_LEN 64
+#define ETHER_MAX_LEN 1518
+#define ETHER_ADDR_LEN 6
+
+/*
+ * Ethernet software status per interface.
+ */
+struct ep_softc {
+ struct arpcom arpcom; /* Ethernet common part */
+ short ep_io_addr; /* i/o bus address */
+ char ep_connectors; /* Connectors on this card. */
+#define MAX_MBS 8 /* # of mbufs we keep around */
+ struct mbuf *mb[MAX_MBS]; /* spare mbuf storage. */
+ int next_mb; /* Which mbuf to use next. */
+ int last_mb; /* Last mbuf. */
+ int tx_start_thresh; /* Current TX_start_thresh. */
+ caddr_t bpf; /* BPF "magic cookie" */
+ char bus32bit; /* 32bit access possible */
+} ep_softc[NEP];
+
+static int epprobe __P((struct isa_device *));
+static int epattach __P((struct isa_device *));
+static int epioctl __P((struct ifnet * ifp, int, caddr_t));
+
+void epinit __P((int));
+void epintr __P((int));
+void epmbuffill __P((caddr_t, int));
+void epmbufempty __P((struct ep_softc *));
+void epread __P((struct ep_softc *));
+void epreset __P((int));
+void epstart __P((struct ifnet *));
+void epstop __P((int));
+void epwatchdog __P((int));
+
+struct isa_driver epdriver = {
+ epprobe,
+ epattach,
+ "ep"
+};
+
+static int send_ID_sequence __P((u_short));
+static u_short get_eeprom_data __P((int, int));
+static int is_eeprom_busy __P((struct isa_device *));
+
+/*
+ * Rudimentary support for multiple cards is here but is not
+ * currently handled. In the future we will have to add code
+ * for tagging the cards for later activation. We wanna do something
+ * about the id_port. We're limited due to current config procedure.
+ * Magnum config holds promise of a fix but we'll have to wait a bit.
+ */
+int
+epprobe(is)
+ struct isa_device *is;
+{
+ struct ep_softc *sc = &ep_softc[is->id_unit];
+ u_short k;
+ int id_port = 0x100; /* XXX */
+
+ outw(BASE + EP_COMMAND, GLOBAL_RESET);
+ DELAY(1000);
+ outb(id_port, 0xc0); /* Global reset to id_port. */
+ DELAY(1000);
+ send_ID_sequence(id_port);
+ DELAY(1000);
+
+ /*
+ * MFG_ID should have 0x6d50.
+ * PROD_ID should be 0x9[0-f]50
+ */
+ k = get_eeprom_data(id_port, EEPROM_MFG_ID);
+ if (k != MFG_ID)
+ return (0);
+ k = get_eeprom_data(id_port, EEPROM_PROD_ID);
+ if ((k & 0xf0ff) != (PROD_ID & 0xf0ff))
+ return (0);
+
+ k = get_eeprom_data(id_port, EEPROM_ADDR_CFG); /* get addr cfg */
+ k = (k & 0x1f) * 0x10 + 0x200; /* decode base addr. */
+ if (k != (u_short)is->id_iobase)
+ return (0);
+
+ k = get_eeprom_data(id_port, EEPROM_RESOURCE_CFG);
+ k >>= 12;
+ if (is->id_irq != (1 << ((k == 2) ? 9 : k)))
+ return (0);
+
+ outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG);
+
+ return (0x10); /* 16 bytes of I/O space used. */
+}
+
+static int
+epattach(is)
+ struct isa_device *is;
+{
+ struct ep_softc *sc = &ep_softc[is->id_unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ u_short i;
+ struct ifaddr *ifa;
+ struct sockaddr_dl *sdl;
+
+ sc->ep_io_addr = is->id_iobase;
+
+ printf("ep%d: ", is->id_unit);
+
+ sc->ep_connectors = 0;
+ i = inw(is->id_iobase + EP_W0_CONFIG_CTRL);
+ if (i & IS_AUI) {
+ printf("aui");
+ sc->ep_connectors |= AUI;
+ }
+ if (i & IS_BNC) {
+ if (sc->ep_connectors)
+ printf("/");
+ printf("bnc");
+ sc->ep_connectors |= BNC;
+ }
+ if (i & IS_UTP) {
+ if (sc->ep_connectors)
+ printf("/");
+ printf("utp");
+ sc->ep_connectors |= UTP;
+ }
+ if (!sc->ep_connectors)
+ printf("no connectors!");
+
+ /*
+ * Read the station address from the eeprom
+ */
+ for (i = 0; i < 3; i++) {
+ u_short *p;
+ GO_WINDOW(0);
+ if (is_eeprom_busy(is))
+ return(0);
+ outw(BASE + EP_W0_EEPROM_COMMAND, READ_EEPROM | i);
+ if (is_eeprom_busy(is))
+ return(0);
+ p =(u_short *)&sc->arpcom.ac_enaddr[i*2];
+ *p = htons(inw(BASE + EP_W0_EEPROM_DATA));
+ GO_WINDOW(2);
+ outw(BASE + EP_W2_ADDR_0 + (i * 2), ntohs(*p));
+ }
+ printf(" address %s\n", ether_sprintf(sc->arpcom.ac_enaddr));
+
+ ifp->if_unit = is->id_unit;
+ ifp->if_name = "ep";
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
+ ifp->if_init = epinit;
+ ifp->if_output = ether_output;
+ ifp->if_start = epstart;
+ ifp->if_ioctl = epioctl;
+ ifp->if_watchdog = epwatchdog;
+
+ if_attach(ifp);
+
+ /*
+ * Fill the hardware address into ifa_addr if we find an
+ * AF_LINK entry. We need to do this so bpf's can get the hardware
+ * addr of this card. netstat likes this too!
+ */
+ ifa = ifp->if_addrlist;
+ while ((ifa != 0) && (ifa->ifa_addr != 0) &&
+ (ifa->ifa_addr->sa_family != AF_LINK))
+ ifa = ifa->ifa_next;
+
+ if ((ifa != 0) && (ifa->ifa_addr != 0)) {
+ sdl = (struct sockaddr_dl *) ifa->ifa_addr;
+ sdl->sdl_type = IFT_ETHER;
+ sdl->sdl_alen = ETHER_ADDR_LEN;
+ sdl->sdl_slen = 0;
+ bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN);
+ }
+#if NBPFILTER > 0
+ bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+ return 1;
+}
+
+
+/*
+ * The order in here seems important. Otherwise we may not receive
+ * interrupts. ?!
+ */
+void
+epinit(unit)
+ int unit;
+{
+ register struct ep_softc *sc = &ep_softc[unit];
+ register struct ifnet *ifp = &sc->arpcom.ac_if;
+ int s, i;
+
+ if (ifp->if_addrlist == (struct ifaddr *) 0)
+ return;
+
+ s = splimp();
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+ ;
+
+ GO_WINDOW(0);
+
+ /* Disable the card */
+ outw(BASE + EP_W0_CONFIG_CTRL, 0);
+
+ /* Enable the card */
+ outw(BASE + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ);
+
+ GO_WINDOW(2);
+
+ /* Reload the ether_addr. */
+ for (i = 0; i < 6; i++)
+ outb(BASE + EP_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]);
+
+ outw(BASE + EP_COMMAND, RX_RESET);
+ outw(BASE + EP_COMMAND, TX_RESET);
+
+ /* Window 1 is operating window */
+ GO_WINDOW(1);
+ for (i = 0; i < 31; i++)
+ inb(BASE + EP_W1_TX_STATUS);
+
+ /* get rid of stray intr's */
+ outw(BASE + EP_COMMAND, ACK_INTR | 0xff);
+
+ outw(BASE + EP_COMMAND, SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
+ S_TX_COMPLETE | S_TX_AVAIL);
+ outw(BASE + EP_COMMAND, SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE |
+ S_TX_COMPLETE | S_TX_AVAIL);
+
+ outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
+ FIL_GROUP | FIL_BRDCST);
+
+ /*
+ * you can `ifconfig (link0|-link0) ep0' to get the following
+ * behaviour:
+ * -link0 disable AUI/UTP. enable BNC.
+ * link0 disable BNC. enable AUI. if the card has a UTP
+ * connector, that is enabled too. not sure, but it
+ * seems you have to be careful to not plug things
+ * into both AUI & UTP.
+ */
+#if defined(__NetBSD__)
+ if (!(ifp->if_flags & IFF_LINK0) && (sc->ep_connectors & BNC)) {
+#else
+ if (!(ifp->if_flags & IFF_ALTPHYS) && (sc->ep_connectors & BNC)) {
+#endif
+ outw(BASE + EP_COMMAND, START_TRANSCEIVER);
+ DELAY(1000);
+ }
+#if defined(__NetBSD__)
+ if ((ifp->if_flags & IFF_LINK0) && (sc->ep_connectors & UTP)) {
+#else
+ if ((ifp->if_flags & IFF_ALTPHYS) && (sc->ep_connectors & UTP)) {
+#endif
+ GO_WINDOW(4);
+ outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP);
+ GO_WINDOW(1);
+ }
+
+ outw(BASE + EP_COMMAND, RX_ENABLE);
+ outw(BASE + EP_COMMAND, TX_ENABLE);
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE; /* just in case */
+ sc->tx_start_thresh = 20; /* probably a good starting point. */
+ /*
+ * Store up a bunch of mbuf's for use later. (MAX_MBS). First we
+ * free up any that we had in case we're being called from intr or
+ * somewhere else.
+ */
+ sc->last_mb = 0;
+ sc->next_mb = 0;
+ epmbuffill((caddr_t)sc, 0);
+
+ epstart(ifp);
+
+ splx(s);
+}
+
+static const char padmap[] = {0, 3, 2, 1};
+
+void
+epstart(ifp)
+ struct ifnet *ifp;
+{
+ register struct ep_softc *sc = &ep_softc[ifp->if_unit];
+ struct mbuf *m, *top;
+ int s, len, pad;
+
+ s = splimp();
+ if (sc->arpcom.ac_if.if_flags & IFF_OACTIVE) {
+ splx(s);
+ return;
+ }
+
+startagain:
+ /* Sneak a peek at the next packet */
+ m = sc->arpcom.ac_if.if_snd.ifq_head;
+ if (m == 0) {
+ splx(s);
+ return;
+ }
+#if 0
+ len = m->m_pkthdr.len;
+#else
+ for (len = 0, top = m; m; m = m->m_next)
+ len += m->m_len;
+#endif
+
+ pad = padmap[len & 3];
+
+ /*
+ * The 3c509 automatically pads short packets to minimum ethernet
+ * length, but we drop packets that are too large. Perhaps we should
+ * truncate them instead?
+ */
+ if (len + pad > ETHER_MAX_LEN) {
+ /* packet is obviously too large: toss it */
+ ++sc->arpcom.ac_if.if_oerrors;
+ IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
+ m_freem(m);
+ goto readcheck;
+ }
+
+ if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) {
+ /* no room in FIFO */
+ outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | (len + pad + 4));
+ sc->arpcom.ac_if.if_flags |= IFF_OACTIVE;
+ splx(s);
+ return;
+ }
+ IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
+ if (m == 0) { /* not really needed */
+ splx(s);
+ return;
+ }
+ outw(BASE + EP_COMMAND, SET_TX_START_THRESH |
+ (len / 4 + sc->tx_start_thresh));
+
+ outw(BASE + EP_W1_TX_PIO_WR_1, len);
+ outw(BASE + EP_W1_TX_PIO_WR_1, 0xffff); /* Second dword meaningless */
+
+ for (top = m; m != 0; m = m->m_next) {
+ if (sc->bus32bit) {
+ outsl(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t),
+ m->m_len/4);
+ if (m->m_len & 3)
+ outsb(BASE + EP_W1_TX_PIO_WR_1,
+ mtod(m, caddr_t) + m->m_len/4,
+ m->m_len & 3);
+ } else {
+ outsw(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len/2);
+ if (m->m_len & 1)
+ outb(BASE + EP_W1_TX_PIO_WR_1,
+ *(mtod(m, caddr_t) + m->m_len - 1));
+ }
+ }
+ while (pad--)
+ outb(BASE + EP_W1_TX_PIO_WR_1, 0); /* Padding */
+
+#if NBPFILTER > 0
+ if (sc->bpf) {
+ u_short etype;
+ int off, datasize, resid;
+ struct ether_header *eh;
+ struct trailer_header {
+ u_short ether_type;
+ u_short ether_residual;
+ } trailer_header;
+ char ether_packet[ETHER_MAX_LEN];
+ char *ep;
+
+ ep = ether_packet;
+
+ /*
+ * We handle trailers below:
+ * Copy ether header first, then residual data,
+ * then data. Put all this in a temporary buffer
+ * 'ether_packet' and send off to bpf. Since the
+ * system has generated this packet, we assume
+ * that all of the offsets in the packet are
+ * correct; if they're not, the system will almost
+ * certainly crash in m_copydata.
+ * We make no assumptions about how the data is
+ * arranged in the mbuf chain (i.e. how much
+ * data is in each mbuf, if mbuf clusters are
+ * used, etc.), which is why we use m_copydata
+ * to get the ether header rather than assume
+ * that this is located in the first mbuf.
+ */
+ /* copy ether header */
+ m_copydata(top, 0, sizeof(struct ether_header), ep);
+ eh = (struct ether_header *) ep;
+ ep += sizeof(struct ether_header);
+ eh->ether_type = etype = ntohs(eh->ether_type);
+ if (etype >= ETHERTYPE_TRAIL &&
+ etype < ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER) {
+ datasize = ((etype - ETHERTYPE_TRAIL) << 9);
+ off = datasize + sizeof(struct ether_header);
+
+ /* copy trailer_header into a data structure */
+ m_copydata(top, off, sizeof(struct trailer_header),
+ (caddr_t)&trailer_header.ether_type);
+
+ /* copy residual data */
+ resid = trailer_header.ether_residual -
+ sizeof(struct trailer_header);
+ resid = ntohs(resid);
+ m_copydata(top, off + sizeof(struct trailer_header),
+ resid, ep);
+ ep += resid;
+
+ /* copy data */
+ m_copydata(top, sizeof(struct ether_header),
+ datasize, ep);
+ ep += datasize;
+
+ /* restore original ether packet type */
+ eh->ether_type = trailer_header.ether_type;
+
+ bpf_tap(sc->bpf, ether_packet, ep - ether_packet);
+ } else
+ bpf_mtap(sc->bpf, top);
+ }
+#endif
+
+ m_freem(top);
+ ++sc->arpcom.ac_if.if_opackets;
+
+ /*
+ * Is another packet coming in? We don't want to overflow the
+ * tiny RX fifo.
+ */
+readcheck:
+ if (inw(BASE + EP_W1_RX_STATUS) & RX_BYTES_MASK) {
+ splx(s);
+ return;
+ }
+ goto startagain;
+}
+
+void
+epintr(unit)
+ int unit;
+{
+ int status, i;
+ register struct ep_softc *sc = &ep_softc[unit];
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct mbuf *m;
+
+ status = 0;
+checkintr:
+ status = inw(BASE + EP_STATUS) &
+ (S_TX_COMPLETE | S_TX_AVAIL | S_RX_COMPLETE | S_CARD_FAILURE);
+ if (status == 0) {
+ /* No interrupts. */
+ outw(BASE + EP_COMMAND, C_INTR_LATCH);
+ return;
+ }
+ /* important that we do this first. */
+ outw(BASE + EP_COMMAND, ACK_INTR | status);
+
+ if (status & S_TX_AVAIL) {
+ status &= ~S_TX_AVAIL;
+ inw(BASE + EP_W1_FREE_TX);
+ sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+ epstart(&sc->arpcom.ac_if);
+ }
+ if (status & S_RX_COMPLETE) {
+ status &= ~S_RX_COMPLETE;
+ epread(sc);
+ }
+ if (status & S_CARD_FAILURE) {
+ printf("ep%d: reset (status: %x)\n", unit, status);
+ outw(BASE + EP_COMMAND, C_INTR_LATCH);
+ epinit(unit);
+ return;
+ }
+ if (status & S_TX_COMPLETE) {
+ status &= ~S_TX_COMPLETE;
+ /*
+ * We need to read TX_STATUS until we get a 0 status in
+ * order to turn off the interrupt flag.
+ */
+ while ((i = inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE) {
+ outw(BASE + EP_W1_TX_STATUS, 0x0);
+ if (i & (TXS_MAX_COLLISION | TXS_JABBER | TXS_UNDERRUN)) {
+ if (i & TXS_MAX_COLLISION)
+ ++sc->arpcom.ac_if.if_collisions;
+ if (i & (TXS_JABBER | TXS_UNDERRUN)) {
+ outw(BASE + EP_COMMAND, TX_RESET);
+ if (i & TXS_UNDERRUN) {
+ if (sc->tx_start_thresh < ETHER_MAX_LEN) {
+ sc->tx_start_thresh += 20;
+ outw(BASE + EP_COMMAND,
+ SET_TX_START_THRESH |
+ sc->tx_start_thresh);
+ }
+ }
+ }
+ outw(BASE + EP_COMMAND, TX_ENABLE);
+ ++sc->arpcom.ac_if.if_oerrors;
+ }
+ }
+ epstart(ifp);
+ }
+ goto checkintr;
+}
+
+void
+epread(sc)
+ register struct ep_softc *sc;
+{
+ struct ether_header *eh;
+ struct mbuf *mcur, *m, *m0, *top;
+ int totlen, lenthisone;
+ int save_totlen;
+ u_short etype;
+ int off, resid;
+ int count, spinwait;
+ int i;
+
+ totlen = inw(BASE + EP_W1_RX_STATUS);
+ off = 0;
+ top = 0;
+
+ if (totlen & ERR_RX) {
+ ++sc->arpcom.ac_if.if_ierrors;
+ goto out;
+ }
+ save_totlen = totlen &= RX_BYTES_MASK; /* Lower 11 bits = RX bytes. */
+
+ m = sc->mb[sc->next_mb];
+ sc->mb[sc->next_mb] = 0;
+
+ if (m == 0) {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ goto out;
+ } else {
+ /* Convert one of our saved mbuf's */
+ sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
+ m->m_data = m->m_pktdat;
+ m->m_flags = M_PKTHDR;
+ }
+
+ top = m0 = m; /* We assign top so we can "goto out" */
+#define EROUND ((sizeof(struct ether_header) + 3) & ~3)
+#define EOFF (EROUND - sizeof(struct ether_header))
+ m0->m_data += EOFF;
+ /* Read what should be the header. */
+ insw(BASE + EP_W1_RX_PIO_RD_1,
+ mtod(m0, caddr_t), sizeof(struct ether_header) / 2);
+ m->m_len = sizeof(struct ether_header);
+ totlen -= sizeof(struct ether_header);
+ /*
+ * mostly deal with trailer here. (untested)
+ * We do this in a couple of parts. First we check for a trailer, if
+ * we have one we convert the mbuf back to a regular mbuf and set the offset and
+ * subtract sizeof(struct ether_header) from the pktlen.
+ * After we've read the packet off the interface (all except for the trailer
+ * header, we then get a header mbuf, read the trailer into it, and fix up
+ * the mbuf pointer chain.
+ */
+ eh = mtod(m, struct ether_header *);
+ eh->ether_type = etype = ntohs((u_short) eh->ether_type);
+ if (etype >= ETHERTYPE_TRAIL &&
+ etype < ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER) {
+ m->m_data = m->m_dat; /* Convert back to regular mbuf. */
+ m->m_flags = 0; /* This sucks but non-trailers are the norm */
+ off = (etype - ETHERTYPE_TRAIL) * 512;
+ if (off >= ETHERMTU) {
+ m_freem(m);
+ return; /* sanity */
+ }
+ totlen -= sizeof(struct ether_header); /* We don't read the trailer */
+ m->m_data += 2 * sizeof(u_short); /* Get rid of type & len */
+ }
+ while (totlen > 0) {
+ lenthisone = min(totlen, M_TRAILINGSPACE(m));
+ if (lenthisone == 0) { /* no room in this one */
+ mcur = m;
+ m = sc->mb[sc->next_mb];
+ sc->mb[sc->next_mb] = 0;
+ if (!m) {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ goto out;
+ } else {
+ timeout(epmbuffill, (caddr_t)sc, 0);
+ sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
+ }
+ if (totlen >= MINCLSIZE)
+ MCLGET(m, M_DONTWAIT);
+ m->m_len = 0;
+ mcur->m_next = m;
+ lenthisone = min(totlen, M_TRAILINGSPACE(m));
+ }
+ if (sc->bus32bit) {
+ insl(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
+ lenthisone / 4);
+ m->m_len += (lenthisone & ~3);
+ if (lenthisone & 3)
+ insb(BASE + EP_W1_RX_PIO_RD_1,
+ mtod(m, caddr_t) + m->m_len,
+ lenthisone & 3);
+ m->m_len += (lenthisone & 3);
+ } else {
+ insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len,
+ lenthisone / 2);
+ m->m_len += lenthisone;
+ if (lenthisone & 1)
+ *(mtod(m, caddr_t) + m->m_len - 1) = inb(BASE + EP_W1_RX_PIO_RD_1);
+ }
+ totlen -= lenthisone;
+ }
+ if (off) {
+ top = sc->mb[sc->next_mb];
+ sc->mb[sc->next_mb] = 0;
+ if (top == 0) {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (top == 0) {
+ top = m0;
+ goto out;
+ }
+ } else {
+ /* Convert one of our saved mbuf's */
+ sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
+ top->m_data = top->m_pktdat;
+ top->m_flags = M_PKTHDR;
+ }
+ insw(BASE + EP_W1_RX_PIO_RD_1, mtod(top, caddr_t),
+ sizeof(struct ether_header));
+ top->m_next = m0;
+ top->m_len = sizeof(struct ether_header);
+ /* XXX Accomodate for type and len from beginning of trailer */
+ top->m_pkthdr.len = save_totlen - (2 * sizeof(u_short));
+ } else {
+ top = m0;
+ top->m_pkthdr.len = save_totlen;
+ }
+
+ top->m_pkthdr.rcvif = &sc->arpcom.ac_if;
+ outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+ ;
+ ++sc->arpcom.ac_if.if_ipackets;
+#if NBPFILTER > 0
+ if (sc->bpf) {
+ bpf_mtap(sc->bpf, top);
+
+ /*
+ * Note that the interface cannot be in promiscuous mode if
+ * there are no BPF listeners. And if we are in promiscuous
+ * mode, we have to check if this packet is really ours.
+ */
+ if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) &&
+ (eh->ether_dhost[0] & 1) == 0 &&
+ bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
+ sizeof(eh->ether_dhost)) != 0 &&
+ bcmp(eh->ether_dhost, etherbroadcastaddr,
+ sizeof(eh->ether_dhost)) != 0) {
+ m_freem(top);
+ return;
+ }
+ }
+#endif
+ m_adj(top, sizeof(struct ether_header));
+ ether_input(&sc->arpcom.ac_if, eh, top);
+ return;
+
+out: outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+ ;
+ if (top)
+ m_freem(top);
+
+}
+
+
+/*
+ * Look familiar?
+ */
+static int
+epioctl(ifp, cmd, data)
+ register struct ifnet *ifp;
+ int cmd;
+ caddr_t data;
+{
+ register struct ifaddr *ifa = (struct ifaddr *) data;
+ struct ep_softc *sc = &ep_softc[ifp->if_unit];
+ struct ifreq *ifr = (struct ifreq *) data;
+ int s, error = 0;
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ epinit(ifp->if_unit); /* before arpwhohas */
+ ((struct arpcom *) ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
+ arpwhohas((struct arpcom *) ifp, &IA_SIN(ifa)->sin_addr);
+ break;
+#endif
+#ifdef NS
+ case AF_NS:
+ {
+ register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+
+ if (ns_nullhost(*ina))
+ ina->x_host =
+ *(union ns_host *)(sc->arpcom.ac_enaddr);
+ else {
+ ifp->if_flags &= ~IFF_RUNNING;
+ bcopy((caddr_t) ina->x_host.c_host,
+ (caddr_t)sc->arpcom.ac_enaddr,
+ sizeof(sc->arpcom.ac_enaddr));
+ }
+ epinit(ifp->if_unit);
+ break;
+ }
+#endif
+ default:
+ epinit(ifp->if_unit);
+ break;
+ }
+ break;
+ case SIOCSIFFLAGS:
+ if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) {
+ ifp->if_flags &= ~IFF_RUNNING;
+ epstop(ifp->if_unit);
+ epmbufempty(sc);
+ break;
+ }
+ if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0)
+ epinit(ifp->if_unit);
+ break;
+#ifdef notdef
+ case SIOCGHWADDR:
+ bcopy((caddr_t) sc->sc_addr, (caddr_t) &ifr->ifr_data,
+ sizeof(sc->sc_addr));
+ break;
+#endif
+ default:
+ error = EINVAL;
+ }
+ return (error);
+}
+
+void
+epreset(unit)
+ int unit;
+{
+ int s = splimp();
+
+ epstop(unit);
+ epinit(unit);
+ splx(s);
+}
+
+void
+epwatchdog(unit)
+ int unit;
+{
+ struct ep_softc *sc = &ep_softc[unit];
+
+ log(LOG_ERR, "ep%d: watchdog\n", unit);
+ ++sc->arpcom.ac_if.if_oerrors;
+
+ epreset(unit);
+}
+
+void
+epstop(unit)
+ int unit;
+{
+ struct ep_softc *sc = &ep_softc[unit];
+
+ outw(BASE + EP_COMMAND, RX_DISABLE);
+ outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK);
+ while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
+ ;
+ outw(BASE + EP_COMMAND, TX_DISABLE);
+ outw(BASE + EP_COMMAND, STOP_TRANSCEIVER);
+ outw(BASE + EP_COMMAND, RX_RESET);
+ outw(BASE + EP_COMMAND, TX_RESET);
+ outw(BASE + EP_COMMAND, C_INTR_LATCH);
+ outw(BASE + EP_COMMAND, SET_RD_0_MASK);
+ outw(BASE + EP_COMMAND, SET_INTR_MASK);
+ outw(BASE + EP_COMMAND, SET_RX_FILTER);
+}
+
+
+/*
+ * This is adapted straight from the book. There's probably a better way.
+ */
+static int
+send_ID_sequence(port)
+ u_short port;
+{
+ char cx, al;
+
+ cx = 0x0ff;
+ al = 0x0ff;
+
+ outb(port, 0x0);
+ DELAY(1000);
+ outb(port, 0x0);
+ DELAY(1000);
+
+loop1: cx--;
+ outb(port, al);
+ if (!(al & 0x80)) {
+ al = al << 1;
+ goto loop1;
+ }
+ al = al << 1;
+ al ^= 0xcf;
+ if (cx)
+ goto loop1;
+
+ return(1);
+}
+
+
+/*
+ * We get eeprom data from the id_port given an offset into the
+ * eeprom. Basically; after the ID_sequence is sent to all of
+ * the cards; they enter the ID_CMD state where they will accept
+ * command requests. 0x80-0xbf loads the eeprom data. We then
+ * read the port 16 times and with every read; the cards check
+ * for contention (ie: if one card writes a 0 bit and another
+ * writes a 1 bit then the host sees a 0. At the end of the cycle;
+ * each card compares the data on the bus; if there is a difference
+ * then that card goes into ID_WAIT state again). In the meantime;
+ * one bit of data is returned in the AX register which is conveniently
+ * returned to us by inb(). Hence; we read 16 times getting one
+ * bit of data with each read.
+ */
+static u_short
+get_eeprom_data(id_port, offset)
+ int id_port;
+ int offset;
+{
+ int i, data = 0;
+ outb(id_port, 0x80 + offset);
+ DELAY(1000);
+ for (i = 0; i < 16; i++)
+ data = (data << 1) | (inw(id_port) & 1);
+ return (data);
+}
+
+static int
+is_eeprom_busy(is)
+ struct isa_device *is;
+{
+ int i = 0, j;
+ register struct ep_softc *sc = &ep_softc[is->id_unit];
+
+ while (i++ < 100) {
+ j = inw(BASE + EP_W0_EEPROM_COMMAND);
+ if (j & EEPROM_BUSY)
+ DELAY(100);
+ else
+ break;
+ }
+ if (i >= 100) {
+ printf("\nep%d: eeprom failed to come ready.\n", is->id_unit);
+ return (1);
+ }
+ if (j & EEPROM_TST_MODE) {
+ printf("\nep%d: 3c509 in test mode. Erase pencil mark!\n", is->id_unit);
+ return (1);
+ }
+ return (0);
+}
+
+void
+epmbuffill(sp, dummy_arg)
+ caddr_t sp;
+ int dummy_arg;
+{
+ struct ep_softc *sc = (struct ep_softc *)sp;
+ int s, i;
+
+ s = splimp();
+ i = sc->last_mb;
+ do {
+ if(sc->mb[i] == NULL)
+ MGET(sc->mb[i], M_DONTWAIT, MT_DATA);
+ if(sc->mb[i] == NULL)
+ break;
+ i = (i + 1) % MAX_MBS;
+ } while (i != sc->next_mb);
+ sc->last_mb = i;
+ splx(s);
+}
+
+static void
+epmbufempty(sc)
+ struct ep_softc *sc;
+{
+ int s, i;
+
+ s = splimp();
+ for (i = 0; i<MAX_MBS; i++) {
+ if (sc->mb[i]) {
+ m_freem(sc->mb[i]);
+ sc->mb[i] = NULL;
+ }
+ }
+ sc->last_mb = sc->next_mb = 0;
+ untimeout(epmbuffill, sc);
+ splx(s);
+}
+
+#endif /* NEP > 0 */
diff --git a/sys/i386/isa/if_epreg.h b/sys/i386/isa/if_epreg.h
new file mode 100644
index 0000000..f0b4cd9
--- /dev/null
+++ b/sys/i386/isa/if_epreg.h
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 1993 Herb Peyerl (hpeyerl@novatel.ca)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: if_epreg.h,v 1.1 1993/12/14 04:26:47 hpeyerl Exp $
+ */
+/**************************************************************************
+ * *
+ * These define the EEPROM data structure. They are used in the probe
+ * function to verify the existance of the adapter after having sent
+ * the ID_Sequence.
+ *
+ * There are others but only the ones we use are defined here.
+ *
+ **************************************************************************/
+
+#define EEPROM_NODE_ADDR_0 0x0 /* Word */
+#define EEPROM_NODE_ADDR_1 0x1 /* Word */
+#define EEPROM_NODE_ADDR_2 0x2 /* Word */
+#define EEPROM_PROD_ID 0x3 /* 0x9[0-f]50 */
+#define EEPROM_MFG_ID 0x7 /* 0x6d50 */
+#define EEPROM_ADDR_CFG 0x8 /* Base addr */
+#define EEPROM_RESOURCE_CFG 0x9 /* IRQ. Bits 12-15 */
+
+/**************************************************************************
+ * *
+ * These are the registers for the 3Com 3c509 and their bit patterns when *
+ * applicable. They have been taken out the the "EtherLink III Parallel *
+ * Tasking EISA and ISA Technical Reference" "Beta Draft 10/30/92" manual *
+ * from 3com. *
+ * *
+ **************************************************************************/
+
+#define EP_COMMAND 0x0e /* Write. BASE+0x0e is always a command reg. */
+#define EP_STATUS 0x0e /* Read. BASE+0x0e is always status reg. */
+#define EP_WINDOW 0x0f /* Read. BASE+0x0f is always window reg. */
+/*
+ * Window 0 registers. Setup.
+ */
+ /* Write */
+#define EP_W0_EEPROM_DATA 0x0c
+#define EP_W0_EEPROM_COMMAND 0x0a
+#define EP_W0_RESOURCE_CFG 0x08
+#define EP_W0_ADDRESS_CFG 0x06
+#define EP_W0_CONFIG_CTRL 0x04
+ /* Read */
+#define EP_W0_PRODUCT_ID 0x02
+#define EP_W0_MFG_ID 0x00
+
+/*
+ * Window 1 registers. Operating Set.
+ */
+ /* Write */
+#define EP_W1_TX_PIO_WR_2 0x02
+#define EP_W1_TX_PIO_WR_1 0x00
+ /* Read */
+#define EP_W1_FREE_TX 0x0c
+#define EP_W1_TX_STATUS 0x0b /* byte */
+#define EP_W1_TIMER 0x0a /* byte */
+#define EP_W1_RX_STATUS 0x08
+#define EP_W1_RX_PIO_RD_2 0x02
+#define EP_W1_RX_PIO_RD_1 0x00
+
+/*
+ * Window 2 registers. Station Address Setup/Read
+ */
+ /* Read/Write */
+#define EP_W2_ADDR_5 0x05
+#define EP_W2_ADDR_4 0x04
+#define EP_W2_ADDR_3 0x03
+#define EP_W2_ADDR_2 0x02
+#define EP_W2_ADDR_1 0x01
+#define EP_W2_ADDR_0 0x00
+
+/*
+ * Window 3 registers. FIFO Management.
+ */
+ /* Read */
+#define EP_W3_FREE_TX 0x0c
+#define EP_W3_FREE_RX 0x0a
+
+/*
+ * Window 4 registers. Diagnostics.
+ */
+ /* Read/Write */
+#define EP_W4_MEDIA_TYPE 0x0a
+#define EP_W4_CTRLR_STATUS 0x08
+#define EP_W4_NET_DIAG 0x06
+#define EP_W4_FIFO_DIAG 0x04
+#define EP_W4_HOST_DIAG 0x02
+#define EP_W4_TX_DIAG 0x00
+
+/*
+ * Window 5 Registers. Results and Internal status.
+ */
+ /* Read */
+#define EP_W5_READ_0_MASK 0x0c
+#define EP_W5_INTR_MASK 0x0a
+#define EP_W5_RX_FILTER 0x08
+#define EP_W5_RX_EARLY_THRESH 0x06
+#define EP_W5_TX_AVAIL_THRESH 0x02
+#define EP_W5_TX_START_THRESH 0x00
+
+/*
+ * Window 6 registers. Statistics.
+ */
+ /* Read/Write */
+#define TX_TOTAL_OK 0x0c
+#define RX_TOTAL_OK 0x0a
+#define TX_DEFERRALS 0x08
+#define RX_FRAMES_OK 0x07
+#define TX_FRAMES_OK 0x06
+#define RX_OVERRUNS 0x05
+#define TX_COLLISIONS 0x04
+#define TX_AFTER_1_COLLISION 0x03
+#define TX_AFTER_X_COLLISIONS 0x02
+#define TX_NO_SQE 0x01
+#define TX_CD_LOST 0x00
+
+/****************************************
+ *
+ * Register definitions.
+ *
+ ****************************************/
+
+/*
+ * Command register. All windows.
+ *
+ * 16 bit register.
+ * 15-11: 5-bit code for command to be executed.
+ * 10-0: 11-bit arg if any. For commands with no args;
+ * this can be set to anything.
+ */
+#define GLOBAL_RESET (u_short) 0x0000 /* Wait at least 1ms after issuing */
+#define WINDOW_SELECT (u_short) (0x1<<11)
+#define START_TRANSCEIVER (u_short) (0x2<<11) /* Read ADDR_CFG reg to determine
+ whether this is needed. If so;
+ wait 800 uSec before using trans-
+ ceiver. */
+#define RX_DISABLE (u_short) (0x3<<11) /* state disabled on power-up */
+#define RX_ENABLE (u_short) (0x4<<11)
+#define RX_RESET (u_short) (0x5<<11)
+#define RX_DISCARD_TOP_PACK (u_short) (0x8<<11)
+#define TX_ENABLE (u_short) (0x9<<11)
+#define TX_DISABLE (u_short) (0xa<<11)
+#define TX_RESET (u_short) (0xb<<11)
+#define REQ_INTR (u_short) (0xc<<11)
+ /*
+ * The following C_* acknowledge the various interrupts.
+ * Some of them don't do anything. See the manual.
+ */
+#define ACK_INTR (u_short) (0x6800)
+# define C_INTR_LATCH (u_short) (ACK_INTR|0x1)
+# define C_CARD_FAILURE (u_short) (ACK_INTR|0x2)
+# define C_TX_COMPLETE (u_short) (ACK_INTR|0x4)
+# define C_TX_AVAIL (u_short) (ACK_INTR|0x8)
+# define C_RX_COMPLETE (u_short) (ACK_INTR|0x10)
+# define C_RX_EARLY (u_short) (ACK_INTR|0x20)
+# define C_INT_RQD (u_short) (ACK_INTR|0x40)
+# define C_UPD_STATS (u_short) (ACK_INTR|0x80)
+#define SET_INTR_MASK (u_short) (0xe<<11)
+#define SET_RD_0_MASK (u_short) (0xf<<11)
+#define SET_RX_FILTER (u_short) (0x10<<11)
+# define FIL_INDIVIDUAL (u_short) (0x1)
+# define FIL_GROUP (u_short) (0x2)
+# define FIL_BRDCST (u_short) (0x4)
+# define FIL_ALL (u_short) (0x8)
+#define SET_RX_EARLY_THRESH (u_short) (0x11<<11)
+#define SET_TX_AVAIL_THRESH (u_short) (0x12<<11)
+#define SET_TX_START_THRESH (u_short) (0x13<<11)
+#define STATS_ENABLE (u_short) (0x15<<11)
+#define STATS_DISABLE (u_short) (0x16<<11)
+#define STOP_TRANSCEIVER (u_short) (0x17<<11)
+
+/*
+ * Status register. All windows.
+ *
+ * 15-13: Window number(0-7).
+ * 12: Command_in_progress.
+ * 11: reserved.
+ * 10: reserved.
+ * 9: reserved.
+ * 8: reserved.
+ * 7: Update Statistics.
+ * 6: Interrupt Requested.
+ * 5: RX Early.
+ * 4: RX Complete.
+ * 3: TX Available.
+ * 2: TX Complete.
+ * 1: Adapter Failure.
+ * 0: Interrupt Latch.
+ */
+#define S_INTR_LATCH (u_short) (0x1)
+#define S_CARD_FAILURE (u_short) (0x2)
+#define S_TX_COMPLETE (u_short) (0x4)
+#define S_TX_AVAIL (u_short) (0x8)
+#define S_RX_COMPLETE (u_short) (0x10)
+#define S_RX_EARLY (u_short) (0x20)
+#define S_INT_RQD (u_short) (0x40)
+#define S_UPD_STATS (u_short) (0x80)
+#define S_COMMAND_IN_PROGRESS (u_short) (0x1000)
+
+/*
+ * FIFO Registers. RX Status.
+ *
+ * 15: Incomplete or FIFO empty.
+ * 14: 1: Error in RX Packet 0: Incomplete or no error.
+ * 13-11: Type of error.
+ * 1000 = Overrun.
+ * 1011 = Run Packet Error.
+ * 1100 = Alignment Error.
+ * 1101 = CRC Error.
+ * 1001 = Oversize Packet Error (>1514 bytes)
+ * 0010 = Dribble Bits.
+ * (all other error codes, no errors.)
+ *
+ * 10-0: RX Bytes (0-1514)
+ */
+#define ERR_INCOMPLETE (u_short) (0x8000)
+#define ERR_RX (u_short) (0x4000)
+#define ERR_RX_PACKET (u_short) (0x2000)
+#define ERR_OVERRUN (u_short) (0x1000)
+#define ERR_RUNT (u_short) (0x1300)
+#define ERR_ALIGNMENT (u_short) (0x1400)
+#define ERR_CRC (u_short) (0x1500)
+#define ERR_OVERSIZE (u_short) (0x1100)
+#define ERR_DRIBBLE (u_short) (0x200)
+
+/*
+ * TX Status
+ *
+ * Reports the transmit status of a completed transmission. Writing this
+ * register pops the transmit completion stack.
+ *
+ * Window 1/Port 0x0b.
+ *
+ * 7: Complete
+ * 6: Interrupt on successful transmission requested.
+ * 5: Jabber Error (TP Only, TX Reset required. )
+ * 4: Underrun (TX Reset required. )
+ * 3: Maximum Collisions.
+ * 2: TX Status Overflow.
+ * 1-0: Undefined.
+ *
+ */
+#define TXS_COMPLETE 0x80
+#define TXS_INTR_REQ 0x40
+#define TXS_JABBER 0x20
+#define TXS_UNDERRUN 0x10
+#define TXS_MAX_COLLISION 0x8
+#define TXS_STATUS_OVERFLOW 0x4
+
+/*
+ * Misc defines for various things.
+ */
+#define TAG_ADAPTER_0 0xd0
+#define ACTIVATE_ADAPTER_TO_CONFIG 0xff
+#define ENABLE_DRQ_IRQ 0x0001
+#define MFG_ID 0x6d50
+#define PROD_ID 0x9150
+#define BASE sc->ep_io_addr
+#define GO_WINDOW(x) outw(BASE+EP_COMMAND, WINDOW_SELECT|x)
+#define AUI 0x1
+#define BNC 0x2
+#define UTP 0x4
+#define IS_AUI (1<<13)
+#define IS_BNC (1<<12)
+#define IS_UTP (1<<9)
+#define EEPROM_BUSY (1<<15)
+#define EEPROM_TST_MODE (1<<14)
+#define READ_EEPROM (1<<7)
+#define ETHER_ADDR_LEN 6
+#define ETHER_MAX 1536
+#define ENABLE_UTP 0xc0
+#define DISABLE_UTP 0x0
+#define RX_BYTES_MASK (u_short) (0x07ff)
diff --git a/sys/i386/isa/if_ie.c b/sys/i386/isa/if_ie.c
new file mode 100644
index 0000000..95095bd
--- /dev/null
+++ b/sys/i386/isa/if_ie.c
@@ -0,0 +1,1802 @@
+/*-
+ * Copyright (c) 1992, 1993, University of Vermont and State
+ * Agricultural College.
+ * Copyright (c) 1992, 1993, Garrett A. Wollman.
+ *
+ * Portions:
+ * Copyright (c) 1990, 1991, William F. Jolitz
+ * Copyright (c) 1990, The Regents of the University of California
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * Vermont and State Agricultural College and Garrett A. Wollman,
+ * by William F. Jolitz, by the University of California,
+ * Berkeley, by Larwence Berkeley Laboratory, and its contributors.
+ * 4. Neither the names of the Universities nor the names of the authors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR AUTHORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: if_ie.c,v 1.2 1993/11/25 01:31:36 wollman Exp $
+ */
+
+/*
+ * Intel 82586 Ethernet chip
+ * Register, bit, and structure definitions.
+ *
+ * Written by GAW with reference to the Clarkson Packet Driver code for this
+ * chip written by Russ Nelson and others.
+ *
+ * BPF support code stolen directly from hpdev/if_le.c, supplied with
+ * tcpdump.
+ */
+
+/*
+ * The i82586 is a very versatile chip, found in many implementations.
+ * Programming this chip is mostly the same, but certain details differ
+ * from card to card. This driver is written so that different cards
+ * can be automatically detected at run-time. Currently, only the
+ * AT&T EN100/StarLAN 10 series are supported.
+ */
+
+/*
+Mode of operation:
+
+We run the 82586 in a standard Ethernet mode. We keep NFRAMES received
+frame descriptors around for the receiver to use, and NBUFFS associated
+receive buffer descriptors, both in a circular list. Whenever a frame is
+received, we rotate both lists as necessary. (The 586 treats both lists
+as a simple queue.) We also keep a transmit command around so that packets
+can be sent off quickly.
+
+We configure the adapter in AL-LOC = 1 mode, which means that the
+Ethernet/802.3 MAC header is placed at the beginning of the receive buffer
+rather than being split off into various fields in the RFD. This also
+means that we must include this header in the transmit buffer as well.
+
+By convention, all transmit commands, and only transmit commands, shall
+have the I (IE_CMD_INTR) bit set in the command. This way, when an
+interrupt arrives at ieintr(), it is immediately possible to tell
+what precisely caused it. ANY OTHER command-sending routines should
+run at splimp(), and should post an acknowledgement to every interrupt
+they generate.
+
+The 82586 has a 24-bit address space internally, and the adaptor's
+memory is located at the top of this region. However, the value we are
+given in configuration is normally the *bottom* of the adaptor RAM. So,
+we must go through a few gyrations to come up with a kernel virtual address
+which represents the actual beginning of the 586 address space. First,
+we autosize the RAM by running through several possible sizes and trying
+to initialize the adapter under the assumption that the selected size
+is correct. Then, knowing the correct RAM size, we set up our pointers
+in ie_softc[unit]. `iomem' represents the computed base of the 586
+address space. `iomembot' represents the actual configured base
+of adapter RAM. Finally, `iosize' represents the calculated size
+of 586 RAM. Then, when laying out commands, we use the interval
+[iomembot, iomembot + iosize); to make 24-pointers, we subtract
+iomem, and to make 16-pointers, we subtract iomem and and with 0xffff.
+
+*/
+
+#include "ie.h"
+#if NIE > 0
+
+#include "param.h"
+#include "systm.h"
+#include "mbuf.h"
+#include "protosw.h"
+#include "socket.h"
+#include "ioctl.h"
+#include "errno.h"
+#include "syslog.h"
+
+#include "net/if.h"
+#include "net/if_types.h"
+#include "net/if_dl.h"
+#include "net/route.h"
+
+#include "bpfilter.h"
+
+#ifdef INET
+#include "netinet/in.h"
+#include "netinet/in_systm.h"
+#include "netinet/in_var.h"
+#include "netinet/ip.h"
+#include "netinet/if_ether.h"
+#endif
+
+#ifdef NS
+#include "netns/ns.h"
+#include "netns/ns_if.h"
+#endif
+
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/ic/i82586.h"
+#include "i386/isa/if_iereg.h"
+#include "i386/isa/icu.h"
+
+#include "vm/vm.h"
+
+#if NBPFILTER > 0
+#include "net/bpf.h"
+#include "net/bpfdesc.h"
+#endif
+
+#if (NBPFILTER > 0) || defined(MULTICAST)
+#define FILTER
+static struct mbuf *last_not_for_us;
+#endif
+
+#ifdef DEBUG
+#define IED_RINT 1
+#define IED_TINT 2
+#define IED_RNR 4
+#define IED_CNA 8
+#define IED_READFRAME 16
+int ie_debug = IED_RNR;
+#endif
+
+#ifndef ETHERMINLEN
+#define ETHERMINLEN 60
+#endif
+
+#define IE_BUF_LEN 1512 /* length of transmit buffer */
+
+/* Forward declaration */
+struct ie_softc;
+
+static int ieprobe(struct isa_device *dvp);
+static int ieattach(struct isa_device *dvp);
+static void ieinit(int unit);
+static int ieioctl(struct ifnet *ifp, int command, caddr_t data);
+static void iestart(struct ifnet *ifp);
+static void sl_reset_586(int unit);
+static void sl_chan_attn(int unit);
+static void iereset(int unit, int dummy);
+static void ie_readframe(int unit, struct ie_softc *ie, int bufno);
+static void ie_drop_packet_buffer(int unit, struct ie_softc *ie);
+static void sl_read_ether(int unit, unsigned char addr[6]);
+static void find_ie_mem_size(int unit);
+static int command_and_wait(int unit, int command, void volatile *pcmd, int);
+static int ierint(int unit, struct ie_softc *ie);
+static int ietint(int unit, struct ie_softc *ie);
+static int iernr(int unit, struct ie_softc *ie);
+static void start_receiver(int unit);
+static int ieget(int, struct ie_softc *, struct mbuf **,
+ struct ether_header *, int *);
+static caddr_t setup_rfa(caddr_t ptr, struct ie_softc *ie);
+static int mc_setup(int, caddr_t, volatile struct ie_sys_ctl_block *);
+#ifdef MULTICAST
+static void ie_mc_reset(int unit);
+#endif
+
+#ifdef DEBUG
+void print_rbd(volatile struct ie_recv_buf_desc *rbd);
+
+int in_ierint = 0;
+int in_ietint = 0;
+#endif
+
+/*
+ * This tells the autoconf code how to set us up.
+ */
+struct isa_driver iedriver = {
+ ieprobe, ieattach, "ie",
+};
+
+enum ie_hardware {
+ IE_STARLAN10,
+ IE_EN100,
+ IE_SLFIBER,
+ IE_UNKNOWN
+};
+
+const char *ie_hardware_names[] = {
+ "StarLAN 10",
+ "EN100",
+ "StarLAN Fiber",
+ "Unknown"
+};
+
+/*
+sizeof(iscp) == 1+1+2+4 == 8
+sizeof(scb) == 2+2+2+2+2+2+2+2 == 16
+NFRAMES * sizeof(rfd) == NFRAMES*(2+2+2+2+6+6+2+2) == NFRAMES*24 == 384
+sizeof(xmit_cmd) == 2+2+2+2+6+2 == 18
+sizeof(transmit buffer) == 1512
+sizeof(transmit buffer desc) == 8
+-----
+1946
+
+NBUFFS * sizeof(rbd) == NBUFFS*(2+2+4+2+2) == NBUFFS*12
+NBUFFS * IE_RBUF_SIZE == NBUFFS*256
+
+NBUFFS should be (16384 - 1946) / (256 + 12) == 14438 / 268 == 53
+
+With NBUFFS == 48, this leaves us 1574 bytes for another command or
+more buffers. Another transmit command would be 18+8+1512 == 1538
+---just barely fits!
+
+Obviously all these would have to be reduced for smaller memory sizes.
+With a larger memory, it would be possible to roughly double the number of
+both transmit and receive buffers.
+*/
+
+#define NFRAMES 16 /* number of frames to allow for receive */
+#define NBUFFS 48 /* number of buffers to allocate */
+#define IE_RBUF_SIZE 256 /* size of each buffer, MUST BE POWER OF TWO */
+
+/*
+ * Ethernet status, per interface.
+ */
+struct ie_softc {
+ struct arpcom arpcom;
+ void (*ie_reset_586)(int);
+ void (*ie_chan_attn)(int);
+ enum ie_hardware hard_type;
+ int hard_vers;
+
+ u_short port;
+ caddr_t iomem;
+ caddr_t iomembot;
+ unsigned iosize;
+
+ int want_mcsetup;
+ int promisc;
+ volatile struct ie_int_sys_conf_ptr *iscp;
+ volatile struct ie_sys_ctl_block *scb;
+ volatile struct ie_recv_frame_desc *rframes[NFRAMES];
+ volatile struct ie_recv_buf_desc *rbuffs[NBUFFS];
+ volatile char *cbuffs[NBUFFS];
+ int rfhead, rftail, rbhead, rbtail;
+
+ volatile struct ie_xmit_cmd *xmit_cmds[2];
+ volatile struct ie_xmit_buf *xmit_buffs[2];
+ int xmit_count;
+ u_char *xmit_cbuffs[2];
+
+ struct ie_en_addr mcast_addrs[MAXMCAST + 1];
+ int mcast_count;
+
+#if NBPFILTER > 0
+ caddr_t ie_bpf;
+#endif
+
+} ie_softc[NIE];
+
+#define MK_24(base, ptr) ((caddr_t)((u_long)ptr - (u_long)base))
+#define MK_16(base, ptr) ((u_short)(u_long)MK_24(base, ptr))
+
+#define PORT ie_softc[unit].port
+#define MEM ie_softc[unit].iomem
+
+
+int ieprobe(dvp)
+ struct isa_device *dvp;
+{
+ int unit = dvp->id_unit;
+ u_char c;
+
+ ie_softc[unit].port = dvp->id_iobase;
+ ie_softc[unit].iomembot = dvp->id_maddr;
+ ie_softc[unit].iomem = 0;
+
+ c = inb(PORT + IEATT_REVISION);
+ switch(SL_BOARD(c)) {
+ case SL10_BOARD:
+ ie_softc[unit].hard_type = IE_STARLAN10;
+ ie_softc[unit].ie_reset_586 = sl_reset_586;
+ ie_softc[unit].ie_chan_attn = sl_chan_attn;
+ break;
+ case EN100_BOARD:
+ ie_softc[unit].hard_type = IE_EN100;
+ ie_softc[unit].ie_reset_586 = sl_reset_586;
+ ie_softc[unit].ie_chan_attn = sl_chan_attn;
+ break;
+ case SLFIBER_BOARD:
+ ie_softc[unit].hard_type = IE_SLFIBER;
+ ie_softc[unit].ie_reset_586 = sl_reset_586;
+ ie_softc[unit].ie_chan_attn = sl_chan_attn;
+ break;
+
+ /*
+ * Anything else is not recognized or cannot be used.
+ */
+ default:
+ return 0;
+ }
+
+ ie_softc[unit].hard_vers = SL_REV(c);
+
+ /*
+ * Divine memory size on-board the card. Ususally 16k.
+ */
+ find_ie_mem_size(unit);
+
+ if(!ie_softc[unit].iosize) {
+ return 0;
+ }
+
+ dvp->id_msize = ie_softc[unit].iosize;
+
+ switch(ie_softc[unit].hard_type) {
+ case IE_EN100:
+ case IE_STARLAN10:
+ case IE_SLFIBER:
+ sl_read_ether(unit, ie_softc[unit].arpcom.ac_enaddr);
+ break;
+
+ default:
+ printf("ie%d: unknown AT&T board type code %d\n", unit,
+ ie_softc[unit].hard_type);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Taken almost exactly from Bill's if_is.c, then modified beyond recognition.
+ */
+int
+ieattach(dvp)
+ struct isa_device *dvp;
+{
+ int unit = dvp->id_unit;
+ struct ie_softc *ie = &ie_softc[unit];
+ struct ifnet *ifp = &ie->arpcom.ac_if;
+
+ ifp->if_unit = unit;
+ ifp->if_name = iedriver.name;
+ ifp->if_mtu = ETHERMTU;
+ printf("<%s R%d> ethernet address %s",
+ ie_hardware_names[ie_softc[unit].hard_type],
+ ie_softc[unit].hard_vers + 1,
+ ether_sprintf(ie->arpcom.ac_enaddr));
+
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
+#ifdef MULTICAST
+ ifp->if_flags |= IFF_MULTICAST;
+#endif /* MULTICAST */
+
+ ifp->if_init = ieinit;
+ ifp->if_output = ether_output;
+ ifp->if_start = iestart;
+ ifp->if_ioctl = ieioctl;
+ ifp->if_reset = iereset;
+ ifp->if_type = IFT_ETHER;
+ ifp->if_addrlen = 6;
+ ifp->if_hdrlen = 14;
+
+#if NBPFILTER > 0
+ printf("\n");
+ bpfattach(&ie_softc[unit].ie_bpf, ifp, DLT_EN10MB,
+ sizeof(struct ether_header));
+#endif
+
+ if_attach(ifp);
+ {
+ struct ifaddr *ifa = ifp->if_addrlist;
+ struct sockaddr_dl *sdl;
+ while(ifa && ifa->ifa_addr && ifa->ifa_addr->sa_family != AF_LINK)
+ ifa = ifa->ifa_next;
+
+ if(!ifa || !ifa->ifa_addr) return 1;
+
+ /* Provide our ether address to the higher layers */
+ sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ sdl->sdl_type = IFT_ETHER;
+ sdl->sdl_alen = 6;
+ sdl->sdl_slen = 0;
+ bcopy(ie->arpcom.ac_enaddr, LLADDR(sdl), 6);
+ return 1;
+ }
+}
+
+/*
+ * What to do upon receipt of an interrupt.
+ */
+int ieintr(unit)
+ int unit;
+{
+ register struct ie_softc *ie = &ie_softc[unit];
+ register u_short status;
+
+ status = ie->scb->ie_status;
+
+loop:
+ if(status & (IE_ST_RECV | IE_ST_RNR)) {
+#ifdef DEBUG
+ in_ierint++;
+ if(ie_debug & IED_RINT)
+ printf("ie%d: rint\n", unit);
+#endif
+ ierint(unit, ie);
+#ifdef DEBUG
+ in_ierint--;
+#endif
+ }
+
+ if(status & IE_ST_DONE) {
+#ifdef DEBUG
+ in_ietint++;
+ if(ie_debug & IED_TINT)
+ printf("ie%d: tint\n", unit);
+#endif
+ ietint(unit, ie);
+#ifdef DEBUG
+ in_ietint--;
+#endif
+ }
+
+ if(status & IE_ST_RNR) {
+#ifdef DEBUG
+ if(ie_debug & IED_RNR)
+ printf("ie%d: rnr\n", unit);
+#endif
+ iernr(unit, ie);
+ }
+
+#ifdef DEBUG
+ if((status & IE_ST_ALLDONE)
+ && (ie_debug & IED_CNA))
+ printf("ie%d: cna\n", unit);
+#endif
+
+ /* Don't ack interrupts which we didn't receive */
+ ie_ack(ie->scb, IE_ST_WHENCE & status, unit, ie->ie_chan_attn);
+
+ if((status = ie->scb->ie_status) & IE_ST_WHENCE)
+ goto loop;
+
+ return unit;
+}
+
+/*
+ * Process a received-frame interrupt.
+ */
+static int ierint(unit, ie)
+ int unit;
+ struct ie_softc *ie;
+{
+ int i, status;
+ static int timesthru = 1024;
+
+ i = ie->rfhead;
+ while(1) {
+ status = ie->rframes[i]->ie_fd_status;
+
+ if((status & IE_FD_COMPLETE) && (status & IE_FD_OK)) {
+ ie->arpcom.ac_if.if_ipackets++;
+ if(!--timesthru) {
+ ie->arpcom.ac_if.if_ierrors += ie->scb->ie_err_crc + ie->scb->ie_err_align +
+ ie->scb->ie_err_resource + ie->scb->ie_err_overrun;
+ ie->scb->ie_err_crc = 0;
+ ie->scb->ie_err_align = 0;
+ ie->scb->ie_err_resource = 0;
+ ie->scb->ie_err_overrun = 0;
+ timesthru = 1024;
+ }
+ ie_readframe(unit, ie, i);
+ } else {
+ if(status & IE_FD_RNR) {
+ if(!(ie->scb->ie_status & IE_RU_READY)) {
+ ie->rframes[0]->ie_fd_next = MK_16(MEM, ie->rbuffs[0]);
+ ie->scb->ie_recv_list = MK_16(MEM, ie->rframes[0]);
+ command_and_wait(unit, IE_RU_START, 0, 0);
+ }
+ }
+ break;
+ }
+ i = (i + 1) % NFRAMES;
+ }
+ return 0;
+}
+
+/*
+ * Process a command-complete interrupt. These are only generated by
+ * the transmission of frames. This routine is deceptively simple, since
+ * most of the real work is done by iestart().
+ */
+static int ietint(unit, ie)
+ int unit;
+ struct ie_softc *ie;
+{
+ int status;
+ int i;
+
+ ie->arpcom.ac_if.if_timer = 0;
+ ie->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+
+ for(i = 0; i < ie->xmit_count; i++) {
+ status = ie->xmit_cmds[i]->ie_xmit_status;
+
+ if(status & IE_XS_LATECOLL) {
+ printf("ie%d: late collision\n", unit);
+ ie->arpcom.ac_if.if_collisions++;
+ ie->arpcom.ac_if.if_oerrors++;
+ } else if(status & IE_XS_NOCARRIER) {
+ printf("ie%d: no carrier\n", unit);
+ ie->arpcom.ac_if.if_oerrors++;
+ } else if(status & IE_XS_LOSTCTS) {
+ printf("ie%d: lost CTS\n", unit);
+ ie->arpcom.ac_if.if_oerrors++;
+ } else if(status & IE_XS_UNDERRUN) {
+ printf("ie%d: DMA underrun\n", unit);
+ ie->arpcom.ac_if.if_oerrors++;
+ } else if(status & IE_XS_EXCMAX) {
+ printf("ie%d: too many collisions\n", unit);
+ ie->arpcom.ac_if.if_collisions += 16;
+ ie->arpcom.ac_if.if_oerrors++;
+ } else {
+ ie->arpcom.ac_if.if_opackets++;
+ ie->arpcom.ac_if.if_collisions += status & IE_XS_MAXCOLL;
+ }
+ }
+ ie->xmit_count = 0;
+
+ /*
+ * If multicast addresses were added or deleted while we were transmitting,
+ * ie_mc_reset() set the want_mcsetup flag indicating that we should do it.
+ */
+ if(ie->want_mcsetup) {
+ mc_setup(unit, (caddr_t)ie->xmit_cbuffs[0], ie->scb);
+ ie->want_mcsetup = 0;
+ }
+
+ /* Wish I knew why this seems to be necessary... */
+ ie->xmit_cmds[0]->ie_xmit_status |= IE_STAT_COMPL;
+
+ iestart(&ie->arpcom.ac_if);
+ return 0; /* shouldn't be necessary */
+}
+
+/*
+ * Process a receiver-not-ready interrupt. I believe that we get these
+ * when there aren't enough buffers to go around. For now (FIXME), we
+ * just restart the receiver, and hope everything's ok.
+ */
+static int iernr(unit, ie)
+ int unit;
+ struct ie_softc *ie;
+{
+#ifdef doesnt_work
+ setup_rfa((caddr_t)ie->rframes[0], ie);
+
+ ie->scb->ie_recv_list = MK_16(MEM, ie_softc[unit].rframes[0]);
+ command_and_wait(unit, IE_RU_START, 0, 0);
+#else
+ /* This doesn't work either, but it doesn't hang either. */
+ command_and_wait(unit, IE_RU_DISABLE, 0, 0); /* just in case */
+ setup_rfa((caddr_t)ie->rframes[0], ie); /* ignore cast-qual */
+
+ ie->scb->ie_recv_list = MK_16(MEM, ie_softc[unit].rframes[0]);
+ command_and_wait(unit, IE_RU_START, 0, 0); /* was ENABLE */
+
+#endif
+ ie_ack(ie->scb, IE_ST_WHENCE, unit, ie->ie_chan_attn);
+
+ ie->arpcom.ac_if.if_ierrors++;
+ return 0;
+}
+
+#ifdef FILTER
+/*
+ * Compare two Ether/802 addresses for equality, inlined and
+ * unrolled for speed. I'd love to have an inline assembler
+ * version of this...
+ */
+static inline int ether_equal(u_char *one, u_char *two) {
+ if(one[0] != two[0]) return 0;
+ if(one[1] != two[1]) return 0;
+ if(one[2] != two[2]) return 0;
+ if(one[3] != two[3]) return 0;
+ if(one[4] != two[4]) return 0;
+ if(one[5] != two[5]) return 0;
+ return 1;
+}
+
+/*
+ * Check for a valid address. to_bpf is filled in with one of the following:
+ * 0 -> BPF doesn't get this packet
+ * 1 -> BPF does get this packet
+ * 2 -> BPF does get this packet, but we don't
+ * Return value is true if the packet is for us, and false otherwise.
+ *
+ * This routine is a mess, but it's also critical that it be as fast
+ * as possible. It could be made cleaner if we can assume that the
+ * only client which will fiddle with IFF_PROMISC is BPF. This is
+ * probably a good assumption, but we do not make it here. (Yet.)
+ */
+static inline int check_eh(struct ie_softc *ie,
+ struct ether_header *eh,
+ int *to_bpf) {
+ int i;
+
+ switch(ie->promisc) {
+ case IFF_ALLMULTI:
+ /*
+ * Receiving all multicasts, but no unicasts except those destined for us.
+ */
+#if NBPFILTER > 0
+ *to_bpf = (ie->ie_bpf != 0); /* BPF gets this packet if anybody cares */
+#endif
+ if(eh->ether_dhost[0] & 1) {
+ return 1;
+ }
+ if(ether_equal(eh->ether_dhost, ie->arpcom.ac_enaddr)) return 1;
+ return 0;
+
+ case IFF_PROMISC:
+ /*
+ * Receiving all packets. These need to be passed on to BPF.
+ */
+#if NBPFILTER > 0
+ *to_bpf = (ie->ie_bpf != 0);
+#endif
+ /* If for us, accept and hand up to BPF */
+ if(ether_equal(eh->ether_dhost, ie->arpcom.ac_enaddr)) return 1;
+
+#if NBPFILTER > 0
+ if(*to_bpf) *to_bpf = 2; /* we don't need to see it */
+#endif
+
+#ifdef MULTICAST
+ /*
+ * Not a multicast, so BPF wants to see it but we don't.
+ */
+ if(!(eh->ether_dhost[0] & 1)) return 1;
+
+ /*
+ * If it's one of our multicast groups, accept it and pass it
+ * up.
+ */
+ for(i = 0; i < ie->mcast_count; i++) {
+ if(ether_equal(eh->ether_dhost, (u_char *)&ie->mcast_addrs[i])) {
+#if NBPFILTER > 0
+ if(*to_bpf) *to_bpf = 1;
+#endif
+ return 1;
+ }
+ }
+#endif /* MULTICAST */
+ return 1;
+
+ case IFF_ALLMULTI | IFF_PROMISC:
+ /*
+ * Acting as a multicast router, and BPF running at the same time.
+ * Whew! (Hope this is a fast machine...)
+ */
+#if NBPFILTER > 0
+ *to_bpf = (ie->ie_bpf != 0);
+#endif
+ /* We want to see multicasts. */
+ if(eh->ether_dhost[0] & 1) return 1;
+
+ /* We want to see our own packets */
+ if(ether_equal(eh->ether_dhost, ie->arpcom.ac_enaddr)) return 1;
+
+ /* Anything else goes to BPF but nothing else. */
+#if NBPFILTER > 0
+ if(*to_bpf) *to_bpf = 2;
+#endif
+ return 1;
+
+ default:
+ /*
+ * Only accept unicast packets destined for us, or multicasts
+ * for groups that we belong to. For now, we assume that the
+ * '586 will only return packets that we asked it for. This
+ * isn't strictly true (it uses hashing for the multicast filter),
+ * but it will do in this case, and we want to get out of here
+ * as quickly as possible.
+ */
+#if NBPFILTER > 0
+ *to_bpf = (ie->ie_bpf != 0);
+#endif
+ return 1;
+ }
+ return 0;
+}
+#endif /* FILTER */
+
+/*
+ * We want to isolate the bits that have meaning... This assumes that
+ * IE_RBUF_SIZE is an even power of two. If somehow the act_len exceeds
+ * the size of the buffer, then we are screwed anyway.
+ */
+static inline int ie_buflen(struct ie_softc *ie, int head) {
+ return (ie->rbuffs[head]->ie_rbd_actual
+ & (IE_RBUF_SIZE | (IE_RBUF_SIZE - 1)));
+}
+
+static inline int ie_packet_len(int unit, struct ie_softc *ie) {
+ int i;
+ int head = ie->rbhead;
+ int acc = 0;
+
+ do {
+ if(!(ie->rbuffs[ie->rbhead]->ie_rbd_actual & IE_RBD_USED)) {
+#ifdef DEBUG
+ print_rbd(ie->rbuffs[ie->rbhead]);
+#endif
+ log(LOG_ERR, "ie%d: receive descriptors out of sync at %d\n",
+ unit, ie->rbhead);
+ iereset(unit, 0);
+ return -1;
+ }
+
+ i = ie->rbuffs[head]->ie_rbd_actual & IE_RBD_LAST;
+
+ acc += ie_buflen(ie, head);
+ head = (head + 1) % NBUFFS;
+ } while(!i);
+
+ return acc;
+}
+
+/*
+ * Read data off the interface, and turn it into an mbuf chain.
+ *
+ * This code is DRAMATICALLY different from the previous version; this
+ * version tries to allocate the entire mbuf chain up front, given the
+ * length of the data available. This enables us to allocate mbuf
+ * clusters in many situations where before we would have had a long
+ * chain of partially-full mbufs. This should help to speed up the
+ * operation considerably. (Provided that it works, of course.)
+ */
+static inline int ieget(unit, ie, mp, ehp, to_bpf)
+ int unit;
+ struct ie_softc *ie;
+ struct mbuf **mp;
+ struct ether_header *ehp;
+ int *to_bpf;
+{
+ struct mbuf *m, *top, **mymp;
+ int i;
+ int offset;
+ int totlen, resid;
+ int thismboff;
+ int head;
+
+ totlen = ie_packet_len(unit, ie);
+ if(totlen <= 0) return -1;
+
+ i = ie->rbhead;
+
+ /*
+ * Snarf the Ethernet header.
+ */
+ bcopy((caddr_t)ie->cbuffs[i], (caddr_t)ehp, sizeof *ehp);
+ /* ignore cast-qual warning here */
+
+ /*
+ * As quickly as possible, check if this packet is for us.
+ * If not, don't waste a single cycle copying the rest of the
+ * packet in.
+ * This is only a consideration when FILTER is defined; i.e., when
+ * we are either running BPF or doing multicasting.
+ */
+#ifdef FILTER
+ if(!check_eh(ie, ehp, to_bpf)) {
+ ie_drop_packet_buffer(unit, ie);
+ ie->arpcom.ac_if.if_ierrors--; /* just this case, it's not an error */
+ return -1;
+ }
+#endif
+ totlen -= (offset = sizeof *ehp);
+
+ MGETHDR(*mp, M_DONTWAIT, MT_DATA);
+ if(!*mp) {
+ ie_drop_packet_buffer(unit, ie);
+ return -1;
+ }
+
+ m = *mp;
+ m->m_pkthdr.rcvif = &ie->arpcom.ac_if;
+ m->m_len = MHLEN;
+ resid = m->m_pkthdr.len = totlen;
+ top = 0;
+ mymp = &top;
+
+ /*
+ * This loop goes through and allocates mbufs for all the data we will
+ * be copying in. It does not actually do the copying yet.
+ */
+ do { /* while(resid > 0) */
+ /*
+ * Try to allocate an mbuf to hold the data that we have. If we
+ * already allocated one, just get another one and stick it on the
+ * end (eventually). If we don't already have one, try to allocate
+ * an mbuf cluster big enough to hold the whole packet, if we think it's
+ * reasonable, or a single mbuf which may or may not be big enough.
+ * Got that?
+ */
+ if(top) {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if(!m) {
+ m_freem(top);
+ ie_drop_packet_buffer(unit, ie);
+ return -1;
+ }
+ m->m_len = MLEN;
+ }
+
+ if(resid >= MINCLSIZE) {
+ MCLGET(m, M_DONTWAIT);
+ if(m->m_flags & M_EXT)
+ m->m_len = min(resid, MCLBYTES);
+ } else {
+ if(resid < m->m_len) {
+ if(!top && resid + max_linkhdr <= m->m_len)
+ m->m_data += max_linkhdr;
+ m->m_len = resid;
+ }
+ }
+ resid -= m->m_len;
+ *mymp = m;
+ mymp = &m->m_next;
+ } while(resid > 0);
+
+ resid = totlen;
+ m = top;
+ thismboff = 0;
+ head = ie->rbhead;
+
+ /*
+ * Now we take the mbuf chain (hopefully only one mbuf most of the
+ * time) and stuff the data into it. There are no possible failures
+ * at or after this point.
+ */
+ while(resid > 0) { /* while there's stuff left */
+ int thislen = ie_buflen(ie, head) - offset;
+
+ /*
+ * If too much data for the current mbuf, then fill the current one
+ * up, go to the next one, and try again.
+ */
+ if(thislen > m->m_len - thismboff) {
+ int newlen = m->m_len - thismboff;
+ bcopy((caddr_t)(ie->cbuffs[head] + offset),
+ mtod(m, caddr_t) + thismboff, (unsigned)newlen);
+ /* ignore cast-qual warning */
+ m = m->m_next;
+ thismboff = 0; /* new mbuf, so no offset */
+ offset += newlen; /* we are now this far into the packet */
+ resid -= newlen; /* so there is this much left to get */
+ continue;
+ }
+
+ /*
+ * If there is more than enough space in the mbuf to hold the
+ * contents of this buffer, copy everything in, advance pointers,
+ * and so on.
+ */
+ if(thislen < m->m_len - thismboff) {
+ bcopy((caddr_t)(ie->cbuffs[head] + offset), /* ignore warning */
+ mtod(m, caddr_t) + thismboff, (unsigned)thislen);
+ thismboff += thislen; /* we are this far into the mbuf */
+ resid -= thislen; /* and this much is left */
+ goto nextbuf;
+ }
+
+ /*
+ * Otherwise, there is exactly enough space to put this buffer's
+ * contents into the current mbuf. Do the combination of the above
+ * actions.
+ */
+ bcopy((caddr_t)(ie->cbuffs[head] + offset), /* ignore warning */
+ mtod(m, caddr_t) + thismboff, (unsigned)thislen);
+ m = m->m_next;
+ thismboff = 0; /* new mbuf, start at the beginning */
+ resid -= thislen; /* and we are this far through */
+
+ /*
+ * Advance all the pointers. We can get here from either of the
+ * last two cases, but never the first.
+ */
+nextbuf:
+ offset = 0;
+ ie->rbuffs[head]->ie_rbd_actual = 0;
+ ie->rbuffs[head]->ie_rbd_length |= IE_RBD_LAST;
+ ie->rbhead = head = (head + 1) % NBUFFS;
+ ie->rbuffs[ie->rbtail]->ie_rbd_length &= ~IE_RBD_LAST;
+ ie->rbtail = (ie->rbtail + 1) % NBUFFS;
+ }
+
+ /*
+ * Unless something changed strangely while we were doing the copy,
+ * we have now copied everything in from the shared memory.
+ * This means that we are done.
+ */
+ return 0;
+}
+
+/*
+ * Read frame NUM from unit UNIT (pre-cached as IE).
+ *
+ * This routine reads the RFD at NUM, and copies in the buffers from
+ * the list of RBD, then rotates the RBD and RFD lists so that the receiver
+ * doesn't start complaining. Trailers are DROPPED---there's no point
+ * in wasting time on confusing code to deal with them. Hopefully,
+ * this machine will never ARP for trailers anyway.
+ */
+static void ie_readframe(unit, ie, num)
+ int unit;
+ struct ie_softc *ie;
+ int num; /* frame number to read */
+{
+ struct ie_recv_frame_desc rfd;
+ struct mbuf *m = 0;
+ struct ether_header eh;
+#if NBPFILTER > 0
+ int bpf_gets_it = 0;
+#endif
+
+ bcopy((caddr_t)(ie->rframes[num]), &rfd, sizeof(struct ie_recv_frame_desc));
+
+ /* Immediately advance the RFD list, since we we have copied ours now. */
+ ie->rframes[num]->ie_fd_status = 0;
+ ie->rframes[num]->ie_fd_last |= IE_FD_LAST;
+ ie->rframes[ie->rftail]->ie_fd_last &= ~IE_FD_LAST;
+ ie->rftail = (ie->rftail + 1) % NFRAMES;
+ ie->rfhead = (ie->rfhead + 1) % NFRAMES;
+
+ if(rfd.ie_fd_status & IE_FD_OK) {
+ if(
+#if NBPFILTER > 0
+ ieget(unit, ie, &m, &eh, &bpf_gets_it)
+#else
+ ieget(unit, ie, &m, &eh, (int *)0)
+#endif
+ ) {
+ ie->arpcom.ac_if.if_ierrors++; /* this counts as an error */
+ return;
+ }
+ }
+
+#ifdef DEBUG
+ if(ie_debug & IED_READFRAME) {
+ printf("ie%d: frame from ether %s type %x\n", unit,
+ ether_sprintf(eh.ether_shost), (unsigned)eh.ether_type);
+ }
+ if(ntohs(eh.ether_type) > ETHERTYPE_TRAIL
+ && ntohs(eh.ether_type) < (ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER))
+ printf("received trailer!\n");
+#endif
+
+ if(!m) return;
+
+#ifdef FILTER
+ if(last_not_for_us) {
+ m_freem(last_not_for_us);
+ last_not_for_us = 0;
+ }
+
+#if NBPFILTER > 0
+ /*
+ * Check for a BPF filter; if so, hand it up.
+ * Note that we have to stick an extra mbuf up front, because
+ * bpf_mtap expects to have the ether header at the front.
+ * It doesn't matter that this results in an ill-formatted mbuf chain,
+ * since BPF just looks at the data. (It doesn't try to free the mbuf,
+ * tho' it will make a copy for tcpdump.)
+ */
+ if(bpf_gets_it) {
+ struct mbuf m0;
+ m0.m_len = sizeof eh;
+ m0.m_data = (caddr_t)&eh;
+ m0.m_next = m;
+
+ /* Pass it up */
+ bpf_mtap(ie->ie_bpf, &m0);
+ }
+ /*
+ * A signal passed up from the filtering code indicating that the
+ * packet is intended for BPF but not for the protocol machinery.
+ * We can save a few cycles by not handing it off to them.
+ */
+ if(bpf_gets_it == 2) {
+ last_not_for_us = m;
+ return;
+ }
+#endif /* NBPFILTER > 0 */
+ /*
+ * In here there used to be code to check destination addresses upon
+ * receipt of a packet. We have deleted that code, and replaced it
+ * with code to check the address much earlier in the cycle, before
+ * copying the data in; this saves us valuable cycles when operating
+ * as a multicast router or when using BPF.
+ */
+#endif /* FILTER */
+
+ eh.ether_type = ntohs(eh.ether_type);
+
+ /*
+ * Finally pass this packet up to higher layers.
+ */
+ ether_input(&ie->arpcom.ac_if, &eh, m);
+}
+
+static void ie_drop_packet_buffer(int unit, struct ie_softc *ie) {
+ int i;
+
+ do {
+ /*
+ * This means we are somehow out of sync. So, we reset the
+ * adapter.
+ */
+ if(!(ie->rbuffs[ie->rbhead]->ie_rbd_actual & IE_RBD_USED)) {
+#ifdef DEBUG
+ print_rbd(ie->rbuffs[ie->rbhead]);
+#endif
+ log(LOG_ERR, "ie%d: receive descriptors out of sync at %d\n",
+ unit, ie->rbhead);
+ iereset(unit, 0);
+ return;
+ }
+
+ i = ie->rbuffs[ie->rbhead]->ie_rbd_actual & IE_RBD_LAST;
+
+ ie->rbuffs[ie->rbhead]->ie_rbd_length |= IE_RBD_LAST;
+ ie->rbuffs[ie->rbhead]->ie_rbd_actual = 0;
+ ie->rbhead = (ie->rbhead + 1) % NBUFFS;
+ ie->rbuffs[ie->rbtail]->ie_rbd_length &= ~IE_RBD_LAST;
+ ie->rbtail = (ie->rbtail + 1) % NBUFFS;
+ } while(!i);
+}
+
+
+/*
+ * Start transmission on an interface.
+ */
+static void
+iestart(ifp)
+ struct ifnet *ifp;
+{
+ struct ie_softc *ie = &ie_softc[ifp->if_unit];
+ struct mbuf *m0, *m;
+ unsigned char *buffer;
+ u_short len;
+ /* This is not really volatile, in this routine, but it makes gcc happy. */
+ volatile u_short *bptr = &ie->scb->ie_command_list;
+
+ if(!(ifp->if_flags & IFF_RUNNING))
+ return;
+ if(ifp->if_flags & IFF_OACTIVE)
+ return;
+
+ do {
+ IF_DEQUEUE(&ie->arpcom.ac_if.if_snd, m);
+ if(!m)
+ break;
+
+ buffer = ie->xmit_cbuffs[ie->xmit_count];
+ len = 0;
+
+ for(m0 = m; m && len < IE_BUF_LEN; m = m->m_next) {
+ bcopy(mtod(m, caddr_t), buffer, m->m_len);
+ buffer += m->m_len;
+ len += m->m_len;
+ }
+
+ m_freem(m0);
+ len = MAX(len, ETHERMINLEN);
+
+#if NBPFILTER > 0
+ /*
+ * See if bpf is listening on this interface, let it see the packet
+ * before we commit it to the wire.
+ */
+ if(ie->ie_bpf)
+ bpf_tap(ie->ie_bpf, ie->xmit_cbuffs[ie->xmit_count], len);
+#endif
+
+ ie->xmit_buffs[ie->xmit_count]->ie_xmit_flags = IE_XMIT_LAST | len;
+ ie->xmit_buffs[ie->xmit_count]->ie_xmit_next = 0xffff;
+ ie->xmit_buffs[ie->xmit_count]->ie_xmit_buf =
+ MK_24(ie->iomem, ie->xmit_cbuffs[ie->xmit_count]);
+
+ ie->xmit_cmds[ie->xmit_count]->com.ie_cmd_cmd = IE_CMD_XMIT;
+ ie->xmit_cmds[ie->xmit_count]->ie_xmit_status = 0;
+ ie->xmit_cmds[ie->xmit_count]->ie_xmit_desc =
+ MK_16(ie->iomem, ie->xmit_buffs[ie->xmit_count]);
+
+ *bptr = MK_16(ie->iomem, ie->xmit_cmds[ie->xmit_count]);
+ bptr = &ie->xmit_cmds[ie->xmit_count]->com.ie_cmd_link;
+ ie->xmit_count++;
+ } while(ie->xmit_count < 2);
+
+ /*
+ * If we queued up anything for transmission, send it.
+ */
+ if(ie->xmit_count) {
+ ie->xmit_cmds[ie->xmit_count - 1]->com.ie_cmd_cmd |=
+ IE_CMD_LAST | IE_CMD_INTR;
+
+ /*
+ * By passing the command pointer as a null, we tell
+ * command_and_wait() to pretend that this isn't an action
+ * command. I wish I understood what was happening here.
+ */
+ command_and_wait(ifp->if_unit, IE_CU_START, 0, 0);
+ ifp->if_flags |= IFF_OACTIVE;
+ }
+
+ return;
+}
+
+/*
+ * Check to see if there's an 82586 out there.
+ */
+int check_ie_present(unit, where, size)
+ int unit;
+ caddr_t where;
+ unsigned size;
+{
+ volatile struct ie_sys_conf_ptr *scp;
+ volatile struct ie_int_sys_conf_ptr *iscp;
+ volatile struct ie_sys_ctl_block *scb;
+ u_long realbase;
+ int s;
+
+ s = splimp();
+
+ realbase = (u_long)where + size - (1 << 24);
+
+ scp = (volatile struct ie_sys_conf_ptr *)(realbase + IE_SCP_ADDR);
+ bzero((char *)scp, sizeof *scp); /* ignore cast-qual */
+
+ /*
+ * First we put the ISCP at the bottom of memory; this tests to make
+ * sure that our idea of the size of memory is the same as the controller's.
+ * This is NOT where the ISCP will be in normal operation.
+ */
+ iscp = (volatile struct ie_int_sys_conf_ptr *)where;
+ bzero((char *)iscp, sizeof *iscp); /* ignore cast-qual */
+
+ scb = (volatile struct ie_sys_ctl_block *)where;
+ bzero((char *)scb, sizeof *scb); /* ignore cast-qual */
+
+ scp->ie_bus_use = 0; /* 16-bit */
+ scp->ie_iscp_ptr = (caddr_t)((volatile caddr_t)iscp - /* ignore cast-qual */
+ (volatile caddr_t)realbase);
+
+ iscp->ie_busy = 1;
+ iscp->ie_scb_offset = MK_16(realbase, scb) + 256;
+
+ (*ie_softc[unit].ie_reset_586)(unit);
+ (*ie_softc[unit].ie_chan_attn)(unit);
+
+ DELAY(100); /* wait a while... */
+
+ if(iscp->ie_busy) {
+ splx(s);
+ return 0;
+ }
+
+ /*
+ * Now relocate the ISCP to its real home, and reset the controller
+ * again.
+ */
+ iscp = (void *)Align((caddr_t)(realbase + IE_SCP_ADDR -
+ sizeof(struct ie_int_sys_conf_ptr)));
+ bzero((char *)iscp, sizeof *iscp); /* ignore cast-qual */
+
+ scp->ie_iscp_ptr = (caddr_t)((caddr_t)iscp - (caddr_t)realbase);
+ /* ignore cast-qual */
+
+ iscp->ie_busy = 1;
+ iscp->ie_scb_offset = MK_16(realbase, scb);
+
+ (*ie_softc[unit].ie_reset_586)(unit);
+ (*ie_softc[unit].ie_chan_attn)(unit);
+
+ DELAY(100);
+
+ if(iscp->ie_busy) {
+ splx(s);
+ return 0;
+ }
+
+ ie_softc[unit].iosize = size;
+ ie_softc[unit].iomem = (caddr_t)realbase;
+
+ ie_softc[unit].iscp = iscp;
+ ie_softc[unit].scb = scb;
+
+ /*
+ * Acknowledge any interrupts we may have caused...
+ */
+ ie_ack(scb, IE_ST_WHENCE, unit, ie_softc[unit].ie_chan_attn);
+ splx(s);
+
+ return 1;
+}
+
+/*
+ * Divine the memory size of ie board UNIT.
+ * Better hope there's nothing important hiding just below the ie card...
+ */
+static void find_ie_mem_size(unit)
+ int unit;
+{
+ unsigned size;
+
+ ie_softc[unit].iosize = 0;
+
+ for(size = 65536; size >= 16384; size -= 16384) {
+ if(check_ie_present(unit, ie_softc[unit].iomembot, size)) {
+ return;
+ }
+ }
+
+ return;
+}
+
+void sl_reset_586(unit)
+ int unit;
+{
+ outb(PORT + IEATT_RESET, 0);
+}
+
+void sl_chan_attn(unit)
+ int unit;
+{
+ outb(PORT + IEATT_ATTN, 0);
+}
+
+void sl_read_ether(unit, addr)
+ int unit;
+ unsigned char addr[6];
+{
+ int i;
+
+ for(i = 0; i < 6; i++)
+ addr[i] = inb(PORT + i);
+}
+
+
+static void
+iereset(unit, dummy)
+ int unit, dummy;
+{
+ int s = splimp();
+
+ if(unit >= NIE) {
+ splx(s);
+ return;
+ }
+
+ printf("ie%d: reset\n", unit);
+ ie_softc[unit].arpcom.ac_if.if_flags &= ~IFF_UP;
+ ieioctl(&ie_softc[unit].arpcom.ac_if, SIOCSIFFLAGS, 0);
+
+ /*
+ * Stop i82586 dead in its tracks.
+ */
+ if(command_and_wait(unit, IE_RU_ABORT | IE_CU_ABORT, 0, 0))
+ printf("ie%d: abort commands timed out\n", unit);
+
+ if(command_and_wait(unit, IE_RU_DISABLE | IE_CU_STOP, 0, 0))
+ printf("ie%d: disable commands timed out\n", unit);
+
+#ifdef notdef
+ if(!check_ie_present(unit, ie_softc[unit].iomembot, ie_softc[unit].iosize))
+ panic("ie disappeared!\n");
+#endif
+
+ ie_softc[unit].arpcom.ac_if.if_flags |= IFF_UP;
+ ieioctl(&ie_softc[unit].arpcom.ac_if, SIOCSIFFLAGS, 0);
+
+ splx(s);
+ return;
+}
+
+/*
+ * This is called if we time out.
+ */
+static void
+chan_attn_timeout(rock, arg2)
+ caddr_t rock;
+ int arg2;
+{
+ *(int *)rock = 1;
+}
+
+/*
+ * Send a command to the controller and wait for it to either
+ * complete or be accepted, depending on the command. If the
+ * command pointer is null, then pretend that the command is
+ * not an action command. If the command pointer is not null,
+ * and the command is an action command, wait for
+ * ((volatile struct ie_cmd_common *)pcmd)->ie_cmd_status & MASK
+ * to become true.
+ */
+static int command_and_wait(unit, cmd, pcmd, mask)
+ int unit;
+ int cmd;
+ volatile void *pcmd;
+ int mask;
+{
+ volatile struct ie_cmd_common *cc = pcmd;
+ volatile int timedout = 0;
+ extern int hz;
+
+ ie_softc[unit].scb->ie_command = (u_short)cmd;
+
+ if(IE_ACTION_COMMAND(cmd) && pcmd) {
+ (*ie_softc[unit].ie_chan_attn)(unit);
+
+ /*
+ * According to the packet driver, the minimum timeout should be
+ * .369 seconds, which we round up to .37.
+ */
+ timeout(chan_attn_timeout, (caddr_t)&timedout, 37 * hz / 100);
+ /* ignore cast-qual */
+
+ /*
+ * Now spin-lock waiting for status. This is not a very nice
+ * thing to do, but I haven't figured out how, or indeed if, we
+ * can put the process waiting for action to sleep. (We may
+ * be getting called through some other timeout running in the
+ * kernel.)
+ */
+ while(1) {
+ if((cc->ie_cmd_status & mask) || timedout)
+ break;
+ }
+
+ untimeout(chan_attn_timeout, (caddr_t)&timedout);
+ /* ignore cast-qual */
+
+ return timedout;
+ } else {
+
+ /*
+ * Otherwise, just wait for the command to be accepted.
+ */
+ (*ie_softc[unit].ie_chan_attn)(unit);
+
+ while(ie_softc[unit].scb->ie_command)
+ ; /* spin lock */
+
+ return 0;
+ }
+}
+
+/*
+ * Run the time-domain reflectometer...
+ */
+static void run_tdr(unit, cmd)
+ int unit;
+ struct ie_tdr_cmd *cmd;
+{
+ int result;
+
+ cmd->com.ie_cmd_status = 0;
+ cmd->com.ie_cmd_cmd = IE_CMD_TDR | IE_CMD_LAST;
+ cmd->com.ie_cmd_link = 0xffff;
+ cmd->ie_tdr_time = 0;
+
+ ie_softc[unit].scb->ie_command_list = MK_16(MEM, cmd);
+ cmd->ie_tdr_time = 0;
+
+ if(command_and_wait(unit, IE_CU_START, cmd, IE_STAT_COMPL))
+ result = 0x2000;
+ else
+ result = cmd->ie_tdr_time;
+
+ ie_ack(ie_softc[unit].scb, IE_ST_WHENCE, unit,
+ ie_softc[unit].ie_chan_attn);
+
+ if(result & IE_TDR_SUCCESS)
+ return;
+
+ if(result & IE_TDR_XCVR) {
+ printf("ie%d: transceiver problem\n", unit);
+ } else if(result & IE_TDR_OPEN) {
+ printf("ie%d: TDR detected an open %d clocks away\n", unit,
+ result & IE_TDR_TIME);
+ } else if(result & IE_TDR_SHORT) {
+ printf("ie%d: TDR detected a short %d clocks away\n", unit,
+ result & IE_TDR_TIME);
+ } else {
+ printf("ie%d: TDR returned unknown status %x\n", result);
+ }
+}
+
+static void start_receiver(unit)
+ int unit;
+{
+ int s = splimp();
+
+ ie_softc[unit].scb->ie_recv_list = MK_16(MEM, ie_softc[unit].rframes[0]);
+ command_and_wait(unit, IE_RU_START, 0, 0);
+
+ ie_ack(ie_softc[unit].scb, IE_ST_WHENCE, unit, ie_softc[unit].ie_chan_attn);
+
+ splx(s);
+}
+
+/*
+ * Here is a helper routine for iernr() and ieinit(). This sets up
+ * the RFA.
+ */
+static caddr_t setup_rfa(caddr_t ptr, struct ie_softc *ie) {
+ volatile struct ie_recv_frame_desc *rfd = (void *)ptr;
+ volatile struct ie_recv_buf_desc *rbd;
+ int i;
+ int unit = ie - &ie_softc[0];
+
+ /* First lay them out */
+ for(i = 0; i < NFRAMES; i++) {
+ ie->rframes[i] = rfd;
+ bzero((char *)rfd, sizeof *rfd); /* ignore cast-qual */
+ rfd++;
+ }
+
+ ptr = (caddr_t)Align((caddr_t)rfd); /* ignore cast-qual */
+
+ /* Now link them together */
+ for(i = 0; i < NFRAMES; i++) {
+ ie->rframes[i]->ie_fd_next =
+ MK_16(MEM, ie->rframes[(i + 1) % NFRAMES]);
+ }
+
+ /* Finally, set the EOL bit on the last one. */
+ ie->rframes[NFRAMES - 1]->ie_fd_last |= IE_FD_LAST;
+
+ /*
+ * Now lay out some buffers for the incoming frames. Note that
+ * we set aside a bit of slop in each buffer, to make sure that
+ * we have enough space to hold a single frame in every buffer.
+ */
+ rbd = (void *)ptr;
+
+ for(i = 0; i < NBUFFS; i++) {
+ ie->rbuffs[i] = rbd;
+ bzero((char *)rbd, sizeof *rbd); /* ignore cast-qual */
+ ptr = (caddr_t)Align(ptr + sizeof *rbd);
+ rbd->ie_rbd_length = IE_RBUF_SIZE;
+ rbd->ie_rbd_buffer = MK_24(MEM, ptr);
+ ie->cbuffs[i] = (void *)ptr;
+ ptr += IE_RBUF_SIZE;
+ rbd = (void *)ptr;
+ }
+
+ /* Now link them together */
+ for(i = 0; i < NBUFFS; i++) {
+ ie->rbuffs[i]->ie_rbd_next = MK_16(MEM, ie->rbuffs[(i + 1) % NBUFFS]);
+ }
+
+ /* Tag EOF on the last one */
+ ie->rbuffs[NBUFFS - 1]->ie_rbd_length |= IE_RBD_LAST;
+
+ /* We use the head and tail pointers on receive to keep track of
+ * the order in which RFDs and RBDs are used. */
+ ie->rfhead = 0;
+ ie->rftail = NFRAMES - 1;
+ ie->rbhead = 0;
+ ie->rbtail = NBUFFS - 1;
+
+ ie->scb->ie_recv_list = MK_16(MEM, ie->rframes[0]);
+ ie->rframes[0]->ie_fd_buf_desc = MK_16(MEM, ie->rbuffs[0]);
+
+ ptr = Align(ptr);
+ return ptr;
+}
+
+/*
+ * Run the multicast setup command.
+ * Call at splimp().
+ */
+static int mc_setup(int unit, caddr_t ptr,
+ volatile struct ie_sys_ctl_block *scb) {
+ struct ie_softc *ie = &ie_softc[unit];
+ volatile struct ie_mcast_cmd *cmd = (void *)ptr;
+
+ cmd->com.ie_cmd_status = 0;
+ cmd->com.ie_cmd_cmd = IE_CMD_MCAST | IE_CMD_LAST;
+ cmd->com.ie_cmd_link = 0xffff;
+
+ /* ignore cast-qual */
+ bcopy((caddr_t)ie->mcast_addrs, (caddr_t)cmd->ie_mcast_addrs,
+ ie->mcast_count * sizeof *ie->mcast_addrs);
+
+ cmd->ie_mcast_bytes = ie->mcast_count * 6; /* grrr... */
+
+ scb->ie_command_list = MK_16(MEM, cmd);
+ if(command_and_wait(unit, IE_CU_START, cmd, IE_STAT_COMPL)
+ || !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
+ printf("ie%d: multicast address setup command failed\n", unit);
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * This routine takes the environment generated by check_ie_present()
+ * and adds to it all the other structures we need to operate the adapter.
+ * This includes executing the CONFIGURE, IA-SETUP, and MC-SETUP commands,
+ * starting the receiver unit, and clearing interrupts.
+ *
+ * THIS ROUTINE MUST BE CALLED AT splimp() OR HIGHER.
+ */
+static void
+ieinit(unit)
+ int unit;
+{
+ struct ie_softc *ie = &ie_softc[unit];
+ volatile struct ie_sys_ctl_block *scb = ie->scb;
+ caddr_t ptr;
+
+ ptr = (caddr_t)Align((caddr_t)scb + sizeof *scb); /* ignore cast-qual */
+
+ /*
+ * Send the configure command first.
+ */
+ {
+ volatile struct ie_config_cmd *cmd = (void *)ptr;
+
+ ie_setup_config(cmd, ie->promisc, ie->hard_type == IE_STARLAN10);
+ cmd->com.ie_cmd_status = 0;
+ cmd->com.ie_cmd_cmd = IE_CMD_CONFIG | IE_CMD_LAST;
+ cmd->com.ie_cmd_link = 0xffff;
+
+ scb->ie_command_list = MK_16(MEM, cmd);
+
+ if(command_and_wait(unit, IE_CU_START, cmd, IE_STAT_COMPL)
+ || !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
+ printf("ie%d: configure command failed\n", unit);
+ return;
+ }
+ }
+ /*
+ * Now send the Individual Address Setup command.
+ */
+ {
+ volatile struct ie_iasetup_cmd *cmd = (void *)ptr;
+
+ cmd->com.ie_cmd_status = 0;
+ cmd->com.ie_cmd_cmd = IE_CMD_IASETUP | IE_CMD_LAST;
+ cmd->com.ie_cmd_link = 0xffff;
+
+ bcopy((char *)ie_softc[unit].arpcom.ac_enaddr, (char *)&cmd->ie_address,
+ sizeof cmd->ie_address); /* ignore cast-qual */
+
+ scb->ie_command_list = MK_16(MEM, cmd);
+ if(command_and_wait(unit, IE_CU_START, cmd, IE_STAT_COMPL)
+ || !(cmd->com.ie_cmd_status & IE_STAT_OK)) {
+ printf("ie%d: individual address setup command failed\n", unit);
+ return;
+ }
+ }
+
+ /*
+ * Now run the time-domain reflectometer.
+ */
+ run_tdr(unit, (void *)ptr);
+
+ /*
+ * Acknowledge any interrupts we have generated thus far.
+ */
+ ie_ack(ie->scb, IE_ST_WHENCE, unit, ie->ie_chan_attn);
+
+ /*
+ * Set up the RFA.
+ */
+ ptr = setup_rfa(ptr, ie);
+
+ /*
+ * Finally, the transmit command and buffer are the last little bit of work.
+ */
+ ie->xmit_cmds[0] = (void *)ptr;
+ ptr += sizeof *ie->xmit_cmds[0];
+ ptr = Align(ptr);
+ ie->xmit_buffs[0] = (void *)ptr;
+ ptr += sizeof *ie->xmit_buffs[0];
+ ptr = Align(ptr);
+
+ /* Second transmit command */
+ ie->xmit_cmds[1] = (void *)ptr;
+ ptr += sizeof *ie->xmit_cmds[1];
+ ptr = Align(ptr);
+ ie->xmit_buffs[1] = (void *)ptr;
+ ptr += sizeof *ie->xmit_buffs[1];
+ ptr = Align(ptr);
+
+ /* Both transmit buffers */
+ ie->xmit_cbuffs[0] = (void *)ptr;
+ ptr += IE_BUF_LEN;
+ ptr = Align(ptr);
+ ie->xmit_cbuffs[1] = (void *)ptr;
+
+ bzero((caddr_t)ie->xmit_cmds[0], sizeof *ie->xmit_cmds[0]); /* ignore */
+ bzero((caddr_t)ie->xmit_buffs[0], sizeof *ie->xmit_buffs[0]); /* cast-qual */
+ bzero((caddr_t)ie->xmit_cmds[1], sizeof *ie->xmit_cmds[0]); /* warnings */
+ bzero((caddr_t)ie->xmit_buffs[1], sizeof *ie->xmit_buffs[0]); /* here */
+
+ /*
+ * This must be coordinated with iestart() and ietint().
+ */
+ ie->xmit_cmds[0]->ie_xmit_status = IE_STAT_COMPL;
+
+ ie->arpcom.ac_if.if_flags |= IFF_RUNNING; /* tell higher levels that we are here */
+ start_receiver(unit);
+ return;
+}
+
+static void ie_stop(unit)
+ int unit;
+{
+ command_and_wait(unit, IE_RU_DISABLE, 0, 0);
+}
+
+static int
+ieioctl(ifp, command, data)
+ struct ifnet *ifp;
+ int command;
+ caddr_t data;
+{
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ struct ie_softc *ie = &ie_softc[ifp->if_unit];
+ int s, error = 0;
+
+ s = splimp();
+
+ switch(command) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+
+ switch(ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ ieinit(ifp->if_unit);
+ ((struct arpcom *)ifp)->ac_ipaddr =
+ IA_SIN(ifa)->sin_addr;
+ arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
+ break;
+#endif /* INET */
+
+#ifdef NS
+ /* This magic copied from if_is.c; I don't use XNS, so I have no
+ * way of telling if this actually works or not.
+ */
+ case AF_NS:
+ {
+ struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+
+ if(ns_nullhost(*ina)) {
+ ina->x_host = *(union ns_host *)(ie->arpcom.ac_enaddr);
+ } else {
+ ifp->if_flags &= ~IFF_RUNNING;
+ bcopy((caddr_t)ina->x_host.c_host,
+ (caddr_t)ie->arpcom.ac_enaddr,
+ sizeof ie->arpcom.ac_enaddr);
+ }
+
+ ieinit(ifp->if_unit);
+ }
+ break;
+#endif /* NS */
+
+ default:
+ ieinit(ifp->if_unit);
+ break;
+ }
+ break;
+
+ case SIOCSIFFLAGS:
+ /*
+ * Note that this device doesn't have an "all multicast" mode, so we
+ * must turn on promiscuous mode and do the filtering manually.
+ */
+ if((ifp->if_flags & IFF_UP) == 0 &&
+ (ifp->if_flags & IFF_RUNNING)) {
+ ifp->if_flags &= ~IFF_RUNNING;
+ ie_stop(ifp->if_unit);
+ } else if((ifp->if_flags & IFF_UP) &&
+ (ifp->if_flags & IFF_RUNNING) == 0) {
+ ie_softc[ifp->if_unit].promisc =
+ ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI);
+ ieinit(ifp->if_unit);
+ } else if(ie_softc[ifp->if_unit].promisc ^
+ (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI))) {
+ ie_softc[ifp->if_unit].promisc =
+ ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI);
+ ieinit(ifp->if_unit);
+ }
+ break;
+
+#ifdef MULTICAST
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ /*
+ * Update multicast listeners
+ */
+ error = ((command == SIOCADDMULTI)
+ ? ether_addmulti((struct ifreq *)data, &ie->arpcom)
+ : ether_delmulti((struct ifreq *)data, &ie->arpcom));
+
+ if(error == ENETRESET) {
+ /* reset multicast filtering */
+ ie_mc_reset(ifp->if_unit);
+ error = 0;
+ }
+ break;
+#endif /* MULTICAST */
+
+ default:
+ error = EINVAL;
+ }
+
+ splx(s);
+ return error;
+}
+
+#ifdef MULTICAST
+static void ie_mc_reset(int unit) {
+ struct ie_softc *ie = &ie_softc[unit];
+ struct ether_multi *enm;
+ struct ether_multistep step;
+
+ /*
+ * Step through the list of addresses.
+ */
+ ie->mcast_count = 0;
+ ETHER_FIRST_MULTI(step, &ie->arpcom, enm);
+ while(enm) {
+ if(ie->mcast_count >= MAXMCAST
+ || bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
+ ie->arpcom.ac_if.if_flags |= IFF_ALLMULTI;
+ ieioctl(&ie->arpcom.ac_if, SIOCSIFFLAGS, (void *)0);
+ goto setflag;
+ }
+
+ bcopy(enm->enm_addrlo, &(ie->mcast_addrs[ie->mcast_count]), 6);
+ ie->mcast_count++;
+ ETHER_NEXT_MULTI(step, enm);
+ }
+
+setflag:
+ ie->want_mcsetup = 1;
+}
+
+#endif
+
+#ifdef DEBUG
+void print_rbd(volatile struct ie_recv_buf_desc *rbd) {
+ printf("RBD at %08lx:\n"
+ "actual %04x, next %04x, buffer %08x\n"
+ "length %04x, mbz %04x\n",
+ (unsigned long)rbd,
+ rbd->ie_rbd_actual, rbd->ie_rbd_next, rbd->ie_rbd_buffer,
+ rbd->ie_rbd_length, rbd->mbz);
+}
+#endif /* DEBUG */
+#endif /* NIE > 0 */
+
diff --git a/sys/i386/isa/if_iereg.h b/sys/i386/isa/if_iereg.h
new file mode 100644
index 0000000..3588b84
--- /dev/null
+++ b/sys/i386/isa/if_iereg.h
@@ -0,0 +1,24 @@
+/*
+ * $Id$
+ * definitions for AT&T StarLAN 10 etc...
+ */
+
+#define IEATT_RESET 0 /* any write here resets the 586 */
+#define IEATT_ATTN 1 /* any write here sends a Chan attn */
+#define IEATT_REVISION 6 /* read here to figure out this board */
+#define IEATT_ATTRIB 7 /* more information about this board */
+
+#define SL_BOARD(x) ((x) & 0x0f)
+#define SL_REV(x) ((x) >> 4)
+
+#define SL1_BOARD 0
+#define SL10_BOARD 1
+#define EN100_BOARD 2
+#define SLFIBER_BOARD 3
+
+#define SL_ATTR_WIDTH 0x04 /* bus width: clear -> 8-bit */
+#define SL_ATTR_SPEED 0x08 /* medium speed: clear -> 10 Mbps */
+#define SL_ATTR_CODING 0x10 /* encoding: clear -> Manchester */
+#define SL_ATTR_HBW 0x20 /* host bus width: clear -> 16-bit */
+#define SL_ATTR_TYPE 0x40 /* medium type: clear -> Ethernet */
+#define SL_ATTR_BOOTROM 0x80 /* set -> boot ROM present */
diff --git a/sys/i386/isa/if_is.c b/sys/i386/isa/if_is.c
new file mode 100644
index 0000000..9f0e6ad
--- /dev/null
+++ b/sys/i386/isa/if_is.c
@@ -0,0 +1,1148 @@
+/*
+ * Isolan AT 4141-0 Ethernet driver
+ * Isolink 4110
+ *
+ * By Paul Richards
+ *
+ * Copyright (C) 1993, Paul Richards. This software may be used, modified,
+ * copied, distributed, and sold, in both source and binary form provided
+ * that the above copyright and these terms are retained. Under no
+ * circumstances is the author responsible for the proper functioning
+ * of this software, nor does the author assume any responsibility
+ * for damages incurred with its use.
+ *
+*/
+
+/* TODO
+
+1) Add working multicast support
+2) Use better allocation of memory to card
+3) Advertise for more packets until all transmit buffers are full
+4) Add more of the timers/counters e.g. arpcom.opackets etc.
+*/
+
+#include "is.h"
+#if NIS > 0
+
+#include "bpfilter.h"
+
+#include "param.h"
+#include "systm.h"
+#include "errno.h"
+#include "ioctl.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "syslog.h"
+
+#include "net/if.h"
+#include "net/if_dl.h"
+#include "net/if_types.h"
+
+#ifdef INET
+#include "netinet/in.h"
+#include "netinet/in_systm.h"
+#include "netinet/in_var.h"
+#include "netinet/ip.h"
+#include "netinet/if_ether.h"
+#endif
+
+#ifdef NS
+#include "netns/ns.h"
+#include "netns/ns_if.h"
+#endif
+
+#if NBPFILTER > 0
+#include "net/bpf.h"
+#include "net/bpfdesc.h"
+#endif
+
+#include "i386/isa/isa_device.h"
+#include "i386/isa/if_isreg.h"
+#include "i386/isa/icu.h"
+
+#include "vm/vm.h"
+
+#define ETHER_MIN_LEN 64
+#define ETHER_MAX_LEN 1518
+#define ETHER_ADDR_LEN 6
+
+char *card_type[] = {"Unknown",
+ "BICC Isolan",
+ "NE2100"};
+
+char *ic_type[] = {"Unknown",
+ "Am7990 LANCE",
+ "Am79960 PCnet_ISA"};
+
+
+struct is_softc {
+ struct arpcom arpcom; /* Ethernet common part */
+ int iobase;
+ int rap;
+ int rdp;
+ int ic_type; /* Am 7990 or Am79960 */
+ int card_type;
+ int is_debug;
+ struct init_block *init_block; /* Lance initialisation block */
+ struct mds *rd;
+ struct mds *td;
+ unsigned char *rbuf;
+ unsigned char *tbuf;
+ int last_rd;
+ int last_td;
+ int no_td;
+ caddr_t bpf; /* BPF "magic cookie" */
+
+} is_softc[NIS] ;
+
+
+/* Function prototypes */
+static int is_probe(struct isa_device *);
+static int is_attach(struct isa_device *);
+static void is_watchdog(int);
+static int is_ioctl(struct ifnet *, int, caddr_t);
+static void is_init(int);
+static void is_start(struct ifnet *);
+static void istint(int);
+static void recv_print(int, int);
+static void xmit_print(int, int);
+
+
+
+static inline void is_rint(int unit);
+static inline void isread(struct is_softc*, unsigned char*, int);
+
+struct mbuf *isget();
+
+struct isa_driver isdriver = {
+ is_probe,
+ is_attach,
+ "is"
+};
+
+void
+iswrcsr(unit,port,val)
+ int unit;
+ u_short port;
+ u_short val;
+{
+ outw(is_softc[unit].rap,port);
+ outw(is_softc[unit].rdp,val);
+}
+
+u_short isrdcsr(unit,port)
+ int unit;
+ u_short port;
+{
+ outw(is_softc[unit].rap,port);
+ return(inw(is_softc[unit].rdp));
+}
+
+int
+is_probe(isa_dev)
+ struct isa_device *isa_dev;
+{
+ int unit = isa_dev->id_unit ;
+ int nports;
+
+int i;
+ is_softc[unit].iobase = isa_dev->id_iobase;
+
+ /*
+ * It's impossible to do a non-invasive probe of the
+ * LANCE and PCnet_ISA. The LANCE requires setting the
+ * STOP bit to access the registers and the PCnet_ISA
+ * address port resets to an unknown state!!
+ */
+
+ /*
+ * Check for BICC cards first since for the NE2100 and
+ * PCnet-ISA cards this write will hit the Address PROM.
+ */
+
+#ifdef DEBUG
+ printf("Dumping io space for is%d starting at %x\n",unit,is_softc[unit].iobase);
+ for (i=0; i< 32; i++)
+ printf(" %x ",inb(is_softc[unit].iobase+i));
+ printf("\n");
+#endif /* DEBUG*/
+
+ if (nports = bicc_probe(unit))
+ return (nports);
+ if (nports = ne2100_probe(unit))
+ return (nports);
+
+
+ return (0);
+}
+
+int
+ne2100_probe(unit)
+ int unit;
+{
+struct is_softc *is = &is_softc[unit];
+int i;
+
+ is->rap = is->iobase + NE2100_RAP;
+ is->rdp = is->iobase + NE2100_RDP;
+
+ if (is->ic_type = lance_probe(unit)) {
+ is->card_type = NE2100;
+ /*
+ * Extract the physical MAC address from ROM
+ */
+ for(i=0;i<ETHER_ADDR_LEN;i++)
+ is->arpcom.ac_enaddr[i]=inb(is->iobase+i);
+
+ /*
+ * Return number of I/O ports used by card
+ */
+ return (24);
+ }
+ return (0);
+}
+
+
+int
+bicc_probe(unit)
+ int unit;
+{
+struct is_softc *is = &is_softc[unit];
+int i;
+
+ is->rap = is->iobase + BICC_RAP;
+ is->rdp = is->iobase + BICC_RDP;
+
+ if (is->ic_type = lance_probe(unit)) {
+ is->card_type = BICC;
+
+ /*
+ * Extract the physical ethernet address from ROM
+ */
+
+ for(i=0;i<ETHER_ADDR_LEN;i++)
+ is->arpcom.ac_enaddr[i]=inb(is->iobase+(i*2));
+
+ /*
+ * Return number of I/O ports used by card
+ */
+ return (16);
+ }
+ return (0);
+}
+
+
+/*
+ * Determine which, if any, of the LANCE or
+ * PCnet-ISA are present on the card.
+ */
+
+int
+lance_probe(unit)
+ int unit;
+{
+int type=0;
+
+ /*
+ * Have to reset the LANCE to get any
+ * stable information from it.
+ */
+
+ iswrcsr(unit,0,STOP);
+ DELAY(100);
+
+ if (isrdcsr(unit,0) != STOP)
+ /*
+ * This either isn't a LANCE
+ * or there's a major problem.
+ */
+ return(0);
+
+ /*
+ * Depending on which controller it is, CSR3 will have
+ * different settable bits. Write to them all and see which ones
+ * get set.
+ */
+
+ iswrcsr(unit,3, LANCE_MASK);
+
+ if (isrdcsr(unit,3) == LANCE_MASK)
+ type = LANCE;
+
+ if (isrdcsr(unit,3) == PCnet_ISA_MASK)
+ type = PCnet_ISA;
+
+ return (type);
+}
+
+/*
+ * Reset of interface.
+ */
+static void
+is_reset(int unit, int uban)
+{
+ int s;
+ struct is_softc *is = &is_softc[unit];
+
+ if (unit >= NIS)
+ return;
+ printf("is%d: reset\n", unit);
+ is_init(unit);
+}
+
+/*
+ * Interface exists: make available by filling in network interface
+ * record. System will initialize the interface when it is ready
+ * to accept packets. We get the ethernet address here.
+ */
+int
+is_attach(isa_dev)
+ struct isa_device *isa_dev;
+{
+ int unit = isa_dev->id_unit;
+ struct is_softc *is = &is_softc[unit];
+ struct ifnet *ifp = &is->arpcom.ac_if;
+ struct ifaddr *ifa;
+ struct sockaddr_dl *sdl;
+
+ ifp->if_unit = unit;
+ ifp->if_name = isdriver.name ;
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
+ ifp->if_init = is_init;
+ ifp->if_output = ether_output;
+ ifp->if_start = is_start;
+ ifp->if_ioctl = is_ioctl;
+ ifp->if_reset = is_reset;
+ ifp->if_watchdog = is_watchdog;
+
+ /*
+ * XXX -- not sure this is right place to do this
+ * Allocate memory for use by Lance
+ * Memory allocated for:
+ * initialisation block,
+ * ring descriptors,
+ * transmit and receive buffers.
+ */
+
+ /*
+ * XXX - hopefully have better way to get dma'able memory later,
+ * this code assumes that the physical memory address returned
+ * from malloc will be below 16Mb. The Lance's address registers
+ * are only 16 bits wide!
+ */
+
+#define MAXMEM ((NRBUF+NTBUF)*(BUFSIZE) + (NRBUF+NTBUF)*sizeof(struct mds) \
+ + sizeof(struct init_block) + 8)
+ is->init_block = (struct init_block *)malloc(MAXMEM,M_TEMP,M_NOWAIT);
+ if (!is->init_block) {
+ printf("is%d : Couldn't allocate memory for card\n",unit);
+ }
+ /*
+ * XXX -- should take corrective action if not
+ * quadword alilgned, the 8 byte slew factor in MAXMEM
+ * allows for this.
+ */
+
+ if ((u_long)is->init_block & 0x3)
+ printf("is%d: memory allocated not quadword aligned\n");
+
+ /* Set up DMA */
+ isa_dmacascade(isa_dev->id_drq);
+
+ if_attach(ifp);
+
+ /*
+ * Search down the ifa address list looking
+ * for the AF_LINK type entry
+ */
+
+ ifa = ifp->if_addrlist;
+ while ((ifa != 0) && (ifa->ifa_addr != 0) &&
+ (ifa->ifa_addr->sa_family != AF_LINK))
+ ifa = ifa->ifa_next;
+
+ /*
+ * If we find an AF_LINK type entry, we will fill
+ * in the hardware address for this interface.
+ */
+
+ if ((ifa != 0) && (ifa->ifa_addr != 0)) {
+
+ /*
+ * Fill in the link level address for this interface
+ */
+
+ sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ sdl->sdl_type = IFT_ETHER;
+ sdl->sdl_alen = ETHER_ADDR_LEN;
+ sdl->sdl_slen = 0;
+ bcopy(is->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN);
+ }
+
+ printf ("is%d: address %s\n", unit,
+ ether_sprintf(is->arpcom.ac_enaddr)) ;
+ printf("%s, %s\n",ic_type[is->ic_type],card_type[is->card_type]);
+
+#if NBPFILTER > 0
+ bpfattach(&is->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+ return 1;
+}
+
+static void
+is_watchdog(unit)
+ int unit;
+{
+ log(LOG_ERR, "is%d: device timeout\n", unit);
+ is_reset(unit, 0);
+}
+
+
+/* Lance initialisation block set up */
+void
+init_mem(unit)
+ int unit;
+{
+ int i;
+ void *temp;
+ struct is_softc *is = &is_softc[unit];
+
+ /*
+ * At this point we assume that the
+ * memory allocated to the Lance is
+ * quadword aligned. If it isn't
+ * then the initialisation is going
+ * fail later on.
+ */
+
+
+ /*
+ * Set up lance initialisation block
+ */
+
+ temp = (void *)is->init_block;
+ temp += sizeof(struct init_block);
+ is->rd = (struct mds *) temp;
+ is->td = (struct mds *) (temp + (NRBUF*sizeof(struct mds)));
+ temp += (NRBUF+NTBUF) * sizeof(struct mds);
+
+ is->init_block->mode = 0;
+ for (i=0; i<ETHER_ADDR_LEN; i++)
+ is->init_block->padr[i] = is->arpcom.ac_enaddr[i];
+ for (i = 0; i < 8; ++i)
+ is->init_block->ladrf[i] = MULTI_INIT_ADDR;
+ is->init_block->rdra = kvtop(is->rd);
+ is->init_block->rlen = ((kvtop(is->rd) >> 16) & 0xff) | (RLEN<<13);
+ is->init_block->tdra = kvtop(is->td);
+ is->init_block->tlen = ((kvtop(is->td) >> 16) & 0xff) | (TLEN<<13);
+
+
+ /*
+ * Set up receive ring descriptors
+ */
+
+ is->rbuf = (unsigned char *)temp;
+ for (i=0; i<NRBUF; i++) {
+ (is->rd+i)->addr = kvtop(temp);
+ (is->rd+i)->flags= ((kvtop(temp) >> 16) & 0xff) | OWN;
+ (is->rd+i)->bcnt = -BUFSIZE;
+ (is->rd+i)->mcnt = 0;
+ temp += BUFSIZE;
+ }
+
+ /*
+ * Set up transmit ring descriptors
+ */
+
+ is->tbuf = (unsigned char *)temp;
+ for (i=0; i<NTBUF; i++) {
+ (is->td+i)->addr = kvtop(temp);
+ (is->td+i)->flags= ((kvtop(temp) >> 16) & 0xff);
+ (is->td+i)->bcnt = 0;
+ (is->td+i)->mcnt = 0;
+ temp += BUFSIZE;
+ }
+
+}
+
+/*
+ * Initialization of interface; set up initialization block
+ * and transmit/receive descriptor rings.
+ */
+
+static void
+is_init(unit)
+ int unit;
+{
+ register struct is_softc *is = &is_softc[unit];
+ struct ifnet *ifp = &is->arpcom.ac_if;
+ int s;
+ register i;
+
+ /* Address not known */
+ if (ifp->if_addrlist == (struct ifaddr *)0) return;
+
+ s = splimp();
+
+ /*
+ * Lance must be stopped
+ * to access registers.
+ */
+
+ iswrcsr(unit,0,STOP);
+
+ is->last_rd = is->last_td = is->no_td = 0;
+
+ /* Set up lance's memory area */
+ init_mem(unit);
+
+ /* No byte swapping etc */
+ iswrcsr(unit,3,0);
+
+ /* Give lance the physical address of its memory area */
+ iswrcsr(unit,1,kvtop(is->init_block));
+ iswrcsr(unit,2,(kvtop(is->init_block) >> 16) & 0xff);
+
+ /* OK, let's try and initialise the Lance */
+ iswrcsr(unit,0,INIT);
+
+ /* Wait for initialisation to finish */
+ for(i=0; i<1000; i++){
+ if (isrdcsr(unit,0)&IDON)
+ break;
+ }
+ if (isrdcsr(unit,0)&IDON) {
+ /* Start lance */
+ iswrcsr(unit,0,STRT|IDON|INEA);
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ is_start(ifp);
+ }
+ else
+ printf("is%d: card failed to initialise\n", unit);
+
+ (void) splx(s);
+}
+
+/*
+ * Setup output on interface.
+ * Get another datagram to send off of the interface queue,
+ * and map it to the interface before starting the output.
+ * called only at splimp or interrupt level.
+ */
+static void
+is_start(ifp)
+ struct ifnet *ifp;
+{
+ int unit = ifp->if_unit;
+ register struct is_softc *is = &is_softc[unit];
+ struct mbuf *m0, *m;
+ unsigned char *buffer;
+ u_short len;
+ int i;
+ struct mds *cdm;
+
+
+ if ((is->arpcom.ac_if.if_flags & IFF_RUNNING) == 0)
+ return;
+
+ do {
+ cdm = (is->td + is->last_td);
+ if (cdm->flags&OWN)
+ return;
+
+ IF_DEQUEUE(&is->arpcom.ac_if.if_snd, m);
+
+ if (m == 0)
+ return;
+
+ /*
+ * Copy the mbuf chain into the transmit buffer
+ */
+
+ buffer = is->tbuf+(BUFSIZE*is->last_td);
+ len=0;
+ for (m0=m; m != 0; m=m->m_next) {
+ bcopy(mtod(m,caddr_t),buffer,m->m_len);
+ buffer += m->m_len;
+ len += m->m_len;
+ }
+#if NBPFILTER > 0
+ if (is->bpf) {
+ u_short etype;
+ int off, datasize, resid;
+ struct ether_header *eh;
+ struct trailer_header {
+ u_short ether_type;
+ u_short ether_residual;
+ } trailer_header;
+ char ether_packet[ETHER_MAX_LEN];
+ char *ep;
+
+ ep = ether_packet;
+
+ /*
+ * We handle trailers below:
+ * Copy ether header first, then residual data,
+ * then data. Put all this in a temporary buffer
+ * 'ether_packet' and send off to bpf. Since the
+ * system has generated this packet, we assume
+ * that all of the offsets in the packet are
+ * correct; if they're not, the system will almost
+ * certainly crash in m_copydata.
+ * We make no assumptions about how the data is
+ * arranged in the mbuf chain (i.e. how much
+ * data is in each mbuf, if mbuf clusters are
+ * used, etc.), which is why we use m_copydata
+ * to get the ether header rather than assume
+ * that this is located in the first mbuf.
+ */
+ /* copy ether header */
+ m_copydata(m0, 0, sizeof(struct ether_header), ep);
+ eh = (struct ether_header *) ep;
+ ep += sizeof(struct ether_header);
+ etype = ntohs(eh->ether_type);
+ if (etype >= ETHERTYPE_TRAIL &&
+ etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+ datasize = ((etype - ETHERTYPE_TRAIL) << 9);
+ off = datasize + sizeof(struct ether_header);
+
+ /* copy trailer_header into a data structure */
+ m_copydata(m0, off, sizeof(struct trailer_header),
+ (caddr_t)&trailer_header.ether_type);
+
+ /* copy residual data */
+ resid = trailer_header.ether_residual -
+ sizeof(struct trailer_header);
+ resid = ntohs(resid);
+ m_copydata(m0, off+sizeof(struct trailer_header),
+ resid, ep);
+ ep += resid;
+
+ /* copy data */
+ m_copydata(m0, sizeof(struct ether_header),
+ datasize, ep);
+ ep += datasize;
+
+ /* restore original ether packet type */
+ eh->ether_type = trailer_header.ether_type;
+
+ bpf_tap(is->bpf, ether_packet, ep - ether_packet);
+ } else
+ bpf_mtap(is->bpf, m0);
+ }
+#endif
+
+
+ m_freem(m0);
+ len = MAX(len,ETHER_MIN_LEN);
+
+ /*
+ * Init transmit registers, and set transmit start flag.
+ */
+
+ cdm->flags |= (OWN|STP|ENP);
+ cdm->bcnt = -len;
+ cdm->mcnt = 0;
+#ifdef ISDEBUG
+ if (is->is_debug)
+ xmit_print(unit,is->last_td);
+#endif
+
+ iswrcsr(unit,0,TDMD|INEA);
+ if (++is->last_td >= NTBUF)
+ is->last_td=0;
+ }while(++is->no_td < NTBUF);
+ is->no_td = NTBUF;
+ is->arpcom.ac_if.if_flags |= IFF_OACTIVE;
+#ifdef ISDEBUG
+ if (is->is_debug)
+ printf("no_td = %x, last_td = %x\n",is->no_td, is->last_td);
+#endif
+}
+
+
+/*
+ * Controller interrupt.
+ */
+void
+isintr(unit)
+ int unit;
+{
+ register struct is_softc *is = &is_softc[unit];
+ u_short isr;
+
+ while((isr=isrdcsr(unit,0))&INTR) {
+ if (isr&ERR) {
+ if (isr&BABL){
+ printf("is%d: BABL\n",unit);
+ is->arpcom.ac_if.if_oerrors++;
+ }
+ if (isr&CERR) {
+ printf("is%d: CERR\n",unit);
+ is->arpcom.ac_if.if_collisions++;
+ }
+ if (isr&MISS) {
+ printf("is%d: MISS\n",unit);
+ is->arpcom.ac_if.if_ierrors++;
+ }
+ if (isr&MERR)
+ printf("is%d: MERR\n",unit);
+ iswrcsr(unit,0,BABL|CERR|MISS|MERR|INEA);
+ }
+ if (!(isr&RXON)) {
+ printf("is%d: !(isr&RXON)\n", unit);
+ is->arpcom.ac_if.if_ierrors++;
+ is_reset(unit, 0);
+ return;
+ }
+ if (!(isr&TXON)) {
+ printf("is%d: !(isr&TXON)\n", unit);
+ is->arpcom.ac_if.if_oerrors++;
+ is_reset(unit, 0);
+ return;
+ }
+
+ if (isr&RINT) {
+ /* reset watchdog timer */
+ is->arpcom.ac_if.if_timer = 0;
+ is_rint(unit);
+ }
+ if (isr&TINT) {
+ /* reset watchdog timer */
+ is->arpcom.ac_if.if_timer = 0;
+ iswrcsr(unit,0,TINT|INEA);
+ istint(unit);
+ }
+ }
+}
+
+static void
+istint(unit)
+ int unit;
+{
+ struct is_softc *is = &is_softc[unit];
+ register struct ifnet *ifp = &is->arpcom.ac_if;
+ int i,loopcount=0;
+ struct mds *cdm;
+
+ is->arpcom.ac_if.if_opackets++;
+ do {
+ if ((i=is->last_td - is->no_td) < 0)
+ i+=NTBUF;
+ cdm = (is->td+i);
+#ifdef ISDEBUG
+ if (is->is_debug)
+ printf("Trans cdm = %x\n",cdm);
+#endif
+ if (cdm->flags&OWN) {
+ if (loopcount)
+ break;
+ return;
+ }
+ loopcount++;
+ is->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
+ }while(--is->no_td > 0);
+ is_start(ifp);
+
+}
+
+#define NEXTRDS \
+ if (++rmd == NRBUF) rmd=0, cdm=is->rd; else ++cdm
+
+/* only called from one place, so may as well integrate */
+static inline void is_rint(int unit)
+{
+ register struct is_softc *is=&is_softc[unit];
+ register int rmd = is->last_rd;
+ struct mds *cdm = (is->rd + rmd);
+
+ /* Out of sync with hardware, should never happen */
+
+ if (cdm->flags & OWN) {
+ printf("is%d: error: out of sync\n",unit);
+ iswrcsr(unit,0,RINT|INEA);
+ return;
+ }
+
+ /* Process all buffers with valid data */
+ while (!(cdm->flags&OWN)) {
+ /* Clear interrupt to avoid race condition */
+ iswrcsr(unit,0,RINT|INEA);
+ if (cdm->flags&ERR) {
+ if (cdm->flags&FRAM)
+ printf("is%d: FRAM\n",unit);
+ if (cdm->flags&OFLO)
+ printf("is%d: OFLO\n",unit);
+ if (cdm->flags&CRC)
+ printf("is%d: CRC\n",unit);
+ if (cdm->flags&RBUFF)
+ printf("is%d: RBUFF\n",unit);
+ }else
+ if (cdm->flags&(STP|ENP) != (STP|ENP)) {
+ do {
+ iswrcsr(unit,0,RINT|INEA);
+ cdm->mcnt = 0;
+ cdm->flags |= OWN;
+ NEXTRDS;
+ }while (!(cdm->flags&(OWN|ERR|STP|ENP)));
+ is->last_rd = rmd;
+ printf("is%d: Chained buffer\n",unit);
+ if ((cdm->flags & (OWN|ERR|STP|ENP)) != ENP) {
+ is_reset(unit, 0);
+ return;
+ }
+ }else
+ {
+#ifdef ISDEBUG
+ if (is->is_debug)
+ recv_print(unit,is->last_rd);
+#endif
+ isread(is,is->rbuf+(BUFSIZE*rmd),(int)cdm->mcnt);
+ is->arpcom.ac_if.if_ipackets++;
+ }
+
+ cdm->flags |= OWN;
+ cdm->mcnt = 0;
+ NEXTRDS;
+#ifdef ISDEBUG
+ if (is->is_debug)
+ printf("is->last_rd = %x, cdm = %x\n",is->last_rd,cdm);
+#endif
+ } /* while */
+ is->last_rd = rmd;
+} /* is_rint */
+
+
+/*
+ * Pass a packet to the higher levels.
+ * We deal with the trailer protocol here.
+ */
+static inline void
+isread(struct is_softc *is, unsigned char *buf, int len)
+{
+ register struct ether_header *eh;
+ struct mbuf *m;
+ int off, resid;
+ register struct ifqueue *inq;
+
+ /*
+ * Deal with trailer protocol: if type is trailer type
+ * get true type from first 16-bit word past data.
+ * Remember that type was trailer by setting off.
+ */
+ eh = (struct ether_header *)buf;
+ eh->ether_type = ntohs((u_short)eh->ether_type);
+ len = len - sizeof(struct ether_header) - 4;
+#define nedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
+ if (eh->ether_type >= ETHERTYPE_TRAIL &&
+ eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+ off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
+ if (off >= ETHERMTU) return; /* sanity */
+ eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *));
+ resid = ntohs(*(nedataaddr(eh, off+2, u_short *)));
+ if (off + resid > len) return; /* sanity */
+ len = off + resid;
+ } else off = 0;
+
+ if (len == 0) return;
+
+ /*
+ * Pull packet off interface. Off is nonzero if packet
+ * has trailing header; neget will then force this header
+ * information to be at the front, but we still have to drop
+ * the type and length which are at the front of any trailer data.
+ */
+ m = isget(buf, len, off, &is->arpcom.ac_if);
+ if (m == 0) return;
+#if NBPFILTER > 0
+ /*
+ * Check if there's a BPF listener on this interface.
+ * If so, hand off the raw packet to bpf.
+ */
+ if (is->bpf) {
+ bpf_mtap(is->bpf, m);
+
+ /*
+ * Note that the interface cannot be in promiscuous mode if
+ * there are no BPF listeners. And if we are in promiscuous
+ * mode, we have to check if this packet is really ours.
+ *
+ * XXX This test does not support multicasts.
+ */
+ if ((is->arpcom.ac_if.if_flags & IFF_PROMISC) &&
+ bcmp(eh->ether_dhost, is->arpcom.ac_enaddr,
+ sizeof(eh->ether_dhost)) != 0 &&
+ bcmp(eh->ether_dhost, etherbroadcastaddr,
+ sizeof(eh->ether_dhost)) != 0) {
+
+ m_freem(m);
+ return;
+ }
+ }
+#endif
+
+
+ ether_input(&is->arpcom.ac_if, eh, m);
+}
+
+/*
+ * Supporting routines
+ */
+
+/*
+ * Pull read data off a interface.
+ * Len is length of data, with local net header stripped.
+ * Off is non-zero if a trailer protocol was used, and
+ * gives the offset of the trailer information.
+ * We copy the trailer information and then all the normal
+ * data into mbufs. When full cluster sized units are present
+ * we copy into clusters.
+ */
+struct mbuf *
+isget(buf, totlen, off0, ifp)
+ caddr_t buf;
+ int totlen, off0;
+ struct ifnet *ifp;
+{
+ struct mbuf *top, **mp, *m, *p;
+ int off = off0, len;
+ register caddr_t cp = buf;
+ char *epkt;
+
+ buf += sizeof(struct ether_header);
+ cp = buf;
+ epkt = cp + totlen;
+
+
+ if (off) {
+ cp += off + 2 * sizeof(u_short);
+ totlen -= 2 * sizeof(u_short);
+ }
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == 0)
+ return (0);
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = totlen;
+ m->m_len = MHLEN;
+ top = 0;
+ mp = &top;
+ while (totlen > 0) {
+ if (top) {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == 0) {
+ m_freem(top);
+ return (0);
+ }
+ m->m_len = MLEN;
+ }
+ len = min(totlen, epkt - cp);
+ if (len >= MINCLSIZE) {
+ MCLGET(m, M_DONTWAIT);
+ if (m->m_flags & M_EXT)
+ m->m_len = len = min(len, MCLBYTES);
+ else
+ len = m->m_len;
+ } else {
+ /*
+ * Place initial small packet/header at end of mbuf.
+ */
+ if (len < m->m_len) {
+ if (top == 0 && len + max_linkhdr <= m->m_len)
+ m->m_data += max_linkhdr;
+ m->m_len = len;
+ } else
+ len = m->m_len;
+ }
+ bcopy(cp, mtod(m, caddr_t), (unsigned)len);
+ cp += len;
+ *mp = m;
+ mp = &m->m_next;
+ totlen -= len;
+ if (cp == epkt)
+ cp = buf;
+ }
+ return (top);
+}
+
+
+/*
+ * Process an ioctl request.
+ */
+int
+is_ioctl(ifp, cmd, data)
+ register struct ifnet *ifp;
+ int cmd;
+ caddr_t data;
+{
+ register struct ifaddr *ifa = (struct ifaddr *)data;
+ int unit = ifp->if_unit;
+ struct is_softc *is = &is_softc[unit];
+ struct ifreq *ifr = (struct ifreq *)data;
+ int s, error = 0;
+
+ s = splimp();
+
+ switch (cmd) {
+
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ is_init(ifp->if_unit); /* before arpwhohas */
+ /*
+ * See if another station has *our* IP address.
+ * i.e.: There is an address conflict! If a
+ * conflict exists, a message is sent to the
+ * console.
+ */
+ ((struct arpcom *)ifp)->ac_ipaddr =
+ IA_SIN(ifa)->sin_addr;
+ arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
+ break;
+#endif
+#ifdef NS
+ /*
+ * XXX - This code is probably wrong
+ */
+ case AF_NS:
+ {
+ register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
+
+ if (ns_nullhost(*ina))
+ ina->x_host =
+ *(union ns_host *)(is->arpcom.ac_enaddr);
+ else {
+ /*
+ *
+ */
+ bcopy((caddr_t)ina->x_host.c_host,
+ (caddr_t)is->arpcom.ac_enaddr,
+ sizeof(is->arpcom.ac_enaddr));
+ }
+ /*
+ * Set new address
+ */
+ is_init(ifp->if_unit);
+ break;
+ }
+#endif
+ default:
+ is_init(ifp->if_unit);
+ break;
+ }
+ break;
+
+ case SIOCSIFFLAGS:
+ /*
+ * If interface is marked down and it is running, then stop it
+ */
+ if ((ifp->if_flags & IFF_UP) == 0 &&
+ ifp->if_flags & IFF_RUNNING) {
+ iswrcsr(unit,0,STOP);
+ ifp->if_flags &= ~IFF_RUNNING;
+ } else {
+ /*
+ * If interface is marked up and it is stopped, then start it
+ */
+ if ((ifp->if_flags & IFF_UP) &&
+ (ifp->if_flags & IFF_RUNNING) == 0)
+ is_init(ifp->if_unit);
+ }
+#ifdef ISDEBUG
+ if (ifp->if_flags & IFF_DEBUG)
+ is->is_debug = 1;
+ else
+ is->is_debug = 0;
+#endif
+#if NBPFILTER > 0
+ if (ifp->if_flags & IFF_PROMISC) {
+ /*
+ * Set promiscuous mode on interface.
+ * XXX - for multicasts to work, we would need to
+ * write 1's in all bits of multicast
+ * hashing array. For now we assume that
+ * this was done in is_init().
+ */
+ is->init_block->mode = PROM;
+ } else
+ /*
+ * XXX - for multicasts to work, we would need to
+ * rewrite the multicast hashing array with the
+ * proper hash (would have been destroyed above).
+ */
+ { /* Don't know about this */};
+#endif
+ break;
+
+#ifdef notdef
+ case SIOCGHWADDR:
+ bcopy((caddr_t)is->arpcom.ac_enaddr, (caddr_t) &ifr->ifr_data,
+ sizeof(is->arpcom.ac_enaddr));
+ break;
+#endif
+
+ default:
+ error = EINVAL;
+ }
+ (void) splx(s);
+ return (error);
+}
+
+#ifdef ISDEBUG
+void
+recv_print(unit,no)
+ int unit,no;
+{
+ register struct is_softc *is=&is_softc[unit];
+ struct mds *rmd;
+ int len,i,printed=0;
+
+ rmd = (is->rd+no);
+ len = rmd->mcnt;
+ printf("is%d: Receive buffer %d, len = %d\n",unit,no,len);
+ printf("is%d: Status %x\n",unit,isrdcsr(unit,0));
+ for (i=0; i<len; i++) {
+ if (!printed) {
+ printed=1;
+ printf("is%d: data: ", unit);
+ }
+ printf("%x ",*(is->rbuf+(BUFSIZE*no)+i));
+ }
+ if (printed)
+ printf("\n");
+}
+
+void
+xmit_print(unit,no)
+ int unit,no;
+{
+ register struct is_softc *is=&is_softc[unit];
+ struct mds *rmd;
+ int i, printed=0;
+ u_short len;
+
+ rmd = (is->td+no);
+ len = -(rmd->bcnt);
+ printf("is%d: Transmit buffer %d, len = %d\n",unit,no,len);
+ printf("is%d: Status %x\n",unit,isrdcsr(unit,0));
+ printf("is%d: addr %x, flags %x, bcnt %x, mcnt %x\n",
+ unit,rmd->addr,rmd->flags,rmd->bcnt,rmd->mcnt);
+ for (i=0; i<len; i++) {
+ if (!printed) {
+ printed = 1;
+ printf("is%d: data: ", unit);
+ }
+ printf("%x ",*(is->tbuf+(BUFSIZE*no)+i));
+ }
+ if (printed)
+ printf("\n");
+}
+#endif /* ISDEBUG */
+
+#endif /* NIS > 0 */
diff --git a/sys/i386/isa/if_isreg.h b/sys/i386/isa/if_isreg.h
new file mode 100644
index 0000000..b4b4ece
--- /dev/null
+++ b/sys/i386/isa/if_isreg.h
@@ -0,0 +1,129 @@
+/*
+ * Isolan AT 4141-0 Ethernet driver header file
+ * Isolink 4110
+ *
+ * By Paul Richards
+ *
+ * Copyright (C) 1993, Paul Richards. This software may be used, modified,
+ * copied, distributed, and sold, in both source and binary form provided
+ * that the above copyright and these terms are retained. Under no
+ * circumstances is the author responsible for the proper functioning
+ * of this software, nor does the author assume any responsibility
+ * for damages incurred with its use.
+ *
+ * $Id: if_isreg.h,v 1.3 1993/10/24 04:27:00 paul Exp $
+ */
+
+/*
+ * Initialize multicast address hashing registers to accept
+ * all multicasts (only used when in promiscuous mode)
+ */
+#if NBPFILTER > 0
+#define MULTI_INIT_ADDR 0xff
+#else
+#define MULTI_INIT_ADDR 0
+#endif
+
+/* Declarations specific to this driver */
+#define NTBUF 2
+#define TLEN 1
+#define NRBUF 8
+#define RLEN 3
+#define BUFSIZE 1518
+#define BICC_RDP 0xc
+#define BICC_RAP 0xe
+#define NE2100_RDP 0x10
+#define NE2100_RAP 0x12
+
+/* Board types */
+#define BICC 1
+#define NE2100 2
+
+/* Am7990 or Am79960 */
+#define LANCE 1
+#define LANCE_MASK 0x07
+#define PCnet_ISA 2
+#define PCnet_ISA_MASK 0x0
+
+
+/* Control and status register 0 flags */
+
+#define ERR 0x8000
+#define BABL 0x4000
+#define CERR 0x2000
+#define MISS 0x1000
+#define MERR 0x0800
+#define RINT 0x0400
+#define TINT 0x0200
+#define IDON 0x0100
+#define INTR 0x0080
+#define INEA 0x0040
+#define RXON 0x0020
+#define TXON 0x0010
+#define TDMD 0x0008
+#define STOP 0x0004
+#define STRT 0x0002
+#define INIT 0x0001
+
+/* Coontrol and status register 3 flags */
+
+#define BSWP 0x0004
+#define ACON 0x0002
+#define BCON 0x0001
+
+/* Initialisation block (must be on word boundary) */
+
+struct init_block {
+ u_short mode; /* Mode register */
+ u_char padr[6]; /* Ethernet address */
+ u_char ladrf[8]; /* Logical address filter (multicast) */
+ u_short rdra; /* Low order pointer to receive ring */
+ u_short rlen; /* High order pointer and no. rings */
+ u_short tdra; /* Low order pointer to transmit ring */
+ u_short tlen; /* High order pointer and no rings */
+ };
+
+/* Mode settings */
+
+#define PROM 0x8000 /* Promiscuous */
+#define INTL 0x0040 /* Internal loopback */
+#define DRTY 0x0020 /* Disable retry */
+#define COLL 0x0010 /* Force collision */
+#define DTCR 0x0008 /* Disable transmit crc */
+#define LOOP 0x0004 /* Loop back */
+#define DTX 0x0002 /* Disable transmitter */
+#define DRX 0x0001 /* Disable receiver */
+
+/* Message descriptor structure */
+
+struct mds {
+ u_short addr;
+ u_short flags;
+ u_short bcnt;
+ u_short mcnt;
+ };
+
+/* Receive ring status flags */
+
+#define OWN 0x8000 /* Owner bit, 0=host, 1=Lance */
+#define MDERR 0x4000 /* Error */
+#define FRAM 0x2000 /* Framing error error */
+#define OFLO 0x1000 /* Silo overflow */
+#define CRC 0x0800 /* CRC error */
+#define RBUFF 0x0400 /* Buffer error */
+#define STP 0x0200 /* Start of packet */
+#define ENP 0x0100 /* End of packet */
+
+/* Transmit ring flags */
+
+#define MORE 0x1000 /* More than 1 retry */
+#define ONE 0x0800 /* One retry */
+#define DEF 0x0400 /* Deferred transmit */
+
+/* Transmit errors */
+
+#define TBUFF 0x8000 /* Buffer error */
+#define UFLO 0x4000 /* Silo underflow */
+#define LCOL 0x1000 /* Late collision */
+#define LCAR 0x0800 /* Loss of carrier */
+#define RTRY 0x0400 /* Tried 16 times */
diff --git a/sys/i386/isa/isa.c b/sys/i386/isa/isa.c
new file mode 100644
index 0000000..b0d84ef
--- /dev/null
+++ b/sys/i386/isa/isa.c
@@ -0,0 +1,670 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)isa.c 7.2 (Berkeley) 5/13/91
+ * $Id: isa.c,v 1.16 1994/04/02 20:43:25 ache Exp $
+ */
+
+/*
+ * code to manage AT bus
+ *
+ * 92/08/18 Frank P. MacLachlan (fpm@crash.cts.com):
+ * Fixed uninitialized variable problem and added code to deal
+ * with DMA page boundaries in isa_dmarangecheck(). Fixed word
+ * mode DMA count compution and reorganized DMA setup code in
+ * isa_dmastart()
+ */
+
+#include "param.h"
+#include "systm.h" /* isn't it a joy */
+#include "kernel.h" /* to have three of these */
+#include "conf.h"
+#include "file.h"
+#include "buf.h"
+#include "uio.h"
+#include "syslog.h"
+#include "malloc.h"
+#include "rlist.h"
+#include "machine/segments.h"
+#include "vm/vm.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/ic/i8237.h"
+#include "i386/isa/ic/i8042.h"
+
+/*
+** Register definitions for DMA controller 1 (channels 0..3):
+*/
+#define DMA1_CHN(c) (IO_DMA1 + 1*(2*(c))) /* addr reg for channel c */
+#define DMA1_SMSK (IO_DMA1 + 1*10) /* single mask register */
+#define DMA1_MODE (IO_DMA1 + 1*11) /* mode register */
+#define DMA1_FFC (IO_DMA1 + 1*12) /* clear first/last FF */
+
+/*
+** Register definitions for DMA controller 2 (channels 4..7):
+*/
+#define DMA2_CHN(c) (IO_DMA2 + 2*(2*(c))) /* addr reg for channel c */
+#define DMA2_SMSK (IO_DMA2 + 2*10) /* single mask register */
+#define DMA2_MODE (IO_DMA2 + 2*11) /* mode register */
+#define DMA2_FFC (IO_DMA2 + 2*12) /* clear first/last FF */
+
+void config_isadev __P((struct isa_device *, u_int *));
+
+/*
+ * print a conflict message
+ */
+void
+conflict(dvp, tmpdvp, item, reason, format)
+ struct isa_device *dvp, *tmpdvp;
+ int item;
+ char *reason;
+ char *format;
+{
+ printf("%s%d not probed due to %s conflict with %s%d at ",
+ dvp->id_driver->name, dvp->id_unit, reason,
+ tmpdvp->id_driver->name, tmpdvp->id_unit);
+ printf(format, item);
+ printf("\n");
+}
+
+/*
+ * Check to see if things are alread in use, like IRQ's, I/O addresses
+ * and Memory addresses.
+ */
+int
+haveseen(dvp, tmpdvp)
+ struct isa_device *dvp, *tmpdvp;
+{
+ int status = 0;
+
+ /*
+ * Only check against devices that have already been found
+ */
+ if (tmpdvp->id_alive) {
+ /*
+ * Check for I/O address conflict. We can only check the
+ * starting address of the device against the range of the
+ * device that has already been probed since we do not
+ * know how many I/O addresses this device uses.
+ */
+ if (tmpdvp->id_alive != -1) {
+ if ((dvp->id_iobase >= tmpdvp->id_iobase) &&
+ (dvp->id_iobase <=
+ (tmpdvp->id_iobase + tmpdvp->id_alive - 1))) {
+ conflict(dvp, tmpdvp, dvp->id_iobase,
+ "I/O address", "0x%x");
+ status = 1;
+ }
+ }
+ /*
+ * Check for Memory address conflict. We can check for
+ * range overlap, but it will not catch all cases since the
+ * driver may adjust the msize paramater during probe, for
+ * now we just check that the starting address does not
+ * fall within any allocated region.
+ * XXX could add a second check after the probe for overlap,
+ * since at that time we would know the full range.
+ * XXX KERNBASE is a hack, we should have vaddr in the table!
+ */
+ if(tmpdvp->id_maddr) {
+ if((KERNBASE + dvp->id_maddr >= tmpdvp->id_maddr) &&
+ (KERNBASE + dvp->id_maddr <=
+ (tmpdvp->id_maddr + tmpdvp->id_msize - 1))) {
+ conflict(dvp, tmpdvp, dvp->id_maddr, "maddr",
+ "0x%x");
+ status = 1;
+ }
+ }
+#ifndef COM_MULTIPORT
+ /*
+ * Check for IRQ conflicts.
+ */
+ if(tmpdvp->id_irq) {
+ if (tmpdvp->id_irq == dvp->id_irq) {
+ conflict(dvp, tmpdvp, ffs(dvp->id_irq) - 1,
+ "irq", "%d");
+ status = 1;
+ }
+ }
+#endif
+ /*
+ * Check for DRQ conflicts.
+ */
+ if(tmpdvp->id_drq != -1) {
+ if (tmpdvp->id_drq == dvp->id_drq) {
+ conflict(dvp, tmpdvp, dvp->id_drq,
+ "drq", "%d");
+ status = 1;
+ }
+ }
+ }
+ return (status);
+}
+
+/*
+ * Search through all the isa_devtab_* tables looking for anything that
+ * conflicts with the current device.
+ */
+int
+haveseen_isadev(dvp)
+ struct isa_device *dvp;
+{
+ struct isa_device *tmpdvp;
+ int status = 0;
+
+ for (tmpdvp = isa_devtab_tty; tmpdvp->id_driver; tmpdvp++) {
+ status |= haveseen(dvp, tmpdvp);
+ }
+ for (tmpdvp = isa_devtab_bio; tmpdvp->id_driver; tmpdvp++) {
+ status |= haveseen(dvp, tmpdvp);
+ }
+ for (tmpdvp = isa_devtab_net; tmpdvp->id_driver; tmpdvp++) {
+ status |= haveseen(dvp, tmpdvp);
+ }
+ for (tmpdvp = isa_devtab_null; tmpdvp->id_driver; tmpdvp++) {
+ status |= haveseen(dvp, tmpdvp);
+ }
+ return(status);
+}
+
+/*
+ * Configure all ISA devices
+ */
+void
+isa_configure() {
+ struct isa_device *dvp;
+
+ enable_intr();
+ splhigh();
+ INTREN(IRQ_SLAVE);
+ printf("Probing for devices on the ISA bus:\n");
+ for (dvp = isa_devtab_tty; dvp->id_driver; dvp++) {
+ if (!haveseen_isadev(dvp))
+ config_isadev(dvp,&tty_imask);
+ }
+ for (dvp = isa_devtab_bio; dvp->id_driver; dvp++) {
+ if (!haveseen_isadev(dvp))
+ config_isadev(dvp,&bio_imask);
+ }
+ for (dvp = isa_devtab_net; dvp->id_driver; dvp++) {
+ if (!haveseen_isadev(dvp))
+ config_isadev(dvp,&net_imask);
+ }
+ for (dvp = isa_devtab_null; dvp->id_driver; dvp++) {
+ if (!haveseen_isadev(dvp))
+ config_isadev(dvp,(u_int *) NULL);
+ }
+ bio_imask |= SWI_CLOCK_MASK;
+ net_imask |= SWI_NET_MASK;
+ tty_imask |= SWI_TTY_MASK;
+
+/*
+ * XXX we should really add the tty device to net_imask when the line is
+ * switched to SLIPDISC, and then remove it when it is switched away from
+ * SLIPDISC. No need to block out ALL ttys during a splimp when only one
+ * of them is running slip.
+ *
+ * XXX actually, blocking all ttys during a splimp doesn't matter so much
+ * with sio because the serial interrupt layer doesn't use tty_imask. Only
+ * non-serial ttys suffer. It's more stupid that ALL 'net's are blocked
+ * during spltty.
+ */
+#include "sl.h"
+#if NSL > 0
+ net_imask |= tty_imask;
+ tty_imask = net_imask;
+#endif
+ /* bio_imask |= tty_imask ; can some tty devices use buffers? */
+#ifdef DIAGNOSTIC
+ printf("bio_imask %x tty_imask %x net_imask %x\n",
+ bio_imask, tty_imask, net_imask);
+#endif
+ splnone();
+}
+
+/*
+ * Configure an ISA device.
+ */
+void
+config_isadev(isdp, mp)
+ struct isa_device *isdp;
+ u_int *mp;
+{
+ struct isa_driver *dp = isdp->id_driver;
+
+ if (isdp->id_maddr) {
+ extern u_int atdevbase;
+
+ isdp->id_maddr -= 0xa0000; /* XXX should be a define */
+ isdp->id_maddr += atdevbase;
+ }
+ isdp->id_alive = (*dp->probe)(isdp);
+ if (isdp->id_alive) {
+ /*
+ * Only print the I/O address range if id_alive != -1
+ * Right now this is a temporary fix just for the new
+ * NPX code so that if it finds a 486 that can use trap
+ * 16 it will not report I/O addresses.
+ * Rod Grimes 04/26/94
+ */
+ printf("%s%d", dp->name, isdp->id_unit);
+ if (isdp->id_alive != -1) {
+ printf(" at 0x%x", isdp->id_iobase);
+ if ((isdp->id_iobase + isdp->id_alive - 1) !=
+ isdp->id_iobase) {
+ printf("-0x%x",
+ isdp->id_iobase +
+ isdp->id_alive - 1);
+ }
+ }
+ if(isdp->id_irq)
+ printf(" irq %d", ffs(isdp->id_irq) - 1);
+ if (isdp->id_drq != -1)
+ printf(" drq %d", isdp->id_drq);
+ if (isdp->id_maddr)
+ printf(" maddr 0x%x", kvtop(isdp->id_maddr));
+ if (isdp->id_msize)
+ printf(" msize %d", isdp->id_msize);
+ if (isdp->id_flags)
+ printf(" flags 0x%x", isdp->id_flags);
+ if (isdp->id_iobase) {
+ if (isdp->id_iobase < 0x100) {
+ printf(" on motherboard\n");
+ } else {
+ if (isdp->id_iobase >= 0x1000) {
+ printf (" on eisa\n");
+ } else {
+ printf (" on isa\n");
+ }
+ }
+ }
+
+ (*dp->attach)(isdp);
+
+ if(isdp->id_irq) {
+ int intrno;
+
+ intrno = ffs(isdp->id_irq)-1;
+ setidt(ICU_OFFSET+intrno, isdp->id_intr,
+ SDT_SYS386IGT, SEL_KPL);
+ if(mp) {
+ INTRMASK(*mp,isdp->id_irq);
+ }
+ INTREN(isdp->id_irq);
+ }
+ } else {
+ printf("%s%d not found", dp->name, isdp->id_unit);
+ if (isdp->id_iobase) {
+ printf(" at 0x%x", isdp->id_iobase);
+ }
+ printf("\n");
+ }
+}
+
+#define IDTVEC(name) __CONCAT(X,name)
+/* default interrupt vector table entries */
+typedef void inthand_t();
+typedef void (*inthand_func_t)();
+extern inthand_t
+ IDTVEC(intr0), IDTVEC(intr1), IDTVEC(intr2), IDTVEC(intr3),
+ IDTVEC(intr4), IDTVEC(intr5), IDTVEC(intr6), IDTVEC(intr7),
+ IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10), IDTVEC(intr11),
+ IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14), IDTVEC(intr15);
+
+static inthand_func_t defvec[ICU_LEN] = {
+ &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
+ &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
+ &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
+ &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15) };
+
+/*
+ * Fill in default interrupt table (in case of spuruious interrupt
+ * during configuration of kernel, setup interrupt control unit
+ */
+void
+isa_defaultirq()
+{
+ int i;
+
+ /* icu vectors */
+ for (i = 0; i < ICU_LEN; i++)
+ setidt(ICU_OFFSET + i, defvec[i], SDT_SYS386IGT, SEL_KPL);
+
+ /* initialize 8259's */
+ outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
+ outb(IO_ICU1+1, NRSVIDT); /* starting at this vector index */
+ outb(IO_ICU1+1, 1<<2); /* slave on line 2 */
+#ifdef AUTO_EOI_1
+ outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */
+#else
+ outb(IO_ICU1+1, 1); /* 8086 mode */
+#endif
+ outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
+ outb(IO_ICU1, 0x0a); /* default to IRR on read */
+ outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
+
+ outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
+ outb(IO_ICU2+1, NRSVIDT+8); /* staring at this vector index */
+ outb(IO_ICU2+1,2); /* my slave id is 2 */
+#ifdef AUTO_EOI_2
+ outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */
+#else
+ outb(IO_ICU2+1,1); /* 8086 mode */
+#endif
+ outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
+ outb(IO_ICU2, 0x0a); /* default to IRR on read */
+}
+
+/* region of physical memory known to be contiguous */
+vm_offset_t isaphysmem;
+static caddr_t dma_bounce[8]; /* XXX */
+static char bounced[8]; /* XXX */
+#define MAXDMASZ 512 /* XXX */
+
+/* high byte of address is stored in this port for i-th dma channel */
+static short dmapageport[8] =
+ { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
+
+/*
+ * isa_dmacascade(): program 8237 DMA controller channel to accept
+ * external dma control by a board.
+ */
+void isa_dmacascade(unsigned chan)
+{
+ if (chan > 7)
+ panic("isa_dmacascade: impossible request");
+
+ /* set dma channel mode, and set dma channel mode */
+ if ((chan & 4) == 0) {
+ outb(DMA1_MODE, DMA37MD_CASCADE | chan);
+ outb(DMA1_SMSK, chan);
+ } else {
+ outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3));
+ outb(DMA2_SMSK, chan & 3);
+ }
+}
+
+/*
+ * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment
+ * problems by using a bounce buffer.
+ */
+void isa_dmastart(int flags, caddr_t addr, unsigned nbytes, unsigned chan)
+{ vm_offset_t phys;
+ int waport;
+ caddr_t newaddr;
+
+ if ( chan > 7
+ || (chan < 4 && nbytes > (1<<16))
+ || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1)))
+ panic("isa_dmastart: impossible request");
+
+ if (isa_dmarangecheck(addr, nbytes, chan)) {
+ if (dma_bounce[chan] == 0)
+ dma_bounce[chan] =
+ /*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/
+ (caddr_t) isaphysmem + NBPG*chan;
+ bounced[chan] = 1;
+ newaddr = dma_bounce[chan];
+ *(int *) newaddr = 0; /* XXX */
+
+ /* copy bounce buffer on write */
+ if (!(flags & B_READ))
+ bcopy(addr, newaddr, nbytes);
+ addr = newaddr;
+ }
+
+ /* translate to physical */
+ phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
+
+ if ((chan & 4) == 0) {
+ /*
+ * Program one of DMA channels 0..3. These are
+ * byte mode channels.
+ */
+ /* set dma channel mode, and reset address ff */
+ if (flags & B_READ)
+ outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan);
+ else
+ outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan);
+ outb(DMA1_FFC, 0);
+
+ /* send start address */
+ waport = DMA1_CHN(chan);
+ outb(waport, phys);
+ outb(waport, phys>>8);
+ outb(dmapageport[chan], phys>>16);
+
+ /* send count */
+ outb(waport + 1, --nbytes);
+ outb(waport + 1, nbytes>>8);
+
+ /* unmask channel */
+ outb(DMA1_SMSK, chan);
+ } else {
+ /*
+ * Program one of DMA channels 4..7. These are
+ * word mode channels.
+ */
+ /* set dma channel mode, and reset address ff */
+ if (flags & B_READ)
+ outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3));
+ else
+ outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3));
+ outb(DMA2_FFC, 0);
+
+ /* send start address */
+ waport = DMA2_CHN(chan - 4);
+ outb(waport, phys>>1);
+ outb(waport, phys>>9);
+ outb(dmapageport[chan], phys>>16);
+
+ /* send count */
+ nbytes >>= 1;
+ outb(waport + 2, --nbytes);
+ outb(waport + 2, nbytes>>8);
+
+ /* unmask channel */
+ outb(DMA2_SMSK, chan & 3);
+ }
+}
+
+void isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
+{
+
+ /* copy bounce buffer on read */
+ /*if ((flags & (B_PHYS|B_READ)) == (B_PHYS|B_READ))*/
+ if (bounced[chan]) {
+ bcopy(dma_bounce[chan], addr, nbytes);
+ bounced[chan] = 0;
+ }
+}
+
+/*
+ * Check for problems with the address range of a DMA transfer
+ * (non-contiguous physical pages, outside of bus address space,
+ * crossing DMA page boundaries).
+ * Return true if special handling needed.
+ */
+
+int
+isa_dmarangecheck(caddr_t va, unsigned length, unsigned chan) {
+ vm_offset_t phys, priorpage = 0, endva;
+ u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1);
+
+ endva = (vm_offset_t)round_page(va + length);
+ for (; va < (caddr_t) endva ; va += NBPG) {
+ phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va));
+#define ISARAM_END RAM_END
+ if (phys == 0)
+ panic("isa_dmacheck: no physical page present");
+ if (phys >= ISARAM_END)
+ return (1);
+ if (priorpage) {
+ if (priorpage + NBPG != phys)
+ return (1);
+ /* check if crossing a DMA page boundary */
+ if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk)
+ return (1);
+ }
+ priorpage = phys;
+ }
+ return (0);
+}
+
+/* head of queue waiting for physmem to become available */
+struct buf isa_physmemq;
+
+/* blocked waiting for resource to become free for exclusive use */
+static isaphysmemflag;
+/* if waited for and call requested when free (B_CALL) */
+static void (*isaphysmemunblock)(); /* needs to be a list */
+
+/*
+ * Allocate contiguous physical memory for transfer, returning
+ * a *virtual* address to region. May block waiting for resource.
+ * (assumed to be called at splbio())
+ */
+caddr_t
+isa_allocphysmem(caddr_t va, unsigned length, void (*func)()) {
+
+ isaphysmemunblock = func;
+ while (isaphysmemflag & B_BUSY) {
+ isaphysmemflag |= B_WANTED;
+ tsleep((caddr_t)&isaphysmemflag, PRIBIO, "isaphys", 0);
+ }
+ isaphysmemflag |= B_BUSY;
+
+ return((caddr_t)isaphysmem);
+}
+
+/*
+ * Free contiguous physical memory used for transfer.
+ * (assumed to be called at splbio())
+ */
+void
+isa_freephysmem(caddr_t va, unsigned length) {
+
+ isaphysmemflag &= ~B_BUSY;
+ if (isaphysmemflag & B_WANTED) {
+ isaphysmemflag &= B_WANTED;
+ wakeup((caddr_t)&isaphysmemflag);
+ if (isaphysmemunblock)
+ (*isaphysmemunblock)();
+ }
+}
+
+/*
+ * Handle a NMI, possibly a machine check.
+ * return true to panic system, false to ignore.
+ */
+int
+isa_nmi(cd)
+ int cd;
+{
+
+ log(LOG_CRIT, "\nNMI port 61 %x, port 70 %x\n", inb(0x61), inb(0x70));
+ return(0);
+}
+
+/*
+ * Caught a stray interrupt, notify
+ */
+void
+isa_strayintr(d)
+ int d;
+{
+
+ /* DON'T BOTHER FOR NOW! */
+ /* for some reason, we get bursts of intr #7, even if not enabled! */
+ /*
+ * Well the reason you got bursts of intr #7 is because someone
+ * raised an interrupt line and dropped it before the 8259 could
+ * prioritize it. This is documented in the intel data book. This
+ * means you have BAD hardware! I have changed this so that only
+ * the first 5 get logged, then it quits logging them, and puts
+ * out a special message. rgrimes 3/25/1993
+ */
+ extern u_long intrcnt_stray;
+
+ intrcnt_stray++;
+ if (intrcnt_stray <= 5)
+ log(LOG_ERR,"ISA strayintr %x\n", d);
+ if (intrcnt_stray == 5)
+ log(LOG_CRIT,"Too many ISA strayintr not logging any more\n");
+}
+
+/*
+ * find an ISA device in a given isa_devtab_* table, given
+ * the table to search, the expected id_driver entry, and the unit number.
+ *
+ * this function is defined in isa_device.h, and this location is debatable;
+ * i put it there because it's useless w/o, and directly operates on
+ * the other stuff in that file.
+ *
+ */
+
+struct isa_device *find_isadev(table, driverp, unit)
+ struct isa_device *table;
+ struct isa_driver *driverp;
+ int unit;
+{
+ if (driverp == NULL) /* sanity check */
+ return NULL;
+
+ while ((table->id_driver != driverp) || (table->id_unit != unit)) {
+ if (table->id_driver == 0)
+ return NULL;
+
+ table++;
+ }
+
+ return table;
+}
+
+/*
+ * Return nonzero if a (masked) irq is pending for a given device.
+ */
+int
+isa_irq_pending(dvp)
+ struct isa_device *dvp;
+{
+ unsigned id_irq;
+
+ id_irq = (unsigned short) dvp->id_irq; /* XXX silly type in struct */
+ if (id_irq & 0xff)
+ return (inb(IO_ICU1) & id_irq);
+ return (inb(IO_ICU2) & (id_irq >> 8));
+}
diff --git a/sys/i386/isa/isa.h b/sys/i386/isa/isa.h
new file mode 100644
index 0000000..e2a26e7
--- /dev/null
+++ b/sys/i386/isa/isa.h
@@ -0,0 +1,181 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)isa.h 5.7 (Berkeley) 5/9/91
+ * $Id: isa.h,v 1.4 1994/01/05 15:03:28 rgrimes Exp $
+ */
+
+#ifndef _I386_ISA_ISA_H_
+#define _I386_ISA_ISA_H_ 1
+
+/*
+ * ISA Bus conventions
+ */
+
+#ifndef LOCORE
+#include <sys/cdefs.h>
+
+extern unsigned int atdevbase; /* offset in virtual memory of ISA io mem */
+unsigned char rtcin __P((int));
+#endif
+
+
+/*
+ * Input / Output Port Assignments
+ */
+
+#ifndef IO_BEGIN
+#define IO_ISABEGIN 0x000 /* 0x000 - Beginning of I/O Registers */
+
+ /* CPU Board */
+#define IO_DMA1 0x000 /* 8237A DMA Controller #1 */
+#define IO_ICU1 0x020 /* 8259A Interrupt Controller #1 */
+#define IO_TIMER1 0x040 /* 8253 Timer #1 */
+#define IO_TIMER2 0x048 /* 8253 Timer #2 */
+#define IO_KBD 0x060 /* 8042 Keyboard */
+#define IO_PPI 0x061 /* Programmabel Peripheral Interface */
+#define IO_RTC 0x070 /* RTC */
+#define IO_NMI IO_RTC /* NMI Control */
+#define IO_DMAPG 0x080 /* DMA Page Registers */
+#define IO_ICU2 0x0A0 /* 8259A Interrupt Controller #2 */
+#define IO_DMA2 0x0C0 /* 8237A DMA Controller #2 */
+#define IO_NPX 0x0F0 /* Numeric Coprocessor */
+
+ /* Cards */
+ /* 0x100 - 0x16F Open */
+
+#define IO_WD2 0x170 /* Secondary Fixed Disk Controller */
+
+ /* 0x178 - 0x1EF Open */
+
+#define IO_WD1 0x1f0 /* Primary Fixed Disk Controller */
+#define IO_GAME 0x200 /* Game Controller */
+
+ /* 0x208 - 0x277 Open */
+
+#define IO_LPT2 0x278 /* Parallel Port #2 */
+
+ /* 0x280 - 0x2E7 Open */
+
+#define IO_COM4 0x2e8 /* COM4 i/o address */
+
+ /* 0x2F0 - 0x2F7 Open */
+
+#define IO_COM2 0x2f8 /* COM2 i/o address */
+ /* 0x300 - 0x32F Open */
+
+#define IO_BT0 0x330 /* bustek 742a default addr. */
+#define IO_AHA0 0x330 /* adaptec 1542 default addr. */
+#define IO_UHA0 0x330 /* ultrastore 14f default addr. */
+#define IO_BT1 0x334 /* bustek 742a default addr. */
+#define IO_AHA1 0x334 /* adaptec 1542 default addr. */
+ /* 0x338 - 0x36F Open */
+
+#define IO_FD2 0x370 /* secondary base i/o address */
+#define IO_LPT1 0x378 /* Parallel Port #1 */
+
+ /* 0x380 - 0x3AF Open */
+
+#define IO_MDA 0x3B0 /* Monochome Adapter */
+#define IO_LPT3 0x3BC /* Monochome Adapter Printer Port */
+#define IO_VGA 0x3C0 /* E/VGA Ports */
+#define IO_CGA 0x3D0 /* CGA Ports */
+
+ /* 0x3E0 - 0x3E7 Open */
+
+#define IO_COM3 0x3e8 /* COM3 i/o address */
+#define IO_FD1 0x3f0 /* primary base i/o address */
+#define IO_COM1 0x3f8 /* COM1 i/o address */
+
+#define IO_ISAEND 0x3FF /* - 0x3FF End of I/O Registers */
+#endif IO_ISABEGIN
+
+/*
+ * Input / Output Port Sizes - these are from several sources, and tend
+ * to be the larger of what was found, ie COM ports can be 4, but some
+ * boards do not fully decode the address, thus 8 ports are used.
+ */
+
+#ifndef IO_ISASIZES
+#define IO_ISASIZES
+
+#define IO_COMSIZE 8 /* 8250, 16X50 com controllers (4?) */
+#define IO_CGASIZE 16 /* CGA controllers */
+#define IO_DMASIZE 16 /* 8237 DMA controllers */
+#define IO_DPGSIZE 32 /* 74LS612 DMA page reisters */
+#define IO_FDCSIZE 8 /* Nec765 floppy controllers */
+#define IO_WDCSIZE 8 /* WD compatible disk controllers */
+#define IO_GAMSIZE 16 /* AT compatible game controllers */
+#define IO_ICUSIZE 16 /* 8259A interrupt controllers */
+#define IO_KBDSIZE 16 /* 8042 Keyboard controllers */
+#define IO_LPTSIZE 8 /* LPT controllers, some use only 4 */
+#define IO_MDASIZE 16 /* Monochrome display controllers */
+#define IO_RTCSIZE 16 /* CMOS real time clock, NMI control */
+#define IO_TMRSIZE 16 /* 8253 programmable timers */
+#define IO_NPXSIZE 16 /* 80387/80487 NPX registers */
+#define IO_VGASIZE 16 /* VGA controllers */
+
+#endif /* IO_ISASIZES */
+
+/*
+ * Input / Output Memory Physical Addresses
+ */
+
+#ifndef IOM_BEGIN
+#define IOM_BEGIN 0x0a0000 /* Start of I/O Memory "hole" */
+#define IOM_END 0x100000 /* End of I/O Memory "hole" */
+#define IOM_SIZE (IOM_END - IOM_BEGIN)
+#endif IOM_BEGIN
+
+/*
+ * RAM Physical Address Space (ignoring the above mentioned "hole")
+ */
+
+#ifndef RAM_BEGIN
+#define RAM_BEGIN 0x0000000 /* Start of RAM Memory */
+#define RAM_END 0x1000000 /* End of RAM Memory */
+#define RAM_SIZE (RAM_END - RAM_BEGIN)
+#endif RAM_BEGIN
+
+/*
+ * Oddball Physical Memory Addresses
+ */
+#ifndef COMPAQ_RAMRELOC
+#define COMPAQ_RAMRELOC 0x80c00000 /* Compaq RAM relocation/diag */
+#define COMPAQ_RAMSETUP 0x80c00002 /* Compaq RAM setup */
+#define WEITEK_FPU 0xC0000000 /* WTL 2167 */
+#define CYRIX_EMC 0xC0000000 /* Cyrix EMC */
+#endif COMPAQ_RAMRELOC
+#endif /* _I386_ISA_ISA_H_ */
diff --git a/sys/i386/isa/isa_device.h b/sys/i386/isa/isa_device.h
new file mode 100644
index 0000000..16fac9a
--- /dev/null
+++ b/sys/i386/isa/isa_device.h
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)isa_device.h 7.1 (Berkeley) 5/9/91
+ * $Id: isa_device.h,v 1.4 1993/12/19 00:50:42 wollman Exp $
+ */
+
+#ifndef _I386_ISA_ISA_DEVICE_H_
+#define _I386_ISA_ISA_DEVICE_H_ 1
+
+/*
+ * ISA Bus Autoconfiguration
+ */
+
+/*
+ * Per device structure.
+ */
+struct isa_device {
+ struct isa_driver *id_driver;
+ short id_iobase; /* base i/o address */
+ u_short id_irq; /* interrupt request */
+ short id_drq; /* DMA request */
+ caddr_t id_maddr; /* physical i/o memory address on bus (if any)*/
+ int id_msize; /* size of i/o memory */
+ void (*id_intr)(); /* interrupt interface routine */
+ int id_unit; /* unit number */
+ int id_flags; /* flags */
+ int id_scsiid; /* scsi id if needed */
+ int id_alive; /* device is present */
+};
+
+/*
+ * Per-driver structure.
+ *
+ * Each device driver defines entries for a set of routines
+ * as well as an array of types which are acceptable to it.
+ * These are used at boot time by the configuration program.
+ */
+struct isa_driver {
+ int (*probe)(); /* test whether device is present */
+ int (*attach)(); /* setup driver for a device */
+ char *name; /* device name */
+};
+
+extern struct isa_device isa_devtab_bio[], isa_devtab_tty[], isa_devtab_net[],
+ isa_devtab_null[], isa_biotab_wdc[], isa_biotab_fdc[];
+
+extern struct isa_device *find_isadev(/* table, driver, unit*/);
+
+extern void isa_dmastart(int, caddr_t, unsigned, unsigned);
+extern void isa_dmadone(int, caddr_t, int, int);
+
+#endif /* _I386_ISA_ISA_DEVICE_H_ */
diff --git a/sys/i386/isa/iso8859.font b/sys/i386/isa/iso8859.font
new file mode 100644
index 0000000..89c9b29
--- /dev/null
+++ b/sys/i386/isa/iso8859.font
@@ -0,0 +1,1243 @@
+/*
+ * Copyright (C) 1992, 1993, 1994 Søren Schmidt
+ *
+ * This program is free software; you may redistribute it and/or
+ * modify it, provided that it retain the above copyright notice
+ * and the following disclaimer.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Søren Schmidt Email: sos@login.dkuug.dk
+ * Tritonvej 36 UUCP: ...uunet!dkuug!login!sos
+ * DK9210 Aalborg SO Phone: +45 9814 8076
+ *
+ * from:@(#)iso8859.font 1.1 940105
+ * $Id: iso8859.font,v 1.4 1993/10/28 06:15:05 rgrimes Exp $
+ */
+
+char font_8x8[256*8] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E,
+0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E,
+0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00,
+0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00,
+0x38, 0x7C, 0x38, 0xFE, 0xFE, 0x7C, 0x38, 0x7C,
+0x10, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x7C,
+0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00,
+0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF,
+0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
+0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF,
+0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78,
+0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
+0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0,
+0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0,
+0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99,
+0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00,
+0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00,
+0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18,
+0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
+0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00,
+0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0xCC, 0x78,
+0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00,
+0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF,
+0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
+0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00,
+0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
+0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
+0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00,
+0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00,
+0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00,
+0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
+0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
+0x30, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x30, 0x00,
+0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00,
+0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00,
+0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
+0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
+0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
+0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
+0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
+0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00,
+0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00,
+0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00,
+0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00,
+0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00,
+0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00,
+0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00,
+0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00,
+0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
+0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00,
+0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00,
+0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
+0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
+0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00,
+0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00,
+0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
+0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
+0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00,
+0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00,
+0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00,
+0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00,
+0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00,
+0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00,
+0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00,
+0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00,
+0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00,
+0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00,
+0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00,
+0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00,
+0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
+0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00,
+0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00,
+0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00,
+0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00,
+0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00,
+0x78, 0xCC, 0xE0, 0x70, 0x1C, 0xCC, 0x78, 0x00,
+0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00,
+0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
+0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00,
+0xC6, 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0x00,
+0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00,
+0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00,
+0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
+0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00,
+0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
+0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
+0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00,
+0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00,
+0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00,
+0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
+0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00,
+0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
+0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00,
+0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78,
+0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00,
+0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
+0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
+0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
+0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0,
+0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E,
+0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00,
+0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00,
+0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00,
+0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
+0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
+0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00,
+0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00,
+0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
+0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00,
+0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00,
+0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
+0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00,
+0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3C, 0x7E, 0xFF, 0x7E, 0x18, 0x00,
+0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA,
+0x44, 0x44, 0x44, 0x44, 0x1F, 0x04, 0x04, 0x04,
+0x7C, 0x40, 0x40, 0x40, 0x1F, 0x10, 0x10, 0x10,
+0x38, 0x44, 0x44, 0x38, 0x1E, 0x11, 0x14, 0x13,
+0x40, 0x40, 0x40, 0x7C, 0x1F, 0x10, 0x10, 0x10,
+0x38, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00,
+0x44, 0x64, 0x4C, 0x44, 0x10, 0x10, 0x10, 0x1F,
+0x44, 0x44, 0x28, 0x10, 0x1F, 0x04, 0x04, 0x04,
+0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00,
+0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x00, 0x0C, 0x30, 0x60, 0x18, 0x0C, 0x7E, 0x00,
+0x00, 0x30, 0x0C, 0x06, 0x18, 0x30, 0x7E, 0x00,
+0x00, 0x00, 0x03, 0x3E, 0x36, 0x36, 0x6C, 0x00,
+0x00, 0x00, 0x04, 0x7E, 0x10, 0x7E, 0x40, 0x00,
+0x00, 0x1C, 0x30, 0x30, 0x30, 0x30, 0x7E, 0x00,
+0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x30, 0x00, 0x30, 0x30, 0x78, 0x78, 0x30, 0x00,
+0x00, 0x00, 0x10, 0x7C, 0xC0, 0xC0, 0x7C, 0x10,
+0x00, 0x38, 0x60, 0x60, 0xF0, 0x60, 0xFC, 0x00,
+0x00, 0xC3, 0x3C, 0x66, 0x66, 0x3C, 0xC3, 0x00,
+0x00, 0xCC, 0xCC, 0x78, 0x30, 0xFC, 0x30, 0x00,
+0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
+0x7E, 0xC0, 0x7C, 0xC6, 0x7C, 0x06, 0xFC, 0x00,
+0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x7C, 0x82, 0xBA, 0xA2, 0xBA, 0x82, 0x7C, 0x00,
+0x1C, 0x06, 0x1E, 0x22, 0x1F, 0x3F, 0x00, 0x00,
+0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00,
+0x00, 0xFE, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x7C, 0x82, 0xBA, 0xB2, 0xAA, 0x82, 0x7C, 0x00,
+0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x38, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x10, 0x7C, 0x10, 0x00, 0x7C, 0x00, 0x00,
+0x1C, 0x36, 0x06, 0x18, 0x3E, 0x00, 0x00, 0x00,
+0x1E, 0x02, 0x0E, 0x02, 0x1E, 0x00, 0x00, 0x00,
+0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0xC0,
+0x7E, 0xCA, 0xCA, 0x7E, 0x0A, 0x0A, 0x0A, 0x00,
+0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30,
+0x06, 0x0E, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00,
+0x0E, 0x11, 0x11, 0x11, 0x0E, 0x1F, 0x00, 0x00,
+0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00,
+0x60, 0xE0, 0x66, 0x6C, 0x33, 0x67, 0x0F, 0x03,
+0x60, 0xE0, 0x66, 0x6C, 0x36, 0x6A, 0x04, 0x0E,
+0xF0, 0x20, 0x96, 0x6C, 0x33, 0x67, 0x0F, 0x03,
+0x30, 0x00, 0x30, 0x60, 0xC0, 0xCC, 0x78, 0x00,
+0x18, 0x0C, 0x30, 0x78, 0xCC, 0xFC, 0xCC, 0x00,
+0x60, 0xC0, 0x30, 0x78, 0xCC, 0xFC, 0xCC, 0x00,
+0x78, 0x84, 0x30, 0x78, 0xCC, 0xFC, 0xCC, 0x00,
+0x66, 0x98, 0x30, 0x78, 0xCC, 0xFC, 0xCC, 0x00,
+0xCC, 0x00, 0x30, 0x78, 0xCC, 0xFC, 0xCC, 0x00,
+0x30, 0x48, 0x30, 0x78, 0xCC, 0xFC, 0xCC, 0x00,
+0x3E, 0x78, 0x98, 0x9C, 0xF8, 0x98, 0x9E, 0x00,
+0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x1C, 0x30,
+0x30, 0x18, 0xFE, 0x62, 0x78, 0x62, 0xFE, 0x00,
+0x18, 0x30, 0xFE, 0x62, 0x78, 0x62, 0xFE, 0x00,
+0x38, 0x44, 0xFE, 0x62, 0x78, 0x62, 0xFE, 0x00,
+0x66, 0x00, 0xFE, 0x62, 0x78, 0x62, 0xFE, 0x00,
+0x60, 0x30, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00,
+0x18, 0x30, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00,
+0x78, 0x84, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00,
+0xCC, 0x00, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00,
+0x78, 0x6C, 0x66, 0xF6, 0x66, 0x6C, 0x78, 0x00,
+0x66, 0x98, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0x00,
+0x30, 0x18, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00,
+0x18, 0x30, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00,
+0x38, 0x44, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00,
+0x66, 0x98, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00,
+0xC6, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00,
+0x00, 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0x00,
+0x06, 0x7C, 0xCE, 0x9A, 0xB2, 0xE6, 0x78, 0xC0,
+0x60, 0x30, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00,
+0x18, 0x30, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00,
+0x78, 0x84, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00,
+0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00,
+0x18, 0x30, 0xCC, 0xCC, 0x78, 0x30, 0x78, 0x00,
+0x60, 0x78, 0x6C, 0x78, 0x60, 0x60, 0x60, 0x00,
+0x78, 0xCC, 0xC4, 0xDC, 0xC6, 0xC6, 0xDC, 0xC0,
+0x30, 0x18, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
+0x18, 0x30, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
+0x78, 0x84, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
+0x66, 0x98, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
+0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
+0x30, 0x48, 0x38, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
+0x00, 0x00, 0xEC, 0x32, 0x7E, 0xB0, 0x6E, 0x00,
+0x00, 0x00, 0x3C, 0x66, 0xC0, 0x66, 0x1C, 0x30,
+0x30, 0x18, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
+0x18, 0x30, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
+0x78, 0x84, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
+0xCC, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
+0x60, 0x30, 0x00, 0x70, 0x30, 0x30, 0x78, 0x00,
+0x18, 0x30, 0x00, 0x70, 0x30, 0x30, 0x78, 0x00,
+0x70, 0x88, 0x00, 0x70, 0x30, 0x30, 0x78, 0x00,
+0xCC, 0x00, 0x00, 0x70, 0x30, 0x30, 0x78, 0x00,
+0x6C, 0x38, 0x6C, 0x0C, 0x6C, 0xCC, 0x78, 0x00,
+0x66, 0x98, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
+0x60, 0x30, 0x00, 0x7C, 0xC6, 0xC6, 0x7C, 0x00,
+0x18, 0x30, 0x00, 0x7C, 0xC6, 0xC6, 0x7C, 0x00,
+0x38, 0x44, 0x00, 0x7C, 0xC6, 0xC6, 0x7C, 0x00,
+0x66, 0x98, 0x00, 0x7C, 0xC6, 0xC6, 0x7C, 0x00,
+0xC6, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x7C, 0x00,
+0x00, 0x00, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x00,
+0x00, 0x00, 0x06, 0x7C, 0xDE, 0xF6, 0x7C, 0xC0,
+0x60, 0x30, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
+0x18, 0x30, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
+0x30, 0x48, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
+0xCC, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
+0x18, 0x30, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
+0xE0, 0x78, 0x6C, 0x66, 0x6C, 0x78, 0xE0, 0x00,
+0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8
+};
+
+char font_8x14[256*14] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD, 0x99, 0x81,
+0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xFF,
+0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x7F, 0x7F,
+0x7F, 0x7F, 0x3E, 0x1C, 0x08, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x08, 0x1C, 0x3E, 0x7F, 0x3E,
+0x1C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x3C, 0x3C, 0xE7, 0xE7, 0xE7, 0x18, 0x18,
+0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C,
+0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x3C, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC3, 0xC3,
+0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
+0x00, 0x00, 0x3C, 0x24, 0x42, 0x42, 0x24, 0x3C,
+0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+0xC3, 0xDB, 0xBD, 0xBD, 0xDB, 0xC3, 0xFF, 0xFF,
+0xFF, 0xFF, 0x00, 0x00, 0x1F, 0x07, 0x0D, 0x19,
+0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18,
+0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x0C, 0x0A, 0x09, 0x09, 0x09, 0x0A, 0x08, 0x38,
+0x78, 0x78, 0x30, 0x00, 0x00, 0x00, 0x1F, 0x11,
+0x1F, 0x11, 0x11, 0x11, 0x13, 0x37, 0x77, 0x72,
+0x20, 0x00, 0x00, 0x00, 0x18, 0x18, 0xDB, 0x3C,
+0xE7, 0x3C, 0xDB, 0x18, 0x18, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x40, 0x60, 0x70, 0x7C, 0x7F, 0x7C,
+0x70, 0x60, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x01, 0x03, 0x07, 0x1F, 0x7F, 0x1F, 0x07, 0x03,
+0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C,
+0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33,
+0x33, 0x33, 0x00, 0x33, 0x33, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B,
+0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x3E,
+0x63, 0x30, 0x1C, 0x36, 0x63, 0x63, 0x36, 0x1C,
+0x06, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18,
+0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C,
+0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x0C, 0x06, 0x7F, 0x06, 0x0C, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30,
+0x7F, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x60, 0x60,
+0x7F, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18,
+0x18, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66,
+0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x7F, 0x36,
+0x36, 0x36, 0x7F, 0x36, 0x36, 0x00, 0x00, 0x00,
+0x08, 0x08, 0x3E, 0x63, 0x60, 0x60, 0x3E, 0x03,
+0x03, 0x63, 0x3E, 0x08, 0x08, 0x00, 0x00, 0x00,
+0x00, 0x61, 0x63, 0x06, 0x0C, 0x18, 0x30, 0x63,
+0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x36,
+0x36, 0x1C, 0x3B, 0x6E, 0x66, 0x66, 0x3B, 0x00,
+0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x60, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30,
+0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x18,
+0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x66, 0x3C, 0x7E, 0x3C, 0x66, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
+0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x06, 0x0C,
+0x18, 0x30, 0x60, 0x40, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3E, 0x63, 0x67, 0x6F, 0x7B, 0x73,
+0x63, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x0C, 0x1C, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x63,
+0x03, 0x06, 0x0C, 0x18, 0x30, 0x63, 0x7F, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x3E, 0x63, 0x03, 0x03,
+0x1E, 0x03, 0x03, 0x63, 0x3E, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x06, 0x0E, 0x1E, 0x36, 0x66, 0x7F,
+0x06, 0x06, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x7E, 0x60, 0x60, 0x60, 0x7E, 0x03, 0x03, 0x63,
+0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x30,
+0x60, 0x60, 0x7E, 0x63, 0x63, 0x63, 0x3E, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7F, 0x63, 0x03, 0x06,
+0x0C, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3E, 0x63, 0x63, 0x63, 0x3E, 0x63,
+0x63, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x3E, 0x63, 0x63, 0x63, 0x3F, 0x03, 0x03, 0x06,
+0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00,
+0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30,
+0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x7E, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30,
+0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x3E, 0x63, 0x63, 0x06,
+0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3E, 0x63, 0x63, 0x6F, 0x6F, 0x6F,
+0x6E, 0x60, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x08, 0x1C, 0x36, 0x63, 0x63, 0x7F, 0x63, 0x63,
+0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x33,
+0x33, 0x33, 0x3E, 0x33, 0x33, 0x33, 0x7E, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x60, 0x60,
+0x60, 0x60, 0x60, 0x33, 0x1E, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7C, 0x36, 0x33, 0x33, 0x33, 0x33,
+0x33, 0x36, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x7F, 0x33, 0x30, 0x34, 0x3C, 0x34, 0x30, 0x33,
+0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x33,
+0x30, 0x34, 0x3C, 0x34, 0x30, 0x30, 0x78, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x60, 0x60,
+0x60, 0x6F, 0x63, 0x33, 0x1D, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x7F, 0x63,
+0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x06,
+0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x73, 0x33, 0x36, 0x36,
+0x3C, 0x36, 0x36, 0x33, 0x73, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30,
+0x30, 0x33, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x63, 0x77, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x63,
+0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x73,
+0x7B, 0x7F, 0x6F, 0x67, 0x63, 0x63, 0x63, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x1C, 0x36, 0x63, 0x63,
+0x63, 0x63, 0x63, 0x36, 0x1C, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7E, 0x33, 0x33, 0x33, 0x3E, 0x30,
+0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x1C, 0x36, 0x63, 0x63, 0x63, 0x63, 0x6B, 0x3E,
+0x1C, 0x06, 0x03, 0x00, 0x00, 0x00, 0x7E, 0x33,
+0x33, 0x33, 0x3E, 0x36, 0x33, 0x33, 0x73, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x3E, 0x63, 0x63, 0x30,
+0x1C, 0x06, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63,
+0x63, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x08, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63,
+0x63, 0x6B, 0x6B, 0x7F, 0x36, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x36,
+0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18,
+0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x63,
+0x06, 0x0C, 0x18, 0x30, 0x60, 0x63, 0x7F, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x3C, 0x30, 0x30, 0x30,
+0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06,
+0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+0x3C, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x36, 0x63,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+0x18, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66,
+0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x30,
+0x30, 0x3E, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E,
+0x63, 0x60, 0x60, 0x63, 0x3E, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x0E, 0x06, 0x06, 0x3E, 0x66, 0x66,
+0x66, 0x66, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x3E, 0x63, 0x7F, 0x60, 0x63,
+0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x33,
+0x30, 0x7C, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B,
+0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00,
+0x00, 0x00, 0x70, 0x30, 0x30, 0x36, 0x3B, 0x33,
+0x33, 0x33, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x0C, 0x0C, 0x00, 0x1C, 0x0C, 0x0C, 0x0C, 0x0C,
+0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C,
+0x00, 0x1C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xCC,
+0x78, 0x00, 0x00, 0x00, 0x70, 0x30, 0x30, 0x33,
+0x36, 0x3C, 0x36, 0x33, 0x73, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x1C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x66, 0x7F, 0x6B, 0x6B, 0x6B,
+0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x6E, 0x33, 0x33, 0x33, 0x33, 0x33, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E,
+0x63, 0x63, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x33, 0x33,
+0x33, 0x3E, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x3B, 0x66, 0x66, 0x66, 0x3E,
+0x06, 0x06, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x6E, 0x33, 0x30, 0x30, 0x30, 0x78, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E,
+0x63, 0x38, 0x0E, 0x63, 0x3E, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x08, 0x18, 0x7E, 0x18, 0x18,
+0x18, 0x1B, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66,
+0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x08, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63,
+0x63, 0x6B, 0x6B, 0x7F, 0x36, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x36, 0x1C,
+0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x63, 0x66, 0x66, 0x66, 0x3E,
+0x06, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x7F, 0x66, 0x0C, 0x18, 0x33, 0x7F, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x0E, 0x18, 0x18, 0x18,
+0x70, 0x18, 0x18, 0x18, 0x0E, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x70, 0x18, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x18,
+0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x6E,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C,
+0x36, 0x63, 0x63, 0x7F, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C,
+0x18, 0x00, 0x00, 0x00, 0x55, 0xAA, 0x55, 0xAA,
+0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
+0x55, 0xAA, 0x00, 0x44, 0x44, 0x7C, 0x44, 0x44,
+0x00, 0x1F, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00,
+0x00, 0x7C, 0x40, 0x78, 0x40, 0x40, 0x00, 0x1F,
+0x10, 0x1E, 0x10, 0x10, 0x00, 0x00, 0x00, 0x38,
+0x44, 0x40, 0x44, 0x38, 0x00, 0x1E, 0x11, 0x1E,
+0x14, 0x13, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40,
+0x40, 0x7C, 0x00, 0x1F, 0x10, 0x1E, 0x10, 0x10,
+0x00, 0x00, 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18,
+0x18, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x44,
+0x64, 0x54, 0x4C, 0x44, 0x00, 0x10, 0x10, 0x10,
+0x10, 0x1F, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44,
+0x28, 0x10, 0x00, 0x1F, 0x04, 0x04, 0x04, 0x04,
+0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x0C, 0x18,
+0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, 0x7E, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x0C, 0x06,
+0x0C, 0x18, 0x30, 0x00, 0x7E, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x03, 0x3E, 0x76, 0x36,
+0x36, 0x36, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x02, 0x04, 0x7E, 0x08, 0x10, 0x7E, 0x20,
+0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x36,
+0x30, 0x30, 0x7C, 0x30, 0x30, 0x73, 0x7E, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x18, 0x00, 0x18, 0x18, 0x3C, 0x3C, 0x3C,
+0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+0x08, 0x3E, 0x63, 0x60, 0x60, 0x63, 0x3E, 0x08,
+0x08, 0x00, 0x00, 0x00, 0x1C, 0x36, 0x30, 0x30,
+0x7C, 0x30, 0x30, 0x73, 0x7E, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x42, 0x3C, 0x66, 0x66, 0x66,
+0x3C, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x7E,
+0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
+0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+0x00, 0x00, 0x00, 0x3E, 0x63, 0x30, 0x1C, 0x36,
+0x63, 0x63, 0x36, 0x1C, 0x06, 0x63, 0x3E, 0x00,
+0x00, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x3E, 0x41, 0x5D, 0x51, 0x51, 0x5D, 0x41,
+0x3E, 0x00, 0x00, 0x00, 0x00, 0x38, 0x04, 0x3C,
+0x44, 0x3C, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x36,
+0x6C, 0x36, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x03,
+0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E,
+0x41, 0x5D, 0x55, 0x59, 0x55, 0x41, 0x3E, 0x00,
+0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00,
+0x7E, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x18,
+0x30, 0x64, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x7C, 0x0C, 0x38, 0x0C, 0x6C,
+0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x06, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66,
+0x3B, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x7F, 0xDB,
+0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x0C, 0x0C, 0x06, 0x1C, 0x00, 0x30,
+0x70, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44,
+0x44, 0x38, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x36,
+0x1B, 0x36, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x60, 0xE0, 0x63, 0x66, 0x6C, 0x18, 0x33,
+0x67, 0xCF, 0x1F, 0x03, 0x03, 0x00, 0x00, 0x60,
+0xE0, 0x63, 0x66, 0x6C, 0x18, 0x30, 0x6E, 0xC3,
+0x06, 0x0C, 0x1F, 0x00, 0x00, 0xF0, 0x30, 0x63,
+0xF6, 0x6C, 0x18, 0x33, 0x67, 0xCF, 0x1F, 0x03,
+0x03, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18,
+0x18, 0x30, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00,
+0x60, 0x30, 0x18, 0x00, 0x1C, 0x36, 0x63, 0x63,
+0x7F, 0x63, 0x63, 0x00, 0x00, 0x00, 0x03, 0x06,
+0x0C, 0x00, 0x1C, 0x36, 0x63, 0x63, 0x7F, 0x63,
+0x63, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x36, 0x00,
+0x1C, 0x36, 0x63, 0x63, 0x7F, 0x63, 0x63, 0x00,
+0x00, 0x00, 0x3B, 0x6E, 0x00, 0x08, 0x1C, 0x36,
+0x63, 0x63, 0x7F, 0x63, 0x63, 0x00, 0x00, 0x00,
+0x00, 0x63, 0x63, 0x08, 0x1C, 0x36, 0x63, 0x63,
+0x7F, 0x63, 0x63, 0x00, 0x00, 0x00, 0x1C, 0x36,
+0x1C, 0x00, 0x1C, 0x36, 0x63, 0x63, 0x7F, 0x63,
+0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x36,
+0x66, 0x66, 0x67, 0x7E, 0x66, 0x66, 0x67, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x1E, 0x33, 0x60, 0x60,
+0x60, 0x60, 0x60, 0x33, 0x1E, 0x0C, 0x06, 0x1C,
+0x60, 0x30, 0x18, 0x00, 0x7F, 0x33, 0x30, 0x3E,
+0x30, 0x33, 0x7F, 0x00, 0x00, 0x00, 0x06, 0x0C,
+0x18, 0x00, 0x7F, 0x33, 0x30, 0x3E, 0x30, 0x33,
+0x7F, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x36, 0x00,
+0x7F, 0x33, 0x30, 0x3E, 0x30, 0x33, 0x7F, 0x00,
+0x00, 0x00, 0x00, 0x63, 0x63, 0x00, 0x7F, 0x33,
+0x30, 0x3E, 0x30, 0x33, 0x7F, 0x00, 0x00, 0x00,
+0x60, 0x30, 0x18, 0x00, 0x3C, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x06, 0x0C,
+0x18, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x3C, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x66, 0x00,
+0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00,
+0x00, 0x00, 0x00, 0x66, 0x66, 0x00, 0x3C, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3C, 0x36, 0x33, 0x33, 0x7B, 0x33,
+0x33, 0x36, 0x3C, 0x00, 0x00, 0x00, 0x3B, 0x6E,
+0x00, 0x63, 0x73, 0x7B, 0x7F, 0x6F, 0x67, 0x63,
+0x63, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00,
+0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00,
+0x00, 0x00, 0x03, 0x06, 0x0C, 0x00, 0x1C, 0x36,
+0x63, 0x63, 0x63, 0x36, 0x1C, 0x00, 0x00, 0x00,
+0x08, 0x1C, 0x36, 0x00, 0x1C, 0x36, 0x63, 0x63,
+0x63, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x3B,
+0x6E, 0x00, 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36,
+0x1C, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x00,
+0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x36, 0x1C,
+0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x03, 0x1E, 0x36, 0x67, 0x6F, 0x6B, 0x7B,
+0x73, 0x36, 0x3C, 0x60, 0x00, 0x00, 0x60, 0x30,
+0x18, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+0x3E, 0x00, 0x00, 0x00, 0x03, 0x06, 0x0C, 0x00,
+0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3E, 0x00,
+0x00, 0x00, 0x08, 0x1C, 0x36, 0x00, 0x63, 0x63,
+0x63, 0x63, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00,
+0x00, 0x63, 0x63, 0x00, 0x63, 0x63, 0x63, 0x63,
+0x63, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x06, 0x0C,
+0x18, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18,
+0x3C, 0x00, 0x00, 0x00, 0x00, 0x78, 0x30, 0x3E,
+0x33, 0x33, 0x3E, 0x30, 0x30, 0x30, 0x78, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x1C, 0x36, 0x63, 0x66,
+0x6C, 0x67, 0x63, 0x6B, 0x6E, 0x60, 0x60, 0x00,
+0x00, 0x60, 0x30, 0x18, 0x00, 0x3C, 0x06, 0x3E,
+0x66, 0x66, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x06,
+0x0C, 0x18, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66,
+0x3B, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x36,
+0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x3B, 0x6E, 0x00, 0x3C,
+0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x66, 0x66, 0x00, 0x3C, 0x06, 0x3E,
+0x66, 0x66, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x1C,
+0x36, 0x1C, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66,
+0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x76, 0x0B, 0x3B, 0x6E, 0x68, 0x37, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E,
+0x63, 0x60, 0x60, 0x63, 0x3E, 0x0C, 0x06, 0x1C,
+0x00, 0x30, 0x18, 0x0C, 0x00, 0x3E, 0x63, 0x7F,
+0x60, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x03,
+0x06, 0x0C, 0x00, 0x3E, 0x63, 0x7F, 0x60, 0x63,
+0x3E, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1C, 0x36,
+0x00, 0x3E, 0x63, 0x7F, 0x60, 0x63, 0x3E, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x00, 0x3E,
+0x63, 0x7F, 0x60, 0x63, 0x3E, 0x00, 0x00, 0x00,
+0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18,
+0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x06,
+0x0C, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18,
+0x3C, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x66,
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x00, 0x38,
+0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x36, 0x1C, 0x36, 0x06, 0x3E, 0x66,
+0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x3B, 0x6E, 0x00, 0x6E, 0x33, 0x33, 0x33, 0x33,
+0x33, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18,
+0x00, 0x3E, 0x63, 0x63, 0x63, 0x63, 0x3E, 0x00,
+0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x00, 0x3E,
+0x63, 0x63, 0x63, 0x63, 0x3E, 0x00, 0x00, 0x00,
+0x00, 0x08, 0x1C, 0x36, 0x00, 0x3E, 0x63, 0x63,
+0x63, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x3B, 0x6E, 0x00, 0x3E, 0x63, 0x63, 0x63, 0x63,
+0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63,
+0x00, 0x3E, 0x63, 0x63, 0x63, 0x63, 0x3E, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+0x7E, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x03, 0x3E, 0x67, 0x6F,
+0x7B, 0x73, 0x3E, 0x60, 0x00, 0x00, 0x00, 0x60,
+0x30, 0x18, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66,
+0x3B, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18,
+0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3B, 0x00,
+0x00, 0x00, 0x00, 0x18, 0x3C, 0x66, 0x00, 0x66,
+0x66, 0x66, 0x66, 0x66, 0x3B, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x66, 0x66, 0x00, 0x66, 0x66, 0x66,
+0x66, 0x66, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x06,
+0x0C, 0x18, 0x00, 0x63, 0x66, 0x66, 0x66, 0x3E,
+0x06, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x78,
+0x30, 0x3E, 0x33, 0x33, 0x33, 0x33, 0x3E, 0x30,
+0x78, 0x00, 0x00, 0x00, 0x66, 0x66, 0x00, 0x66,
+0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00
+};
+
+char font_8x16[256*16] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD,
+0x99, 0x81, 0x81, 0x7E, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7E, 0xFF, 0xDB, 0xFF, 0xFF, 0xC3,
+0xE7, 0xFF, 0xFF, 0x7E, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xFE,
+0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE,
+0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0xE7, 0xE7,
+0xE7, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF,
+0x7E, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C,
+0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC3,
+0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x42,
+0x42, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0xBD,
+0xBD, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+0x00, 0x00, 0x1E, 0x0E, 0x1A, 0x32, 0x78, 0xCC,
+0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C,
+0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x30,
+0x30, 0x70, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x63,
+0x63, 0x67, 0xE7, 0xE6, 0xC0, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x18, 0x18, 0xDB, 0x3C, 0xE7,
+0x3C, 0xDB, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFE, 0xF8,
+0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x02, 0x06, 0x0E, 0x1E, 0x3E, 0xFE, 0x3E,
+0x1E, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18,
+0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B,
+0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6,
+0x6C, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18,
+0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0C, 0xFE,
+0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE,
+0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0,
+0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xFF,
+0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7C,
+0x7C, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x7C,
+0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x18,
+0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C,
+0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x18, 0x7C, 0xC6, 0xC2, 0xC0, 0x7C, 0x06,
+0x06, 0x86, 0xC6, 0x7C, 0x18, 0x18, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xC2, 0xC6, 0x0C, 0x18,
+0x30, 0x60, 0xC6, 0x86, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x76, 0xDC,
+0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30,
+0x30, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x0C,
+0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3C, 0xFF,
+0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E,
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0C, 0x18,
+0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3C, 0x66, 0xC3, 0xC3, 0xDB, 0xDB,
+0xC3, 0xC3, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7C, 0xC6, 0x06, 0x0C, 0x18, 0x30,
+0x60, 0xC0, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x3C, 0x06,
+0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x0C, 0x1C, 0x3C, 0x6C, 0xCC, 0xFE,
+0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xFE, 0xC0, 0xC0, 0xC0, 0xFC, 0x06,
+0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x38, 0x60, 0xC0, 0xC0, 0xFC, 0xC6,
+0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xFE, 0xC6, 0x06, 0x06, 0x0C, 0x18,
+0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0xC6,
+0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7E, 0x06,
+0x06, 0x06, 0x0C, 0x78, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60,
+0x30, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00,
+0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0C, 0x06,
+0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18,
+0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xDE, 0xDE,
+0xDE, 0xDC, 0xC0, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE,
+0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x66,
+0x66, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0,
+0xC0, 0xC2, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x66,
+0x66, 0x66, 0x6C, 0xF8, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68,
+0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68,
+0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xDE,
+0xC6, 0xC6, 0x66, 0x3A, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6,
+0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xE6, 0x66, 0x66, 0x6C, 0x78, 0x78,
+0x6C, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60,
+0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xC3, 0xE7, 0xFF, 0xFF, 0xDB, 0xC3,
+0xC3, 0xC3, 0xC3, 0xC3, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE,
+0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
+0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x60,
+0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
+0xC6, 0xD6, 0xDE, 0x7C, 0x0C, 0x0E, 0x00, 0x00,
+0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x6C,
+0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x60, 0x38, 0x0C,
+0x06, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xFF, 0xDB, 0x99, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
+0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
+0xC3, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xDB,
+0xDB, 0xFF, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xC3, 0xC3, 0x66, 0x3C, 0x18, 0x18,
+0x3C, 0x66, 0xC3, 0xC3, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xC3, 0xC3, 0xC3, 0x66, 0x3C, 0x18,
+0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xFF, 0xC3, 0x86, 0x0C, 0x18, 0x30,
+0x60, 0xC1, 0xC3, 0xFF, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30,
+0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0x70, 0x38,
+0x1C, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C,
+0x0C, 0x0C, 0x0C, 0x3C, 0x00, 0x00, 0x00, 0x00,
+0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
+0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C,
+0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xE0, 0x60, 0x60, 0x78, 0x6C, 0x66,
+0x66, 0x66, 0x66, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0,
+0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x1C, 0x0C, 0x0C, 0x3C, 0x6C, 0xCC,
+0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xFE,
+0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60,
+0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC,
+0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xCC, 0x78, 0x00,
+0x00, 0x00, 0xE0, 0x60, 0x60, 0x6C, 0x76, 0x66,
+0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x06, 0x06, 0x00, 0x0E, 0x06, 0x06,
+0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0x00,
+0x00, 0x00, 0xE0, 0x60, 0x60, 0x66, 0x6C, 0x78,
+0x78, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xFF, 0xDB,
+0xDB, 0xDB, 0xDB, 0xDB, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66,
+0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6,
+0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66,
+0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC,
+0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0x0C, 0x1E, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x76, 0x66,
+0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x60,
+0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x10, 0x30, 0x30, 0xFC, 0x30, 0x30,
+0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC,
+0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xC3, 0xC3,
+0xC3, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xC3, 0xC3,
+0xDB, 0xDB, 0xFF, 0x66, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x66, 0x3C,
+0x18, 0x3C, 0x66, 0xC3, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6,
+0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0xF8, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xCC, 0x18,
+0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x0E, 0x18, 0x18, 0x18, 0x70, 0x18,
+0x18, 0x18, 0x18, 0x0E, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0E, 0x18,
+0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6,
+0xC6, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF,
+0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
+0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
+0x00, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x88, 0x00,
+0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
+0x00, 0xF8, 0x80, 0xF0, 0x80, 0x80, 0x80, 0x00,
+0x3E, 0x20, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00,
+0x00, 0x70, 0x88, 0x80, 0x80, 0x88, 0x70, 0x00,
+0x3C, 0x22, 0x3C, 0x28, 0x24, 0x22, 0x00, 0x00,
+0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF8, 0x00,
+0x3E, 0x20, 0x3C, 0x20, 0x20, 0x20, 0x00, 0x00,
+0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18,
+0x18, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x88, 0xC8, 0xA8, 0xA8, 0x98, 0x88, 0x00,
+0x20, 0x20, 0x20, 0x20, 0x20, 0x3E, 0x00, 0x00,
+0x00, 0x88, 0x88, 0x88, 0x88, 0x50, 0x20, 0x00,
+0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30,
+0x18, 0x0C, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C,
+0x18, 0x30, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x02, 0x7E, 0xEC, 0x6C, 0x6C,
+0x6C, 0x6C, 0x6C, 0xCC, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x06, 0x0C, 0x7E, 0x18, 0x18,
+0x7E, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60,
+0x60, 0x60, 0xE6, 0xFC, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18,
+0x3C, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x18, 0x18, 0x7E, 0xC3, 0xC0, 0xC0, 0xC0,
+0xC3, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60,
+0x60, 0x60, 0xE6, 0xFC, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x82, 0xC6, 0x7C, 0xC6, 0xC6,
+0xC6, 0xC6, 0x7C, 0xC6, 0x82, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xC3, 0x66, 0x3C, 0x18, 0xFF, 0x18,
+0xFF, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18,
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6,
+0x6C, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00,
+0x00, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7C, 0xC6, 0x82, 0xBA, 0xA2, 0xA2,
+0xBA, 0x82, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x70, 0x18, 0x78, 0xC8, 0x78, 0x00, 0xF8,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6C, 0xD8,
+0x6C, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x06,
+0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7C, 0xC6, 0x82, 0xBA, 0xAA, 0xB2,
+0xAA, 0x82, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18,
+0x18, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x70, 0xD8, 0x30, 0x60, 0xC8, 0xF8, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xF8, 0x18, 0x30, 0x18, 0xD8, 0x70, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66,
+0x66, 0x7E, 0x63, 0x60, 0xC0, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B,
+0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x18, 0x0C, 0x06, 0x3C, 0x00, 0x00,
+0x00, 0x60, 0xE0, 0x60, 0x60, 0x60, 0xF0, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x70, 0xD8, 0x88, 0xD8, 0x70, 0x00, 0xF8,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x6C, 0x36,
+0x6C, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30,
+0x66, 0xCE, 0x96, 0x3E, 0x06, 0x06, 0x00, 0x00,
+0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30,
+0x60, 0xCE, 0x9B, 0x06, 0x0C, 0x1F, 0x00, 0x00,
+0x00, 0xF0, 0x30, 0x72, 0x36, 0xEC, 0x18, 0x30,
+0x66, 0xCE, 0x96, 0x3E, 0x06, 0x06, 0x00, 0x00,
+0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60,
+0xC0, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x60, 0x30, 0x18, 0x00, 0x38, 0x6C, 0xC6, 0xC6,
+0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
+0x0C, 0x18, 0x30, 0x00, 0x38, 0x6C, 0xC6, 0xC6,
+0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
+0x10, 0x38, 0x6C, 0x00, 0x38, 0x6C, 0xC6, 0xC6,
+0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x76, 0xDC, 0x00, 0x38, 0x6C, 0xC6, 0xC6,
+0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xC6, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6,
+0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
+0x38, 0x6C, 0x38, 0x00, 0x38, 0x6C, 0xC6, 0xC6,
+0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3E, 0x6C, 0xCC, 0xCC, 0xFE, 0xCC,
+0xCC, 0xCC, 0xCC, 0xCE, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0,
+0xC2, 0x66, 0x3C, 0x0C, 0x06, 0x7C, 0x00, 0x00,
+0x30, 0x18, 0x0C, 0x00, 0xFE, 0x66, 0x60, 0x7C,
+0x60, 0x60, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x30, 0x60, 0x00, 0xFE, 0x66, 0x60, 0x7C,
+0x60, 0x60, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00,
+0x10, 0x38, 0x6C, 0x00, 0xFE, 0x66, 0x60, 0x7C,
+0x60, 0x60, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xC6, 0x00, 0xFE, 0x66, 0x60, 0x60, 0x7C,
+0x60, 0x60, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00,
+0x30, 0x18, 0x0C, 0x00, 0x3C, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+0x0C, 0x18, 0x30, 0x00, 0x3C, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+0x18, 0x3C, 0x66, 0x00, 0x3C, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x66, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x78, 0x6C, 0x66, 0x66, 0x66, 0xF6,
+0x66, 0x66, 0x6C, 0x78, 0x00, 0x00, 0x00, 0x00,
+0x76, 0xDC, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE,
+0xCE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
+0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xC6, 0xC6,
+0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x0C, 0x18, 0x30, 0x00, 0x7C, 0xC6, 0xC6, 0xC6,
+0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xC6, 0xC6,
+0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x76, 0xDC, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6,
+0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xC6, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6,
+0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x10,
+0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x02, 0x06, 0x7C, 0xCE, 0xCE, 0xDE, 0xD6, 0xD6,
+0xF6, 0xE6, 0xE6, 0x7C, 0xC0, 0x80, 0x00, 0x00,
+0x60, 0x30, 0x18, 0x00, 0xC6, 0xC6, 0xC6, 0xC6,
+0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x0C, 0x18, 0x30, 0x00, 0xC6, 0xC6, 0xC6, 0xC6,
+0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x10, 0x38, 0x6C, 0x00, 0xC6, 0xC6, 0xC6, 0xC6,
+0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
+0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x0C, 0x18, 0x30, 0x00, 0xC3, 0xC3, 0x66, 0x3C,
+0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+0xF0, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60,
+0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x38, 0x6C, 0xC6, 0xCE, 0xDC, 0xD8,
+0xCC, 0xC6, 0xD6, 0xDC, 0xC0, 0x80, 0x00, 0x00,
+0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0C, 0x7C,
+0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0C, 0x7C,
+0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x10, 0x38, 0x6C, 0x00, 0x78, 0x0C, 0x7C,
+0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x76, 0xDC, 0x00, 0x78, 0x0C, 0x7C,
+0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xCC, 0x00, 0x00, 0x78, 0x0C, 0x7C,
+0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x38, 0x6C, 0x38, 0x00, 0x78, 0x0C, 0x7C,
+0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x3B, 0x1B,
+0x7E, 0xD8, 0xDC, 0x77, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x60, 0x60,
+0x66, 0x3C, 0x0C, 0x06, 0x3C, 0x00, 0x00, 0x00,
+0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xFE,
+0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x0C, 0x18, 0x30, 0x00, 0x7C, 0xC6, 0xFE,
+0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xFE,
+0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xC6, 0x00, 0x00, 0x7C, 0xC6, 0xFE,
+0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x06, 0x0C, 0x18, 0x00, 0x38, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x18, 0x3C, 0x66, 0x00, 0x38, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18,
+0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x6C, 0x38, 0x38, 0x6C, 0x0C, 0x3C, 0x6C,
+0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x76, 0xDC, 0x00, 0xDC, 0x66, 0x66,
+0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xC6,
+0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x18, 0x30, 0x60, 0x00, 0x7C, 0xC6, 0xC6,
+0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xC6,
+0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x76, 0xDC, 0x00, 0x7C, 0xC6, 0xC6,
+0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xC6, 0x00, 0x00, 0x7C, 0xC6, 0xC6,
+0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7E,
+0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x02, 0x06, 0x7C, 0xCE, 0xDE,
+0xD6, 0xF6, 0xE6, 0x7C, 0xC0, 0x80, 0x00, 0x00,
+0x00, 0x60, 0x30, 0x18, 0x00, 0xCC, 0xCC, 0xCC,
+0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x18, 0x30, 0x60, 0x00, 0xCC, 0xCC, 0xCC,
+0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x30, 0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC,
+0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xCC, 0x00, 0x00, 0xCC, 0xCC, 0xCC,
+0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x18, 0x30, 0x60, 0x00, 0xC6, 0xC6, 0xC6,
+0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0xF8, 0x00,
+0x00, 0x00, 0x00, 0xF0, 0x60, 0x7C, 0x66, 0x66,
+0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00,
+0x00, 0x00, 0x66, 0x66, 0x00, 0xEE, 0x66, 0x66,
+0x66, 0x66, 0x66, 0x3E, 0x06, 0x0C, 0x38, 0x00
+};
diff --git a/sys/i386/isa/kbd.h b/sys/i386/isa/kbd.h
new file mode 100644
index 0000000..b7b6009
--- /dev/null
+++ b/sys/i386/isa/kbd.h
@@ -0,0 +1,56 @@
+/*
+ * Keyboard definitions
+ * from: unknown origin, 386BSD 0.1
+ * $Id: kbd.h,v 1.2 1993/10/16 13:46:04 rgrimes Exp $
+ */
+
+#ifndef _I386_ISA_KBD_H_
+#define _I386_ISA_KBD_H_ 1
+
+/* Reference: IBM AT Technical Reference Manual,
+ * pp. 1-38 to 1-43, 4-3 to 4-22
+ */
+
+/* commands sent to KBCMDP */
+
+#define KBC_CMDREAD 0x20 /* read kbd cntrl command byte */
+#define KBC_CMDWRITE 0x60 /* == LD_CMDBYTE in kd.h, write command */
+#define KBC_SELFTEST 0xAA /* perform self test, returns 55 when ok */
+#define KBC_IFTEST 0xAB /* perform interface test */
+#define KBC_DIAGDUMP 0xAC /* send 19 status bytes to system */
+#define KBC_DISKBD 0xAD /* disable keyboard */
+#define KBC_ENAKBD 0xAE /* enable keyboard */
+#define KBC_RDINP 0xC0 /* read input port */
+#define KBC_RDID 0xC4 /* read keyboard ID */
+#define KBC_RDOUTP 0xD0 /* read output port */
+#define KBC_WROUTP 0xD1 /* write output port */
+#define KBC_RDTINP 0xE0 /* read test inputs */
+
+/* commands sent to KBDATAP */
+#define KBC_STSIND 0xED /* set keyboard status indicators */
+#define KBC_ECHO 0xEE /* reply with 0xEE */
+#define KBC_SETTPM 0xF3 /* Set typematic rate/delay */
+#define KBC_ENABLE 0xF4 /* Start scanning */
+#define KBC_SETDEFD 0xF5 /* =KBC_SETDEF, but disable scanning */
+#define KBC_SETDEF 0xF6 /* Set power on defaults */
+#define KBC_RESEND 0xFE /* system wants keyboard to resend last code */
+#define KBC_RESET 0xFF /* Reset the keyboard */
+
+/* responses */
+#define KBR_OVERRUN 0x00 /* Keyboard flooded */
+#define KBR_STOK 0x55 /* Selftest ok response */
+#define KBR_IFOK 0x00 /* Interface test ok */
+#define KBR_IFCL_SA0 0x01 /* Clock Stuck-at-0 fault */
+#define KBR_IFCL_SA1 0x02 /* Clock Stuck-at-1 fault */
+#define KBR_IFDA_SA0 0x03 /* Data Stuck-at-0 fault */
+#define KBR_IFDA_SA1 0x04 /* Data Stuck-at-1 fault */
+#define KBR_RSTDONE 0xAA /* Keyboard reset (BAT) complete */
+#define KBR_E0 0xE0 /* Extended prefix */
+#define KBR_E1 0xE1 /* BREAK'S HIT :-( */
+#define KBR_ECHO 0xEE /* Echo response */
+#define KBR_F0 0xF0 /* Break code prefix */
+#define KBR_ACK 0xFA /* Keyboard did receive command */
+#define KBR_BATFAIL 0xFC /* BAT failed */
+#define KBR_DIAGFAIL 0xFD /* Diagnostic failed response */
+#define KBR_RESEND 0xFE /* Keyboard needs resend of command */
+#endif /* _I386_ISA_KBD_H_ */
diff --git a/sys/i386/isa/kbdtables.h b/sys/i386/isa/kbdtables.h
new file mode 100644
index 0000000..a923c45
--- /dev/null
+++ b/sys/i386/isa/kbdtables.h
@@ -0,0 +1,859 @@
+/*
+ * Copyright (C) 1992, 1993, 1994 Søren Schmidt
+ *
+ * This program is free software; you may redistribute it and/or
+ * modify it, provided that it retain the above copyright notice
+ * and the following disclaimer.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Søren Schmidt Email: sos@login.dkuug.dk
+ * Tritonvej 36 UUCP: ...uunet!dkuug!login!sos
+ * DK9210 Aalborg SO Phone: +45 9814 8076
+ *
+ * @(#)kbdtables.h 1.3 940123
+ * $Id: kbdtables.h,v 1.11 1994/02/01 09:27:43 ache Exp $
+ */
+
+#define SET8 0x80 /* eight bit for emacs SET8-key */
+
+#ifdef DKKEYMAP
+keymap_t key_map = { 0x69, /* DK iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, '1', '!', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '"', 0x00, 0x00, '@', '"', 0x00, 0x00, 0x00, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, 0x9E, '#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', 0xA4, NOP, NOP, '$', 0xA4, NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, '5', '%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '&', NOP, NOP, '6', '&', NOP, NOP, 0x33, 0x00,
+/* sc=08 */ '7', '/', NOP, NOP, '{', '/', NOP, NOP, 0x33, 0x00,
+/* sc=09 */ '8', '(', 0x1B, 0x1B, '[', '(', 0x1B, 0x1B, 0x00, 0x00,
+/* sc=0a */ '9', ')', 0x1D, 0x1D, ']', ')', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=0b */ '0', '=', NOP, NOP, '}', '=', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '+', '?', NOP, NOP, '+', '?', NOP, NOP, 0x33, 0x00,
+/* sc=0d */ '\'', '`', NOP, NOP, '|', '`', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x33, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ 0xE5, 0xC5, NOP, NOP, 0x86, 0x8F, NOP, NOP, 0x33, 0x01,
+/* sc=1b */ '"', '^', 0x1E, 0x1E, '~', '^', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ 0xE6, 0xC6, NOP, NOP, 0x91, 0x92, NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xF8, 0xD8, NOP, NOP, 0x9B, 0x9D, NOP, NOP, 0x33, 0x01,
+/* sc=29 */ 0xBD, 0xA7, NOP, NOP, 0xBD, 0xA7, NOP, NOP, 0x33, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\'', '*', NOP, NOP, '\'', '*', NOP, NOP, 0x33, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', ';', NOP, NOP, ',', ';', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', ':', NOP, NOP, '.', ':', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '-', '_', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, 0x00, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', '*', '*', '*', '*', '*', '*', 0x00, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, 0xFF, 0x00,
+/* sc=46 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', '-', '-', '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ NOP, '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', '6', '6', '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ '<', '>', 0x1C, 0x1C, '\\', '>', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x00, 0x02,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x00,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+#endif
+
+#ifdef UKKEYMAP
+keymap_t key_map = { 0x69, /* uk iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, '`', '`', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '"', 0x00, 0x00, '@', '@', 0x00, 0x00, 0x00, 0x00,
+/* sc=04 */ '3', 0xA3, NOP, NOP, '#', '#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, '4', '$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, '5', '%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '^', 0x1E, 0x1E, '^', '^', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=08 */ '7', '&', NOP, NOP, '[', '[', 0x1B, 0x1B, 0x30, 0x00,
+/* sc=09 */ '8', '*', NOP, NOP, '8', '*', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '9', '(', NOP, NOP, ']', ']', 0x1D, 0x1D, 0x30, 0x00,
+/* sc=0b */ '0', ')', NOP, NOP, '{', '{', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '-', '_', 0x1F, 0x1F, '|', '|', 0x1F, 0x1F, 0x00, 0x00,
+/* sc=0d */ '=', '+', NOP, NOP, '}', '}', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ '[', '{', 0x1B, 0x1B, '[', '{', 0x1B, 0x1B, 0x00, 0x00,
+/* sc=1b */ ']', '}', 0x1D, 0x1D, ']', '}', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ ';', ':', NOP, NOP, ';', ':', NOP, NOP, 0x33, 0x00,
+/* sc=28 */ '\'', '@', 0x00, 0x00, '\'', '@', 0x00, 0x00, 0x00, 0x00,
+/* sc=29 */ '\\', '|', 0x1C, 0x1C, '\\', '\\', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '#', '~', NOP, NOP, '~', '~', NOP, NOP, 0x33, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', '<', NOP, NOP, ',', '<', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', '>', NOP, NOP, '.', '>', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '/', '?', NOP, NOP, '/', '?', NOP, NOP, 0x33, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, 0x13, 0x13, NLK, NLK, 0x13, 0x13, 0xCC, 0x00,
+/* sc=46 */ SLK, SLK, 0x7F, 0x7F, SLK, SLK, 0x7F, 0x7F, 0xCC, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', 0x1F, 0x1F, '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ F(54), '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', 0x1E, 0x1E, '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ '\\', '|', 0x1C, 0x1C, '\\', '|', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0xFF, 0x02,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x02,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+#endif
+
+#ifdef GRKEYMAP
+keymap_t key_map = { 0x69, /* german iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, '`', '`', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '"', 0x00, 0x00, '@', '@', 0x00, 0x00, 0x00, 0x00,
+/* sc=04 */ '3', 0xA7, NOP, NOP, '#', '#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, '4', '$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, '5', '%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '&', 0x1E, 0x1E, '^', '^', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=08 */ '7', '/', 0x1B, 0x1B, '[', '[', 0x1B, 0x1B, 0x00, 0x00,
+/* sc=09 */ '8', '(', NOP, NOP, '8', '(', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '9', ')', 0x1D, 0x1D, ']', ']', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=0b */ '0', '=', NOP, NOP, '{', '{', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ 0xDF, '?', NOP, NOP, '|', '|', NOP, NOP, 0x33, 0x00,
+/* sc=0d */ 0x92, 0x93, NOP, NOP, '\'', '`', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ 0xFC, 0xDC, 0x1B, 0x1B, '[', '{', 0x1B, 0x1B, 0x00, 0x01,
+/* sc=1b */ '+', '*', 0x1D, 0x1D, ']', '}', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ 0xF6, 0xD6, NOP, NOP, 0xF6, 0xD6, NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xE4, 0xC4, NOP, NOP, 0xE4, 0xC4, NOP, NOP, 0x33, 0x01,
+/* sc=29 */ '<', '>', 0x1C, 0x1C, '\\', '|', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '#', '^', 0x1E, 0x1E, '`', '~', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=2c */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', ';', NOP, NOP, ',', ';', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', ':', NOP, NOP, '.', ':', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '-', '_', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, 0x00, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, 0x13, 0x13, NLK, NLK, 0x13, 0x13, 0xCC, 0x00,
+/* sc=46 */ SLK, SLK, 0x7F, 0x7F, SLK, SLK, 0x7F, 0x7F, 0xCC, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', 0x1F, 0x1F, '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ F(54), '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', 0x1E, 0x1E, '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0xFF, 0x02,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x02,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+#endif
+
+#ifdef SWKEYMAP
+keymap_t key_map = { 0x69, /* swedish iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=03 */ '2', '"', NOP, NOP, '@', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, 0xA3, NOP, NOP, NOP, 0x37, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, 0xA4, NOP, NOP, NOP, 0x37, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=07 */ '6', '&', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=08 */ '7', '/', NOP, NOP, '{', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=09 */ '8', '(', NOP, NOP, '[', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0a */ '9', ')', NOP, NOP, ']', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0b */ '0', '=', NOP, NOP, '}', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0c */ '+', '?', NOP, NOP, '\\', NOP, 0x1C, NOP, 0x35, 0x00,
+/* sc=0d */ 0x180, '`', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ 0xE5, 0xC5, NOP, NOP, '}', ']', NOP, NOP, 0x33, 0x01,
+/* sc=1b */ 0xA8, '^', NOP, NOP, '~', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ 0xF6, 0xD6, NOP, NOP, '|', '\\', NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xE4, 0xC4, NOP, NOP, '{', '[', NOP, NOP, 0x33, 0x01,
+/* sc=29 */ 0xA7, 0xBD, NOP, NOP, '\\', '|', NOP, NOP, 0x33, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\'', '*', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', ';', NOP, NOP, NOP, '<', NOP, NOP, 0x3B, 0x00,
+/* sc=34 */ '.', ':', NOP, NOP, NOP, '>', NOP, NOP, 0x3B, 0x00,
+/* sc=35 */ '-', '_', 0x1F, NOP, '/', '?', NOP, NOP, 0x13, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, 0x13, 0x13, NLK, NLK, 0x13, 0x13, 0xCC, 0x00,
+/* sc=46 */ SLK, SLK, 0x7F, 0x7F, SLK, SLK, 0x7F, 0x7F, 0xCC, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', 0x1F, 0x1F, '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ F(54), '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', 0x1E, 0x1E, '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ '<', '>', NOP, NOP, '|', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0xFF, 0x02,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x02,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+#endif
+
+#ifdef RUKEYMAP
+keymap_t key_map = { 0xe9, /* keys number */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * -------------------------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, NOP, NOP, SET8|0x1B, SET8|0x1B, DBG, NOP, 0x33, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, SET8|'1', SET8|'!', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '@', 0x00, 0x00, SET8|'2', SET8|'@', SET8|0x00, SET8|0x00, 0x00, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, SET8|'3', SET8|'#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, SET8|'4', SET8|'$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, SET8|'5', SET8|'%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '^', 0x1E, 0x1E, SET8|'6', SET8|'^', SET8|0x1E, SET8|0x1E, 0x00, 0x00,
+/* sc=08 */ '7', '&', NOP, NOP, SET8|'7', SET8|'&', NOP, NOP, 0x33, 0x00,
+/* sc=09 */ '8', '*', NOP, NOP, SET8|'8', SET8|'*', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '9', '(', NOP, NOP, SET8|'9', SET8|'(', NOP, NOP, 0x33, 0x00,
+/* sc=0b */ '0', ')', NOP, NOP, SET8|'0', SET8|')', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '-', '_', 0x1F, 0x1F, SET8|'-', SET8|'_', SET8|0x1F, SET8|0x1F, 0x00, 0x00,
+/* sc=0d */ '=', '+', NOP, NOP, SET8|'=', SET8|'+', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, SET8|0x08, SET8|0x08, SET8|0x7F, SET8|0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, F(16), NOP, NOP, SET8|0x09, F(16), NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, SET8|'q', SET8|'Q', SET8|0x11, SET8|0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, SET8|'w', SET8|'W', SET8|0x17, SET8|0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, SET8|'e', SET8|'E', SET8|0x05, SET8|0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, SET8|'r', SET8|'R', SET8|0x12, SET8|0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, SET8|'t', SET8|'T', SET8|0x14, SET8|0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, SET8|'y', SET8|'Y', SET8|0x19, SET8|0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, SET8|'u', SET8|'U', SET8|0x15, SET8|0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, SET8|'i', SET8|'I', SET8|0x09, SET8|0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, SET8|'o', SET8|'O', SET8|0x0F, SET8|0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, SET8|'p', SET8|'P', SET8|0x10, SET8|0x10, 0x00, 0x01,
+/* sc=1a */ '[', '{', 0x1B, 0x1B, SET8|'[', SET8|'{', SET8|0x1B, SET8|0x1B, 0x00, 0x00,
+/* sc=1b */ ']', '}', 0x1D, 0x1D, SET8|']', SET8|'}', SET8|0x1D, SET8|0x1D, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, SET8|0x0D, SET8|0x0D, SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, SET8|'a', SET8|'A', SET8|0x01, SET8|0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, SET8|'s', SET8|'S', SET8|0x13, SET8|0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, SET8|'d', SET8|'D', SET8|0x04, SET8|0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, SET8|'f', SET8|'F', SET8|0x06, SET8|0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, SET8|'g', SET8|'G', SET8|0x07, SET8|0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, SET8|'h', SET8|'H', SET8|0x08, SET8|0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, SET8|'j', SET8|'J', SET8|0x0A, SET8|0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, SET8|'k', SET8|'K', SET8|0x0B, SET8|0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, SET8|'l', SET8|'L', SET8|0x0C, SET8|0x0C, 0x00, 0x01,
+/* sc=27 */ ';', ':', NOP, NOP, SET8|';', SET8|':', NOP, NOP, 0x33, 0x00,
+/* sc=28 */ '\'', '"', NOP, NOP, SET8|'\'', SET8|'"', NOP, NOP, 0x33, 0x00,
+/* sc=29 */ '`', '~', NOP, NOP, SET8|'`', SET8|'~', NOP, NOP, 0x33, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\\', '|', 0x1C, 0x1C, SET8|'\\', SET8|'|', SET8|0x1C, SET8|0x1C, 0x00, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, SET8|'z', SET8|'Z', SET8|0x1A, SET8|0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, SET8|'x', SET8|'X', SET8|0x18, SET8|0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, SET8|'c', SET8|'C', SET8|0x03, SET8|0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, SET8|'v', SET8|'V', SET8|0x16, SET8|0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, SET8|'b', SET8|'B', SET8|0x02, SET8|0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, SET8|'n', SET8|'N', SET8|0x0E, SET8|0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, SET8|'m', SET8|'M', SET8|0x0D, SET8|0x0D, 0x00, 0x01,
+/* sc=33 */ ',', '<', NOP, NOP, SET8|',', SET8|'<', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', '>', NOP, NOP, SET8|'.', SET8|'>', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '/', '?', NOP, NOP, SET8|'/', SET8|'?', NOP, NOP, 0x33, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, SET8|'*', SET8|'*', SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', SET8|' ', SET8|' ', SET8|' ', SET8|' ', 0x00, 0x00,
+/* sc=3a */ ALK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, 0xFF, 0x00,
+/* sc=46 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', SET8|'7', SET8|'7', SET8|'7', SET8|'7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', SET8|'8', SET8|'8', SET8|'8', SET8|'8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', SET8|'9', SET8|'9', SET8|'9', SET8|'9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', '-', '-', SET8|'-', SET8|'-', SET8|'-', SET8|'-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', SET8|'4', SET8|'4', SET8|'4', SET8|'4', 0x80, 0x02,
+/* sc=4c */ F(48), '5', '5', '5', SET8|'5', SET8|'5', SET8|'5', SET8|'5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', '6', '6', SET8|'6', SET8|'6', SET8|'6', SET8|'6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', SET8|'+', SET8|'+', SET8|'+', SET8|'+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', SET8|'1', SET8|'1', SET8|'1', SET8|'1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', SET8|'2', SET8|'2', SET8|'2', SET8|'2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', SET8|'3', SET8|'3', SET8|'3', SET8|'3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', SET8|'0', SET8|'0', SET8|'0', SET8|'0', 0x80, 0x02,
+/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0x82, 0x02,
+/* sc=54 */ ALK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0A, 0x0A, SET8|0x0D, SET8|0x0D, SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', NOP, NOP, SET8|'/', SET8|'/', NOP, NOP, 0x33, 0x00,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0xC2, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=69 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6a */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6b */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6c */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6d */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6e */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6f */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=70 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=71 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=72 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=73 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=74 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=75 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=76 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=77 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=78 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=79 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7a */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7b */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7c */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7d */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7e */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7f */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* extended (ALTGR LOCK keys) */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, NOP, NOP, SET8|0x1B, SET8|0x1B, DBG, NOP, 0x33, 0x00,
+/* sc=02 */ '!', '1', NOP, NOP, SET8|'1', SET8|'!', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '"', '2', 0x00, 0x00, SET8|'2', SET8|'@', SET8|0x00, SET8|0x00, 0x00, 0x00,
+/* sc=04 */ '\'', '3', NOP, NOP, SET8|'3', SET8|'#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ ';', '4', NOP, NOP, SET8|'4', SET8|'$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ ':', '5', NOP, NOP, SET8|'5', SET8|'%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ ',', '6', 0x1E, 0x1E, SET8|'6', SET8|'^', SET8|0x1E, SET8|0x1E, 0x00, 0x00,
+/* sc=08 */ '.', '7', NOP, NOP, SET8|'7', SET8|'&', NOP, NOP, 0x33, 0x00,
+/* sc=09 */ '*', '8', NOP, NOP, SET8|'8', SET8|'*', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '(', '9', NOP, NOP, SET8|'9', SET8|'(', NOP, NOP, 0x33, 0x00,
+/* sc=0b */ ')', '0', NOP, NOP, SET8|'0', SET8|')', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '-', '_', 0x1F, 0x1F, SET8|'-', SET8|'_', SET8|0x1F, SET8|0x1F, 0x00, 0x00,
+/* sc=0d */ '=', '+', NOP, NOP, SET8|'=', SET8|'+', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, SET8|0x08, SET8|0x08, SET8|0x7F, SET8|0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, F(16), NOP, NOP, SET8|0x09, F(16), NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 0xca, 0xea, 0x11, 0x11, SET8|'q', SET8|'Q', SET8|0x11, SET8|0x11, 0x00, 0x01,
+/* sc=11 */ 0xc3, 0xe3, 0x17, 0x17, SET8|'w', SET8|'W', SET8|0x17, SET8|0x17, 0x00, 0x01,
+/* sc=12 */ 0xd5, 0xf5, 0x05, 0x05, SET8|'e', SET8|'E', SET8|0x05, SET8|0x05, 0x00, 0x01,
+/* sc=13 */ 0xcb, 0xeb, 0x12, 0x12, SET8|'r', SET8|'R', SET8|0x12, SET8|0x12, 0x00, 0x01,
+/* sc=14 */ 0xc5, 0xe5, 0x14, 0x14, SET8|'t', SET8|'T', SET8|0x14, SET8|0x14, 0x00, 0x01,
+/* sc=15 */ 0xce, 0xee, 0x19, 0x19, SET8|'y', SET8|'Y', SET8|0x19, SET8|0x19, 0x00, 0x01,
+/* sc=16 */ 0xc7, 0xe7, 0x15, 0x15, SET8|'u', SET8|'U', SET8|0x15, SET8|0x15, 0x00, 0x01,
+/* sc=17 */ 0xdb, 0xfb, 0x09, 0x09, SET8|'i', SET8|'I', SET8|0x09, SET8|0x09, 0x00, 0x01,
+/* sc=18 */ 0xdd, 0xfd, 0x0F, 0x0F, SET8|'o', SET8|'O', SET8|0x0F, SET8|0x0F, 0x00, 0x01,
+/* sc=19 */ 0xda, 0xfa, 0x10, 0x10, SET8|'p', SET8|'P', SET8|0x10, SET8|0x10, 0x00, 0x01,
+/* sc=1a */ 0xc8, 0xe8, 0x1B, 0x1B, SET8|'[', SET8|'{', SET8|0x1B, SET8|0x1B, 0x00, 0x01,
+/* sc=1b */ 0xdf, 0xff, 0x1D, 0x1D, SET8|']', SET8|'}', SET8|0x1D, SET8|0x1D, 0x00, 0x01,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, SET8|0x0D, SET8|0x0D, SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 0xc6, 0xe6, 0x01, 0x01, SET8|'a', SET8|'A', SET8|0x01, SET8|0x01, 0x00, 0x01,
+/* sc=1f */ 0xd9, 0xf9, 0x13, 0x13, SET8|'s', SET8|'S', SET8|0x13, SET8|0x13, 0x00, 0x01,
+/* sc=20 */ 0xd7, 0xf7, 0x04, 0x04, SET8|'d', SET8|'D', SET8|0x04, SET8|0x04, 0x00, 0x01,
+/* sc=21 */ 0xc1, 0xe1, 0x06, 0x06, SET8|'f', SET8|'F', SET8|0x06, SET8|0x06, 0x00, 0x01,
+/* sc=22 */ 0xd0, 0xf0, 0x07, 0x07, SET8|'g', SET8|'G', SET8|0x07, SET8|0x07, 0x00, 0x01,
+/* sc=23 */ 0xd2, 0xf2, 0x08, 0x08, SET8|'h', SET8|'H', SET8|0x08, SET8|0x08, 0x00, 0x01,
+/* sc=24 */ 0xcf, 0xef, 0x0A, 0x0A, SET8|'j', SET8|'J', SET8|0x0A, SET8|0x0A, 0x00, 0x01,
+/* sc=25 */ 0xcc, 0xec, 0x0B, 0x0B, SET8|'k', SET8|'K', SET8|0x0B, SET8|0x0B, 0x00, 0x01,
+/* sc=26 */ 0xc4, 0xe4, 0x0C, 0x0C, SET8|'l', SET8|'L', SET8|0x0C, SET8|0x0C, 0x00, 0x01,
+/* sc=27 */ 0xd6, 0xf6, NOP, NOP, SET8|';', SET8|':', NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xdc, 0xfc, NOP, NOP, SET8|'\'', SET8|'"', NOP, NOP, 0x33, 0x01,
+/* sc=29 */ 0xa3, 0xb3, NOP, NOP, SET8|'`', SET8|'~', NOP, NOP, 0x33, 0x01,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\\', '|', 0x1C, 0x1C, SET8|'\\', SET8|'|', SET8|0x1C, SET8|0x1C, 0x00, 0x00,
+/* sc=2c */ 0xd1, 0xf1, 0x1A, 0x1A, SET8|'z', SET8|'Z', SET8|0x1A, SET8|0x1A, 0x00, 0x01,
+/* sc=2d */ 0xde, 0xfe, 0x18, 0x18, SET8|'x', SET8|'X', SET8|0x18, SET8|0x18, 0x00, 0x01,
+/* sc=2e */ 0xd3, 0xf3, 0x03, 0x03, SET8|'c', SET8|'C', SET8|0x03, SET8|0x03, 0x00, 0x01,
+/* sc=2f */ 0xcd, 0xed, 0x16, 0x16, SET8|'v', SET8|'V', SET8|0x16, SET8|0x16, 0x00, 0x01,
+/* sc=30 */ 0xc9, 0xe9, 0x02, 0x02, SET8|'b', SET8|'B', SET8|0x02, SET8|0x02, 0x00, 0x01,
+/* sc=31 */ 0xd4, 0xf4, 0x0E, 0x0E, SET8|'n', SET8|'N', SET8|0x0E, SET8|0x0E, 0x00, 0x01,
+/* sc=32 */ 0xd8, 0xf8, 0x0D, 0x0D, SET8|'m', SET8|'M', SET8|0x0D, SET8|0x0D, 0x00, 0x01,
+/* sc=33 */ 0xc2, 0xe2, NOP, NOP, SET8|',', SET8|'<', NOP, NOP, 0x33, 0x01,
+/* sc=34 */ 0xc0, 0xe0, NOP, NOP, SET8|'.', SET8|'>', NOP, NOP, 0x33, 0x01,
+/* sc=35 */ '/', '?', NOP, NOP, SET8|'/', SET8|'?', NOP, NOP, 0x33, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, SET8|'*', SET8|'*', SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', SET8|' ', SET8|' ', SET8|' ', SET8|' ', 0x00, 0x00,
+/* sc=3a */ ALK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, 0xFF, 0x00,
+/* sc=46 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', SET8|'7', SET8|'7', SET8|'7', SET8|'7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', SET8|'8', SET8|'8', SET8|'8', SET8|'8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', SET8|'9', SET8|'9', SET8|'9', SET8|'9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', '-', '-', SET8|'-', SET8|'-', SET8|'-', SET8|'-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', SET8|'4', SET8|'4', SET8|'4', SET8|'4', 0x80, 0x02,
+/* sc=4c */ F(48), '5', '5', '5', SET8|'5', SET8|'5', SET8|'5', SET8|'5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', '6', '6', SET8|'6', SET8|'6', SET8|'6', SET8|'6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', SET8|'+', SET8|'+', SET8|'+', SET8|'+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', SET8|'1', SET8|'1', SET8|'1', SET8|'1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', SET8|'2', SET8|'2', SET8|'2', SET8|'2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', SET8|'3', SET8|'3', SET8|'3', SET8|'3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', SET8|'0', SET8|'0', SET8|'0', SET8|'0', 0x80, 0x02,
+/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0x82, 0x02,
+/* sc=54 */ ALK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0A, 0x0A, SET8|0x0D, SET8|0x0D, SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', NOP, NOP, SET8|'/', SET8|'/', NOP, NOP, 0x33, 0x00,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0xC2, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+
+#endif
+
+#if !defined(DKKEYMAP) && !defined(UKKEYMAP) && !defined(GRKEYMAP) && !defined(SWKEYMAP) && !defined(RUKEYMAP)
+keymap_t key_map = { 0x69, /* US iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, '1', '!', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '@', 0x00, 0x00, '2', '@', 0x00, 0x00, 0x00, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, '3', '#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, '4', '$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, '5', '%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '^', 0x1E, 0x1E, '6', '^', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=08 */ '7', '&', NOP, NOP, '7', '&', NOP, NOP, 0x33, 0x00,
+/* sc=09 */ '8', '*', NOP, NOP, '8', '*', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '9', '(', NOP, NOP, '9', '(', NOP, NOP, 0x33, 0x00,
+/* sc=0b */ '0', ')', NOP, NOP, '0', ')', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '-', '_', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, 0x00, 0x00,
+/* sc=0d */ '=', '+', NOP, NOP, '=', '+', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x33, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ '[', '{', 0x1B, 0x1B, '[', '{', 0x1B, 0x1B, 0x00, 0x00,
+/* sc=1b */ ']', '}', 0x1D, 0x1D, ']', '}', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ ';', ':', NOP, NOP, ';', ':', NOP, NOP, 0x33, 0x00,
+/* sc=28 */ '\'', '"', NOP, NOP, '\'', '"', NOP, NOP, 0x33, 0x00,
+/* sc=29 */ '`', '~', NOP, NOP, '`', '~', NOP, NOP, 0x33, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\\', '|', 0x1C, 0x1C, '\\', '|', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', '<', NOP, NOP, ',', '<', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', '>', NOP, NOP, '.', '>', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '/', '?', NOP, NOP, '/', '?', NOP, NOP, 0x33, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, 0xFF, 0x00,
+/* sc=46 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', '-', '-', '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ NOP, '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', '6', '6', '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x00, 0x00,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x00,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+
+#endif
+
+fkeytab_t fkey_tab[60] = {
+/* 00-03 */ {"\033[M", 3}, {"\033[N", 3}, {"\033[O", 3}, {"\033[P", 3},
+/* 04-07 */ {"\033[Q", 3}, {"\033[R", 3}, {"\033[S", 3}, {"\033[T", 3},
+/* 08-0B */ {"\033[U", 3}, {"\033[V", 3}, {"\033[W", 3}, {"\033[X", 3},
+/* 0C-0F */ {"\033[W", 3}, {"\033[X", 3}, {"\033[Y", 3}, {"\033[Z", 3},
+/* 10-13 */ {"\033[a", 3}, {"\033[b", 3}, {"\033[c", 3}, {"\033[d", 3},
+/* 14-17 */ {"\033[e", 3}, {"\033[f", 3}, {"\033[g", 3}, {"\033[h", 3},
+/* 18-1B */ {"\033[g", 3}, {"\033[h", 3}, {"\033[i", 3}, {"\033[j", 3},
+/* 1C-1F */ {"\033[k", 3}, {"\033[l", 3}, {"\033[m", 3}, {"\033[n", 3},
+/* 20-23 */ {"\033[o", 3}, {"\033[p", 3}, {"\033[q", 3}, {"\033[r", 3},
+/* 24-27 */ {"\033[g", 3}, {"\033[h", 3}, {"\033[i", 3}, {"\033[j", 3},
+/* 28-2B */ {"\033[k", 3}, {"\033[l", 3}, {"\033[m", 3}, {"\033[n", 3},
+/* 2C-2F */ {"\033[o", 3}, {"\033[p", 3}, {"\033[q", 3}, {"\033[r", 3},
+/* 30-33 */ {"\033[H", 3}, {"\033[A", 3}, {"\033[I", 3}, {"-" , 1},
+/* 34-37 */ {"\033[D", 3}, {"\177" , 1}, {"\033[C", 3}, {"+" , 1},
+/* 38-3B */ {"\033[F", 3}, {"\033[B", 3}, {"\033[G", 3}, {"\033[L", 3}
+};
diff --git a/sys/i386/isa/lpt.c b/sys/i386/isa/lpt.c
new file mode 100644
index 0000000..3317d12
--- /dev/null
+++ b/sys/i386/isa/lpt.c
@@ -0,0 +1,653 @@
+/*
+ * Copyright (c) 1990 William F. Jolitz, TeleMuse
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This software is a component of "386BSD" developed by
+ * William F. Jolitz, TeleMuse.
+ * 4. Neither the name of the developer nor the name "386BSD"
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
+ * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
+ * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
+ * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
+ * NOT MAKE USE OF THIS WORK.
+ *
+ * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
+ * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
+ * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES
+ * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
+ * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
+ * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
+ * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
+ * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: unknown origin, 386BSD 0.1
+ * $Id: lpt.c,v 1.10 1994/04/06 16:42:33 csgr Exp $
+ */
+
+/*
+ * Device Driver for AT parallel printer port
+ * Written by William Jolitz 12/18/90
+ */
+
+#include "lpt.h"
+#if NLPT > 0
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "user.h"
+#include "buf.h"
+#include "kernel.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "uio.h"
+#include "syslog.h"
+
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/lptreg.h"
+
+#include "i386/include/lpt.h"
+
+#define LPINITRDY 4 /* wait up to 4 seconds for a ready */
+#define LPTOUTTIME 4 /* wait up to 4 seconds for a ready */
+#define LPPRI (PZERO+8)
+#define BUFSIZE 1024
+
+
+/* BIOS printer list - used by BIOS probe*/
+#define BIOS_LPT_PORTS 0x408
+#define BIOS_PORTS (short *)(KERNBASE+BIOS_LPT_PORTS)
+#define BIOS_MAX_LPT 4
+
+
+#ifndef DEBUG
+#define lprintf (void)
+#else
+#define lprintf if (lptflag) printf
+int lptflag = 1;
+#endif
+
+#define LPTUNIT(s) ((s)&0x03)
+#define LPTFLAGS(s) ((s)&0xfc)
+
+struct lpt_softc {
+ short sc_port;
+ short sc_state;
+ /* default case: negative prime, negative ack, handshake strobe,
+ prime once */
+ u_char sc_control;
+ char sc_flags;
+#define LP_POS_INIT 0x04 /* if we are a postive init signal */
+#define LP_POS_ACK 0x08 /* if we are a positive going ack */
+#define LP_NO_PRIME 0x10 /* don't prime the printer at all */
+#define LP_PRIMEOPEN 0x20 /* prime on every open */
+#define LP_AUTOLF 0x40 /* tell printer to do an automatic lf */
+#define LP_BYPASS 0x80 /* bypass printer ready checks */
+ struct buf *sc_inbuf;
+ short sc_xfercnt ;
+ char sc_primed;
+ char *sc_cp ;
+ u_char sc_irq ; /* IRQ status of port */
+#define LP_HAS_IRQ 0x01 /* we have an irq available */
+#define LP_USE_IRQ 0x02 /* we are using our irq */
+#define LP_ENABLE_IRQ 0x04 /* enable IRQ on open */
+
+} lpt_sc[NLPT] ;
+
+/* bits for state */
+#define OPEN (1<<0) /* device is open */
+#define ASLP (1<<1) /* awaiting draining of printer */
+#define ERROR (1<<2) /* error was received from printer */
+#define OBUSY (1<<3) /* printer is busy doing output */
+#define LPTOUT (1<<4) /* timeout while not selected */
+#define TOUT (1<<5) /* timeout while not selected */
+#define INIT (1<<6) /* waiting to initialize for open */
+#define INTERRUPTED (1<<7) /* write call was interrupted */
+
+
+/* status masks to interrogate printer status */
+#define RDY_MASK (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR) /* ready ? */
+#define LP_READY (LPS_SEL|LPS_NBSY|LPS_NERR)
+
+/* Printer Ready condition - from lpa.c */
+/* Only used in polling code */
+#define LPS_INVERT (LPS_NBSY | LPS_NACK | LPS_SEL | LPS_NERR)
+#define LPS_MASK (LPS_NBSY | LPS_NACK | LPS_OUT | LPS_SEL | LPS_NERR)
+#define NOT_READY(x) ((inb(x)^LPS_INVERT)&LPS_MASK)
+
+#define MAX_SLEEP (hz*5) /* Timeout while waiting for device ready */
+#define MAX_SPIN 20 /* Max delay for device ready in usecs */
+
+
+static void lptout (struct lpt_softc * sc);
+int lptprobe (struct isa_device *dvp);
+int lptattach (struct isa_device *isdp);
+void lptintr (int unit);
+
+struct isa_driver lptdriver = {
+ lptprobe, lptattach, "lpt"
+};
+
+
+
+/*
+ * Internal routine to lptprobe to do port tests of one byte value
+ */
+static int
+lpt_port_test(short port, u_char data, u_char mask)
+{
+ int temp, timeout;
+
+ data = data & mask;
+ outb(port, data);
+ timeout = 10000;
+ do {
+ DELAY(10);
+ temp = inb(port) & mask;
+ }
+ while (temp != data && --timeout);
+ lprintf("Port 0x%x\tout=%x\tin=%x\ttout=%d\n",
+ port, data, temp, timeout);
+ return (temp == data);
+}
+
+/*
+ * New lpt port probe Geoff Rehmet - Rhodes University - 14/2/94
+ * Based partially on Rod Grimes' printer probe
+ *
+ * Logic:
+ * 1) If no port address was given, use the bios detected ports
+ * and autodetect what ports the printers are on.
+ * 2) Otherwise, probe the data port at the address given,
+ * using the method in Rod Grimes' port probe.
+ * (Much code ripped off directly from Rod's probe.)
+ *
+ * Comments from Rod's probe:
+ * Logic:
+ * 1) You should be able to write to and read back the same value
+ * to the data port. Do an alternating zeros, alternating ones,
+ * walking zero, and walking one test to check for stuck bits.
+ *
+ * 2) You should be able to write to and read back the same value
+ * to the control port lower 5 bits, the upper 3 bits are reserved
+ * per the IBM PC technical reference manauls and different boards
+ * do different things with them. Do an alternating zeros, alternating
+ * ones, walking zero, and walking one test to check for stuck bits.
+ *
+ * Some printers drag the strobe line down when the are powered off
+ * so this bit has been masked out of the control port test.
+ *
+ * XXX Some printers may not like a fast pulse on init or strobe, I
+ * don't know at this point, if that becomes a problem these bits
+ * should be turned off in the mask byte for the control port test.
+ *
+ * We are finally left with a mask of 0x14, due to some printers
+ * being adamant about holding other bits high ........
+ *
+ * Before probing the control port, we write a 0 to the data port -
+ * If not, some printers chuck out garbage when the strobe line
+ * gets toggled.
+ *
+ * 3) Set the data and control ports to a value of 0
+ *
+ * This probe routine has been tested on Epson Lx-800, HP LJ3P,
+ * Epson FX-1170 and C.Itoh 8510RM
+ * printers.
+ * Quick exit on fail added.
+ */
+int
+lptprobe(struct isa_device *dvp)
+{
+ short port;
+ static short next_bios_lpt = 0;
+ int status;
+ u_char data;
+ u_char mask;
+ int i;
+
+ /*
+ * Make sure there is some way for lptopen to see that
+ * the port is not configured
+ * This 0 will remain if the port isn't attached
+ */
+ (lpt_sc + dvp->id_unit)->sc_port = 0;
+
+ status = IO_LPTSIZE;
+ /* If port not specified, use bios list */
+ if(dvp->id_iobase < 0) { /* port? */
+ if((next_bios_lpt < BIOS_MAX_LPT) &&
+ (*(BIOS_PORTS+next_bios_lpt) != 0) ) {
+ dvp->id_iobase = *(BIOS_PORTS+next_bios_lpt++);
+ goto end_probe;
+ } else
+ return (0);
+ }
+
+ /* Port was explicitly specified */
+ /* This allows probing of ports unknown to the BIOS */
+
+ port = dvp->id_iobase + lpt_data;
+ mask = 0xff;
+ data = 0x55; /* Alternating zeros */
+ if (!lpt_port_test(port, data, mask))
+ { status = 0 ; goto end_probe ; }
+
+ data = 0xaa; /* Alternating ones */
+ if (!lpt_port_test(port, data, mask))
+ { status = 0 ; goto end_probe ; }
+
+ for (i = 0; i < 8; i++) { /* Walking zero */
+ data = ~(1 << i);
+ if (!lpt_port_test(port, data, mask))
+ { status = 0 ; goto end_probe ; }
+ }
+
+ for (i = 0; i < 8; i++) { /* Walking one */
+ data = (1 << i);
+ if (!lpt_port_test(port, data, mask))
+ { status = 0 ; goto end_probe ; }
+ }
+
+end_probe:
+ /* write 0's to control and data ports */
+ outb(dvp->id_iobase+lpt_data, 0);
+ outb(dvp->id_iobase+lpt_control, 0);
+
+ return (status);
+}
+
+/* XXX Todo - try and detect if interrupt is working */
+int
+lptattach(struct isa_device *isdp)
+{
+ struct lpt_softc *sc;
+
+ sc = lpt_sc + isdp->id_unit;
+ sc->sc_port = isdp->id_iobase;
+ sc->sc_primed = 0; /* not primed yet */
+ outb(sc->sc_port+lpt_control, LPC_NINIT);
+
+ /* check if we can use interrupt */
+ lprintf("oldirq %x\n", sc->sc_irq);
+ if(isdp->id_irq) {
+ sc->sc_irq = LP_HAS_IRQ | LP_USE_IRQ | LP_ENABLE_IRQ;
+ printf("lpt%d: Interrupt-driven port\n", isdp->id_unit);
+ } else {
+ sc->sc_irq = 0;
+ lprintf("lpt%d: Polled port\n", isdp->id_unit);
+ }
+ lprintf("irq %x\n", sc->sc_irq);
+
+ return (1);
+}
+
+/*
+ * lptopen -- reset the printer, then wait until it's selected and not busy.
+ */
+
+int
+lptopen(dev_t dev, int flag)
+{
+ struct lpt_softc *sc;
+ int s;
+ int trys, port;
+ u_int unit = LPTUNIT(minor(dev));
+
+ sc = lpt_sc + unit;
+ if ((unit >= NLPT) || (sc->sc_port == 0))
+ return (ENXIO);
+
+ if (sc->sc_state) {
+ lprintf("lp: still open\n") ;
+ lprintf("still open %x\n", sc->sc_state);
+ return(EBUSY);
+ } else sc->sc_state |= INIT;
+
+ s = spltty();
+ sc->sc_flags = LPTFLAGS(minor(dev));
+ lprintf("lp flags 0x%x\n", sc->sc_flags);
+ port = sc->sc_port;
+
+ /* set IRQ status according to ENABLE_IRQ flag */
+ if(sc->sc_irq & LP_ENABLE_IRQ)
+ sc->sc_irq |= LP_USE_IRQ;
+ else
+ sc->sc_irq &= ~LP_USE_IRQ;
+
+
+ /* init printer */
+ if((sc->sc_flags & LP_NO_PRIME) == 0) {
+ if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) {
+ outb(port+lpt_control, 0);
+ sc->sc_primed++;
+ DELAY(500);
+ }
+ }
+ outb(port+lpt_control, LPC_SEL|LPC_NINIT);
+
+ /* wait till ready (printer running diagnostics) */
+ trys = 0;
+ do {
+ /* ran out of waiting for the printer */
+ if (trys++ >= LPINITRDY*4) {
+ splx(s);
+ sc->sc_state = 0;
+ lprintf ("status %x\n", inb(port+lpt_status) );
+ return (EBUSY);
+ }
+
+ /* wait 1/4 second, give up if we get a signal */
+ if (tsleep ((caddr_t)sc, LPPRI|PCATCH, "lptinit",
+ hz/4) != EWOULDBLOCK) {
+ sc->sc_state = 0;
+ splx(s);
+ return (EBUSY);
+ }
+
+ /* is printer online and ready for output */
+ } while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
+ (LPS_SEL|LPS_NBSY|LPS_NERR));
+
+ sc->sc_control = LPC_SEL|LPC_NINIT;
+ if(sc->sc_flags&LP_AUTOLF)
+ sc->sc_control |= LPC_AUTOL;
+ /* enable interrupt if interrupt-driven */
+ if(sc->sc_irq & LP_USE_IRQ)
+ sc->sc_control |= LPC_ENA;
+
+ outb(port+lpt_control, sc->sc_control);
+
+ sc->sc_state = OPEN;
+ sc->sc_inbuf = geteblk(BUFSIZE);
+ sc->sc_xfercnt = 0;
+ splx(s);
+
+ /* only use timeout if using interrupt */
+ lprintf("irq %x\n", sc->sc_irq);
+ if(sc->sc_irq & LP_USE_IRQ) {
+ sc->sc_state |= TOUT;
+ timeout ((timeout_func_t)lptout, (caddr_t)sc, hz/2);
+ }
+ lprintf("opened.\n");
+ return(0);
+}
+
+static void
+lptout (struct lpt_softc * sc)
+{ int pl;
+
+ lprintf ("T %x ", inb(sc->sc_port+lpt_status));
+ if (sc->sc_state&OPEN)
+ timeout ((timeout_func_t)lptout, (caddr_t)sc, hz/2);
+ else sc->sc_state &= ~TOUT;
+
+ if (sc->sc_state & ERROR)
+ sc->sc_state &= ~ERROR;
+
+ /*
+ * Avoid possible hangs do to missed interrupts
+ */
+ if (sc->sc_xfercnt) {
+ pl = spltty();
+ lptintr(sc - lpt_sc);
+ splx(pl);
+ } else {
+ sc->sc_state &= ~OBUSY;
+ wakeup((caddr_t)sc);
+ }
+}
+
+/*
+ * lptclose -- close the device, free the local line buffer.
+ *
+ * Check for interrupted write call added.
+ */
+
+int
+lptclose(dev_t dev, int flag)
+{
+ struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
+ int port = sc->sc_port;
+
+ sc->sc_state &= ~OPEN;
+
+ /* if the last write was interrupted, don't complete it */
+ if((!(sc->sc_state & INTERRUPTED)) && (sc->sc_irq & LP_USE_IRQ))
+ while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
+ (LPS_SEL|LPS_NBSY|LPS_NERR) || sc->sc_xfercnt)
+ /* wait 1/4 second, give up if we get a signal */
+ if (tsleep ((caddr_t)sc, LPPRI|PCATCH,
+ "lpclose", hz) != EWOULDBLOCK)
+ break;
+
+ sc->sc_state = 0;
+ sc->sc_xfercnt = 0;
+ outb(sc->sc_port+lpt_control, LPC_NINIT);
+ brelse(sc->sc_inbuf);
+ lprintf("closed.\n");
+ return(0);
+}
+
+/*
+ * pushbytes()
+ * Workhorse for actually spinning and writing bytes to printer
+ * Derived from lpa.c
+ * Originally by ?
+ *
+ * This code is only used when we are polling the port
+ */
+static int
+pushbytes(struct lpt_softc * sc)
+{
+ int spin, err, tic;
+ char ch;
+ int port = sc->sc_port;
+
+ lprintf("p");
+ /* loop for every character .. */
+ while (sc->sc_xfercnt > 0) {
+ /* printer data */
+ ch = *(sc->sc_cp);
+ sc->sc_cp++;
+ sc->sc_xfercnt--;
+
+ /*
+ * Wait for printer ready.
+ * Loop 20 usecs testing BUSY bit, then sleep
+ * for exponentially increasing timeout. (vak)
+ */
+ for (spin=0; NOT_READY(port+lpt_status) && spin<MAX_SPIN; ++spin)
+ DELAY(1); /* XXX delay is NOT this accurate! */
+ if (spin >= MAX_SPIN) {
+ tic = 0;
+ while (NOT_READY(port+lpt_status)) {
+ /*
+ * Now sleep, every cycle a
+ * little longer ..
+ */
+ tic = tic + tic + 1;
+ /*
+ * But no more than 10 seconds. (vak)
+ */
+ if (tic > MAX_SLEEP)
+ tic = MAX_SLEEP;
+ err = tsleep((caddr_t)sc, LPPRI,
+ "lptpoll", tic);
+ if (err != EWOULDBLOCK) {
+ return (err);
+ }
+ }
+ }
+
+ /* output data */
+ outb(port+lpt_data, ch);
+ /* strobe */
+ outb(port+lpt_control, sc->sc_control|LPC_STB);
+ outb(port+lpt_control, sc->sc_control);
+
+ }
+ return(0);
+}
+
+/*
+ * lptwrite --copy a line from user space to a local buffer, then call
+ * putc to get the chars moved to the output queue.
+ *
+ * Flagging of interrupted write added.
+ */
+
+int
+lptwrite(dev_t dev, struct uio * uio)
+{
+ register unsigned n;
+ int pl, err;
+ struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
+
+ sc->sc_state &= ~INTERRUPTED;
+ while (n = MIN(BUFSIZE, uio->uio_resid)) {
+ sc->sc_cp = sc->sc_inbuf->b_un.b_addr ;
+ uiomove(sc->sc_cp, n, uio);
+ sc->sc_xfercnt = n ;
+ while ((sc->sc_xfercnt > 0)&&(sc->sc_irq & LP_USE_IRQ)) {
+ lprintf("i");
+ /* if the printer is ready for a char, */
+ /* give it one */
+ if ((sc->sc_state & OBUSY) == 0){
+ lprintf("\nC %d. ", sc->sc_xfercnt);
+ pl = spltty();
+ lptintr(sc - lpt_sc);
+ (void) splx(pl);
+ }
+ lprintf("W ");
+ if (sc->sc_state & OBUSY)
+ if (err = tsleep ((caddr_t)sc,
+ LPPRI|PCATCH, "lpwrite", 0)) {
+ sc->sc_state |= INTERRUPTED;
+ return(err);
+ }
+ }
+ /* check to see if we must do a polled write */
+ if(!(sc->sc_irq & LP_USE_IRQ) && (sc->sc_xfercnt)) {
+ lprintf("p");
+ if((err = pushbytes(sc)))
+ return(err);
+ }
+ }
+ return(0);
+}
+
+/*
+ * lptintr -- handle printer interrupts which occur when the printer is
+ * ready to accept another char.
+ *
+ * do checking for interrupted write call.
+ */
+
+void
+lptintr(int unit)
+{
+ struct lpt_softc *sc = lpt_sc + unit;
+ int port = sc->sc_port, sts;
+
+ /* is printer online and ready for output */
+ if (((sts=inb(port+lpt_status)) & RDY_MASK) == LP_READY) {
+ sc->sc_state = (sc->sc_state | OBUSY) & ~ERROR;
+
+ if (sc->sc_xfercnt) {
+ /* send char */
+ /*lprintf("%x ", *sc->sc_cp); */
+ outb(port+lpt_data, *sc->sc_cp++) ;
+ outb(port+lpt_control, sc->sc_control|LPC_STB);
+ /* DELAY(X) */
+ outb(port+lpt_control, sc->sc_control);
+
+ /* any more data for printer */
+ if(--(sc->sc_xfercnt) > 0) return;
+ }
+
+ /*
+ * No more data waiting for printer.
+ * Wakeup is not done if write call was interrupted.
+ */
+ sc->sc_state &= ~OBUSY;
+ if(!(sc->sc_state & INTERRUPTED))
+ wakeup((caddr_t)sc);
+ lprintf("w ");
+ return;
+ } else { /* check for error */
+ if(((sts & (LPS_NERR | LPS_OUT) ) != LPS_NERR) &&
+ (sc->sc_state & OPEN))
+ sc->sc_state |= ERROR;
+ }
+ lprintf("sts %x ", sts);
+}
+
+int
+lptioctl(dev_t dev, int cmd, caddr_t data, int flag)
+{
+ int error = 0;
+ struct lpt_softc *sc;
+ u_int unit = LPTUNIT(minor(dev));
+ u_char old_sc_irq; /* old printer IRQ status */
+
+ sc = lpt_sc + unit;
+
+ switch (cmd) {
+ case LPT_IRQ :
+ if(sc->sc_irq & LP_HAS_IRQ) {
+ /*
+ * NOTE:
+ * If the IRQ status is changed,
+ * this will only be visible on the
+ * next open.
+ *
+ * If interrupt status changes,
+ * this gets syslog'd.
+ */
+ old_sc_irq = sc->sc_irq;
+ if(*(int*)data == 0)
+ sc->sc_irq &= (~LP_ENABLE_IRQ);
+ else
+ sc->sc_irq |= LP_ENABLE_IRQ;
+ if (old_sc_irq != sc->sc_irq )
+ log(LOG_NOTICE, "lpt%c switched to %s mode\n",
+ (char)unit+'0',
+ (sc->sc_irq & LP_ENABLE_IRQ)?
+ "interrupt-driven":"polled");
+ } else /* polled port */
+ error = EOPNOTSUPP;
+ break;
+ default:
+ error = ENODEV;
+ }
+
+ return(error);
+}
+
+#endif /* NLPT */
diff --git a/sys/i386/isa/lptreg.h b/sys/i386/isa/lptreg.h
new file mode 100644
index 0000000..9e10ba9
--- /dev/null
+++ b/sys/i386/isa/lptreg.h
@@ -0,0 +1,33 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * form: @(#)lptreg.h 1.1 (Berkeley) 12/19/90
+ * $Id$
+ */
+
+/*
+ * AT Parallel Port (for lineprinter)
+ * Interface port and bit definitions
+ * Written by William Jolitz 12/18/90
+ * Copyright (C) William Jolitz 1990
+ */
+
+#define lpt_data 0 /* Data to/from printer (R/W) */
+
+#define lpt_status 1 /* Status of printer (R) */
+#define LPS_NERR 0x08 /* printer no error */
+#define LPS_SEL 0x10 /* printer selected */
+#define LPS_OUT 0x20 /* printer out of paper */
+#define LPS_NACK 0x40 /* printer no ack of data */
+#define LPS_NBSY 0x80 /* printer no ack of data */
+
+#define lpt_control 2 /* Control printer (R/W) */
+#define LPC_STB 0x01 /* strobe data to printer */
+#define LPC_AUTOL 0x02 /* automatic linefeed */
+#define LPC_NINIT 0x04 /* initialize printer */
+#define LPC_SEL 0x08 /* printer selected */
+#define LPC_ENA 0x10 /* printer out of paper */
diff --git a/sys/i386/isa/mcd.c b/sys/i386/isa/mcd.c
new file mode 100644
index 0000000..7309f42
--- /dev/null
+++ b/sys/i386/isa/mcd.c
@@ -0,0 +1,1335 @@
+/*
+ * Copyright 1993 by Holger Veit (data part)
+ * Copyright 1993 by Brian Moore (audio part)
+ * Changes Copyright 1993 by Gary Clark II
+ *
+ * Rewrote probe routine to work on newer Mitsumi drives.
+ * Additional changes (C) 1994 by Jordan K. Hubbard
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This software was developed by Holger Veit and Brian Moore
+ * for use with "386BSD" and similar operating systems.
+ * "Similar operating systems" includes mainly non-profit oriented
+ * systems for research and education, including but not restricted to
+ * "NetBSD", "FreeBSD", "Mach" (by CMU).
+ * 4. Neither the name of the developer(s) nor the name "386BSD"
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: mcd.c,v 1.15 1994/04/20 07:06:41 davidg Exp $
+ */
+static char COPYRIGHT[] = "mcd-driver (C)1993 by H.Veit & B.Moore";
+
+#include "mcd.h"
+#if NMCD > 0
+#include "types.h"
+#include "param.h"
+#include "systm.h"
+#include "conf.h"
+#include "file.h"
+#include "buf.h"
+#include "stat.h"
+#include "uio.h"
+#include "ioctl.h"
+#include "cdio.h"
+#include "errno.h"
+#include "dkbad.h"
+#include "disklabel.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "mcdreg.h"
+
+/* user definable options */
+/*#define MCD_TO_WARNING_ON*/ /* define to get timeout messages */
+/*#define MCDMINI*/ /* define for a mini configuration for boot kernel */
+
+
+#ifdef MCDMINI
+#define MCD_TRACE(fmt,a,b,c,d)
+#ifdef MCD_TO_WARNING_ON
+#undef MCD_TO_WARNING_ON
+#endif
+#else
+#define MCD_TRACE(fmt,a,b,c,d) {if (mcd_data[unit].debug) {printf("mcd%d st=%02x: ",unit,mcd_data[unit].status); printf(fmt,a,b,c,d);}}
+#endif
+
+#define mcd_part(dev) ((minor(dev)) & 7)
+#define mcd_unit(dev) (((minor(dev)) & 0x38) >> 3)
+#define mcd_phys(dev) (((minor(dev)) & 0x40) >> 6)
+#define RAW_PART 0
+
+/* flags */
+#define MCDOPEN 0x0001 /* device opened */
+#define MCDVALID 0x0002 /* parameters loaded */
+#define MCDINIT 0x0004 /* device is init'd */
+#define MCDWAIT 0x0008 /* waiting for something */
+#define MCDLABEL 0x0010 /* label is read */
+#define MCDPROBING 0x0020 /* probing */
+#define MCDREADRAW 0x0040 /* read raw mode (2352 bytes) */
+#define MCDVOLINFO 0x0080 /* already read volinfo */
+#define MCDTOC 0x0100 /* already read toc */
+#define MCDMBXBSY 0x0200 /* local mbx is busy */
+
+/* status */
+#define MCDAUDIOBSY MCD_ST_AUDIOBSY /* playing audio */
+#define MCDDSKCHNG MCD_ST_DSKCHNG /* sensed change of disk */
+#define MCDDSKIN MCD_ST_DSKIN /* sensed disk in drive */
+#define MCDDOOROPEN MCD_ST_DOOROPEN /* sensed door open */
+
+/* These are apparently the different states a mitsumi can get up to */
+#define MCDCDABSENT 0x0030
+#define MCDCDPRESENT 0x0020
+#define MCDSCLOSED 0x0080
+#define MCDSOPEN 0x00a0
+
+/* toc */
+#define MCD_MAXTOCS 104 /* from the Linux driver */
+#define MCD_LASTPLUS1 170 /* special toc entry */
+
+struct mcd_mbx {
+ short unit;
+ short port;
+ short retry;
+ short nblk;
+ int sz;
+ u_long skip;
+ struct buf *bp;
+ int p_offset;
+ short count;
+};
+
+struct mcd_data {
+ short config;
+ short flags;
+ short status;
+ int blksize;
+ u_long disksize;
+ int iobase;
+ struct disklabel dlabel;
+ int partflags[MAXPARTITIONS];
+ int openflags;
+ struct mcd_volinfo volinfo;
+#ifndef MCDMINI
+ struct mcd_qchninfo toc[MCD_MAXTOCS];
+ short audio_status;
+ struct mcd_read2 lastpb;
+#endif
+ short debug;
+ struct buf head; /* head of buf queue */
+ struct mcd_mbx mbx;
+} mcd_data[NMCD];
+
+/* reader state machine */
+#define MCD_S_BEGIN 0
+#define MCD_S_BEGIN1 1
+#define MCD_S_WAITSTAT 2
+#define MCD_S_WAITMODE 3
+#define MCD_S_WAITREAD 4
+
+/* prototypes */
+int mcdopen(dev_t dev);
+int mcdclose(dev_t dev);
+void mcdstrategy(struct buf *bp);
+int mcdioctl(dev_t dev, int cmd, caddr_t addr, int flags);
+int mcdsize(dev_t dev);
+static void mcd_done(struct mcd_mbx *mbx);
+static void mcd_start(int unit);
+static int mcd_getdisklabel(int unit);
+static void mcd_configure(struct mcd_data *cd);
+static int mcd_get(int unit, char *buf, int nmax);
+static void mcd_setflags(int unit,struct mcd_data *cd);
+static int mcd_getstat(int unit,int sflg);
+static int mcd_send(int unit, int cmd,int nretrys);
+static int bcd2bin(bcd_t b);
+static bcd_t bin2bcd(int b);
+static void hsg2msf(int hsg, bcd_t *msf);
+static int msf2hsg(bcd_t *msf);
+static int mcd_volinfo(int unit);
+static int mcd_waitrdy(int port,int dly);
+static void mcd_doread(int state, struct mcd_mbx *mbxin);
+#ifndef MCDMINI
+static int mcd_setmode(int unit, int mode);
+static int mcd_getqchan(int unit, struct mcd_qchninfo *q);
+static int mcd_subchan(int unit, struct ioc_read_subchannel *sc);
+static int mcd_toc_header(int unit, struct ioc_toc_header *th);
+static int mcd_read_toc(int unit);
+static int mcd_toc_entry(int unit, struct ioc_read_toc_entry *te);
+static int mcd_stop(int unit);
+static int mcd_playtracks(int unit, struct ioc_play_track *pt);
+static int mcd_play(int unit, struct mcd_read2 *pb);
+static int mcd_pause(int unit);
+static int mcd_resume(int unit);
+#endif
+
+extern int hz;
+extern int mcd_probe(struct isa_device *dev);
+extern int mcd_attach(struct isa_device *dev);
+struct isa_driver mcddriver = { mcd_probe, mcd_attach, "mcd" };
+
+#define mcd_put(port,byte) outb(port,byte)
+
+#define MCD_RETRYS 5
+#define MCD_RDRETRYS 8
+
+#define MCDBLK 2048 /* for cooked mode */
+#define MCDRBLK 2352 /* for raw mode */
+
+/* several delays */
+#define RDELAY_WAITSTAT 300
+#define RDELAY_WAITMODE 300
+#define RDELAY_WAITREAD 800
+
+#define DELAY_STATUS 10000l /* 10000 * 1us */
+#define DELAY_GETREPLY 200000l /* 200000 * 2us */
+#define DELAY_SEEKREAD 20000l /* 20000 * 1us */
+#define mcd_delay DELAY
+
+int mcd_attach(struct isa_device *dev)
+{
+ struct mcd_data *cd = mcd_data + dev->id_unit;
+ int i;
+
+ cd->iobase = dev->id_iobase;
+ cd->flags |= MCDINIT;
+ cd->openflags = 0;
+ for (i=0; i<MAXPARTITIONS; i++) cd->partflags[i] = 0;
+
+#ifdef NOTYET
+ /* wire controller for interrupts and dma */
+ mcd_configure(cd);
+#endif
+
+ return 1;
+}
+
+int mcdopen(dev_t dev)
+{
+ int unit,part,phys;
+ struct mcd_data *cd;
+
+ unit = mcd_unit(dev);
+ if (unit >= NMCD)
+ return ENXIO;
+
+ cd = mcd_data + unit;
+ part = mcd_part(dev);
+ phys = mcd_phys(dev);
+
+ /* not initialized*/
+ if (!(cd->flags & MCDINIT))
+ return ENXIO;
+
+ /* invalidated in the meantime? mark all open part's invalid */
+ if (!(cd->flags & MCDVALID) && cd->openflags)
+ return ENXIO;
+
+ if (mcd_getstat(unit,1) < 0)
+ return ENXIO;
+
+ /* XXX get a default disklabel */
+ mcd_getdisklabel(unit);
+
+ if (mcdsize(dev) < 0) {
+ printf("mcd%d: failed to get disk size\n",unit);
+ return ENXIO;
+ } else
+ cd->flags |= MCDVALID;
+
+MCD_TRACE("open: partition=%d, disksize = %d, blksize=%d\n",
+ part,cd->disksize,cd->blksize,0);
+
+ if (part == RAW_PART ||
+ (part < cd->dlabel.d_npartitions &&
+ cd->dlabel.d_partitions[part].p_fstype != FS_UNUSED)) {
+ cd->partflags[part] |= MCDOPEN;
+ cd->openflags |= (1<<part);
+ if (part == RAW_PART && phys != 0)
+ cd->partflags[part] |= MCDREADRAW;
+ return 0;
+ }
+
+ return ENXIO;
+}
+
+int mcdclose(dev_t dev)
+{
+ int unit,part,phys;
+ struct mcd_data *cd;
+
+ unit = mcd_unit(dev);
+ if (unit >= NMCD)
+ return ENXIO;
+
+ cd = mcd_data + unit;
+ part = mcd_part(dev);
+ phys = mcd_phys(dev);
+
+ if (!(cd->flags & MCDINIT))
+ return ENXIO;
+
+ mcd_getstat(unit,1); /* get status */
+
+ /* close channel */
+ cd->partflags[part] &= ~(MCDOPEN|MCDREADRAW);
+ cd->openflags &= ~(1<<part);
+ MCD_TRACE("close: partition=%d\n",part,0,0,0);
+
+ return 0;
+}
+
+void
+mcdstrategy(struct buf *bp)
+{
+ struct mcd_data *cd;
+ struct buf *qp;
+ int s;
+
+ int unit = mcd_unit(bp->b_dev);
+
+ cd = mcd_data + unit;
+
+ /* test validity */
+/*MCD_TRACE("strategy: buf=0x%lx, unit=%ld, block#=%ld bcount=%ld\n",
+ bp,unit,bp->b_blkno,bp->b_bcount);*/
+ if (unit >= NMCD || bp->b_blkno < 0) {
+ printf("mcdstrategy: unit = %d, blkno = %d, bcount = %d\n",
+ unit, bp->b_blkno, bp->b_bcount);
+ pg("mcd: mcdstratregy failure");
+ bp->b_error = EINVAL;
+ bp->b_flags |= B_ERROR;
+ goto bad;
+ }
+
+ /* if device invalidated (e.g. media change, door open), error */
+ if (!(cd->flags & MCDVALID)) {
+MCD_TRACE("strategy: drive not valid\n",0,0,0,0);
+ bp->b_error = EIO;
+ goto bad;
+ }
+
+ /* read only */
+ if (!(bp->b_flags & B_READ)) {
+ bp->b_error = EROFS;
+ goto bad;
+ }
+
+ /* no data to read */
+ if (bp->b_bcount == 0)
+ goto done;
+
+ /* for non raw access, check partition limits */
+ if (mcd_part(bp->b_dev) != RAW_PART) {
+ if (!(cd->flags & MCDLABEL)) {
+ bp->b_error = EIO;
+ goto bad;
+ }
+ /* adjust transfer if necessary */
+ if (bounds_check_with_label(bp,&cd->dlabel,1) <= 0) {
+ goto done;
+ }
+ } else {
+ bp->b_pblkno = bp->b_blkno;
+ bp->b_resid = 0;
+ }
+
+ /* queue it */
+ qp = &cd->head;
+ s = splbio();
+ disksort(qp,bp);
+ splx(s);
+
+ /* now check whether we can perform processing */
+ mcd_start(unit);
+ return;
+
+bad:
+ bp->b_flags |= B_ERROR;
+done:
+ bp->b_resid = bp->b_bcount;
+ biodone(bp);
+ return;
+}
+
+static void mcd_start(int unit)
+{
+ struct mcd_data *cd = mcd_data + unit;
+ struct buf *bp, *qp = &cd->head;
+ struct partition *p;
+ int part;
+ register s = splbio();
+
+ if (cd->flags & MCDMBXBSY)
+ return;
+
+ if ((bp = qp->b_actf) != 0) {
+ /* block found to process, dequeue */
+ /*MCD_TRACE("mcd_start: found block bp=0x%x\n",bp,0,0,0);*/
+ qp->b_actf = bp->av_forw;
+ splx(s);
+ } else {
+ /* nothing to do */
+ splx(s);
+ return;
+ }
+
+ /* changed media? */
+ if (!(cd->flags & MCDVALID)) {
+ MCD_TRACE("mcd_start: drive not valid\n",0,0,0,0);
+ return;
+ }
+
+ p = cd->dlabel.d_partitions + mcd_part(bp->b_dev);
+
+ cd->flags |= MCDMBXBSY;
+ cd->mbx.unit = unit;
+ cd->mbx.port = cd->iobase;
+ cd->mbx.retry = MCD_RETRYS;
+ cd->mbx.bp = bp;
+ cd->mbx.p_offset = p->p_offset;
+
+ /* calling the read routine */
+ mcd_doread(MCD_S_BEGIN,&(cd->mbx));
+ /* triggers mcd_start, when successful finished */
+ return;
+}
+
+int mcdioctl(dev_t dev, int cmd, caddr_t addr, int flags)
+{
+ struct mcd_data *cd;
+ int unit,part;
+
+ unit = mcd_unit(dev);
+ part = mcd_part(dev);
+ cd = mcd_data + unit;
+
+#ifdef MCDMINI
+ return ENOTTY;
+#else
+ if (!(cd->flags & MCDVALID))
+ return EIO;
+MCD_TRACE("ioctl called 0x%x\n",cmd,0,0,0);
+
+ switch (cmd) {
+ case DIOCSBAD:
+ return EINVAL;
+ case DIOCGDINFO:
+ case DIOCGPART:
+ case DIOCWDINFO:
+ case DIOCSDINFO:
+ case DIOCWLABEL:
+ return ENOTTY;
+ case CDIOCPLAYTRACKS:
+ return mcd_playtracks(unit, (struct ioc_play_track *) addr);
+ case CDIOCPLAYBLOCKS:
+ return mcd_play(unit, (struct mcd_read2 *) addr);
+ case CDIOCREADSUBCHANNEL:
+ return mcd_subchan(unit, (struct ioc_read_subchannel *) addr);
+ case CDIOREADTOCHEADER:
+ return mcd_toc_header(unit, (struct ioc_toc_header *) addr);
+ case CDIOREADTOCENTRYS:
+ return mcd_toc_entry(unit, (struct ioc_read_toc_entry *) addr);
+ case CDIOCSETPATCH:
+ case CDIOCGETVOL:
+ case CDIOCSETVOL:
+ case CDIOCSETMONO:
+ case CDIOCSETSTERIO:
+ case CDIOCSETMUTE:
+ case CDIOCSETLEFT:
+ case CDIOCSETRIGHT:
+ return EINVAL;
+ case CDIOCRESUME:
+ return mcd_resume(unit);
+ case CDIOCPAUSE:
+ return mcd_pause(unit);
+ case CDIOCSTART:
+ return EINVAL;
+ case CDIOCSTOP:
+ return mcd_stop(unit);
+ case CDIOCEJECT:
+ return EINVAL;
+ case CDIOCSETDEBUG:
+ cd->debug = 1;
+ return 0;
+ case CDIOCCLRDEBUG:
+ cd->debug = 0;
+ return 0;
+ case CDIOCRESET:
+ return EINVAL;
+ default:
+ return ENOTTY;
+ }
+ /*NOTREACHED*/
+#endif /*!MCDMINI*/
+}
+
+/* this could have been taken from scsi/cd.c, but it is not clear
+ * whether the scsi cd driver is linked in
+ */
+static int mcd_getdisklabel(int unit)
+{
+ struct mcd_data *cd = mcd_data + unit;
+
+ if (cd->flags & MCDLABEL)
+ return -1;
+
+ bzero(&cd->dlabel,sizeof(struct disklabel));
+ strncpy(cd->dlabel.d_typename,"Mitsumi CD ROM ",16);
+ strncpy(cd->dlabel.d_packname,"unknown ",16);
+ cd->dlabel.d_secsize = cd->blksize;
+ cd->dlabel.d_nsectors = 100;
+ cd->dlabel.d_ntracks = 1;
+ cd->dlabel.d_ncylinders = (cd->disksize/100)+1;
+ cd->dlabel.d_secpercyl = 100;
+ cd->dlabel.d_secperunit = cd->disksize;
+ cd->dlabel.d_rpm = 300;
+ cd->dlabel.d_interleave = 1;
+ cd->dlabel.d_flags = D_REMOVABLE;
+ cd->dlabel.d_npartitions= 1;
+ cd->dlabel.d_partitions[0].p_offset = 0;
+ cd->dlabel.d_partitions[0].p_size = cd->disksize;
+ cd->dlabel.d_partitions[0].p_fstype = 9;
+ cd->dlabel.d_magic = DISKMAGIC;
+ cd->dlabel.d_magic2 = DISKMAGIC;
+ cd->dlabel.d_checksum = dkcksum(&cd->dlabel);
+
+ cd->flags |= MCDLABEL;
+ return 0;
+}
+
+int mcdsize(dev_t dev)
+{
+ int size;
+ int unit = mcd_unit(dev);
+ struct mcd_data *cd = mcd_data + unit;
+
+ if (mcd_volinfo(unit) >= 0) {
+ cd->blksize = MCDBLK;
+ size = msf2hsg(cd->volinfo.vol_msf);
+ cd->disksize = size * (MCDBLK/DEV_BSIZE);
+ return 0;
+ }
+ return -1;
+}
+
+/***************************************************************
+ * lower level of driver starts here
+ **************************************************************/
+
+#ifdef NOTDEF
+static char
+irqs[] = {
+ 0x00,0x00,0x10,0x20,0x00,0x30,0x00,0x00,
+ 0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00
+};
+
+static char
+drqs[] = {
+ 0x00,0x01,0x00,0x03,0x00,0x05,0x06,0x07,
+};
+#endif
+
+static void
+mcd_configure(struct mcd_data *cd)
+{
+ outb(cd->iobase+mcd_config,cd->config);
+}
+
+/* Wait for non-busy - return 0 on timeout */
+static int
+twiddle_thumbs(int port, int unit, int count, char *whine)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (!(inb(port+MCD_FLAGS) & MCD_ST_BUSY)) {
+ return 1;
+ }
+ }
+#ifdef MCD_TO_WARNING_ON
+ printf("mcd%d: timeout %s\n", unit, whine);
+#endif
+ return 0;
+}
+
+/* check to see if a Mitsumi CD-ROM is attached to the ISA bus */
+
+int
+mcd_probe(struct isa_device *dev)
+{
+ int port = dev->id_iobase;
+ int unit = dev->id_unit;
+ int i, j;
+ int status;
+ unsigned char stbytes[3];
+
+ mcd_data[unit].flags = MCDPROBING;
+
+#ifdef NOTDEF
+ /* get irq/drq configuration word */
+ mcd_data[unit].config = irqs[dev->id_irq]; /* | drqs[dev->id_drq];*/
+#else
+ mcd_data[unit].config = 0;
+#endif
+
+ /* send a reset */
+ outb(port+MCD_FLAGS, M_RESET);
+
+ /*
+ * delay awhile by getting any pending garbage (old data) and
+ * throwing it away.
+ */
+ for (i = 1000000; i != 0; i--) {
+ inb(port+MCD_FLAGS);
+ }
+
+ /* Get status */
+ outb(port+MCD_DATA, MCD_CMDGETSTAT);
+ if (!twiddle_thumbs(port, unit, 1000000, "getting status")) {
+ return 0; /* Timeout */
+ }
+ status = inb(port+MCD_DATA);
+ if (status != MCDCDABSENT && status != MCDCDPRESENT &&
+ status != MCDSOPEN && status != MCDSCLOSED)
+ return 0; /* Not actually a Mitsumi drive here */
+ /* Get version information */
+ outb(port+MCD_DATA, MCD_CMDCONTINFO);
+ for (j = 0; j < 3; j++) {
+ if (!twiddle_thumbs(port, unit, 3000, "getting version info")) {
+ return 0;
+ }
+ stbytes[j] = (inb(port+MCD_DATA) & 0xFF);
+ }
+ printf("mcd%d: version information is %x %c %x\n", unit,
+ stbytes[0], stbytes[1], stbytes[2]);
+ if (stbytes[1] >= 4) {
+ outb(port+MCD_CTRL, M_PICKLE);
+ printf("mcd%d: Adjusted for newer drive model\n", unit);
+ }
+ return 4;
+}
+
+
+static int
+mcd_waitrdy(int port,int dly)
+{
+ int i;
+
+ /* wait until xfer port senses data ready */
+ for (i=0; i<dly; i++) {
+ if ((inb(port+mcd_xfer) & MCD_ST_BUSY)==0)
+ return 0;
+ mcd_delay(1);
+ }
+ return -1;
+}
+
+static int
+mcd_getreply(int unit,int dly)
+{
+ int i;
+ struct mcd_data *cd = mcd_data + unit;
+ int port = cd->iobase;
+
+ /* wait data to become ready */
+ if (mcd_waitrdy(port,dly)<0) {
+#ifdef MCD_TO_WARNING_ON
+ printf("mcd%d: timeout getreply\n",unit);
+#endif
+ return -1;
+ }
+
+ /* get the data */
+ return inb(port+mcd_status) & 0xFF;
+}
+
+static int
+mcd_getstat(int unit,int sflg)
+{
+ int i;
+ struct mcd_data *cd = mcd_data + unit;
+ int port = cd->iobase;
+
+ /* get the status */
+ if (sflg)
+ outb(port+mcd_command, MCD_CMDGETSTAT);
+ i = mcd_getreply(unit,DELAY_GETREPLY);
+ if (i<0) return -1;
+
+ cd->status = i;
+
+ mcd_setflags(unit,cd);
+ return cd->status;
+}
+
+static void
+mcd_setflags(int unit, struct mcd_data *cd)
+{
+ /* check flags */
+ if (cd->status & (MCDDSKCHNG|MCDDOOROPEN)) {
+ MCD_TRACE("getstat: sensed DSKCHNG or DOOROPEN\n",0,0,0,0);
+ cd->flags &= ~MCDVALID;
+ }
+
+#ifndef MCDMINI
+ if (cd->status & MCDAUDIOBSY)
+ cd->audio_status = CD_AS_PLAY_IN_PROGRESS;
+ else if (cd->audio_status == CD_AS_PLAY_IN_PROGRESS)
+ cd->audio_status = CD_AS_PLAY_COMPLETED;
+#endif
+}
+
+static int
+mcd_get(int unit, char *buf, int nmax)
+{
+ int port = mcd_data[unit].iobase;
+ int i,k;
+
+ for (i=0; i<nmax; i++) {
+ /* wait for data */
+ if ((k = mcd_getreply(unit,DELAY_GETREPLY)) < 0) {
+#ifdef MCD_TO_WARNING_ON
+ printf("mcd%d: timeout mcd_get\n",unit);
+#endif
+ return -1;
+ }
+ buf[i] = k;
+ }
+ return i;
+}
+
+static int
+mcd_send(int unit, int cmd,int nretrys)
+{
+ int i,k;
+ int port = mcd_data[unit].iobase;
+
+/*MCD_TRACE("mcd_send: command = 0x%x\n",cmd,0,0,0);*/
+ for (i=0; i<nretrys; i++) {
+ outb(port+mcd_command, cmd);
+ if ((k=mcd_getstat(unit,0)) != -1) {
+ break;
+ }
+ }
+ if (i == nretrys) {
+ printf("mcd%d: mcd_send retry cnt exceeded\n",unit);
+ return -1;
+ }
+/*MCD_TRACE("mcd_send: status = 0x%x\n",k,0,0,0);*/
+ return 0;
+}
+
+static int
+bcd2bin(bcd_t b)
+{
+ return (b >> 4) * 10 + (b & 15);
+}
+
+static bcd_t
+bin2bcd(int b)
+{
+ return ((b / 10) << 4) | (b % 10);
+}
+
+static void
+hsg2msf(int hsg, bcd_t *msf)
+{
+ hsg += 150;
+ M_msf(msf) = bin2bcd(hsg / 4500);
+ hsg %= 4500;
+ S_msf(msf) = bin2bcd(hsg / 75);
+ F_msf(msf) = bin2bcd(hsg % 75);
+}
+
+static int
+msf2hsg(bcd_t *msf)
+{
+ return (bcd2bin(M_msf(msf)) * 60 +
+ bcd2bin(S_msf(msf))) * 75 +
+ bcd2bin(F_msf(msf)) - 150;
+}
+
+static int
+mcd_volinfo(int unit)
+{
+ struct mcd_data *cd = mcd_data + unit;
+ int i;
+
+/*MCD_TRACE("mcd_volinfo: enter\n",0,0,0,0);*/
+
+ /* Get the status, in case the disc has been changed */
+ if (mcd_getstat(unit, 1) < 0) return EIO;
+
+ /* Just return if we already have it */
+ if (cd->flags & MCDVOLINFO) return 0;
+
+ /* send volume info command */
+ if (mcd_send(unit,MCD_CMDGETVOLINFO,MCD_RETRYS) < 0)
+ return -1;
+
+ /* get data */
+ if (mcd_get(unit,(char*) &cd->volinfo,sizeof(struct mcd_volinfo)) < 0) {
+ printf("mcd%d: mcd_volinfo: error read data\n",unit);
+ return -1;
+ }
+
+ if (cd->volinfo.trk_low != 0 || cd->volinfo.trk_high != 0) {
+ cd->flags |= MCDVOLINFO; /* volinfo is OK */
+ return 0;
+ }
+
+ return -1;
+}
+
+void
+mcdintr(unit)
+ int unit;
+{
+ int port = mcd_data[unit].iobase;
+ u_int i;
+
+ MCD_TRACE("stray interrupt xfer=0x%x\n",inb(port+mcd_xfer),0,0,0);
+
+ /* just read out status and ignore the rest */
+ if ((inb(port+mcd_xfer)&0xFF) != 0xFF) {
+ i = inb(port+mcd_status);
+ }
+}
+
+/* state machine to process read requests
+ * initialize with MCD_S_BEGIN: calculate sizes, and read status
+ * MCD_S_WAITSTAT: wait for status reply, set mode
+ * MCD_S_WAITMODE: waits for status reply from set mode, set read command
+ * MCD_S_WAITREAD: wait for read ready, read data
+ */
+static struct mcd_mbx *mbxsave;
+
+static void
+mcd_doread(int state, struct mcd_mbx *mbxin)
+{
+ struct mcd_mbx *mbx = (state!=MCD_S_BEGIN) ? mbxsave : mbxin;
+ int unit = mbx->unit;
+ int port = mbx->port;
+ struct buf *bp = mbx->bp;
+ struct mcd_data *cd = mcd_data + unit;
+
+ int rm,i,k;
+ struct mcd_read2 rbuf;
+ int blknum;
+ caddr_t addr;
+
+loop:
+ switch (state) {
+ case MCD_S_BEGIN:
+ mbx = mbxsave = mbxin;
+
+ case MCD_S_BEGIN1:
+ /* get status */
+ outb(port+mcd_command, MCD_CMDGETSTAT);
+ mbx->count = RDELAY_WAITSTAT;
+ timeout((timeout_func_t)mcd_doread,
+ (caddr_t)MCD_S_WAITSTAT,hz/100); /* XXX */
+ return;
+ case MCD_S_WAITSTAT:
+ untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITSTAT);
+ if (mbx->count-- >= 0) {
+ if (inb(port+mcd_xfer) & MCD_ST_BUSY) {
+ timeout((timeout_func_t)mcd_doread,
+ (caddr_t)MCD_S_WAITSTAT,hz/100); /* XXX */
+ return;
+ }
+ mcd_setflags(unit,cd);
+ MCD_TRACE("got WAITSTAT delay=%d\n",
+ RDELAY_WAITSTAT-mbx->count,0,0,0);
+ /* reject, if audio active */
+ if (cd->status & MCDAUDIOBSY) {
+ printf("mcd%d: audio is active\n",unit);
+ goto readerr;
+ }
+
+ /* to check for raw/cooked mode */
+ if (cd->flags & MCDREADRAW) {
+ rm = MCD_MD_RAW;
+ mbx->sz = MCDRBLK;
+ } else {
+ rm = MCD_MD_COOKED;
+ mbx->sz = cd->blksize;
+ }
+
+ mbx->count = RDELAY_WAITMODE;
+
+ mcd_put(port+mcd_command, MCD_CMDSETMODE);
+ mcd_put(port+mcd_command, rm);
+ timeout((timeout_func_t)mcd_doread,
+ (caddr_t)MCD_S_WAITMODE,hz/100); /* XXX */
+ return;
+ } else {
+#ifdef MCD_TO_WARNING_ON
+ printf("mcd%d: timeout getstatus\n",unit);
+#endif
+ goto readerr;
+ }
+
+ case MCD_S_WAITMODE:
+ untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITMODE);
+ if (mbx->count-- < 0) {
+#ifdef MCD_TO_WARNING_ON
+ printf("mcd%d: timeout set mode\n",unit);
+#endif
+ goto readerr;
+ }
+ if (inb(port+mcd_xfer) & MCD_ST_BUSY) {
+ timeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITMODE,hz/100);
+ return;
+ }
+ mcd_setflags(unit,cd);
+ MCD_TRACE("got WAITMODE delay=%d\n",
+ RDELAY_WAITMODE-mbx->count,0,0,0);
+ /* for first block */
+ mbx->nblk = (bp->b_bcount + (mbx->sz-1)) / mbx->sz;
+ mbx->skip = 0;
+
+nextblock:
+ blknum = (bp->b_blkno / (mbx->sz/DEV_BSIZE))
+ + mbx->p_offset + mbx->skip/mbx->sz;
+
+ MCD_TRACE("mcd_doread: read blknum=%d for bp=0x%x\n",
+ blknum,bp,0,0);
+
+ /* build parameter block */
+ hsg2msf(blknum,rbuf.start_msf);
+
+ /* send the read command */
+ mcd_put(port+mcd_command,MCD_CMDREAD2);
+ mcd_put(port+mcd_command,rbuf.start_msf[0]);
+ mcd_put(port+mcd_command,rbuf.start_msf[1]);
+ mcd_put(port+mcd_command,rbuf.start_msf[2]);
+ mcd_put(port+mcd_command,0);
+ mcd_put(port+mcd_command,0);
+ mcd_put(port+mcd_command,1);
+ mbx->count = RDELAY_WAITREAD;
+ timeout((timeout_func_t)mcd_doread,
+ (caddr_t)MCD_S_WAITREAD,hz/100); /* XXX */
+ return;
+ case MCD_S_WAITREAD:
+ untimeout((timeout_func_t)mcd_doread,(caddr_t)MCD_S_WAITREAD);
+ if (mbx->count-- > 0) {
+ k = inb(port+mcd_xfer);
+ if ((k & 2)==0) {
+ MCD_TRACE("got data delay=%d\n",
+ RDELAY_WAITREAD-mbx->count,0,0,0);
+ /* data is ready */
+ addr = bp->b_un.b_addr + mbx->skip;
+ outb(port+mcd_ctl2,0x04); /* XXX */
+ for (i=0; i<mbx->sz; i++)
+ *addr++ = inb(port+mcd_rdata);
+ outb(port+mcd_ctl2,0x0c); /* XXX */
+
+ if (--mbx->nblk > 0) {
+ mbx->skip += mbx->sz;
+ goto nextblock;
+ }
+
+ /* return buffer */
+ bp->b_resid = 0;
+ biodone(bp);
+
+ cd->flags &= ~MCDMBXBSY;
+ mcd_start(mbx->unit);
+ return;
+ }
+ if ((k & 4)==0)
+ mcd_getstat(unit,0);
+ timeout((timeout_func_t)mcd_doread,
+ (caddr_t)MCD_S_WAITREAD,hz/100); /* XXX */
+ return;
+ } else {
+#ifdef MCD_TO_WARNING_ON
+ printf("mcd%d: timeout read data\n",unit);
+#endif
+ goto readerr;
+ }
+ }
+
+readerr:
+ if (mbx->retry-- > 0) {
+#ifdef MCD_TO_WARNING_ON
+ printf("mcd%d: retrying\n",unit);
+#endif
+ state = MCD_S_BEGIN1;
+ goto loop;
+ }
+
+ /* invalidate the buffer */
+ bp->b_flags |= B_ERROR;
+ bp->b_resid = bp->b_bcount;
+ biodone(bp);
+ mcd_start(mbx->unit);
+ return;
+
+#ifdef NOTDEF
+ printf("mcd%d: unit timeout, resetting\n",mbx->unit);
+ outb(mbx->port+mcd_reset,MCD_CMDRESET);
+ DELAY(300000);
+ (void)mcd_getstat(mbx->unit,1);
+ (void)mcd_getstat(mbx->unit,1);
+ /*cd->status &= ~MCDDSKCHNG; */
+ cd->debug = 1; /* preventive set debug mode */
+
+#endif
+
+}
+
+#ifndef MCDMINI
+static int
+mcd_setmode(int unit, int mode)
+{
+ struct mcd_data *cd = mcd_data + unit;
+ int port = cd->iobase;
+ int retry;
+
+ printf("mcd%d: setting mode to %d\n", unit, mode);
+ for(retry=0; retry<MCD_RETRYS; retry++)
+ {
+ outb(port+mcd_command, MCD_CMDSETMODE);
+ outb(port+mcd_command, mode);
+ if (mcd_getstat(unit, 0) != -1) return 0;
+ }
+
+ return -1;
+}
+
+static int
+mcd_toc_header(int unit, struct ioc_toc_header *th)
+{
+ struct mcd_data *cd = mcd_data + unit;
+
+ if (mcd_volinfo(unit) < 0) {
+ return ENXIO;
+ }
+
+ th->len = msf2hsg(cd->volinfo.vol_msf);
+ th->starting_track = bcd2bin(cd->volinfo.trk_low);
+ th->ending_track = bcd2bin(cd->volinfo.trk_high);
+
+ return 0;
+}
+
+static int
+mcd_read_toc(int unit)
+{
+ struct mcd_data *cd = mcd_data + unit;
+ struct ioc_toc_header th;
+ struct mcd_qchninfo q;
+ int rc, trk, idx, retry;
+
+ /* Only read TOC if needed */
+ if (cd->flags & MCDTOC) {
+ return 0;
+ }
+
+ printf("mcd%d: reading toc header\n", unit);
+ if (mcd_toc_header(unit, &th) != 0) {
+ return ENXIO;
+ }
+
+ printf("mcd%d: stopping play\n", unit);
+ if ((rc=mcd_stop(unit)) != 0) {
+ return rc;
+ }
+
+ /* try setting the mode twice */
+ if (mcd_setmode(unit, MCD_MD_TOC) != 0) {
+ return EIO;
+ }
+ if (mcd_setmode(unit, MCD_MD_TOC) != 0) {
+ return EIO;
+ }
+
+ printf("mcd%d: get_toc reading qchannel info\n",unit);
+ for(trk=th.starting_track; trk<=th.ending_track; trk++)
+ cd->toc[trk].idx_no = 0;
+ trk = th.ending_track - th.starting_track + 1;
+ for(retry=0; retry<300 && trk>0; retry++)
+ {
+ if (mcd_getqchan(unit, &q) < 0) break;
+ idx = bcd2bin(q.idx_no);
+ if (idx>0 && idx < MCD_MAXTOCS && q.trk_no==0) {
+ if (cd->toc[idx].idx_no == 0) {
+ cd->toc[idx] = q;
+ trk--;
+ }
+ }
+ }
+
+ if (mcd_setmode(unit, MCD_MD_COOKED) != 0) {
+ return EIO;
+ }
+
+ if (trk != 0) {
+ return ENXIO;
+ }
+
+ /* add a fake last+1 */
+ idx = th.ending_track + 1;
+ cd->toc[idx].ctrl_adr = cd->toc[idx-1].ctrl_adr;
+ cd->toc[idx].trk_no = 0;
+ cd->toc[idx].idx_no = 0xAA;
+ cd->toc[idx].hd_pos_msf[0] = cd->volinfo.vol_msf[0];
+ cd->toc[idx].hd_pos_msf[1] = cd->volinfo.vol_msf[1];
+ cd->toc[idx].hd_pos_msf[2] = cd->volinfo.vol_msf[2];
+
+ cd->flags |= MCDTOC;
+
+ return 0;
+}
+
+static int
+mcd_toc_entry(int unit, struct ioc_read_toc_entry *te)
+{
+ struct mcd_data *cd = mcd_data + unit;
+ struct ret_toc {
+ struct ioc_toc_header th;
+ struct cd_toc_entry rt;
+ } ret_toc;
+ struct ioc_toc_header th;
+ int rc, i;
+
+ /* Make sure we have a valid toc */
+ if ((rc=mcd_read_toc(unit)) != 0) {
+ return rc;
+ }
+
+ /* find the toc to copy*/
+ i = te->starting_track;
+ if (i == MCD_LASTPLUS1) {
+ i = bcd2bin(cd->volinfo.trk_high) + 1;
+ }
+
+ /* verify starting track */
+ if (i < bcd2bin(cd->volinfo.trk_low) ||
+ i > bcd2bin(cd->volinfo.trk_high)+1) {
+ return EINVAL;
+ }
+
+ /* do we have room */
+ if (te->data_len < sizeof(struct ioc_toc_header) +
+ sizeof(struct cd_toc_entry)) {
+ return EINVAL;
+ }
+
+ /* Copy the toc header */
+ if (mcd_toc_header(unit, &th) < 0) {
+ return EIO;
+ }
+ ret_toc.th = th;
+
+ /* copy the toc data */
+ ret_toc.rt.control = cd->toc[i].ctrl_adr;
+ ret_toc.rt.addr_type = te->address_format;
+ ret_toc.rt.track = i;
+ if (te->address_format == CD_MSF_FORMAT) {
+ ret_toc.rt.addr.addr[1] = cd->toc[i].hd_pos_msf[0];
+ ret_toc.rt.addr.addr[2] = cd->toc[i].hd_pos_msf[1];
+ ret_toc.rt.addr.addr[3] = cd->toc[i].hd_pos_msf[2];
+ }
+
+ /* copy the data back */
+ copyout(&ret_toc, te->data, sizeof(struct cd_toc_entry)
+ + sizeof(struct ioc_toc_header));
+
+ return 0;
+}
+
+static int
+mcd_stop(int unit)
+{
+ struct mcd_data *cd = mcd_data + unit;
+
+ if (mcd_send(unit, MCD_CMDSTOPAUDIO, MCD_RETRYS) < 0) {
+ return ENXIO;
+ }
+ cd->audio_status = CD_AS_PLAY_COMPLETED;
+ return 0;
+}
+
+static int
+mcd_getqchan(int unit, struct mcd_qchninfo *q)
+{
+ struct mcd_data *cd = mcd_data + unit;
+
+ if (mcd_send(unit, MCD_CMDGETQCHN, MCD_RETRYS) < 0) {
+ return -1;
+ }
+ if (mcd_get(unit, (char *) q, sizeof(struct mcd_qchninfo)) < 0) {
+ return -1;
+ }
+ if (cd->debug) {
+ printf("mcd%d: qchannel ctl=%d, t=%d, i=%d, ttm=%d:%d.%d dtm=%d:%d.%d\n",
+ unit,
+ q->ctrl_adr, q->trk_no, q->idx_no,
+ q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2],
+ q->trk_size_msf[0], q->trk_size_msf[1], q->trk_size_msf[2]);
+ }
+ return 0;
+}
+
+static int
+mcd_subchan(int unit, struct ioc_read_subchannel *sc)
+{
+ struct mcd_data *cd = mcd_data + unit;
+ struct mcd_qchninfo q;
+ struct cd_sub_channel_info data;
+
+ printf("mcd%d: subchan af=%d, df=%d\n", unit,
+ sc->address_format,
+ sc->data_format);
+ if (sc->address_format != CD_MSF_FORMAT) {
+ return EIO;
+ }
+ if (sc->data_format != CD_CURRENT_POSITION) {
+ return EIO;
+ }
+ if (mcd_getqchan(unit, &q) < 0) {
+ return EIO;
+ }
+
+ data.header.audio_status = cd->audio_status;
+ data.what.position.data_format = CD_MSF_FORMAT;
+ data.what.position.track_number = bcd2bin(q.trk_no);
+
+ if (copyout(&data, sc->data, sizeof(struct cd_sub_channel_info))!=0) {
+ return EFAULT;
+ }
+ return 0;
+}
+
+static int
+mcd_playtracks(int unit, struct ioc_play_track *pt)
+{
+ struct mcd_data *cd = mcd_data + unit;
+ struct mcd_read2 pb;
+ int a = pt->start_track;
+ int z = pt->end_track;
+ int rc;
+
+ if ((rc = mcd_read_toc(unit)) != 0) {
+ return rc;
+ }
+ printf("mcd%d: playtracks from %d:%d to %d:%d\n", unit,
+ a, pt->start_index, z, pt->end_index);
+
+ if (a < cd->volinfo.trk_low || a > cd->volinfo.trk_high || a > z ||
+ z < cd->volinfo.trk_low || z > cd->volinfo.trk_high) {
+ return EINVAL;
+ }
+
+ pb.start_msf[0] = cd->toc[a].hd_pos_msf[0];
+ pb.start_msf[1] = cd->toc[a].hd_pos_msf[1];
+ pb.start_msf[2] = cd->toc[a].hd_pos_msf[2];
+ pb.end_msf[0] = cd->toc[z+1].hd_pos_msf[0];
+ pb.end_msf[1] = cd->toc[z+1].hd_pos_msf[1];
+ pb.end_msf[2] = cd->toc[z+1].hd_pos_msf[2];
+
+ return mcd_play(unit, &pb);
+}
+
+static int
+mcd_play(int unit, struct mcd_read2 *pb)
+{
+ struct mcd_data *cd = mcd_data + unit;
+ int port = cd->iobase;
+ int retry, st;
+
+ cd->lastpb = *pb;
+ for(retry=0; retry<MCD_RETRYS; retry++) {
+ outb(port+mcd_command, MCD_CMDREAD2);
+ outb(port+mcd_command, pb->start_msf[0]);
+ outb(port+mcd_command, pb->start_msf[1]);
+ outb(port+mcd_command, pb->start_msf[2]);
+ outb(port+mcd_command, pb->end_msf[0]);
+ outb(port+mcd_command, pb->end_msf[1]);
+ outb(port+mcd_command, pb->end_msf[2]);
+ if ((st=mcd_getstat(unit, 0)) != -1) {
+ break;
+ }
+ }
+
+ if (cd->debug) {
+ printf("mcd%d: mcd_play retry=%d, status=%d\n", unit, retry, st);
+ }
+ if (st == -1) {
+ return ENXIO;
+ }
+ cd->audio_status = CD_AS_PLAY_IN_PROGRESS;
+ return 0;
+}
+
+static int
+mcd_pause(int unit)
+{
+ struct mcd_data *cd = mcd_data + unit;
+ struct mcd_qchninfo q;
+ int rc;
+
+ /* Verify current status */
+ if (cd->audio_status != CD_AS_PLAY_IN_PROGRESS) {
+ printf("mcd%d: pause attempted when not playing\n", unit);
+ return EINVAL;
+ }
+
+ /* Get the current position */
+ if (mcd_getqchan(unit, &q) < 0) {
+ return EIO;
+ }
+
+ /* Copy it into lastpb */
+ cd->lastpb.start_msf[0] = q.hd_pos_msf[0];
+ cd->lastpb.start_msf[1] = q.hd_pos_msf[1];
+ cd->lastpb.start_msf[2] = q.hd_pos_msf[2];
+
+ /* Stop playing */
+ if ((rc=mcd_stop(unit)) != 0) {
+ return rc;
+ }
+
+ /* Set the proper status and exit */
+ cd->audio_status = CD_AS_PLAY_PAUSED;
+ return 0;
+}
+
+static int
+mcd_resume(int unit)
+{
+ struct mcd_data *cd = mcd_data + unit;
+
+ if (cd->audio_status != CD_AS_PLAY_PAUSED) {
+ return EINVAL;
+ }
+ return mcd_play(unit, &cd->lastpb);
+}
+#endif /*!MCDMINI*/
+
+#endif /* NMCD > 0 */
diff --git a/sys/i386/isa/mcdreg.h b/sys/i386/isa/mcdreg.h
new file mode 100644
index 0000000..0ce5de7
--- /dev/null
+++ b/sys/i386/isa/mcdreg.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright 1993 by Holger Veit (data part)
+ * Copyright 1993 by Brian Moore (audio part)
+ * Changes Copyright 1993 by Gary Clark II
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This software was developed by Holger Veit and Brian Moore
+ * for use with "386BSD" and similar operating systems.
+ * "Similar operating systems" includes mainly non-profit oriented
+ * systems for research and education, including but not restricted to
+ * "NetBSD", "FreeBSD", "Mach" (by CMU).
+ * 4. Neither the name of the developer(s) nor the name "386BSD"
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER(S) BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file contains definitions for some cdrom control commands
+ * and status codes. This info was "inherited" from the DOS MTMCDE.SYS
+ * driver, and is thus not complete (and may even be wrong). Some day
+ * the manufacturer or anyone else might provide better documentation,
+ * so this file (and the driver) will then have a better quality.
+ *
+ * $Id: mcdreg.h,v 1.2 1994/01/16 23:34:17 jkh Exp $
+ */
+
+#ifndef MCD_H
+#define MCD_H
+
+#ifdef __GNUC__
+#if __GNUC__ >= 2
+#pragma pack(1)
+#endif
+#endif
+
+typedef unsigned char bcd_t;
+#define M_msf(msf) msf[0]
+#define S_msf(msf) msf[1]
+#define F_msf(msf) msf[2]
+
+/* io lines used */
+#define MCD_IO_BASE 0x300
+
+#define mcd_command 0
+#define mcd_status 0
+#define mcd_rdata 0
+
+#define mcd_reset 1
+#define mcd_xfer 1
+#define mcd_ctl2 2 /* XXX Is this right? */
+#define mcd_config 3
+
+#define MCD_MASK_DMA 0x07 /* bits 2-0 = DMA channel */
+#define MCD_MASK_IRQ 0x70 /* bits 6-4 = INT number */
+ /* 001 = int 2,9 */
+ /* 010 = int 3 */
+ /* 011 = int 5 */
+ /* 100 = int 10 */
+ /* 101 = int 11 */
+/* flags */
+#define STATUS_AVAIL 0xB
+#define DATA_AVAIL 0xF
+
+/* New Flags */
+#define M_STATUS_AVAIL 0xFB
+#define M_DATA_AVAIL 0xFD
+
+/* New Commands */
+#define M_RESET 0x00
+#define M_PICKLE 0x04
+
+/* ports */
+#define MCD_DATA 0
+#define MCD_FLAGS 1
+#define MCD_CTRL 2
+#define CHANNEL 3 /* XXX ??? */
+
+/* Status bits */
+#define MCD_ST_DOOROPEN 0x80
+#define MCD_ST_DSKIN 0x40
+#define MCD_ST_DSKCHNG 0x20
+#define MCD_ST_BUSY 0x04
+#define MCD_ST_AUDIOBSY 0x02
+
+/* commands known by the controller */
+#define MCD_CMDRESET 0x00
+#define MCD_CMDGETVOLINFO 0x10 /* gets mcd_volinfo */
+#define MCD_CMDGETQCHN 0x20 /* gets mcd_qchninfo */
+#define MCD_CMDGETSTAT 0x40 /* gets a byte of status */
+#define MCD_CMDSETMODE 0x50 /* set transmission mode, needs byte */
+#define MCD_MD_RAW 0x60
+#define MCD_MD_COOKED 0x01
+#define MCD_MD_TOC 0x05
+#define MCD_CMDSTOPAUDIO 0x70
+#define MCD_CMDGETVOLUME 0x8E /* gets mcd_volume */
+#define MCD_CMDSETVOLUME 0xAE /* sets mcd_volume */
+#define MCD_CMDREAD1 0xB0 /* read n sectors */
+#define MCD_CMDREAD2 0xC0 /* read from-to */
+#define MCD_CMDCONTINFO 0xDC /* Get controller info */
+#define MCD_CMDEJECTDISK 0xF6
+#define MCD_CMDCLOSETRAY 0xF8
+#define MCD_CMDLOCKDRV 0xFE /* needs byte */
+#define MCD_LK_UNLOCK 0x00
+#define MCD_LK_LOCK 0x01
+#define MCD_LK_TEST 0x02
+
+struct mcd_volinfo {
+ bcd_t trk_low;
+ bcd_t trk_high;
+ bcd_t vol_msf[3];
+ bcd_t trk1_msf[3];
+};
+
+struct mcd_qchninfo {
+ u_char ctrl_adr;
+ u_char trk_no;
+ u_char idx_no;
+ bcd_t trk_size_msf[3];
+ u_char :8;
+ bcd_t hd_pos_msf[3];
+};
+
+struct mcd_volume {
+ u_char v0l;
+ u_char v0rs;
+ u_char v0r;
+ u_char v0ls;
+};
+
+struct mcd_read1 {
+ bcd_t start_msf[3];
+ u_char nsec[3];
+};
+
+struct mcd_read2 {
+ bcd_t start_msf[3];
+ bcd_t end_msf[3];
+};
+#endif /* MCD_H */
diff --git a/sys/i386/isa/mse.c b/sys/i386/isa/mse.c
new file mode 100644
index 0000000..eebe163
--- /dev/null
+++ b/sys/i386/isa/mse.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright 1992 by the University of Guelph
+ *
+ * Permission to use, copy and modify this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation.
+ * University of Guelph makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+/*
+ * Driver for the Logitech and ATI Inport Bus mice for use with 386bsd and
+ * the X386 port, courtesy of
+ * Rick Macklem, rick@snowhite.cis.uoguelph.ca
+ * Caveats: The driver currently uses spltty(), but doesn't use any
+ * generic tty code. It could use splmse() (that only masks off the
+ * bus mouse interrupt, but that would require hacking in i386/isa/icu.s.
+ * (This may be worth the effort, since the Logitech generates 30/60
+ * interrupts/sec continuously while it is open.)
+ * NB: The ATI has NOT been tested yet!
+ */
+
+/*
+ * Modification history:
+ *
+ * Oct 19, 1992 -- E. Stark (stark@cs.sunysb.edu)
+ * fixes to make it work with Microsoft InPort busmouse
+ *
+ * Jan, 1993 -- E. Stark (stark@cs.sunysb.edu)
+ * added patches for new "select" interface
+ *
+ * May 4, 1993 -- E. Stark (stark@cs.sunysb.edu)
+ * changed position of some spl()'s in mseread
+ *
+ * October 8, 1993 -- E. Stark (stark@cs.sunysb.edu)
+ * limit maximum negative x/y value to -127 to work around XFree problem
+ * that causes spurious button pushes.
+ */
+
+#include "mse.h"
+#if NMSE > 0
+#include "param.h"
+#include "proc.h"
+#include "user.h"
+#include "buf.h"
+#include "systm.h"
+#include "kernel.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "uio.h"
+
+#include "i386/isa/isa_device.h"
+#include "i386/isa/icu.h"
+
+static int mseprobe(struct isa_device *);
+static int mseattach(struct isa_device *);
+void mseintr(int);
+
+struct isa_driver msedriver = {
+ mseprobe, mseattach, "mse"
+};
+
+/*
+ * Software control structure for mouse. The sc_enablemouse(),
+ * sc_disablemouse() and sc_getmouse() routines must be called spl'd().
+ */
+#define PROTOBYTES 5
+struct mse_softc {
+ int sc_flags;
+ int sc_mousetype;
+ pid_t sc_selp;
+ u_int sc_port;
+ void (*sc_enablemouse)();
+ void (*sc_disablemouse)();
+ void (*sc_getmouse)();
+ int sc_deltax;
+ int sc_deltay;
+ int sc_obuttons;
+ int sc_buttons;
+ int sc_bytesread;
+ u_char sc_bytes[PROTOBYTES];
+} mse_sc[NMSE];
+
+/* Flags */
+#define MSESC_OPEN 0x1
+#define MSESC_WANT 0x2
+
+/* and Mouse Types */
+#define MSE_LOGITECH 0x1
+#define MSE_ATIINPORT 0x2
+
+#define MSE_PORTA 0
+#define MSE_PORTB 1
+#define MSE_PORTC 2
+#define MSE_PORTD 3
+
+#define MSE_UNIT(dev) (minor(dev) >> 1)
+#define MSE_NBLOCKIO(dev) (minor(dev) & 0x1)
+
+/*
+ * Logitech bus mouse definitions
+ */
+#define MSE_SETUP 0x91 /* What does this mean? */
+#define MSE_HOLD 0x80
+#define MSE_RXLOW 0x00
+#define MSE_RXHIGH 0x20
+#define MSE_RYLOW 0x40
+#define MSE_RYHIGH 0x60
+#define MSE_DISINTR 0x10
+#define MSE_INTREN 0x00
+
+static int mse_probelogi();
+static void mse_enablelogi(), mse_disablelogi(), mse_getlogi();
+
+/*
+ * ATI Inport mouse definitions
+ */
+#define MSE_INPORT_RESET 0x80
+#define MSE_INPORT_STATUS 0x00
+#define MSE_INPORT_DX 0x01
+#define MSE_INPORT_DY 0x02
+#define MSE_INPORT_MODE 0x07
+#define MSE_INPORT_HOLD 0x20
+#define MSE_INPORT_INTREN 0x09
+
+static int mse_probeati();
+static void mse_enableati(), mse_disableati(), mse_getati();
+
+#define MSEPRI (PZERO + 3)
+
+/*
+ * Table of mouse types.
+ * Keep the Logitech last, since I haven't figured out how to probe it
+ * properly yet. (Someday I'll have the documentation.)
+ */
+struct mse_types {
+ int m_type; /* Type of bus mouse */
+ int (*m_probe)(); /* Probe routine to test for it */
+ void (*m_enable)(); /* Start routine */
+ void (*m_disable)(); /* Disable interrupts routine */
+ void (*m_get)(); /* and get mouse status */
+} mse_types[] = {
+ { MSE_ATIINPORT, mse_probeati, mse_enableati, mse_disableati, mse_getati },
+ { MSE_LOGITECH, mse_probelogi, mse_enablelogi, mse_disablelogi, mse_getlogi },
+ { 0, },
+};
+
+int
+mseprobe(idp)
+ register struct isa_device *idp;
+{
+ register struct mse_softc *sc = &mse_sc[idp->id_unit];
+ register int i;
+
+ /*
+ * Check for each mouse type in the table.
+ */
+ i = 0;
+ while (mse_types[i].m_type) {
+ if ((*mse_types[i].m_probe)(idp)) {
+ sc->sc_mousetype = mse_types[i].m_type;
+ sc->sc_enablemouse = mse_types[i].m_enable;
+ sc->sc_disablemouse = mse_types[i].m_disable;
+ sc->sc_getmouse = mse_types[i].m_get;
+ return (1);
+ }
+ i++;
+ }
+ return (0);
+}
+
+int
+mseattach(idp)
+ struct isa_device *idp;
+{
+ struct mse_softc *sc = &mse_sc[idp->id_unit];
+
+ sc->sc_port = idp->id_iobase;
+ return (1);
+}
+
+/*
+ * Exclusive open the mouse, initialize it and enable interrupts.
+ */
+int
+mseopen(dev, flag)
+ dev_t dev;
+ int flag;
+{
+ register struct mse_softc *sc;
+ int s;
+
+ if (MSE_UNIT(dev) >= NMSE)
+ return (ENXIO);
+ sc = &mse_sc[MSE_UNIT(dev)];
+ if (sc->sc_flags & MSESC_OPEN)
+ return (EBUSY);
+ sc->sc_flags |= MSESC_OPEN;
+ sc->sc_obuttons = sc->sc_buttons = 0x7;
+ sc->sc_deltax = sc->sc_deltay = 0;
+ sc->sc_bytesread = PROTOBYTES;
+
+ /*
+ * Initialize mouse interface and enable interrupts.
+ */
+ s = spltty();
+ (*sc->sc_enablemouse)(sc->sc_port);
+ splx(s);
+ return (0);
+}
+
+/*
+ * mseclose: just turn off mouse innterrupts.
+ */
+int
+mseclose(dev, flag)
+ dev_t dev;
+ int flag;
+{
+ struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
+ int s;
+
+ s = spltty();
+ (*sc->sc_disablemouse)(sc->sc_port);
+ sc->sc_flags &= ~MSESC_OPEN;
+ splx(s);
+ return(0);
+}
+
+/*
+ * mseread: return mouse info using the MSC serial protocol, but without
+ * using bytes 4 and 5.
+ * (Yes this is cheesy, but it makes the X386 server happy, so...)
+ */
+int
+mseread(dev, uio)
+ dev_t dev;
+ struct uio *uio;
+{
+ register struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
+ int xfer, s, error;
+
+ /*
+ * If there are no protocol bytes to be read, set up a new protocol
+ * packet.
+ */
+ s = spltty(); /* XXX Should be its own spl, but where is imlXX() */
+ if (sc->sc_bytesread >= PROTOBYTES) {
+ while (sc->sc_deltax == 0 && sc->sc_deltay == 0 &&
+ (sc->sc_obuttons ^ sc->sc_buttons) == 0) {
+ if (MSE_NBLOCKIO(dev)) {
+ splx(s);
+ return (0);
+ }
+ sc->sc_flags |= MSESC_WANT;
+ if (error = tsleep((caddr_t)sc, MSEPRI | PCATCH,
+ "mseread", 0)) {
+ splx(s);
+ return (error);
+ }
+ }
+
+ /*
+ * Generate protocol bytes.
+ * For some reason X386 expects 5 bytes but never uses
+ * the fourth or fifth?
+ */
+ sc->sc_bytes[0] = 0x80 | (sc->sc_buttons & ~0xf8);
+ if (sc->sc_deltax > 127)
+ sc->sc_deltax = 127;
+ if (sc->sc_deltax < -127)
+ sc->sc_deltax = -127;
+ sc->sc_deltay = -sc->sc_deltay; /* Otherwise mousey goes wrong way */
+ if (sc->sc_deltay > 127)
+ sc->sc_deltay = 127;
+ if (sc->sc_deltay < -127)
+ sc->sc_deltay = -127;
+ sc->sc_bytes[1] = sc->sc_deltax;
+ sc->sc_bytes[2] = sc->sc_deltay;
+ sc->sc_bytes[3] = sc->sc_bytes[4] = 0;
+ sc->sc_obuttons = sc->sc_buttons;
+ sc->sc_deltax = sc->sc_deltay = 0;
+ sc->sc_bytesread = 0;
+ }
+ splx(s);
+ xfer = MIN(uio->uio_resid, PROTOBYTES - sc->sc_bytesread);
+ if (error = uiomove(&sc->sc_bytes[sc->sc_bytesread], xfer, uio))
+ return (error);
+ sc->sc_bytesread += xfer;
+ return(0);
+}
+
+/*
+ * mseselect: check for mouse input to be processed.
+ */
+int
+mseselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ register struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)];
+ int s;
+
+ s = spltty();
+ if (sc->sc_bytesread != PROTOBYTES || sc->sc_deltax != 0 ||
+ sc->sc_deltay != 0 || (sc->sc_obuttons ^ sc->sc_buttons) != 0) {
+ splx(s);
+ return (1);
+ }
+
+ /*
+ * Since this is an exclusive open device, any previous proc.
+ * pointer is trash now, so we can just assign it.
+ */
+ sc->sc_selp = p->p_pid;
+ splx(s);
+ return (0);
+}
+
+/*
+ * mseintr: update mouse status. sc_deltax and sc_deltay are accumulative.
+ */
+void
+mseintr(unit)
+ int unit;
+{
+ register struct mse_softc *sc = &mse_sc[unit];
+ pid_t p;
+
+#ifdef DEBUG
+ static int mse_intrcnt = 0;
+ if((mse_intrcnt++ % 10000) == 0)
+ printf("mseintr\n");
+#endif /* DEBUG */
+ if ((sc->sc_flags & MSESC_OPEN) == 0)
+ return;
+
+ (*sc->sc_getmouse)(sc->sc_port, &sc->sc_deltax, &sc->sc_deltay, &sc->sc_buttons);
+
+ /*
+ * If mouse state has changed, wake up anyone wanting to know.
+ */
+ if (sc->sc_deltax != 0 || sc->sc_deltay != 0 ||
+ (sc->sc_obuttons ^ sc->sc_buttons) != 0) {
+ if (sc->sc_flags & MSESC_WANT) {
+ sc->sc_flags &= ~MSESC_WANT;
+ wakeup((caddr_t)sc);
+ }
+ if (sc->sc_selp) {
+ p = sc->sc_selp;
+ sc->sc_selp = (pid_t)0;
+ selwakeup(p, 0);
+ }
+ }
+}
+
+/*
+ * Routines for the Logitech mouse.
+ */
+/*
+ * Test for a Logitech bus mouse and return 1 if it is.
+ * (until I know how to use the signature port properly, just disable
+ * interrupts and return 1)
+ */
+static int
+mse_probelogi(idp)
+ register struct isa_device *idp;
+{
+
+ outb(idp->id_iobase + MSE_PORTB, 0x55);
+ if (inb(idp->id_iobase + MSE_PORTB) == 0x55) {
+ outb(idp->id_iobase + MSE_PORTB, 0xaa);
+ if (inb(idp->id_iobase + MSE_PORTB) == 0xaa)
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Initialize Logitech mouse and enable interrupts.
+ */
+static void
+mse_enablelogi(port)
+ register u_int port;
+{
+ int dx, dy, but;
+
+ outb(port + MSE_PORTD, MSE_SETUP);
+ mse_getlogi(port, &dx, &dy, &but);
+}
+
+/*
+ * Disable interrupts for Logitech mouse.
+ */
+static void
+mse_disablelogi(port)
+ register u_int port;
+{
+
+ outb(port + MSE_PORTC, MSE_DISINTR);
+}
+
+/*
+ * Get the current dx, dy and button up/down state.
+ */
+static void
+mse_getlogi(port, dx, dy, but)
+ register u_int port;
+ int *dx;
+ int *dy;
+ int *but;
+{
+ register char x, y;
+
+ outb(port + MSE_PORTC, MSE_HOLD | MSE_RXLOW);
+ x = inb(port + MSE_PORTA);
+ *but = (x >> 5) & 0x7;
+ x &= 0xf;
+ outb(port + MSE_PORTC, MSE_HOLD | MSE_RXHIGH);
+ x |= (inb(port + MSE_PORTA) << 4);
+ outb(port + MSE_PORTC, MSE_HOLD | MSE_RYLOW);
+ y = (inb(port + MSE_PORTA) & 0xf);
+ outb(port + MSE_PORTC, MSE_HOLD | MSE_RYHIGH);
+ y |= (inb(port + MSE_PORTA) << 4);
+ *dx += x;
+ *dy += y;
+ outb(port + MSE_PORTC, MSE_INTREN);
+}
+
+/*
+ * Routines for the ATI Inport bus mouse.
+ */
+/*
+ * Test for a ATI Inport bus mouse and return 1 if it is.
+ * (do not enable interrupts)
+ */
+static int
+mse_probeati(idp)
+ register struct isa_device *idp;
+{
+ int i;
+
+ for (i = 0; i < 2; i++)
+ if (inb(idp->id_iobase + MSE_PORTC) == 0xde)
+ return (1);
+ return (0);
+}
+
+/*
+ * Initialize ATI Inport mouse and enable interrupts.
+ */
+static void
+mse_enableati(port)
+ register u_int port;
+{
+
+ outb(port + MSE_PORTA, MSE_INPORT_RESET);
+ outb(port + MSE_PORTA, MSE_INPORT_MODE);
+ outb(port + MSE_PORTB, MSE_INPORT_INTREN);
+}
+
+/*
+ * Disable interrupts for ATI Inport mouse.
+ */
+static void
+mse_disableati(port)
+ register u_int port;
+{
+
+ outb(port + MSE_PORTA, MSE_INPORT_MODE);
+ outb(port + MSE_PORTB, 0);
+}
+
+/*
+ * Get current dx, dy and up/down button state.
+ */
+static void
+mse_getati(port, dx, dy, but)
+ register u_int port;
+ int *dx;
+ int *dy;
+ int *but;
+{
+ register char byte;
+
+ outb(port + MSE_PORTA, MSE_INPORT_MODE);
+ outb(port + MSE_PORTB, MSE_INPORT_HOLD);
+ outb(port + MSE_PORTA, MSE_INPORT_STATUS);
+ *but = ~(inb(port + MSE_PORTB) & 0x7);
+ outb(port + MSE_PORTA, MSE_INPORT_DX);
+ byte = inb(port + MSE_PORTB);
+ *dx += byte;
+ outb(port + MSE_PORTA, MSE_INPORT_DY);
+ byte = inb(port + MSE_PORTB);
+ *dy += byte;
+ outb(port + MSE_PORTA, MSE_INPORT_MODE);
+ outb(port + MSE_PORTB, MSE_INPORT_INTREN);
+}
+#endif /* NMSE */
diff --git a/sys/i386/isa/npx.c b/sys/i386/isa/npx.c
new file mode 100644
index 0000000..00424bf
--- /dev/null
+++ b/sys/i386/isa/npx.c
@@ -0,0 +1,552 @@
+/*-
+ * Copyright (c) 1990 William Jolitz.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)npx.c 7.2 (Berkeley) 5/12/91
+ * $Id: npx.c,v 1.6 1994/01/03 07:55:43 davidg Exp $
+ */
+
+#include "npx.h"
+#if NNPX > 0
+
+#include "param.h"
+#include "systm.h"
+#include "conf.h"
+#include "file.h"
+#include "proc.h"
+#include "machine/cpu.h"
+#include "machine/pcb.h"
+#include "machine/trap.h"
+#include "ioctl.h"
+#include "machine/specialreg.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/isa.h"
+
+/*
+ * 387 and 287 Numeric Coprocessor Extension (NPX) Driver.
+ */
+
+#ifdef __GNUC__
+
+#define disable_intr() __asm("cli")
+#define enable_intr() __asm("sti")
+#define fldcw(addr) __asm("fldcw %0" : : "m" (*addr))
+#define fnclex() __asm("fnclex")
+#define fninit() __asm("fninit")
+#define fnsave(addr) __asm("fnsave %0" : "=m" (*addr) : "0" (*addr))
+#define fnstcw(addr) __asm("fnstcw %0" : "=m" (*addr) : "0" (*addr))
+#define fnstsw(addr) __asm("fnstsw %0" : "=m" (*addr) : "0" (*addr))
+#define fp_divide_by_0() __asm("fldz; fld1; fdiv %st,%st(1); fwait")
+#define frstor(addr) __asm("frstor %0" : : "m" (*addr))
+#define fwait() __asm("fwait")
+#define read_eflags() ({u_long ef; \
+ __asm("pushf; popl %0" : "=a" (ef)); \
+ ef; })
+#define start_emulating() __asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \
+ : : "n" (CR0_TS) : "ax")
+#define stop_emulating() __asm("clts")
+#define write_eflags(ef) __asm("pushl %0; popf" : : "a" ((u_long) ef))
+
+#else /* not __GNUC__ */
+
+void disable_intr __P((void));
+void enable_intr __P((void));
+void fldcw __P((caddr_t addr));
+void fnclex __P((void));
+void fninit __P((void));
+void fnsave __P((caddr_t addr));
+void fnstcw __P((caddr_t addr));
+void fnstsw __P((caddr_t addr));
+void fp_divide_by_0 __P((void));
+void frstor __P((caddr_t addr));
+void fwait __P((void));
+u_long read_eflags __P((void));
+void start_emulating __P((void));
+void stop_emulating __P((void));
+void write_eflags __P((u_long ef));
+
+#endif /* __GNUC__ */
+
+typedef u_char bool_t;
+
+extern struct gate_descriptor idt[];
+
+int npxdna __P((void));
+void npxexit __P((struct proc *p));
+void npxinit __P((u_int control));
+void npxintr __P((struct intrframe frame));
+void npxsave __P((struct save87 *addr));
+static int npxattach __P((struct isa_device *dvp));
+static int npxprobe __P((struct isa_device *dvp));
+static int npxprobe1 __P((struct isa_device *dvp));
+
+struct isa_driver npxdriver = {
+ npxprobe, npxattach, "npx",
+};
+
+u_int npx0_imask;
+struct proc *npxproc;
+
+static bool_t npx_ex16;
+static bool_t npx_exists;
+static struct gate_descriptor npx_idt_probeintr;
+static int npx_intrno;
+static volatile u_int npx_intrs_while_probing;
+static bool_t npx_irq13;
+static volatile u_int npx_traps_while_probing;
+
+/*
+ * Special interrupt handlers. Someday intr0-intr15 will be used to count
+ * interrupts. We'll still need a special exception 16 handler. The busy
+ * latch stuff in probintr() can be moved to npxprobe().
+ */
+void probeintr(void);
+asm
+("
+ .text
+_probeintr:
+ ss
+ incl _npx_intrs_while_probing
+ pushl %eax
+ movb $0x20,%al # EOI (asm in strings loses cpp features)
+ outb %al,$0xa0 # IO_ICU2
+ outb %al,$0x20 #IO_ICU1
+ movb $0,%al
+ outb %al,$0xf0 # clear BUSY# latch
+ popl %eax
+ iret
+");
+
+void probetrap(void);
+asm
+("
+ .text
+_probetrap:
+ ss
+ incl _npx_traps_while_probing
+ fnclex
+ iret
+");
+
+/*
+ * Probe routine. Initialize cr0 to give correct behaviour for [f]wait
+ * whether the device exists or not (XXX should be elsewhere). Set flags
+ * to tell npxattach() what to do. Modify device struct if npx doesn't
+ * need to use interrupts. Return 1 if device exists.
+ */
+static int
+npxprobe(dvp)
+ struct isa_device *dvp;
+{
+ int result;
+ u_long save_eflags;
+ u_char save_icu1_mask;
+ u_char save_icu2_mask;
+ struct gate_descriptor save_idt_npxintr;
+ struct gate_descriptor save_idt_npxtrap;
+ /*
+ * This routine is now just a wrapper for npxprobe1(), to install
+ * special npx interrupt and trap handlers, to enable npx interrupts
+ * and to disable other interrupts. Someday isa_configure() will
+ * install suitable handlers and run with interrupts enabled so we
+ * won't need to do so much here.
+ */
+ npx_intrno = NRSVIDT + ffs(dvp->id_irq) - 1;
+ save_eflags = read_eflags();
+ disable_intr();
+ save_icu1_mask = inb(IO_ICU1 + 1);
+ save_icu2_mask = inb(IO_ICU2 + 1);
+ save_idt_npxintr = idt[npx_intrno];
+ save_idt_npxtrap = idt[16];
+ outb(IO_ICU1 + 1, ~(IRQ_SLAVE | dvp->id_irq));
+ outb(IO_ICU2 + 1, ~(dvp->id_irq >> 8));
+ setidt(16, probetrap, SDT_SYS386TGT, SEL_KPL);
+ setidt(npx_intrno, probeintr, SDT_SYS386IGT, SEL_KPL);
+ npx_idt_probeintr = idt[npx_intrno];
+ enable_intr();
+ result = npxprobe1(dvp);
+ disable_intr();
+ outb(IO_ICU1 + 1, save_icu1_mask);
+ outb(IO_ICU2 + 1, save_icu2_mask);
+ idt[npx_intrno] = save_idt_npxintr;
+ idt[16] = save_idt_npxtrap;
+ write_eflags(save_eflags);
+ return (result);
+}
+
+static int
+npxprobe1(dvp)
+ struct isa_device *dvp;
+{
+ int control;
+ int status;
+#ifdef lint
+ npxintr();
+#endif
+ /*
+ * Partially reset the coprocessor, if any. Some BIOS's don't reset
+ * it after a warm boot.
+ */
+ outb(0xf1, 0); /* full reset on some systems, NOP on others */
+ outb(0xf0, 0); /* clear BUSY# latch */
+ /*
+ * Prepare to trap all ESC (i.e., NPX) instructions and all WAIT
+ * instructions. We must set the CR0_MP bit and use the CR0_TS
+ * bit to control the trap, because setting the CR0_EM bit does
+ * not cause WAIT instructions to trap. It's important to trap
+ * WAIT instructions - otherwise the "wait" variants of no-wait
+ * control instructions would degenerate to the "no-wait" variants
+ * after FP context switches but work correctly otherwise. It's
+ * particularly important to trap WAITs when there is no NPX -
+ * otherwise the "wait" variants would always degenerate.
+ *
+ * Try setting CR0_NE to get correct error reporting on 486DX's.
+ * Setting it should fail or do nothing on lesser processors.
+ */
+ load_cr0(rcr0() | CR0_MP | CR0_NE);
+ /*
+ * But don't trap while we're probing.
+ */
+ stop_emulating();
+ /*
+ * Finish resetting the coprocessor, if any. If there is an error
+ * pending, then we may get a bogus IRQ13, but probeintr() will handle
+ * it OK. Bogus halts have never been observed, but we enabled
+ * IRQ13 and cleared the BUSY# latch early to handle them anyway.
+ */
+ fninit();
+ DELAY(1000); /* wait for any IRQ13 (fwait might hang) */
+#ifdef DIAGNOSTIC
+ if (npx_intrs_while_probing != 0)
+ printf("fninit caused %u bogus npx interrupt(s)\n",
+ npx_intrs_while_probing);
+ if (npx_traps_while_probing != 0)
+ printf("fninit caused %u bogus npx trap(s)\n",
+ npx_traps_while_probing);
+#endif
+ /*
+ * Check for a status of mostly zero.
+ */
+ status = 0x5a5a;
+ fnstsw(&status);
+ if ((status & 0xb8ff) == 0) {
+ /*
+ * Good, now check for a proper control word.
+ */
+ control = 0x5a5a;
+ fnstcw(&control);
+ if ((control & 0x1f3f) == 0x033f) {
+ npx_exists = 1;
+ /*
+ * We have an npx, now divide by 0 to see if exception
+ * 16 works.
+ */
+ control &= ~(1 << 2); /* enable divide by 0 trap */
+ fldcw(&control);
+ npx_traps_while_probing = npx_intrs_while_probing = 0;
+ fp_divide_by_0();
+ if (npx_traps_while_probing != 0) {
+ /*
+ * Good, exception 16 works.
+ */
+ npx_ex16 = 1;
+ dvp->id_irq = 0; /* zap the interrupt */
+ /*
+ * special return value to flag that we do not
+ * actually use any I/O registers
+ */
+ return (-1);
+ }
+ if (npx_intrs_while_probing != 0) {
+ /*
+ * Bad, we are stuck with IRQ13.
+ */
+ npx_irq13 = 1;
+ npx0_imask = dvp->id_irq; /* npxattach too late */
+ return (IO_NPXSIZE);
+ }
+ /*
+ * Worse, even IRQ13 is broken. Use emulator.
+ */
+ }
+ }
+ /*
+ * Probe failed, but we want to get to npxattach to initialize the
+ * emulator and say that it has been installed. XXX handle devices
+ * that aren't really devices better.
+ */
+ dvp->id_irq = 0;
+ /*
+ * special return value to flag that we do not
+ * actually use any I/O registers
+ */
+ return (-1);
+}
+
+/*
+ * Attach routine - announce which it is, and wire into system
+ */
+int
+npxattach(dvp)
+ struct isa_device *dvp;
+{
+ if (!npx_ex16 && !npx_irq13) {
+ if (npx_exists)
+ printf("npx%d: Error reporting broken, using 387 emulator\n",dvp->id_unit);
+ else
+ printf("npx%d: 387 Emulator\n",dvp->id_unit);
+ }
+ npxinit(__INITIAL_NPXCW__);
+ return (1); /* XXX unused */
+}
+
+/*
+ * Initialize floating point unit.
+ */
+void
+npxinit(control)
+ u_int control;
+{
+ struct save87 dummy;
+
+ if (!npx_exists)
+ return;
+ /*
+ * fninit has the same h/w bugs as fnsave. Use the detoxified
+ * fnsave to throw away any junk in the fpu. fnsave initializes
+ * the fpu and sets npxproc = NULL as important side effects.
+ */
+ npxsave(&dummy);
+ stop_emulating();
+ fldcw(&control);
+ if (curpcb != NULL)
+ fnsave(&curpcb->pcb_savefpu);
+ start_emulating();
+}
+
+/*
+ * Free coprocessor (if we have it).
+ */
+void
+npxexit(p)
+ struct proc *p;
+{
+
+ if (p == npxproc) {
+ start_emulating();
+ npxproc = NULL;
+ }
+}
+
+/*
+ * Record the FPU state and reinitialize it all except for the control word.
+ * Then generate a SIGFPE.
+ *
+ * Reinitializing the state allows naive SIGFPE handlers to longjmp without
+ * doing any fixups.
+ *
+ * XXX there is currently no way to pass the full error state to signal
+ * handlers, and if this is a nested interrupt there is no way to pass even
+ * a status code! So there is no way to have a non-naive SIGFPE handler. At
+ * best a handler could do an fninit followed by an fldcw of a static value.
+ * fnclex would be of little use because it would leave junk on the FPU stack.
+ * Returning from the handler would be even less safe than usual because
+ * IRQ13 exception handling makes exceptions even less precise than usual.
+ */
+void
+npxintr(frame)
+ struct intrframe frame;
+{
+ int code;
+
+ if (npxproc == NULL || !npx_exists) {
+ /* XXX no %p in stand/printf.c. Cast to quiet gcc -Wall. */
+ printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n",
+ (u_long) npxproc, (u_long) curproc, npx_exists);
+ panic("npxintr from nowhere");
+ }
+ if (npxproc != curproc) {
+ printf("npxintr: npxproc = %lx, curproc = %lx, npx_exists = %d\n",
+ (u_long) npxproc, (u_long) curproc, npx_exists);
+ panic("npxintr from non-current process");
+ }
+ /*
+ * Save state. This does an implied fninit. It had better not halt
+ * the cpu or we'll hang.
+ */
+ outb(0xf0, 0);
+ fnsave(&curpcb->pcb_savefpu);
+ fwait();
+ /*
+ * Restore control word (was clobbered by fnsave).
+ */
+ fldcw(&curpcb->pcb_savefpu.sv_env.en_cw);
+ fwait();
+ /*
+ * Remember the exception status word and tag word. The current
+ * (almost fninit'ed) fpu state is in the fpu and the exception
+ * state just saved will soon be junk. However, the implied fninit
+ * doesn't change the error pointers or register contents, and we
+ * preserved the control word and will copy the status and tag
+ * words, so the complete exception state can be recovered.
+ */
+ curpcb->pcb_savefpu.sv_ex_sw = curpcb->pcb_savefpu.sv_env.en_sw;
+ curpcb->pcb_savefpu.sv_ex_tw = curpcb->pcb_savefpu.sv_env.en_tw;
+
+ /*
+ * Pass exception to process.
+ */
+ if (ISPL(frame.if_cs) == SEL_UPL) {
+ /*
+ * Interrupt is essentially a trap, so we can afford to call
+ * the SIGFPE handler (if any) as soon as the interrupt
+ * returns.
+ *
+ * XXX little or nothing is gained from this, and plenty is
+ * lost - the interrupt frame has to contain the trap frame
+ * (this is otherwise only necessary for the rescheduling trap
+ * in doreti, and the frame for that could easily be set up
+ * just before it is used).
+ */
+ curproc->p_regs = (int *)&frame.if_es;
+#ifdef notyet
+ /*
+ * Encode the appropriate code for detailed information on
+ * this exception.
+ */
+ code = XXX_ENCODE(curpcb->pcb_savefpu.sv_ex_sw);
+#else
+ code = 0; /* XXX */
+#endif
+ trapsignal(curproc, SIGFPE, code);
+ } else {
+ /*
+ * Nested interrupt. These losers occur when:
+ * o an IRQ13 is bogusly generated at a bogus time, e.g.:
+ * o immediately after an fnsave or frstor of an
+ * error state.
+ * o a couple of 386 instructions after
+ * "fstpl _memvar" causes a stack overflow.
+ * These are especially nasty when combined with a
+ * trace trap.
+ * o an IRQ13 occurs at the same time as another higher-
+ * priority interrupt.
+ *
+ * Treat them like a true async interrupt.
+ */
+ psignal(npxproc, SIGFPE);
+ }
+}
+
+/*
+ * Implement device not available (DNA) exception
+ *
+ * It would be better to switch FP context here (only). This would require
+ * saving the state in the proc table instead of in the pcb.
+ */
+int
+npxdna()
+{
+ if (!npx_exists)
+ return (0);
+ if (npxproc != NULL) {
+ printf("npxdna: npxproc = %lx, curproc = %lx\n",
+ (u_long) npxproc, (u_long) curproc);
+ panic("npxdna");
+ }
+ stop_emulating();
+ /*
+ * Record new context early in case frstor causes an IRQ13.
+ */
+ npxproc = curproc;
+ /*
+ * The following frstor may cause an IRQ13 when the state being
+ * restored has a pending error. The error will appear to have been
+ * triggered by the current (npx) user instruction even when that
+ * instruction is a no-wait instruction that should not trigger an
+ * error (e.g., fnclex). On at least one 486 system all of the
+ * no-wait instructions are broken the same as frstor, so our
+ * treatment does not amplify the breakage. On at least one
+ * 386/Cyrix 387 system, fnclex works correctly while frstor and
+ * fnsave are broken, so our treatment breaks fnclex if it is the
+ * first FPU instruction after a context switch.
+ */
+ frstor(&curpcb->pcb_savefpu);
+
+ return (1);
+}
+
+/*
+ * Wrapper for fnsave instruction to handle h/w bugs. If there is an error
+ * pending, then fnsave generates a bogus IRQ13 on some systems. Force
+ * any IRQ13 to be handled immediately, and then ignore it. This routine is
+ * often called at splhigh so it must not use many system services. In
+ * particular, it's much easier to install a special handler than to
+ * guarantee that it's safe to use npxintr() and its supporting code.
+ */
+void
+npxsave(addr)
+ struct save87 *addr;
+{
+ u_char icu1_mask;
+ u_char icu2_mask;
+ u_char old_icu1_mask;
+ u_char old_icu2_mask;
+ struct gate_descriptor save_idt_npxintr;
+
+ disable_intr();
+ old_icu1_mask = inb(IO_ICU1 + 1);
+ old_icu2_mask = inb(IO_ICU2 + 1);
+ save_idt_npxintr = idt[npx_intrno];
+ outb(IO_ICU1 + 1, old_icu1_mask & ~(IRQ_SLAVE | npx0_imask));
+ outb(IO_ICU2 + 1, old_icu2_mask & ~(npx0_imask >> 8));
+ idt[npx_intrno] = npx_idt_probeintr;
+ enable_intr();
+ stop_emulating();
+ fnsave(addr);
+ fwait();
+ start_emulating();
+ npxproc = NULL;
+ disable_intr();
+ icu1_mask = inb(IO_ICU1 + 1); /* masks may have changed */
+ icu2_mask = inb(IO_ICU2 + 1);
+ outb(IO_ICU1 + 1,
+ (icu1_mask & ~npx0_imask) | (old_icu1_mask & npx0_imask));
+ outb(IO_ICU2 + 1,
+ (icu2_mask & ~(npx0_imask >> 8))
+ | (old_icu2_mask & (npx0_imask >> 8)));
+ idt[npx_intrno] = save_idt_npxintr;
+ enable_intr(); /* back to usual state */
+}
+
+#endif /* NNPX > 0 */
diff --git a/sys/i386/isa/pcaudio.c b/sys/i386/isa/pcaudio.c
new file mode 100644
index 0000000..32995b3
--- /dev/null
+++ b/sys/i386/isa/pcaudio.c
@@ -0,0 +1,403 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include "param.h"
+#include "uio.h"
+#include "ioctl.h"
+#include "sound/ulaw.h"
+#include "machine/cpufunc.h"
+#include "machine/pio.h"
+#include "machine/pcaudioio.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/timerreg.h"
+
+#include "pca.h"
+#if NPCA > 0
+
+#define BUF_SIZE 8192
+#define SAMPLE_RATE 8000
+#define INTERRUPT_RATE 16000
+
+static struct pca_status {
+ char open; /* device open */
+ char queries; /* did others try opening */
+ unsigned char *buf[2]; /* double buffering */
+ unsigned char *buffer; /* current buffer ptr */
+ unsigned in_use[2]; /* buffers fill */
+ unsigned index; /* index in current buffer */
+ unsigned counter; /* sample counter */
+ unsigned scale; /* sample counter scale */
+ unsigned sample_rate; /* sample rate */
+ unsigned processed; /* samples processed */
+ unsigned volume; /* volume for pc-speaker */
+ char encoding; /* Ulaw, Alaw or linear */
+ char current; /* current buffer */
+ unsigned char oldval; /* old timer port value */
+ char timer_on; /* is playback running */
+} pca_status;
+
+static char buffer1[BUF_SIZE];
+static char buffer2[BUF_SIZE];
+static char volume_table[256];
+
+static int pca_sleep = 0;
+static int pca_initialized = 0;
+
+void pcaintr(int regs);
+int pcaprobe(struct isa_device *dvp);
+int pcaattach(struct isa_device *dvp);
+int pcaclose(dev_t dev, int flag);
+int pcaopen(dev_t dev, int flag);
+int pcawrite(dev_t dev, struct uio *uio, int flag);
+int pcaioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p);
+
+struct isa_driver pcadriver = {
+ pcaprobe, pcaattach, "pca",
+};
+
+
+inline void conv(const void *table, void *buff, unsigned long n)
+{
+ __asm__("1:\tmovb (%2), %3\n"
+ "\txlatb\n"
+ "\tmovb %3, (%2)\n"
+ "\tinc %2\n"
+ "\tdec %1\n"
+ "\tjnz 1b\n"
+ :
+ :"b" ((long)table), "c" (n), "D" ((long)buff), "a" ((char)n)
+ :"bx","cx","di","ax");
+}
+
+
+static void
+pca_volume(int volume)
+{
+ int i, j;
+
+ for (i=0; i<256; i++) {
+ j = ((i-128)*volume)/100;
+ if (j<-128)
+ j = -128;
+ if (j>127)
+ j = 127;
+ volume_table[i] = (((255-(j + 128))/4)+1);
+ }
+}
+
+
+static void
+pca_init()
+{
+ pca_status.open = 0;
+ pca_status.queries = 0;
+ pca_status.timer_on = 0;
+ pca_status.buf[0] = (unsigned char *)&buffer1[0];
+ pca_status.buf[1] = (unsigned char *)&buffer2[0];
+ pca_status.buffer = pca_status.buf[0];
+ pca_status.in_use[0] = pca_status.in_use[1] = 0;
+ pca_status.current = 0;
+ pca_status.sample_rate = SAMPLE_RATE;
+ pca_status.scale = (pca_status.sample_rate << 8) / INTERRUPT_RATE;
+ pca_status.encoding = AUDIO_ENCODING_ULAW;
+ pca_status.volume = 100;
+
+ pca_volume(pca_status.volume);
+}
+
+
+static int
+pca_start(void)
+{
+ /* use the first buffer */
+ pca_status.current = 0;
+ pca_status.index = 0;
+ pca_status.counter = 0;
+ pca_status.buffer = pca_status.buf[pca_status.current];
+ pca_status.oldval = inb(IO_PPI) | 0x03;
+ /* acquire the timers */
+ if (acquire_timer2(TIMER_LSB|TIMER_ONESHOT)) {
+ return -1;
+ }
+ if (acquire_timer0(INTERRUPT_RATE, pcaintr)) {
+ release_timer2();
+ return -1;
+ }
+ pca_status.timer_on = 1;
+ return 0;
+}
+
+
+static void
+pca_stop(void)
+{
+ /* release the timers */
+ release_timer0();
+ release_timer2();
+ /* reset the buffer */
+ pca_status.in_use[0] = pca_status.in_use[1] = 0;
+ pca_status.index = 0;
+ pca_status.counter = 0;
+ pca_status.current = 0;
+ pca_status.buffer = pca_status.buf[pca_status.current];
+ pca_status.timer_on = 0;
+}
+
+
+static void
+pca_pause()
+{
+ release_timer0();
+ release_timer2();
+ pca_status.timer_on = 0;
+}
+
+
+static void
+pca_continue()
+{
+ pca_status.oldval = inb(IO_PPI) | 0x03;
+ acquire_timer2(TIMER_LSB|TIMER_ONESHOT);
+ acquire_timer0(INTERRUPT_RATE, pcaintr);
+ pca_status.timer_on = 1;
+}
+
+
+static void
+pca_wait(void)
+{
+ while (pca_status.in_use[0] || pca_status.in_use[1]) {
+ pca_sleep = 1;
+ tsleep((caddr_t)&pca_sleep, PZERO|PCATCH, "pca_drain", 0);
+ }
+}
+
+
+int
+pcaprobe(struct isa_device *dvp)
+{
+ return(-1);
+}
+
+
+int
+pcaattach(struct isa_device *dvp)
+{
+ printf(" PCM audio driver\n", dvp->id_unit);
+ pca_init();
+ return 1;
+}
+
+
+int
+pcaopen(dev_t dev, int flag)
+{
+ /* audioctl device can always be opened */
+ if (minor(dev) == 128)
+ return 0;
+ if (minor(dev) > 0)
+ return ENXIO;
+
+ if (!pca_initialized) {
+ pca_init();
+ pca_initialized = 1;
+ }
+
+ /* audio device can only be open by one process */
+ if (pca_status.open) {
+ pca_status.queries = 1;
+ return EBUSY;
+ }
+ pca_status.buffer = pca_status.buf[0];
+ pca_status.in_use[0] = pca_status.in_use[1] = 0;
+ pca_status.timer_on = 0;
+ pca_status.open = 1;
+ pca_status.processed = 0;
+ return 0;
+}
+
+
+int
+pcaclose(dev_t dev, int flag)
+{
+ /* audioctl device can always be closed */
+ if (minor(dev) == 128)
+ return 0;
+ if (minor(dev) > 0)
+ return ENXIO;
+ /* audio device close drains all output and restores timers */
+ pca_wait();
+ pca_stop();
+ pca_status.open = 0;
+ return 0;
+}
+
+
+int
+pcawrite(dev_t dev, struct uio *uio, int flag)
+{
+ int count, which;
+
+ /* only audio device can be written */
+ if (minor(dev) > 0)
+ return ENXIO;
+
+ while ((count = min(BUF_SIZE, uio->uio_resid)) > 0) {
+ which = pca_status.in_use[0] ? 1 : 0;
+ if (count && !pca_status.in_use[which]) {
+ uiomove(pca_status.buf[which], count, uio);
+ pca_status.processed += count;
+ switch (pca_status.encoding) {
+ case AUDIO_ENCODING_ULAW:
+ conv(ulaw_dsp, pca_status.buf[which], count);
+ break;
+
+ case AUDIO_ENCODING_ALAW:
+ break;
+
+ case AUDIO_ENCODING_RAW:
+ break;
+ }
+ pca_status.in_use[which] = count;
+ if (!pca_status.timer_on)
+ if (pca_start())
+ return EBUSY;
+ }
+ if (pca_status.in_use[0] && pca_status.in_use[1]) {
+ pca_sleep = 1;
+ tsleep((caddr_t)&pca_sleep, PZERO|PCATCH, "pca_wait",0);
+ }
+ }
+ return 0;
+}
+
+
+int
+pcaioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
+{
+audio_info_t *auptr;
+
+ switch(cmd) {
+
+ case AUDIO_GETINFO:
+ auptr = (audio_info_t *)data;
+ auptr->play.sample_rate = pca_status.sample_rate;
+ auptr->play.channels = 1;
+ auptr->play.precision = 8;
+ auptr->play.encoding = pca_status.encoding;
+
+ auptr->play.gain = pca_status.volume;
+ auptr->play.port = 0;
+
+ auptr->play.samples = pca_status.processed;
+ auptr->play.eof = 0;
+ auptr->play.pause = !pca_status.timer_on;
+ auptr->play.error = 0;
+ auptr->play.waiting = pca_status.queries;
+
+ auptr->play.open = pca_status.open;
+ auptr->play.active = pca_status.timer_on;
+ return 0;
+
+ case AUDIO_SETINFO:
+ auptr = (audio_info_t *)data;
+ if (auptr->play.sample_rate != (unsigned int)~0) {
+ pca_status.sample_rate = auptr->play.sample_rate;
+ pca_status.scale =
+ (pca_status.sample_rate << 8) / INTERRUPT_RATE;
+ }
+ if (auptr->play.encoding != (unsigned int)~0) {
+ pca_status.encoding = auptr->play.encoding;
+ }
+ if (auptr->play.gain != (unsigned int)~0) {
+ pca_status.volume = auptr->play.gain;
+ pca_volume(pca_status.volume);
+ }
+ if (auptr->play.pause != (unsigned char)~0) {
+ if (auptr->play.pause)
+ pca_pause();
+ else
+ pca_continue();
+ }
+
+ return 0;
+
+ case AUDIO_DRAIN:
+ pca_wait();
+ return 0;
+
+ case AUDIO_FLUSH:
+ pca_stop();
+ return 0;
+
+ }
+ return ENXIO;
+}
+
+
+void
+pcaintr(int regs)
+{
+ if (pca_status.index < pca_status.in_use[pca_status.current]) {
+#if 1
+ disable_intr();
+ __asm__("outb %0,$0x61\n"
+ "andb $0xFE,%0\n"
+ "outb %0,$0x61"
+ : : "a" ((char)pca_status.oldval) );
+ __asm__("xlatb\n"
+ "outb %0,$0x42"
+ : : "a" ((char)pca_status.buffer[pca_status.index]),
+ "b" ((long)volume_table) );
+ enable_intr();
+#else
+ disable_intr();
+ outb(IO_PPI, pca_status.oldval);
+ outb(IO_PPI, pca_status.oldval & 0xFE);
+ outb(TIMER_CNTR2,
+ volume_table[pca_status.buffer[pca_status.index]]);
+ enable_intr();
+#endif
+ pca_status.counter += pca_status.scale;
+ pca_status.index = (pca_status.counter >> 8);
+ }
+ else {
+ pca_status.index = pca_status.counter = 0;
+ pca_status.in_use[pca_status.current] = 0;
+ pca_status.current ^= 1;
+ pca_status.buffer = pca_status.buf[pca_status.current];
+ if (pca_sleep) {
+ wakeup((caddr_t)&pca_sleep);
+ pca_sleep = 0;
+ }
+ }
+}
+
+#endif
diff --git a/sys/i386/isa/rtc.h b/sys/i386/isa/rtc.h
new file mode 100644
index 0000000..ba008b6
--- /dev/null
+++ b/sys/i386/isa/rtc.h
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)rtc.h 7.1 (Berkeley) 5/12/91
+ * $Id: rtc.h,v 1.3 1993/11/07 17:44:34 wollman Exp $
+ */
+
+#ifndef _I386_ISA_RTC_H_
+#define _I386_ISA_RTC_H_ 1
+
+/*
+ * RTC Register locations
+ */
+
+#define RTC_SEC 0x00 /* seconds */
+#define RTC_SECALRM 0x01 /* seconds alarm */
+#define RTC_MIN 0x02 /* minutes */
+#define RTC_MINALRM 0x03 /* minutes alarm */
+#define RTC_HRS 0x04 /* hours */
+#define RTC_HRSALRM 0x05 /* hours alarm */
+#define RTC_WDAY 0x06 /* week day */
+#define RTC_DAY 0x07 /* day of month */
+#define RTC_MONTH 0x08 /* month of year */
+#define RTC_YEAR 0x09 /* month of year */
+#define RTC_STATUSA 0x0a /* status register A */
+#define RTCSA_TUP 0x80 /* time update, don't look now */
+
+#define RTC_STATUSB 0x0b /* status register B */
+
+#define RTC_INTR 0x0c /* status register C (R) interrupt source */
+#define RTCIR_UPDATE 0x10 /* update intr */
+#define RTCIR_ALARM 0x20 /* alarm intr */
+#define RTCIR_PERIOD 0x40 /* periodic intr */
+#define RTCIR_INT 0x80 /* interrupt output signal */
+
+#define RTC_STATUSD 0x0d /* status register D (R) Lost Power */
+#define RTCSD_PWR 0x80 /* clock lost power */
+
+#define RTC_DIAG 0x0e /* status register E - bios diagnostic */
+#define RTCDG_BITS "\020\010clock_battery\007ROM_cksum\006config_unit\005memory_size\004fixed_disk\003invalid_time"
+
+#define RTC_RESET 0x0f /* status register F - reset code byte */
+#define RTCRS_RST 0x00 /* normal reset */
+#define RTCRS_LOAD 0x04 /* load system */
+
+#define RTC_FDISKETTE 0x10 /* diskette drive type in upper/lower nibble */
+#define RTCFDT_NONE 0 /* none present */
+#define RTCFDT_360K 0x10 /* 360K */
+#define RTCFDT_12M 0x20 /* 1.2M */
+#define RTCFDT_720K 0x30 /* 720K */
+#define RTCFDT_144M 0x40 /* 1.44M */
+
+#define RTC_BASELO 0x15 /* low byte of basemem size */
+#define RTC_BASEHI 0x16 /* high byte of basemem size */
+#define RTC_EXTLO 0x17 /* low byte of extended mem size */
+#define RTC_EXTHI 0x18 /* low byte of extended mem size */
+
+#define RTC_CENTURY 0x32 /* current century - please increment in Dec99*/
+#endif /* _I386_ISA_RTC_H_ */
diff --git a/sys/i386/isa/sio.c b/sys/i386/isa/sio.c
new file mode 100644
index 0000000..ad09f7a3
--- /dev/null
+++ b/sys/i386/isa/sio.c
@@ -0,0 +1,1919 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)com.c 7.5 (Berkeley) 5/16/91
+ * $Id: sio.c,v 1.44 1994/04/03 12:25:57 ache Exp $
+ */
+
+#include "sio.h"
+#if NSIO > 0
+/*
+ * Serial driver, based on 386BSD-0.1 com driver.
+ * Mostly rewritten to use pseudo-DMA.
+ * Works for National Semiconductor NS8250-NS16550AF UARTs.
+ * COM driver, based on HP dca driver.
+ */
+#include "param.h"
+#include "systm.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "proc.h"
+#include "user.h"
+#include "conf.h"
+#include "file.h"
+#include "uio.h"
+#include "kernel.h"
+#include "syslog.h"
+
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/comreg.h"
+#include "i386/isa/ic/ns16550.h"
+
+#define FAKE_DCD(unit) ((unit) == comconsole)
+#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
+#define RB_I_HIGH_WATER (RBSZ - 2 * RS_IBUFSIZE)
+#define RB_I_LOW_WATER ((RBSZ - 2 * RS_IBUFSIZE) * 7 / 8)
+#define RS_IBUFSIZE 256
+#define TTY_BI TTY_FE /* XXX */
+#define TTY_OE TTY_PE /* XXX */
+
+#ifdef COM_BIDIR
+#define CALLOUT(x) (minor(x) & COM_CALLOUT_MASK)
+#define COM_CALLOUT_MASK 0x80
+#define COM_MINOR_MAGIC_MASK 0x80
+#else /* COM_BIDIR */
+#define COM_MINOR_MAGIC_MASK 0
+#endif /* COM_BIDIR */
+
+#define UNIT(x) (minor(x) & ~COM_MINOR_MAGIC_MASK)
+
+#ifdef COM_MULTIPORT
+/* checks in flags for multiport and which is multiport "master chip"
+ * for a given card
+ */
+#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
+#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
+#define COM_NOMASTER(dev) ((dev)->id_flags & 0x04)
+#endif /* COM_MULTIPORT */
+
+#define COM_NOFIFO(dev) ((dev)->id_flags & 0x02)
+
+#ifndef FIFO_TRIGGER
+/*
+ * This driver is fast enough to work with any value and for high values
+ * to be only slightly more efficient. Low values may be better because
+ * they give lower latency.
+ * TODO: always use low values for low speeds. Mouse movements are jerky
+ * if more than one packet arrives at once. The low speeds used for
+ * serial mice help avoid this, but not if (large) fifos are enabled.
+ */
+#define FIFO_TRIGGER FIFO_TRIGGER_14
+#endif
+
+#define com_scr 7 /* scratch register for 16450-16550 (R/W) */
+
+#ifndef setsofttty
+#define OLD_INTERRUPT_HANDLING /* XXX FreeBSD-1.1 and earlier */
+#define setsofttty() (ipending |= 1 << 4) /* XXX requires owning IRQ4 */
+extern u_int ipending; /* XXX */
+void softsio1 __P((void));
+#endif
+
+/*
+ * Input buffer watermarks.
+ * The external device is asked to stop sending when the buffer exactly reaches
+ * high water, or when the high level requests it.
+ * The high level is notified immediately (rather than at a later clock tick)
+ * when this watermark is reached.
+ * The buffer size is chosen so the watermark should almost never be reached.
+ * The low watermark is invisibly 0 since the buffer is always emptied all at
+ * once.
+ */
+#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
+
+/*
+ * com state bits.
+ * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
+ * than the other bits so that they can be tested as a group without masking
+ * off the low bits.
+ *
+ * The following com and tty flags correspond closely:
+ * TS_BUSY = CS_BUSY (maintained by comstart() and comflush())
+ * CS_TTGO = ~TS_TTSTOP (maintained by comstart() and siostop())
+ * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam())
+ * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam())
+ * TS_FLUSH is not used.
+ * Bug: I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
+ */
+#define CS_BUSY 0x80 /* output in progress */
+#define CS_TTGO 0x40 /* output not stopped by XOFF */
+#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */
+#define CS_CHECKMSR 1 /* check of MSR scheduled */
+#define CS_CTS_OFLOW 2 /* use CTS output flow control */
+#define CS_ODONE 4 /* output completed */
+#define CS_RTS_IFLOW 8 /* use RTS input flow control */
+
+static char *error_desc[] = {
+#define CE_OVERRUN 0
+ "silo overflow",
+#define CE_INTERRUPT_BUF_OVERFLOW 1
+ "interrupt-level buffer overflow",
+#define CE_TTY_BUF_OVERFLOW 2
+ "tty-level buffer overflow",
+};
+
+#define CE_NTYPES 3
+#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum])
+
+/* types. XXX - should be elsewhere */
+typedef u_int Port_t; /* hardware port */
+typedef u_char bool_t; /* boolean */
+
+/* com device structure */
+struct com_s {
+ u_char state; /* miscellaneous flag bits */
+ u_char cfcr_image; /* copy of value written to CFCR */
+ bool_t hasfifo; /* nonzero for 16550 UARTs */
+ u_char mcr_image; /* copy of value written to MCR */
+#ifdef COM_BIDIR
+ bool_t bidir; /* is this unit bidirectional? */
+ bool_t active; /* is the port active _at all_? */
+ bool_t active_in; /* is the incoming port in use? */
+ bool_t active_out; /* is the outgoing port in use? */
+#endif /* COM_BIDIR */
+#ifdef COM_MULTIPORT
+ bool_t multiport; /* is this unit part of a multiport device? */
+#endif /* COM_MULTIPORT */
+ int dtr_wait; /* time to hold DTR down on close (* 1/HZ) */
+ u_int tx_fifo_size;
+
+ /*
+ * The high level of the driver never reads status registers directly
+ * because there would be too many side effects to handle conveniently.
+ * Instead, it reads copies of the registers stored here by the
+ * interrupt handler.
+ */
+ u_char last_modem_status; /* last MSR read by intr handler */
+ u_char prev_modem_status; /* last MSR handled by high level */
+
+ u_char *ibuf; /* start of input buffer */
+ u_char *ibufend; /* end of input buffer */
+ u_char *ihighwater; /* threshold in input buffer */
+ u_char *iptr; /* next free spot in input buffer */
+
+ u_char *obufend; /* end of output buffer */
+ int ocount; /* original count for current output */
+ u_char *optr; /* next char to output */
+
+ Port_t data_port; /* i/o ports */
+ Port_t int_id_port;
+ Port_t iobase;
+ Port_t modem_ctl_port;
+ Port_t line_status_port;
+ Port_t modem_status_port;
+
+ struct tty *tp; /* cross reference */
+
+#ifdef TIOCTIMESTAMP
+ bool_t do_timestamp;
+ struct timeval timestamp;
+#endif
+
+ u_long bytes_in; /* statistics */
+ u_long bytes_out;
+ u_int delta_error_counts[CE_NTYPES];
+ u_int error_counts[CE_NTYPES];
+
+ /*
+ * Ping-pong input buffers. The extra factor of 2 in the sizes is
+ * to allow for an error byte for each input byte.
+ */
+#define CE_INPUT_OFFSET RS_IBUFSIZE
+ u_char ibuf1[2 * RS_IBUFSIZE];
+ u_char ibuf2[2 * RS_IBUFSIZE];
+};
+
+/*
+ * The public functions in the com module ought to be declared in a com-driver
+ * system header.
+ */
+#define Dev_t int /* promoted dev_t */
+
+/* Interrupt handling entry points. */
+void siointr __P((int unit));
+void siopoll __P((void));
+
+/* Device switch entry points. */
+int sioopen __P((Dev_t dev, int oflags, int devtype,
+ struct proc *p));
+int sioclose __P((Dev_t dev, int fflag, int devtype,
+ struct proc *p));
+int sioread __P((Dev_t dev, struct uio *uio, int ioflag));
+int siowrite __P((Dev_t dev, struct uio *uio, int ioflag));
+int sioioctl __P((Dev_t dev, int cmd, caddr_t data,
+ int fflag, struct proc *p));
+void siostop __P((struct tty *tp, int rw));
+#define sioreset noreset
+int sioselect __P((Dev_t dev, int rw, struct proc *p));
+#define siommap nommap
+#define siostrategy nostrategy
+
+/* Console device entry points. */
+int siocngetc __P((Dev_t dev));
+struct consdev;
+void siocninit __P((struct consdev *cp));
+void siocnprobe __P((struct consdev *cp));
+void siocnputc __P((Dev_t dev, int c));
+
+static int sioattach __P((struct isa_device *dev));
+static void comflush __P((struct com_s *com));
+static void comhardclose __P((struct com_s *com));
+static void siointr1 __P((struct com_s *com));
+static void commctl __P((struct com_s *com, int bits, int how));
+static int comparam __P((struct tty *tp, struct termios *t));
+static int sioprobe __P((struct isa_device *dev));
+static void comstart __P((struct tty *tp));
+static void comwakeup __P((caddr_t chan, int ticks));
+static int tiocm_xxx2mcr __P((int tiocm_xxx));
+
+/* table and macro for fast conversion from a unit number to its com struct */
+static struct com_s *p_com_addr[NSIO];
+#define com_addr(unit) (p_com_addr[unit])
+
+static struct com_s com_structs[NSIO];
+
+#ifdef TIOCTIMESTAMP
+static struct timeval intr_timestamp;
+#endif
+
+struct isa_driver siodriver = {
+ sioprobe, sioattach, "sio"
+};
+
+#ifdef COMCONSOLE
+static int comconsole = COMCONSOLE;
+#else
+static int comconsole = -1;
+#endif
+static speed_t comdefaultrate = TTYDEF_SPEED;
+static u_int com_events; /* input chars + weighted output completions */
+static int commajor;
+#ifdef DONT_MALLOC_TTYS
+#define TB_OUT(tp) (&(tp)->t_out)
+#define TB_RAW(tp) (&(tp)->t_raw)
+struct tty sio_tty[NSIO];
+#else
+#define TB_OUT(tp) ((tp)->t_out)
+#define TB_RAW(tp) ((tp)->t_raw)
+struct tty *sio_tty[NSIO];
+#endif
+extern struct tty *constty;
+extern int tk_nin; /* XXX */
+extern int tk_rawcc; /* XXX */
+
+#ifdef KGDB
+#include "machine/remote-sl.h"
+
+extern int kgdb_dev;
+extern int kgdb_rate;
+extern int kgdb_debug_init;
+#endif
+
+static struct speedtab comspeedtab[] = {
+ 0, 0,
+ 50, COMBRD(50),
+ 75, COMBRD(75),
+ 110, COMBRD(110),
+ 134, COMBRD(134),
+ 150, COMBRD(150),
+ 200, COMBRD(200),
+ 300, COMBRD(300),
+ 600, COMBRD(600),
+ 1200, COMBRD(1200),
+ 1800, COMBRD(1800),
+ 2400, COMBRD(2400),
+ 4800, COMBRD(4800),
+ 9600, COMBRD(9600),
+ 19200, COMBRD(19200),
+ 38400, COMBRD(38400),
+ 57600, COMBRD(57600),
+ 115200, COMBRD(115200),
+ -1, -1
+};
+
+/* XXX - configure this list */
+static Port_t likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, };
+
+static int
+sioprobe(dev)
+ struct isa_device *dev;
+{
+ static bool_t already_init;
+ Port_t *com_ptr;
+ Port_t iobase;
+ int result;
+
+ if (!already_init) {
+ /*
+ * Turn off MCR_IENABLE for all likely serial ports. An unused
+ * port with its MCR_IENABLE gate open will inhibit interrupts
+ * from any used port that shares the interrupt vector.
+ */
+ for (com_ptr = likely_com_ports;
+ com_ptr < &likely_com_ports[sizeof likely_com_ports
+ / sizeof likely_com_ports[0]];
+ ++com_ptr)
+ outb(*com_ptr + com_mcr, 0);
+ already_init = TRUE;
+ }
+ iobase = dev->id_iobase;
+ result = IO_COMSIZE;
+
+ /*
+ * We don't want to get actual interrupts, just masked ones.
+ * Interrupts from this line should already be masked in the ICU,
+ * but mask them in the processor as well in case there are some
+ * (misconfigured) shared interrupts.
+ */
+ disable_intr();
+
+ /*
+ * Initialize the speed so that any junk in the THR or output fifo will
+ * be transmitted in a known time. (There may be lots of junk after a
+ * soft reboot, and output interrupts don't work right after a master
+ * reset, at least for 16550s. (The speed is undefined after MR, but
+ * MR empties the THR and the TSR so it's not clear why this matters)).
+ * Enable output interrupts (only) and check the following:
+ * o the CFCR, IER and MCR in UART hold the values written to them
+ * (the values happen to be all distinct - this is good for
+ * avoiding false positive tests from bus echoes).
+ * o an output interrupt is generated and its vector is correct.
+ * o the interrupt goes away when the IIR in the UART is read.
+ */
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ outb(iobase + com_dlbl, COMBRD(9600) & 0xff);
+ outb(iobase + com_dlbh, (u_int) COMBRD(9600) >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS); /* ensure IER is addressed */
+ outb(iobase + com_mcr, MCR_IENABLE); /* open gate early */
+ outb(iobase + com_ier, 0); /* ensure edge on next intr */
+ outb(iobase + com_ier, IER_ETXRDY); /* generate interrupt */
+ DELAY((16 + 1) * 9600 / 10); /* enough to drain 16 bytes */
+ if ( inb(iobase + com_cfcr) != CFCR_8BITS
+ || inb(iobase + com_ier) != IER_ETXRDY
+ || inb(iobase + com_mcr) != MCR_IENABLE
+#ifndef COM_MULTIPORT /* XXX - need to do more to enable interrupts */
+ || !isa_irq_pending(dev)
+#endif
+ || (inb(iobase + com_iir) & IIR_IMASK) != IIR_TXRDY
+ || isa_irq_pending(dev)
+ || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
+ result = 0;
+
+ /*
+ * Turn off all device interrupts and check that they go off properly.
+ * Leave MCR_IENABLE set. It gates the OUT2 output of the UART to
+ * the ICU input. Closing the gate would give a floating ICU input
+ * (unless there is another device driving at) and spurious interrupts.
+ * (On the system that this was first tested on, the input floats high
+ * and gives a (masked) interrupt as soon as the gate is closed.)
+ */
+ outb(iobase + com_ier, 0);
+ outb(iobase + com_mcr, MCR_IENABLE); /* dummy to avoid bus echo */
+ if ( inb(iobase + com_ier) != 0
+ || isa_irq_pending(dev)
+ || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
+ result = 0;
+ if (result == 0)
+ outb(iobase + com_mcr, 0);
+
+ enable_intr();
+ return (result);
+}
+
+static int
+sioattach(isdp)
+ struct isa_device *isdp;
+{
+ struct com_s *com;
+ static bool_t comwakeup_started = FALSE;
+ Port_t iobase;
+ int s;
+ int unit;
+
+ iobase = isdp->id_iobase;
+ unit = isdp->id_unit;
+ s = spltty();
+
+ /*
+ * sioprobe() has initialized the device registers as follows:
+ * o cfcr = CFCR_8BITS.
+ * It is most important that CFCR_DLAB is off, so that the
+ * data port is not hidden when we enable interrupts.
+ * o ier = 0.
+ * Interrupts are only enabled when the line is open.
+ * o mcr = MCR_IENABLE.
+ * Keeping MCR_DTR and MCR_RTS off might stop the external
+ * device from sending before we are ready.
+ */
+
+ com = &com_structs[unit]; /* XXX malloc it */
+ com->cfcr_image = CFCR_8BITS;
+ com->mcr_image = MCR_IENABLE;
+ com->dtr_wait = 3 * hz;
+ com->tx_fifo_size = 1;
+ com->iptr = com->ibuf = com->ibuf1;
+ com->ibufend = com->ibuf1 + RS_IBUFSIZE;
+ com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
+ com->iobase = iobase;
+ com->data_port = iobase + com_data;
+ com->int_id_port = iobase + com_iir;
+ com->modem_ctl_port = iobase + com_mcr;
+ com->line_status_port = iobase + com_lsr;
+ com->modem_status_port = iobase + com_msr;
+#ifdef DONT_MALLOC_TTYS
+ com->tp = &sio_tty[unit];
+#endif
+
+ /* attempt to determine UART type */
+ printf("sio%d: type", unit);
+#ifdef COM_MULTIPORT
+ if (!COM_ISMULTIPORT(isdp))
+#endif
+ {
+ u_char scr;
+ u_char scr1;
+ u_char scr2;
+
+ scr = inb(iobase + com_scr);
+ outb(iobase + com_scr, 0xa5);
+ scr1 = inb(iobase + com_scr);
+ outb(iobase + com_scr, 0x5a);
+ scr2 = inb(iobase + com_scr);
+ outb(iobase + com_scr, scr);
+ if (scr1 != 0xa5 || scr2 != 0x5a) {
+ printf(" 8250");
+ goto determined_type;
+ }
+ }
+ outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14);
+ DELAY(100);
+ switch (inb(com->int_id_port) & IIR_FIFO_MASK) {
+ case FIFO_TRIGGER_1:
+ printf(" 16450");
+ break;
+ case FIFO_TRIGGER_4:
+ printf(" 16450?");
+ break;
+ case FIFO_TRIGGER_8:
+ printf(" 16550?");
+ break;
+ case FIFO_TRIGGER_14:
+ printf(" 16550A");
+ if (COM_NOFIFO(isdp))
+ printf(" fifo disabled");
+ else {
+ com->hasfifo = TRUE;
+ com->tx_fifo_size = 16;
+ }
+ break;
+ }
+ outb(iobase + com_fifo, 0);
+determined_type: ;
+
+#ifdef COM_MULTIPORT
+ if (COM_ISMULTIPORT(isdp)) {
+ com->multiport = TRUE;
+ printf(" (multiport)");
+
+ /* Note: some cards have no master port (e.g., BocaBoards) */
+ if (!COM_NOMASTER(isdp)) {
+ struct isa_device *masterdev;
+
+ /* set the master's common-interrupt-enable reg.,
+ * as appropriate. YYY See your manual
+ */
+ /* enable only common interrupt for port */
+ outb(com->modem_ctl_port, com->mcr_image = 0);
+
+ masterdev = find_isadev(isa_devtab_tty, &siodriver,
+ COM_MPMASTER(isdp));
+ outb(masterdev->id_iobase + com_scr, 0x80);
+ }
+
+ } else
+ com->multiport = FALSE;
+#endif /* COM_MULTIPORT */
+ printf("\n");
+
+#ifdef KGDB
+ if (kgdb_dev == makedev(commajor, unit)) {
+ if (comconsole == unit)
+ kgdb_dev = -1; /* can't debug over console port */
+ else {
+ int divisor;
+
+ /*
+ * XXX now unfinished and broken. Need to do
+ * something more like a full open(). There's no
+ * suitable interrupt handler so don't enable device
+ * interrupts. Watch out for null tp's.
+ */
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ divisor = ttspeedtab(kgdb_rate, comspeedtab);
+ outb(iobase + com_dlbl, divisor & 0xFF);
+ outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS);
+ outb(com->modem_status_port,
+ com->mcr_image |= MCR_DTR | MCR_RTS);
+
+ if (kgdb_debug_init) {
+ /*
+ * Print prefix of device name,
+ * let kgdb_connect print the rest.
+ */
+ printf("sio%d: ", unit);
+ kgdb_connect(1);
+ } else
+ printf("sio%d: kgdb enabled\n", unit);
+ }
+ }
+#endif
+
+ com_addr(unit) = com;
+ splx(s);
+ if (!comwakeup_started) {
+ comwakeup((caddr_t) NULL, 0);
+ comwakeup_started = TRUE;
+ }
+ return (1);
+}
+
+/* ARGSUSED */
+int
+sioopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+#ifdef COM_BIDIR
+ bool_t callout;
+#endif /* COM_BIDIR */
+ struct com_s *com;
+ int error = 0;
+ bool_t got_status = FALSE;
+ Port_t iobase;
+ int s;
+ struct tty *tp;
+ int unit;
+
+ unit = UNIT(dev);
+ if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL)
+ return (ENXIO);
+#ifdef COM_BIDIR
+ /* if it's a callout device, and bidir not possible on that dev, die */
+ callout = CALLOUT(dev);
+ if (callout && !(com->bidir))
+ return (ENXIO);
+#endif /* COM_BIDIR */
+
+#ifdef DONT_MALLOC_TTYS
+ tp = com->tp;
+#else
+ sio_tty[unit] = ttymalloc(sio_tty[unit]);
+ tp = com->tp = sio_tty[unit];
+#endif
+ s = spltty();
+
+#ifdef COM_BIDIR
+
+bidir_open_top:
+ got_status = FALSE;
+ /* if it's bidirectional, we've gotta deal with it... */
+ if (com->bidir) {
+ if (callout) {
+ if (com->active_in) {
+ /* it's busy. die */
+ splx(s);
+ return (EBUSY);
+ } else {
+ /* it's ours. lock it down, and set it up */
+ com->active_out = TRUE;
+ }
+ } else {
+ if (com->active_out) {
+ /* it's busy, outgoing. wait, if possible */
+ if (flag & O_NONBLOCK) {
+ /* can't wait; bail */
+ splx(s);
+ return (EBUSY);
+ } else {
+ /* wait for it... */
+ error = tsleep((caddr_t)&com->active_out,
+ TTIPRI|PCATCH,
+ "siooth",
+ 0);
+ /* if there was an error, take off. */
+ if (error != 0) {
+ splx(s);
+ return (error);
+ }
+ /* else take it from the top */
+ goto bidir_open_top;
+ }
+ }
+ disable_intr();
+ com->prev_modem_status =
+ com->last_modem_status = inb(com->modem_status_port);
+ enable_intr();
+ got_status = TRUE;
+ if (com->prev_modem_status & MSR_DCD
+ || FAKE_DCD(unit)) {
+ /* there's a carrier on the line; we win */
+ com->active_in = TRUE;
+ } else {
+ /* there is no carrier on the line */
+ if (flag & O_NONBLOCK) {
+ /* can't wait; let it open */
+ com->active_in = TRUE;
+ } else {
+ /* put DTR & RTS up */
+ /* XXX - bring up RTS earlier? */
+ commctl(com, MCR_DTR | MCR_RTS, DMSET);
+ outb(com->iobase + com_ier, IER_EMSC);
+
+ /* wait for it... */
+ error = tsleep((caddr_t)&com->active_in,
+ TTIPRI|PCATCH,
+ "siodcd",
+ 0);
+
+ /* if not active, turn intrs and DTR off */
+ if (!com->active) {
+ outb(com->iobase + com_ier, 0);
+ commctl(com, MCR_DTR, DMBIC);
+ }
+
+ /* if there was an error, take off. */
+ if (error != 0) {
+ splx(s);
+ return (error);
+ }
+ /* else take it from the top */
+ goto bidir_open_top;
+ }
+ }
+ }
+ }
+
+ com->active = TRUE;
+#endif /* COM_BIDIR */
+
+ tp->t_oproc = comstart;
+ tp->t_param = comparam;
+ tp->t_dev = dev;
+ if (!(tp->t_state & TS_ISOPEN)) {
+ tp->t_state |= TS_WOPEN;
+ ttychars(tp);
+ if (tp->t_ispeed == 0) {
+ /*
+ * We don't use all the flags from <sys/ttydefaults.h>
+ * since those are only relevant for logins. It's
+ * important to have echo off initially so that the
+ * line doesn't start blathering before the echo flag
+ * can be turned off.
+ */
+ tp->t_iflag = 0;
+ tp->t_oflag = 0;
+ tp->t_cflag = CREAD | CS8;
+#ifdef COM_BIDIR
+ if (com->bidir && !callout)
+ tp->t_cflag |= HUPCL;
+#endif
+ tp->t_lflag = 0;
+ tp->t_ispeed = tp->t_ospeed = comdefaultrate;
+ if (unit == comconsole) {
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ }
+ }
+
+ /*
+ * XXX the full state after a first open() needs to be
+ * programmable and separate for callin and callout.
+ */
+#ifdef COM_BIDIR
+ if (com->bidir) {
+ if (callout)
+ tp->t_cflag |= CLOCAL;
+ else
+ tp->t_cflag &= ~CLOCAL;
+ }
+#endif
+
+ commctl(com, MCR_DTR | MCR_RTS, DMSET);
+ error = comparam(tp, &tp->t_termios);
+ if (error != 0)
+ goto out;
+ ttsetwater(tp);
+ iobase = com->iobase;
+ if (com->hasfifo) {
+ /* (re)enable and drain FIFO */
+ outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER
+ | FIFO_RCV_RST | FIFO_XMT_RST);
+ DELAY(100);
+ }
+ disable_intr();
+ (void) inb(com->line_status_port);
+ (void) inb(com->data_port);
+ if (!got_status)
+ com->prev_modem_status =
+ com->last_modem_status = inb(com->modem_status_port);
+ outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
+ | IER_EMSC);
+ enable_intr();
+ if (com->prev_modem_status & MSR_DCD || FAKE_DCD(unit))
+ tp->t_state |= TS_CARR_ON;
+ } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
+ splx(s);
+ return (EBUSY);
+ }
+ while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL)
+#ifdef COM_BIDIR
+ /* We went through a lot of trouble to open it,
+ * but it's certain we have a carrier now, so
+ * don't spend any time on it now.
+ */
+ && !(com->bidir)
+#endif /* COM_BIDIR */
+ && !(tp->t_state & TS_CARR_ON)) {
+ tp->t_state |= TS_WOPEN;
+ error = ttysleep(tp, (caddr_t)TB_RAW(tp), TTIPRI | PCATCH,
+ ttopen, 0);
+ if (error != 0)
+ break;
+ }
+out:
+ if (error == 0)
+ error = (*linesw[tp->t_line].l_open)(dev, tp, 0);
+ splx(s);
+
+#ifdef COM_BIDIR
+ /* wakeup sleepers */
+ wakeup((caddr_t) &com->active_in);
+#endif /* COM_BIDIR */
+
+ /*
+ * XXX - the next step was once not done, so interrupts, DTR and RTS
+ * remained hot if the process was killed while it was sleeping
+ * waiting for carrier. Now there is the opposite problem. If several
+ * processes are sleeping waiting for carrier on the same line and one
+ * is killed, interrupts are turned off so the other processes will
+ * never see the carrier rise.
+ */
+ if (error != 0 && !(tp->t_state & TS_ISOPEN))
+ comhardclose(com);
+ tp->t_state &= ~TS_WOPEN;
+
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+sioclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct com_s *com;
+ int s;
+ struct tty *tp;
+
+ com = com_addr(UNIT(dev));
+ tp = com->tp;
+ s = spltty();
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ siostop(tp, FREAD | FWRITE);
+ comhardclose(com);
+ ttyclose(tp);
+ splx(s);
+ return (0);
+}
+
+static void
+comhardclose(com)
+ struct com_s *com;
+{
+ Port_t iobase;
+ int s;
+ struct tty *tp;
+ int unit;
+
+ unit = com - &com_structs[0];
+ iobase = com->iobase;
+ s = spltty();
+#ifdef TIOCTIMESTAMP
+ com->do_timestamp = 0;
+#endif
+ outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
+#ifdef KGDB
+ /* do not disable interrupts or hang up if debugging */
+ if (kgdb_dev != makedev(commajor, unit))
+#endif
+ {
+ outb(iobase + com_ier, 0);
+ tp = com->tp;
+ if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN
+#ifdef COM_BIDIR
+ /*
+ * XXX we will miss any carrier drop between here and the
+ * next open. Perhaps we should watch DCD even when the
+ * port is closed; it is not sufficient to check it at
+ * the next open because it might go up and down while
+ * we're not watching. And we shouldn't look at DCD if
+ * CLOCAL is set (here or for the dialin device ...).
+ * When the termios state is reinitialized for initial
+ * opens, the correct CLOCAL bit will be
+ * ((the bit now) & (the initial bit)).
+ */
+ || com->active_in
+ && !(com->prev_modem_status & MSR_DCD) && !FAKE_DCD(unit)
+#endif
+ || !(tp->t_state & TS_ISOPEN)) {
+ commctl(com, MCR_RTS, DMSET);
+ if (com->dtr_wait != 0)
+ /*
+ * Uninterruptible sleep since we want to
+ * wait a fixed time.
+ * XXX - delay in open() (if necessary),
+ * not here (always).
+ */
+ tsleep((caddr_t)&com->dtr_wait, TTIPRI,
+ "sioclose", com->dtr_wait);
+ }
+ }
+
+#ifdef COM_BIDIR
+ com->active = com->active_in = com->active_out = FALSE;
+
+ /* wakeup sleepers who are waiting for out to finish */
+ wakeup((caddr_t) &com->active_out);
+#endif /* COM_BIDIR */
+
+ splx(s);
+}
+
+int
+sioread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct tty *tp = com_addr(UNIT(dev))->tp;
+
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+int
+siowrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int unit = UNIT(dev);
+ struct tty *tp = com_addr(unit)->tp;
+
+ /*
+ * (XXX) We disallow virtual consoles if the physical console is
+ * a serial port. This is in case there is a display attached that
+ * is not the console. In that situation we don't need/want the X
+ * server taking over the console.
+ */
+ if (constty && unit == comconsole)
+ constty = NULL;
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+#ifdef TIOCTIMESTAMP
+/* Interrupt routine for timekeeping purposes */
+void
+siointrts(unit)
+ int unit;
+{
+ microtime(&intr_timestamp);
+ siointr(unit);
+}
+#endif
+
+void
+siointr(unit)
+ int unit;
+{
+#ifndef COM_MULTIPORT
+ siointr1(com_addr(unit));
+#else /* COM_MULTIPORT */
+ bool_t possibly_more_intrs;
+ struct com_s *com;
+
+ /*
+ * Loop until there is no activity on any port. This is necessary
+ * to get an interrupt edge more than to avoid another interrupt.
+ * If the IRQ signal is just an OR of the IRQ signals from several
+ * devices, then the edge from one may be lost because another is
+ * on.
+ */
+ do {
+ possibly_more_intrs = FALSE;
+ for (unit = 0; unit < NSIO; ++unit) {
+ com = com_addr(unit);
+ if (com != NULL
+ && (inb(com->int_id_port) & IIR_IMASK)
+ != IIR_NOPEND) {
+ siointr1(com);
+ possibly_more_intrs = TRUE;
+ }
+ }
+ } while (possibly_more_intrs);
+#endif /* COM_MULTIPORT */
+}
+
+static void
+siointr1(com)
+ struct com_s *com;
+{
+ u_char line_status;
+ u_char modem_status;
+ u_char *ioptr;
+ u_char recv_data;
+
+#ifdef TIOCTIMESTAMP
+ if (com->do_timestamp)
+ /* XXX a little bloat here... */
+ com->timestamp = intr_timestamp;
+#endif
+ while (TRUE) {
+ line_status = inb(com->line_status_port);
+
+ /* input event? (check first to help avoid overruns) */
+ while (line_status & LSR_RCV_MASK) {
+ /* break/unnattached error bits or real input? */
+ if (!(line_status & LSR_RXRDY))
+ recv_data = 0;
+ else
+ recv_data = inb(com->data_port);
+ ++com->bytes_in;
+ /* XXX reduce SLIP input latency */
+#define FRAME_END 0xc0
+ if (recv_data == FRAME_END)
+ setsofttty();
+#ifdef KGDB
+ /* trap into kgdb? (XXX - needs testing and optim) */
+ if (recv_data == FRAME_END
+ && !(com->tp->t_state & TS_ISOPEN)
+ && kgdb_dev == makedev(commajor, unit)) {
+ kgdb_connect(0);
+ continue;
+ }
+#endif /* KGDB */
+ ioptr = com->iptr;
+ if (ioptr >= com->ibufend)
+ CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
+ else {
+ ++com_events;
+#if 0 /* for testing input latency vs efficiency */
+if (com->iptr - com->ibuf == 8)
+ setsofttty();
+#endif
+ ioptr[0] = recv_data;
+ ioptr[CE_INPUT_OFFSET] = line_status;
+ com->iptr = ++ioptr;
+ if (ioptr == com->ihighwater
+ && com->state & CS_RTS_IFLOW)
+ outb(com->modem_ctl_port,
+ com->mcr_image &= ~MCR_RTS);
+ /* XXX - move this out of isr */
+ if (line_status & LSR_OE)
+ CE_RECORD(com, CE_OVERRUN);
+ }
+
+ /*
+ * "& 0x7F" is to avoid the gcc-1.40 generating a slow
+ * jump from the top of the loop to here
+ */
+ line_status = inb(com->line_status_port) & 0x7F;
+ }
+
+ /* modem status change? (always check before doing output) */
+ modem_status = inb(com->modem_status_port);
+ if (modem_status != com->last_modem_status) {
+ /*
+ * Schedule high level to handle DCD changes. Note
+ * that we don't use the delta bits anywhere. Some
+ * UARTs mess them up, and it's easy to remember the
+ * previous bits and calculate the delta.
+ */
+ com->last_modem_status = modem_status;
+ if (!(com->state & CS_CHECKMSR)) {
+ com_events += LOTS_OF_EVENTS;
+ com->state |= CS_CHECKMSR;
+ setsofttty();
+ }
+
+ /* handle CTS change immediately for crisp flow ctl */
+ if (com->state & CS_CTS_OFLOW) {
+ if (modem_status & MSR_CTS)
+ com->state |= CS_ODEVREADY;
+ else
+ com->state &= ~CS_ODEVREADY;
+ }
+ }
+
+ /* output queued and everything ready? */
+ if (line_status & LSR_TXRDY
+ && com->state >= (CS_ODEVREADY | CS_BUSY | CS_TTGO)) {
+ ioptr = com->optr;
+ if (com->tx_fifo_size > 1) {
+ u_int ocount;
+
+ ocount = com->obufend - ioptr;
+ if (ocount > com->tx_fifo_size)
+ ocount = com->tx_fifo_size;
+ com->bytes_out += ocount;
+ do
+ outb(com->data_port, *ioptr++);
+ while (--ocount != 0);
+ } else {
+ outb(com->data_port, *ioptr++);
+ ++com->bytes_out;
+ }
+ com->optr = ioptr;
+ if (ioptr >= com->obufend) {
+ /* output just completed */
+ com_events += LOTS_OF_EVENTS;
+ com->state ^= (CS_ODONE | CS_BUSY);
+ setsofttty(); /* handle at high level ASAP */
+ }
+ }
+
+ /* finished? */
+#ifndef COM_MULTIPORT
+ if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
+#endif /* COM_MULTIPORT */
+ return;
+ }
+}
+
+static int
+tiocm_xxx2mcr(tiocm_xxx)
+ int tiocm_xxx;
+{
+ int mcr;
+
+ mcr = 0;
+ if (tiocm_xxx & TIOCM_DTR)
+ mcr |= MCR_DTR;
+ if (tiocm_xxx & TIOCM_RTS)
+ mcr |= MCR_RTS;
+ return (mcr);
+}
+
+int
+sioioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct com_s *com;
+ int error;
+ Port_t iobase;
+ int mcr;
+ int msr;
+ int s;
+ int tiocm_xxx;
+ struct tty *tp;
+
+ com = com_addr(UNIT(dev));
+ tp = com->tp;
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
+ if (error >= 0)
+ return (error);
+ error = ttioctl(tp, cmd, data, flag);
+
+#ifdef COM_BIDIR
+ /* XXX: plug security hole while sticky bits not yet implemented */
+ if (com->bidir && com->active_in && p->p_ucred->cr_uid != 0)
+ tp->t_cflag &= ~CLOCAL;
+#endif
+
+ if (error >= 0)
+ return (error);
+
+ iobase = com->iobase;
+ s = spltty();
+ switch (cmd) {
+ case TIOCSBRK:
+ outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
+ break;
+ case TIOCCBRK:
+ outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
+ break;
+ case TIOCSDTR:
+ commctl(com, MCR_DTR, DMBIS);
+ break;
+ case TIOCCDTR:
+ commctl(com, MCR_DTR, DMBIC);
+ break;
+ case TIOCMSET:
+ commctl(com, tiocm_xxx2mcr(*(int *)data), DMSET);
+ break;
+ case TIOCMBIS:
+ commctl(com, tiocm_xxx2mcr(*(int *)data), DMBIS);
+ break;
+ case TIOCMBIC:
+ commctl(com, tiocm_xxx2mcr(*(int *)data), DMBIC);
+ break;
+ case TIOCMGET:
+ tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
+ mcr = com->mcr_image;
+ if (mcr & MCR_DTR)
+ tiocm_xxx |= TIOCM_DTR;
+ if (mcr & MCR_RTS)
+ tiocm_xxx |= TIOCM_RTS;
+ msr = com->prev_modem_status;
+ if (msr & MSR_CTS)
+ tiocm_xxx |= TIOCM_CTS;
+ if (msr & MSR_DCD)
+ tiocm_xxx |= TIOCM_CD;
+ if (msr & MSR_DSR)
+ tiocm_xxx |= TIOCM_DSR;
+ /*
+ * XXX - MSR_RI is naturally volatile, and we make MSR_TERI
+ * more volatile by reading the modem status a lot. Perhaps
+ * we should latch both bits until the status is read here.
+ */
+ if (msr & (MSR_RI | MSR_TERI))
+ tiocm_xxx |= TIOCM_RI;
+ *(int *)data = tiocm_xxx;
+ break;
+#ifdef COM_BIDIR
+ case TIOCMSBIDIR:
+ /* must be root to set bidir. capability */
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0) {
+ splx(s);
+ return(EPERM);
+ }
+
+ /* if it's the console, can't do it (XXX why?) */
+ if (UNIT(dev) == comconsole) {
+ splx(s);
+ return(ENOTTY);
+ }
+
+#if 0
+ /* XXX - can't do the next, for obvious reasons...
+ * but there are problems to be looked at...
+ */
+ /* if the port is active, don't do it */
+ if (com->active) {
+ splx(s);
+ return(EBUSY);
+ }
+#endif
+
+ com->bidir = *(int *)data;
+ break;
+ case TIOCMGBIDIR:
+ *(int *)data = com->bidir;
+ break;
+#endif /* COM_BIDIR */
+ case TIOCMSDTRWAIT:
+ /* must be root since the wait applies to following logins */
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0) {
+ splx(s);
+ return(EPERM);
+ }
+
+ /* if it's the console, can't do it (XXX why?) */
+ if (UNIT(dev) == comconsole) {
+ splx(s);
+ return(ENOTTY);
+ }
+ com->dtr_wait = *(int *)data;
+ break;
+ case TIOCMGDTRWAIT:
+ *(int *)data = com->dtr_wait;
+ break;
+#ifdef TIOCTIMESTAMP
+ case TIOCTIMESTAMP:
+ com->do_timestamp = TRUE;
+ *(struct timeval *)data = com->timestamp;
+ break;
+#endif
+ default:
+ splx(s);
+ return (ENOTTY);
+ }
+ splx(s);
+ return (0);
+}
+
+/* cancel pending output */
+static void
+comflush(com)
+ struct com_s *com;
+{
+ struct ringb *rbp;
+
+ disable_intr();
+ if (com->state & CS_ODONE)
+ com_events -= LOTS_OF_EVENTS;
+ com->state &= ~(CS_ODONE | CS_BUSY);
+ enable_intr();
+ rbp = TB_OUT(com->tp);
+ rbp->rb_hd += com->ocount;
+ rbp->rb_hd = RB_ROLLOVER(rbp, rbp->rb_hd);
+ com->ocount = 0;
+ com->tp->t_state &= ~TS_BUSY;
+}
+
+void
+siopoll()
+{
+#ifdef OLD_INTERRUPT_HANDLING
+ static bool_t awake = FALSE;
+ int s;
+#endif
+ int unit;
+
+ if (com_events == 0)
+ return;
+
+#ifdef OLD_INTERRUPT_HANDLING
+ disable_intr();
+ if (awake) {
+ enable_intr();
+ return;
+ }
+ awake = TRUE;
+ enable_intr();
+ s = spltty();
+#endif
+
+repeat:
+ for (unit = 0; unit < NSIO; ++unit) {
+ u_char *buf;
+ struct com_s *com;
+ u_char *ibuf;
+ int incc;
+ struct tty *tp;
+
+ com = com_addr(unit);
+ if (com == NULL)
+ continue;
+ tp = com->tp;
+#ifdef DONT_MALLOC_TTYS
+ if (tp == NULL)
+ continue;
+#endif
+
+ /* switch the role of the low-level input buffers */
+ if (com->iptr == (ibuf = com->ibuf)) {
+ buf = NULL; /* not used, but compiler can't tell */
+ incc = 0;
+ } else {
+ buf = ibuf;
+ disable_intr();
+ incc = com->iptr - buf;
+ com_events -= incc;
+ if (ibuf == com->ibuf1)
+ ibuf = com->ibuf2;
+ else
+ ibuf = com->ibuf1;
+ com->ibufend = ibuf + RS_IBUFSIZE;
+ com->ihighwater = ibuf + RS_IHIGHWATER;
+ com->iptr = ibuf;
+
+ /*
+ * There is now room for another low-level buffer full
+ * of input, so enable RTS if it is now disabled and
+ * there is room in the high-level buffer.
+ */
+ /*
+ * XXX this used not to look at CS_RTS_IFLOW. The
+ * change is to allow full control of MCR_RTS via
+ * ioctls after turning CS_RTS_IFLOW off. Check
+ * for races. We shouldn't allow the ioctls while
+ * CS_RTS_IFLOW is on.
+ */
+ if ((com->state & CS_RTS_IFLOW)
+ && !(com->mcr_image & MCR_RTS)
+ && !(tp->t_state & TS_RTS_IFLOW))
+ outb(com->modem_ctl_port,
+ com->mcr_image |= MCR_RTS);
+ enable_intr();
+ com->ibuf = ibuf;
+ }
+
+ if (com->state & CS_CHECKMSR) {
+ u_char delta_modem_status;
+
+ disable_intr();
+ delta_modem_status = com->last_modem_status
+ ^ com->prev_modem_status;
+ com->prev_modem_status = com->last_modem_status;
+ com_events -= LOTS_OF_EVENTS;
+ com->state &= ~CS_CHECKMSR;
+ enable_intr();
+ if (delta_modem_status & MSR_DCD && !FAKE_DCD(unit)) {
+ if (com->prev_modem_status & MSR_DCD) {
+ (*linesw[tp->t_line].l_modem)(tp, 1);
+#ifdef COM_BIDIR
+ wakeup((caddr_t) &com->active_in);
+#endif /* COM_BIDIR */
+ } else
+ (*linesw[tp->t_line].l_modem)(tp, 0);
+ }
+ }
+
+ /* XXX */
+ if (TRUE) {
+ u_int delta;
+ int errnum;
+ u_long total;
+
+ for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
+ disable_intr();
+ delta = com->delta_error_counts[errnum];
+ com->delta_error_counts[errnum] = 0;
+ enable_intr();
+ if (delta != 0) {
+ total =
+ com->error_counts[errnum] += delta;
+ log(LOG_WARNING,
+ "sio%d: %u more %s%s (total %lu)\n",
+ unit, delta, error_desc[errnum],
+ delta == 1 ? "" : "s", total);
+ }
+ }
+ }
+ if (com->state & CS_ODONE) {
+ comflush(com);
+ /* XXX - why isn't the table used for t_line == 0? */
+ if (tp->t_line != 0)
+ (*linesw[tp->t_line].l_start)(tp);
+ else
+ comstart(tp);
+ }
+ if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
+ continue;
+ if (com->state & CS_RTS_IFLOW
+ && RB_LEN(TB_RAW(tp)) + incc >= RB_I_HIGH_WATER
+ && !(tp->t_state & TS_RTS_IFLOW)
+ /*
+ * XXX - need RTS flow control for all line disciplines.
+ * Only have it in standard one now.
+ */
+ && linesw[tp->t_line].l_rint == ttyinput) {
+ tp->t_state |= TS_RTS_IFLOW;
+ ttstart(tp);
+ }
+ /*
+ * Avoid the grotesquely inefficient lineswitch routine
+ * (ttyinput) in "raw" mode. It usually takes about 450
+ * instructions (that's without canonical processing or echo!).
+ * slinput is reasonably fast (usually 40 instructions plus
+ * call overhead).
+ */
+ if (!(tp->t_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP
+ | IXOFF | IXON))
+ && !(tp->t_lflag & (ECHO | ECHONL | ICANON | IEXTEN | ISIG
+ | PENDIN))
+ && !(tp->t_state & (TS_CNTTB | TS_LNCH))
+ && linesw[tp->t_line].l_rint == ttyinput) {
+ tk_nin += incc;
+ tk_rawcc += incc;
+ tp->t_rawcc += incc;
+ com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
+ += incc - rb_write(TB_RAW(tp), (char *) buf,
+ incc);
+ ttwakeup(tp);
+ if (tp->t_state & TS_TTSTOP
+ && (tp->t_iflag & IXANY
+ || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
+ tp->t_state &= ~TS_TTSTOP;
+ tp->t_lflag &= ~FLUSHO;
+ ttstart(tp);
+ }
+ } else {
+ do {
+ u_char line_status;
+ int recv_data;
+
+ line_status = (u_char) buf[CE_INPUT_OFFSET];
+ recv_data = (u_char) *buf++;
+ if (line_status
+ & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
+ if (line_status & LSR_BI)
+ recv_data |= TTY_BI;
+ if (line_status & LSR_FE)
+ recv_data |= TTY_FE;
+ if (line_status & LSR_OE)
+ recv_data |= TTY_OE;
+ if (line_status & LSR_PE)
+ recv_data |= TTY_PE;
+ }
+ (*linesw[tp->t_line].l_rint)(recv_data, tp);
+ } while (--incc > 0);
+ }
+ if (com_events == 0)
+ break;
+ }
+ if (com_events >= LOTS_OF_EVENTS)
+ goto repeat;
+
+#ifdef OLD_INTERRUPT_HANDLING
+ splx(s);
+ awake = FALSE;
+#endif
+}
+
+static int
+comparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ u_int cfcr;
+ int cflag;
+ struct com_s *com;
+ int divisor;
+ int error;
+ Port_t iobase;
+ int s;
+ int unit;
+
+ /* check requested parameters */
+ divisor = ttspeedtab(t->c_ospeed, comspeedtab);
+ if (t->c_ispeed == 0)
+ t->c_ispeed = t->c_ospeed;
+ if (divisor < 0 || t->c_ispeed != t->c_ospeed)
+ return (EINVAL);
+
+ /* parameters are OK, convert them to the com struct and the device */
+ unit = UNIT(tp->t_dev);
+ com = com_addr(unit);
+ iobase = com->iobase;
+ s = spltty();
+ if (divisor == 0)
+ commctl(com, MCR_DTR, DMBIC); /* hang up line */
+ else
+ commctl(com, MCR_DTR, DMBIS);
+ cflag = t->c_cflag;
+ switch (cflag & CSIZE) {
+ case CS5:
+ cfcr = CFCR_5BITS;
+ break;
+ case CS6:
+ cfcr = CFCR_6BITS;
+ break;
+ case CS7:
+ cfcr = CFCR_7BITS;
+ break;
+ default:
+ cfcr = CFCR_8BITS;
+ break;
+ }
+ if (cflag & PARENB) {
+ cfcr |= CFCR_PENAB;
+ if (!(cflag & PARODD))
+ cfcr |= CFCR_PEVEN;
+ }
+ if (cflag & CSTOPB)
+ cfcr |= CFCR_STOPB;
+
+ /*
+ * Some UARTs lock up if the divisor latch registers are selected
+ * while the UART is doing output (they refuse to transmit anything
+ * more until given a hard reset). Fix this by stopping filling
+ * the device buffers and waiting for them to drain. Reading the
+ * line status port outside of siointr1() might lose some receiver
+ * error bits, but that is acceptable here.
+ */
+ disable_intr();
+retry:
+ com->state &= ~CS_TTGO;
+ enable_intr();
+ while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
+ != (LSR_TSRE | LSR_TXRDY)) {
+ error = ttysleep(tp, (caddr_t)TB_RAW(tp), TTIPRI | PCATCH,
+ "sioparam", 1);
+ if (error != 0 && error != EAGAIN) {
+ if (!(tp->t_state & TS_TTSTOP)) {
+ disable_intr();
+ com->state |= CS_TTGO;
+ enable_intr();
+ }
+ splx(s);
+ return (error);
+ }
+ }
+
+ disable_intr(); /* very important while com_data is hidden */
+
+ /*
+ * XXX - clearing CS_TTGO is not sufficient to stop further output,
+ * because siopoll() calls comstart() which usually sets it again
+ * because TS_TTSTOP is clear. Setting TS_TTSTOP would not be
+ * sufficient, for similar reasons.
+ */
+ if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
+ != (LSR_TSRE | LSR_TXRDY))
+ goto retry;
+
+ if (divisor != 0) {
+ outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
+ outb(iobase + com_dlbl, divisor & 0xFF);
+ outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ }
+ outb(iobase + com_cfcr, com->cfcr_image = cfcr);
+ if (!(tp->t_state & TS_TTSTOP))
+ com->state |= CS_TTGO;
+ if (cflag & CRTS_IFLOW)
+ com->state |= CS_RTS_IFLOW; /* XXX - secondary changes? */
+ else
+ com->state &= ~CS_RTS_IFLOW;
+
+ /*
+ * Set up state to handle output flow control.
+ * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
+ * Now has 16+ msec latency, while CTS flow has 50- usec latency.
+ */
+ com->state &= ~CS_CTS_OFLOW;
+ com->state |= CS_ODEVREADY;
+ if (cflag & CCTS_OFLOW) {
+ com->state |= CS_CTS_OFLOW;
+ if (!(com->last_modem_status & MSR_CTS))
+ com->state &= ~CS_ODEVREADY;
+ }
+
+ /*
+ * Recover from fiddling with CS_TTGO. We used to call siointr1()
+ * unconditionally, but that defeated the careful discarding of
+ * stale input in sioopen().
+ *
+ * XXX sioopen() is not careful waiting for carrier for the callout
+ * case.
+ */
+ if (com->state >= (CS_BUSY | CS_TTGO))
+ siointr1(com);
+
+ enable_intr();
+ splx(s);
+ return (0);
+}
+
+static void
+comstart(tp)
+ struct tty *tp;
+{
+ struct com_s *com;
+ int s;
+ int unit;
+
+ unit = UNIT(tp->t_dev);
+ com = com_addr(unit);
+ s = spltty();
+ disable_intr();
+ if (tp->t_state & TS_TTSTOP)
+ com->state &= ~CS_TTGO;
+ else
+ com->state |= CS_TTGO;
+ if (tp->t_state & TS_RTS_IFLOW) {
+ if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
+ outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
+ } else {
+ /*
+ * XXX don't raise MCR_RTS if CTS_RTS_IFLOW is off. Set it
+ * appropriately in comparam() if RTS-flow is being changed.
+ * Check for races.
+ */
+ if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater)
+ outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
+ }
+ enable_intr();
+ if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
+ goto out;
+ if (RB_LEN(TB_OUT(tp)) <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)TB_OUT(tp));
+ }
+ if (tp->t_wsel) {
+ selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
+ tp->t_wsel = 0;
+ tp->t_state &= ~TS_WCOLL;
+ }
+ }
+ if (com->ocount != 0) {
+ disable_intr();
+ siointr1(com);
+ enable_intr();
+ } else if (RB_LEN(TB_OUT(tp)) != 0) {
+ tp->t_state |= TS_BUSY;
+ com->ocount = RB_CONTIGGET(TB_OUT(tp));
+ disable_intr();
+ com->obufend = (com->optr = (u_char *)TB_OUT(tp)->rb_hd)
+ + com->ocount;
+ com->state |= CS_BUSY;
+ siointr1(com); /* fake interrupt to start output */
+ enable_intr();
+ }
+out:
+ splx(s);
+}
+
+void
+siostop(tp, rw)
+ struct tty *tp;
+ int rw;
+{
+ struct com_s *com;
+
+ com = com_addr(UNIT(tp->t_dev));
+ if (rw & FWRITE)
+ comflush(com);
+ disable_intr();
+ if (rw & FREAD) {
+ com_events -= (com->iptr - com->ibuf);
+ com->iptr = com->ibuf;
+ }
+ if (tp->t_state & TS_TTSTOP)
+ com->state &= ~CS_TTGO;
+ else
+ com->state |= CS_TTGO;
+ enable_intr();
+}
+
+int
+sioselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ return (ttselect(dev & ~COM_MINOR_MAGIC_MASK, rw, p));
+}
+
+static void
+commctl(com, bits, how)
+ struct com_s *com;
+ int bits;
+ int how;
+{
+ disable_intr();
+ switch (how) {
+ case DMSET:
+ outb(com->modem_ctl_port,
+ com->mcr_image = bits | (com->mcr_image & MCR_IENABLE));
+ break;
+ case DMBIS:
+ outb(com->modem_ctl_port, com->mcr_image |= bits);
+ break;
+ case DMBIC:
+ outb(com->modem_ctl_port, com->mcr_image &= ~bits);
+ break;
+ }
+ enable_intr();
+}
+
+static void
+comwakeup(chan, ticks)
+ caddr_t chan;
+ int ticks;
+{
+ int unit;
+
+ timeout(comwakeup, (caddr_t) NULL, hz / 100);
+
+ if (com_events != 0) {
+#ifndef OLD_INTERRUPT_HANDLING
+ int s = splsofttty();
+#endif
+ siopoll();
+#ifndef OLD_INTERRUPT_HANDLING
+ splx(s);
+#endif
+ }
+
+ /* recover from lost output interrupts */
+ for (unit = 0; unit < NSIO; ++unit) {
+ struct com_s *com;
+
+ com = com_addr(unit);
+ if (com != NULL && com->state >= (CS_BUSY | CS_TTGO)) {
+ disable_intr();
+ siointr1(com);
+ enable_intr();
+ }
+ }
+}
+
+#ifdef OLD_INTERRUPT_HANDLING
+void
+softsio1()
+{
+ siopoll();
+}
+#endif
+
+/*
+ * Following are all routines needed for SIO to act as console
+ */
+#include "i386/i386/cons.h"
+
+struct siocnstate {
+ u_char dlbl;
+ u_char dlbh;
+ u_char ier;
+ u_char cfcr;
+ u_char mcr;
+};
+
+static Port_t siocniobase;
+
+static void
+siocntxwait()
+{
+ int timo;
+
+ /*
+ * Wait for any pending transmission to finish. Required to avoid
+ * the UART lockup bug when the speed is changed, and for normal
+ * transmits.
+ */
+ timo = 100000;
+ while ((inb(siocniobase + com_lsr) & (LSR_TSRE | LSR_TXRDY))
+ != (LSR_TSRE | LSR_TXRDY) && --timo != 0)
+ ;
+}
+
+static void
+siocnopen(sp)
+ struct siocnstate *sp;
+{
+ int divisor;
+ Port_t iobase;
+
+ /*
+ * Save all the device control registers except the fifo register
+ * and set our default ones (cs8 -parenb speed=comdefaultrate).
+ * We can't save the fifo register since it is read-only.
+ */
+ iobase = siocniobase;
+ sp->ier = inb(iobase + com_ier);
+ outb(iobase + com_ier, 0); /* spltty() doesn't stop siointr() */
+ siocntxwait();
+ sp->cfcr = inb(iobase + com_cfcr);
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ sp->dlbl = inb(iobase + com_dlbl);
+ sp->dlbh = inb(iobase + com_dlbh);
+ divisor = ttspeedtab(comdefaultrate, comspeedtab);
+ outb(iobase + com_dlbl, divisor & 0xFF);
+ outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS);
+ sp->mcr = inb(iobase + com_mcr);
+ outb(iobase + com_mcr, MCR_DTR | MCR_RTS);
+}
+
+static void
+siocnclose(sp)
+ struct siocnstate *sp;
+{
+ Port_t iobase;
+
+ /*
+ * Restore the device control registers.
+ */
+ siocntxwait();
+ iobase = siocniobase;
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ outb(iobase + com_dlbl, sp->dlbl);
+ outb(iobase + com_dlbh, sp->dlbh);
+ outb(iobase + com_cfcr, sp->cfcr);
+ /*
+ * XXX damp osicllations of MCR_DTR or MCR_RTS by not restoring them.
+ */
+ outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS);
+ outb(iobase + com_ier, sp->ier);
+}
+
+void
+siocnprobe(cp)
+ struct consdev *cp;
+{
+ int unit;
+
+ /* locate the major number */
+ /* XXX - should be elsewhere since KGDB uses it */
+ for (commajor = 0; commajor < nchrdev; commajor++)
+ if (cdevsw[commajor].d_open == sioopen)
+ break;
+
+ /* XXX: ick */
+ unit = UNIT(CONUNIT);
+ siocniobase = CONADDR;
+
+ /* make sure hardware exists? XXX */
+
+ /* initialize required fields */
+ cp->cn_dev = makedev(commajor, unit);
+#ifdef COMCONSOLE
+ cp->cn_pri = CN_REMOTE; /* Force a serial port console */
+#else
+ cp->cn_pri = CN_NORMAL;
+#endif
+}
+
+void
+siocninit(cp)
+ struct consdev *cp;
+{
+ /*
+ * XXX can delete more comconsole stuff now that i/o routines are
+ * fairly reentrant.
+ */
+ comconsole = UNIT(cp->cn_dev);
+}
+
+int
+siocngetc(dev)
+ dev_t dev;
+{
+ int c;
+ Port_t iobase;
+ int s;
+ struct siocnstate sp;
+
+ iobase = siocniobase;
+ s = spltty();
+ siocnopen(&sp);
+ while (!(inb(iobase + com_lsr) & LSR_RXRDY))
+ ;
+ c = inb(iobase + com_data);
+ siocnclose(&sp);
+ splx(s);
+ return (c);
+}
+
+void
+siocnputc(dev, c)
+ dev_t dev;
+ int c;
+{
+ int s;
+ struct siocnstate sp;
+
+ s = spltty();
+ siocnopen(&sp);
+ siocntxwait();
+ outb(siocniobase + com_data, c);
+ siocnclose(&sp);
+ splx(s);
+}
+
+#endif /* NSIO > 0 */
diff --git a/sys/i386/isa/sioreg.h b/sys/i386/isa/sioreg.h
new file mode 100644
index 0000000..4b0f1b6
--- /dev/null
+++ b/sys/i386/isa/sioreg.h
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)comreg.h 7.2 (Berkeley) 5/9/91
+ * $Id$
+ */
+
+
+/* 16 bit baud rate divisor (lower byte in dca_data, upper in dca_ier) */
+#define COMBRD(x) (1843200 / (16*(x)))
+
+/* interrupt enable register */
+#define IER_ERXRDY 0x1
+#define IER_ETXRDY 0x2
+#define IER_ERLS 0x4
+#define IER_EMSC 0x8
+
+/* interrupt identification register */
+#define IIR_IMASK 0xf
+#define IIR_RXTOUT 0xc
+#define IIR_RLS 0x6
+#define IIR_RXRDY 0x4
+#define IIR_TXRDY 0x2
+#define IIR_NOPEND 0x1
+#define IIR_MLSC 0x0
+#define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */
+
+/* fifo control register */
+#define FIFO_ENABLE 0x01
+#define FIFO_RCV_RST 0x02
+#define FIFO_XMT_RST 0x04
+#define FIFO_DMA_MODE 0x08
+#define FIFO_TRIGGER_1 0x00
+#define FIFO_TRIGGER_4 0x40
+#define FIFO_TRIGGER_8 0x80
+#define FIFO_TRIGGER_14 0xc0
+
+/* character format control register */
+#define CFCR_DLAB 0x80
+#define CFCR_SBREAK 0x40
+#define CFCR_PZERO 0x30
+#define CFCR_PONE 0x20
+#define CFCR_PEVEN 0x10
+#define CFCR_PODD 0x00
+#define CFCR_PENAB 0x08
+#define CFCR_STOPB 0x04
+#define CFCR_8BITS 0x03
+#define CFCR_7BITS 0x02
+#define CFCR_6BITS 0x01
+#define CFCR_5BITS 0x00
+
+/* modem control register */
+#define MCR_LOOPBACK 0x10
+#define MCR_IENABLE 0x08
+#define MCR_DRS 0x04
+#define MCR_RTS 0x02
+#define MCR_DTR 0x01
+
+/* line status register */
+#define LSR_RCV_FIFO 0x80
+#define LSR_TSRE 0x40
+#define LSR_TXRDY 0x20
+#define LSR_BI 0x10
+#define LSR_FE 0x08
+#define LSR_PE 0x04
+#define LSR_OE 0x02
+#define LSR_RXRDY 0x01
+#define LSR_RCV_MASK 0x1f
+
+/* modem status register */
+#define MSR_DCD 0x80
+#define MSR_RI 0x40
+#define MSR_DSR 0x20
+#define MSR_CTS 0x10
+#define MSR_DDCD 0x08
+#define MSR_TERI 0x04
+#define MSR_DDSR 0x02
+#define MSR_DCTS 0x01
+
+/*
+ * WARNING: Serial console is assumed to be at COM1 address
+ * and CONUNIT must be 0.
+ */
+#define CONADDR (0x3f8)
+#define CONUNIT (0)
diff --git a/sys/i386/isa/sound/CHANGELOG b/sys/i386/isa/sound/CHANGELOG
new file mode 100644
index 0000000..6a9bef1
--- /dev/null
+++ b/sys/i386/isa/sound/CHANGELOG
@@ -0,0 +1,75 @@
+Changelog for version 2.5
+-------------------------
+
+Since 2.5-beta2
+- Some fine tuning to the GUS v3.7 mixer code.
+- Fixed speed limits for the plain SB (1.0 to 2.0).
+
+Since 2.5-beta
+- Fixed OPL-3 detection with SB. Caused problems with PAS16.
+- GUS v3.7 mixer support.
+
+Since 2.4
+- Mixer support for Sound Galaxy NX Pro (define __SGNXPRO__ on your local.h).
+- Fixed truncated sound on /dev/dsp when the device is closed.
+- Linear volume mode for GUS
+- Pitch bends larger than +/- 2 octaves.
+- MIDI recording for SB and SB Pro. (Untested).
+- Some other fixes.
+- SB16 MIDI and DSP drivers only initialized if SB16 actually installed.
+- Implemented better detection for OPL-3. This should be usefull if you
+ have an old SB Pro (the non-OPL-3 one) or a SB 2.0 clone which has a OPL-3.
+- SVR4.2 support by Ian Hartas. Initial ALPHA TEST version (untested).
+
+Since 2.3b
+- Fixed bug which made it impossible to make long recordings to disk.
+ Recording was not restarted after a buffer overflow situation.
+- Limited mixer support for GUS.
+- Numerous improvements to the GUS driver by Andrew Robinson. Including
+ some click removal etc.
+
+Since 2.3
+- Fixed some minor bugs in the SB16 driver.
+
+Since 2.2b
+- Full SB16 DSP support. 8/16 bit, mono/stereo
+- The SCO and FreeBSD versions should be in sync now. There are some
+ problems with SB16 and GUS in the freebsd versions.
+ The DMA buffer allocation of the SCO version has been polished but
+ there could still be some problems. At least it hogs memory.
+ The DMA channel
+ configuration method used in the sco/System is a hack.
+- Support for the MPU emulation of the SB16.
+- Some big arrays are now allocated boot time. This makes the bss segment
+ smaller which makes it possible to use the full driver with
+ NetBSD. These arrays are not allocated if no suitable soundcard is available.
+- Fixed a bug in the compute_and_set_volume in gus_wave.c
+- Fixed the too fast mono playback problem of SB Pro and PAS16.
+
+Since 2.2
+- Stereo recording for SB Pro. Somehow it was missing and nobody
+ had noticed it earlier.
+- Minor polishing.
+- Interpreting of boot time arguments (sound=) for Linux.
+- Breakup of sb_dsp.c. Parts of the code has been moved to
+ sb_mixer.c and sb_midi.c
+
+Since 2.1
+- Preliminary support for SB16.
+ - The SB16 mixer is supported in it's native mode.
+ - Digitized voice capability up to 44.1 kHz/8 bit/mono
+ (16 bit and stereo support coming in the next release).
+- Fixed some bugs in the digitized voice driver for PAS16.
+- Proper initialization of the SB emulation of latest PAS16 models.
+
+- Significantly improved /dev/dsp and /dev/audio support.
+ - Now supports half duplex mode. It's now possible to record and
+ playback without closing and reopening the device.
+ - It's possible to use smaller buffers than earlier. There is a new
+ ioctl(fd, SNDCTL_DSP_SUBDIVIDE, &n) where n should be 1, 2 or 4.
+ This call instructs the driver to use smaller buffers. The default
+ buffer size (0.5 to 1.0 seconds) is divided by n. Should be called
+ immediately after opening the device.
+
+Since 2.0
+Just cosmetic changes.
diff --git a/sys/i386/isa/sound/COPYING b/sys/i386/isa/sound/COPYING
new file mode 100644
index 0000000..d1509c5
--- /dev/null
+++ b/sys/i386/isa/sound/COPYING
@@ -0,0 +1,25 @@
+/*
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
diff --git a/sys/i386/isa/sound/HOWTO_MIDI b/sys/i386/isa/sound/HOWTO_MIDI
new file mode 100644
index 0000000..f0601e5
--- /dev/null
+++ b/sys/i386/isa/sound/HOWTO_MIDI
@@ -0,0 +1,51 @@
+The following file describes the procedure for adding modules to MIDI
+Please READ the main documentation files for the driver first!!!
+
+
+ Example: We have a sound card with a MIDI chip & port on it
+ and, we call it the 'MYBLASTER' card:
+
+ **************************************************************************
+
+ 0: Run 'configure'. Select the MIDI on CHIP support option.
+
+ 1: Write a midi driver module; 'blast_midi.c'
+ (with functions for open,close,read,write,attach.)
+
+ 1a: Write all functions except the 'attach' the way you want.
+
+ For the 'attach' function, look at a model in the 'pro_midi.c'
+ file. Just dup it in the same fashion. For the 'generic_midi_operations'
+ structure which is required, see file 'dev_table.h'.
+
+ 2: We called the 'attach' function: 'blast_attach'.
+
+ Go to the file 'dev_table.h' and add your driver name and the function
+ pointer ( which is 'blast_attach' ) to the 'midi_supported' table.
+
+ 3: You are almost set. Go and make a reference
+ to an 'exclude constant'; say EXLCUDE_BLAST_MIDI in your module
+ (refer to the 'pro_midi.c' file for model). Also make sure to
+ add the constant to the file 'sound_config.h' (for example, look
+ where the constant EXCLUDE_PRO_MIDI is in the file.)
+
+ 4: Add the line
+
+ #define ALL_EXTERNAL_TO_ME
+
+ as the 1st line of your 'blast_midi.c' file. This happily, makes
+ you ignorant of everything else specific to the driver! :).
+
+ 4a: And of course, don't forget to make a device :). Note that your
+ minor number should be = ( 15 + position of your driver in the
+ 'midi_supported' table in the 'dev_table.h' file ).
+
+ Eg: Your driver is the second one in the table. viz midi_supported[1].
+ Your device minor number should be ( 15 + 1 = 16 ). Then, make the
+ reference to your device as, say CMIDI_DEV_BLAST in the file
+ 'sound_config.h'. Also add this in 'soundcard.c' for the open, read,
+ write and close routines. See files for example using CMIDI_DEV_PRO
+ (which is the ProAudioSpectrum on chip MIDI).
+
+ 5: You are all set. If ever you have problems, follow the same model
+ as the file 'pro_midi.c', except for substituting your own functions!
diff --git a/sys/i386/isa/sound/README b/sys/i386/isa/sound/README
new file mode 100644
index 0000000..efb0b11
--- /dev/null
+++ b/sys/i386/isa/sound/README
@@ -0,0 +1,17 @@
+CAUTION!
+
+This is a prototype version of the Linux Sound Driver for FreeBSD.
+
+The official and supported version is 1.0c.
+
+This version 'should work' but there may be some bugs and the programmers
+API may change before the final version.
+
+There are some additional programs for GUS owners in the
+gustest subdirectory of this directory, namely a module
+(.MOD, .STM and .669) player and a patch file loader.
+Additionally, there is a midithru program which allows
+you to play the synth on the soundcard with a midi keyboard
+(also usable for OPL-3 owners).
+
+Hannu & FreeBSD team.
diff --git a/sys/i386/isa/sound/RELNOTES b/sys/i386/isa/sound/RELNOTES
new file mode 100644
index 0000000..03d492d
--- /dev/null
+++ b/sys/i386/isa/sound/RELNOTES
@@ -0,0 +1,38 @@
+Welcome to use the Linux sound driver for FreeBSD. This
+driver supports the SoundBlaster, SB Pro, Pro Audio Spectrum 16,
+AdLib and Gravis UltraSound sound cards.
+
+In addition there is rather limited support for MPU-401
+(and compatible) midi cards. Also, the OPL-3 synthesizer
+of the SB Pro and PAS16 cards is now supported in the 4 OP
+modes.
+
+Most of the features of the /dev/sequencer device file are
+available just for GUS owners.
+
+The SoundBlaster 16 and SB 16 ASP cards are not supported,
+though they may work in mono mode with speeds < 22 kHz.
+The OPL-3 chicp of the SB 16 should work (without problems?).
+Is there anybody willing to implement the SB 16 support
+(have the SB 16 and the SDK for it)?
+
+Since this driver is a sound driver, it does not contain support
+for SCSI/CD-ROM/Joystick -devices.
+
+Known bugs
+----------
+
+- It's not possible to open /dev/dsp (or /dev/audio) while the
+ /dev/sequencer is open for output and GUS is the only soundcard
+ installed. It's possible if /dev/dsp is opened before /dev/sequencer
+ but at this time the GUS is not available for access via /dev/sequencer.
+ This is a limitation of the driver.
+- MPU-401 driver hangs the computer on boot if there is no MPU-401 installed.
+ It uses by default the I/O port 0x330, which is also used by the
+ Adaptec 1542 SCSI adapter.
+- The /dev/sequencer playback to GUS sounds sometimes rather weird. Hitting
+ ^C and playing again should solve this problem. This is probably caused by
+ incompatibilities between the GUS and certain VLB motherboards. Try to avoid
+ switching between VTs while patches are being loaded to the GUS.
+- There is a skeleton of the patch manager support. It doesn't work in
+ this version.
diff --git a/sys/i386/isa/sound/RELNOTES.Linux b/sys/i386/isa/sound/RELNOTES.Linux
new file mode 100644
index 0000000..ea57d0a
--- /dev/null
+++ b/sys/i386/isa/sound/RELNOTES.Linux
@@ -0,0 +1,255 @@
+Release notes for the Linux Sound Driver 2.5
+--------------------------------------------
+There is also a version called 2.5-beta floating around the net. This
+version contains some fixes after it. Mainly to the SB and GUS code.
+
+CAUTION! The SVR4.2 port has not been tested much. Backup your system
+ carefully before trying it.
+
+This is mainly a bug fix release. There are couple of new things such as
+linear volume mode for GUS and MIDI recording for SB 2.0 and SB Pro.
+Also this version supports the mixer of GUS v3.7. (Support for GUS MAX and
+the 16-bit daughtercard is coming sooner or later).
+
+NOTE! The sound driver is a part of the Linux kernel distribution also.
+ Check that your kernel doesn't have more recent version than this
+ when installing a separately distributed sound driver. The
+ version number of this driver is defined in the makefile.
+
+This version contains a driver for the SB16 also.
+The SB16 driver requires separate DMA channels for the 8 and 16 bit
+modes. There should be a way to share the 8 bit DMA channels between
+these modes but this feature is not supported yet.
+The SB16 DSP support is by Joerg Schubert (jsb@sth.ruhr-uni-bochum.de).
+
+The SB16 driver has also the Midi input capability even at the same
+time with the /dev/dsp. Also the WaveBlaster daughter board is supported.
+No support for the ASP chip yet (the ASP chip can be installed but it's
+not used by the driver).
+
+You will need the snd-util-2.5.tar.gz and snd-data-0.1.tar.Z
+packages to use this driver. They should be in the same
+ftp site or BBS from where you got this driver. For
+example at nic.funet.fi:pub/OS/Linux/*.
+
+If you are looking for the installation instructions, please
+look at $OS/Readme.
+
+This version supports the following soundcards:
+GUS, SoundBlaster, SB Pro, SB16, Pro Audio Spectrum 16 and AdLib.
+In addition there is rather limited support for MPU-401.
+(and compatible) midi cards. Also the OPL-3 synthesizer
+Most of the features of the /dev/sequencer device file are
+available just for GUS owners.
+
+NOTE! There are separate driver for CD-ROMS supported by
+ some soundcards. The driver for CDU31A (Fusion 16) is
+ called cdu31a-0.6.diff.z. It will be contained in the
+ Linux version 0.99.12. The driver for the CD-ROM of SB Pro
+ is sbpcd0.4.tar.gz (these were the latest versions when I wrote
+ this). These files should be at least at sunsite.unc.edu.
+ Also the SCSI interface of the PAS16 should be supported by
+ Linux 0.99.13k and later.
+
+ There is also a driver for joystick. Look for file joystick-0.5.tar.gz
+ (sunsite).
+
+
+Compatibility with the earlier versions
+---------------------------------------
+
+In this version the ultrasound.h no longer includes the sys/soundcard.h
+You have to change the gmod.c of the snd-util-2.0 package and to add an
+include for it.
+
+IMPORTANT!!!!!!!!!!!!!!!!!!!!!!
+
+This version is not binary or source compatible with the version 1.0c.
+
+The ioctl() interface has changed completely since version 1.0c. All
+programs using this driver must be at least recompiled.
+The snd-util-2.0 package contains some utilities for this version.
+
+The version 1.0c and earlier used a 'nonportable' ioctl calling scheme
+where the input argument was passed by value and the output value was
+returned as the functional return. For example setting the speed of
+/dev/dsp were done as the following:
+
+ int actual_speed;
+ actual_speed = ioctl(fd, SOUND_PCM_WRITE_RATE, 44100);
+
+After version 1.99.0 this must be done as the following:
+
+ int actual_speed = 44100;
+ ioctl(fd, SOUND_PCM_WRITE_RATE, &actual_speed);
+
+If you have an application written for the version 1.0, you should search
+for the strings SNDCTL_ and SOUND_ and to check the parameters.
+The following ioctl calls have changed:
+
+ SNDCTL_SEQ_GETOUTCOUNT
+ SNDCTL_SEQ_GETINCOUNT
+ SNDCTL_SEQ_TESTMIDI
+ SNDCTL_DSP_SPEED
+ SNDCTL_DSP_STEREO
+ SNDCTL_DSP_GETBLKSIZE
+ SNDCTL_DSP_SAMPLESIZE
+ SOUND_PCM_WRITE_CHANNELS
+ SOUND_PCM_WRITE_FILTER
+ SOUND_PCM_READ_RATE
+ SOUND_PCM_READ_CHANNELS
+ SOUND_PCM_READ_BITS
+ SOUND_PCM_READ_FILTER
+ SOUND_PCM_WRITE_BITS
+ SOUND_PCM_WRITE_RATE
+ SOUND_MIXER_READ_* (several ones)
+ SOUND_MIXER_WRITE_* (several ones)
+
+Since the this version will support more than one synthesizer devices
+at the same time, the ioctl(SNDCTL_FM_LOAD_INSTR) is obsolete. In addition
+there is some new fields which must be initialized. Look at the sbiset.c in
+the snd-util-2.0 package for further info.
+
+This version is almost 100% compatible with the alpha test version (1.99.9). The
+difference is in the installation procedure.
+
+Using this driver with other operating systems than Linux
+---------------------------------------------------------
+
+This package contains just the Linux version. The version 2.3
+for SCO is available at nic.funet.fi:pub/OS/Linux/ALPHA/sound.
+The version 2.3 doesn't work well with xxxxxBSD. Use the version
+2.3 for them.
+
+/dev/sndstat
+------------
+
+The /dev/sndstat is now available in the SCO and BSD versions also.
+
+This is a new devicefile for debugging purposes. A better place for
+it is in the /proc -directory but I was just too lazy to implement it
+properly. The /dev/sndstat (major 14, minor 6) is a file which returns
+info about the current configuration (see the example below). If you
+send me a error/problem report, please include a printout from this
+device to your message (cat /dev/sndstat).
+
+Note! This device file is currently present only in the Linux version
+ of this driver.
+
+------ cut here --- cat /dev/sndstat example --------
+Sound Driver:1.99.7 (Fri Jul 9 17:01:47 GMT 1993 root@lucifer.savolai.fi)
+Config options: 0x00000d4b
+
+HW config:
+Type 4: Gravis Ultrasound at 0x210 irq 15 drq 6
+Type 3: ProAudioSpectrum at 0x388 irq 10 drq 3
+Type 2: SoundBlaster at 0x220 irq 7 drq 1
+Type 1: AdLib at 0x388 irq 0 drq 0
+
+PCM devices:
+00: Gravis UltraSound
+01: Pro Audio Spectrum
+02: SoundBlaster 2.0
+
+Synth devices:
+00: Gravis UltraSound
+01: Yamaha OPL-3
+
+Midi devices:
+00: Gravis UltraSound
+01: Pro Audio Spectrum
+
+Mixer(s) installed
+------ cut here ---- End of Example -----------
+
+Known bugs/limitations
+----------------------
+
+- High speed recording of long audio samples (>20 second) to disk
+ is not possible. Everything works until next sync() which delays the
+ recording process too much. A delay longer than 0.1 to 0.3 seconds is
+ too much.
+- The SB16 driver sometimes swaps the left and right channels together.
+- Midi input doesn't work with SB and SB Pro (SB16 works).
+- It's not possible to open /dev/dsp (or /dev/audio) while the
+ /dev/sequencer is open for output and GUS is the only soundcard
+ installed. It's possible if /dev/dsp is opened before /dev/sequencer
+ but at this time the GUS is not available for access via /dev/sequencer.
+ This is a limitation of the driver.
+- MPU-401 driver hangs the computer on boot if there is no MPU-401 installed.
+ It uses by default the I/O port 0x330 whic is used by Adaptec 1542 SCSI
+ adapter.
+- There are some problems in midi input with MPU-401 and the SB16 midi
+ (MPU-401 emulation). This makes it impossible to read long sysex dumps
+ using these devices.
+- The /dev/sequencer playback to GUS sounds sometimes rather weird. Hitting
+ ^C and playing again should solve this problem. This is propably caused by
+ incompatibilities between GUS and certain VLB motherboards (like mine).
+ Try to avoid
+ switching between VTs while patches are being loaded to the GUS.
+ This problem disappears completely if you define GUS_PATCH_NO_DMA in the
+ local.h (after make config in linux). The drawback is that patch loading
+ without DMA takes several times longer than with DMA.
+- There is a skeleton of the patch manager support. It don't work in
+ this version.
+
+
+Future development
+------------------
+
+- Since this driver is no longer just the Linux Sound Driver, it's time
+ to give it a new name. I have planned to use name VoxWare.
+- I'm writing a Hacker's guide to the VoxWare sound driver. Should
+ be ready within this(/next) year (alpha version).
+- Completion of the ISC, SCO and BSD ports. Port to SVR4.2.
+- I'm interested to implement/include support for new soundcards and
+ operating systems.
+
+ Hint for the soundcard and OS manufacturers:
+ I'm collecting soundcards (high end ones) and SDKs for them. In
+ addition I'm collecting PC operating systems. I will be happy if
+ somebody sends me such items. In addition such kind of donation
+ makes it easier to change the VoxWare driver to support your
+ soundcard or operating system. However, please contact me before
+ sending anything.
+
+I will propably release some fix versions within this and next year. At
+least when the non-Linux versions get ready. The next major release (3.0)
+will be quite complete rewrite and released after about a year (end of 94 or
+beginning of 95).
+
+
+Contributors
+------------
+
+This driver contains code by several contributors. In addition several other
+persons have given usefull suggestions. The following is a list of major
+contributors. (I could have forgotten some names.)
+
+ Craig Metz 1/2 of the PAS16 Mixer and PCM support
+ Rob Hooft Volume computation algorithm for the FM synth.
+ Mika Liljeberg uLaw encoding and decoding routines
+ Greg Lee Volume computation algorithm for the GUS and
+ lot's of valuable suggestions.
+ Andy Warner Initial ISC port
+ Jim Lowe Initial FreeBSD port
+ Anders Baekgaard Bughunting and valuable suggestions.
+ Joerg Schubert SB16 DSP support.
+ Andrew Robinson Improvements to the GUS driver
+ Megens SA MIDI recording for SB and SB Pro.
+ Mikael Nordqvist Linear volume support for GUS.
+ Ian Hartas SVR4.2 port
+ Markus Aroharju and
+ Risto Kankkunen Major contributions to the mixer support
+ of GUS v3.7.
+ Hunyue Yau Sound Galaxy NX Pro mixer support.
+
+Regards,
+
+Hannu Savolainen
+hannu@voxware.pp.fi, Hannu.Savolainen@Helsinki.fi
+
+Snail mail: Hannu Savolainen
+ Pallaksentie 4 A 2
+ 00970 Helsinki
+ Finland
diff --git a/sys/i386/isa/sound/adlib_card.c b/sys/i386/isa/sound/adlib_card.c
new file mode 100644
index 0000000..6365069
--- /dev/null
+++ b/sys/i386/isa/sound/adlib_card.c
@@ -0,0 +1,51 @@
+/*
+ * sound/adlib_card.c
+ *
+ * Detection routine for the AdLib card.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_YM3812)
+
+long
+attach_adlib_card (long mem_start, struct address_info *hw_config)
+{
+
+ if (opl3_detect (FM_MONO))
+ {
+ mem_start = opl3_init (mem_start);
+ }
+ return mem_start;
+}
+
+int
+probe_adlib (struct address_info *hw_config)
+{
+ return opl3_detect (FM_MONO);
+}
+
+#endif
diff --git a/sys/i386/isa/sound/audio.c b/sys/i386/isa/sound/audio.c
new file mode 100644
index 0000000..f27f9d5
--- /dev/null
+++ b/sys/i386/isa/sound/audio.c
@@ -0,0 +1,356 @@
+/*
+ * sound/audio.c
+ *
+ * Device file manager for /dev/audio
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+#ifndef EXCLUDE_AUDIO
+
+#include "ulaw.h"
+
+#define ON 1
+#define OFF 0
+
+static int wr_buff_no[MAX_DSP_DEV]; /* != -1, if there is a
+
+ * incomplete output block */
+static int wr_buff_size[MAX_DSP_DEV], wr_buff_ptr[MAX_DSP_DEV];
+
+static int audio_mode[MAX_DSP_DEV];
+
+#define AM_NONE 0
+#define AM_WRITE 1
+#define AM_READ 2
+
+static char *wr_dma_buf[MAX_DSP_DEV];
+
+int
+audio_open (int dev, struct fileinfo *file)
+{
+ int ret;
+ int bits;
+ int dev_type = dev & 0x0f;
+ int mode = file->mode & O_ACCMODE;
+
+ dev = dev >> 4;
+
+ if (dev_type == SND_DEV_DSP16)
+ bits = 16;
+ else
+ bits = 8;
+
+ if ((ret = DMAbuf_open (dev, mode)) < 0)
+ return ret;
+
+ if (DMAbuf_ioctl (dev, SNDCTL_DSP_SAMPLESIZE, bits, 1) != bits)
+ {
+ audio_release (dev, file);
+ return RET_ERROR (ENXIO);
+ }
+
+ wr_buff_no[dev] = -1;
+ audio_mode[dev] = AM_NONE;
+
+ return ret;
+}
+
+void
+audio_release (int dev, struct fileinfo *file)
+{
+ int mode;
+
+ dev = dev >> 4;
+ mode = file->mode & O_ACCMODE;
+
+ if (wr_buff_no[dev] >= 0)
+ {
+ DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+ wr_buff_no[dev] = -1;
+ }
+
+ DMAbuf_release (dev, mode);
+}
+
+#ifdef NO_INLINE_ASM
+static void
+translate_bytes (const unsigned char *table, unsigned char *buff, unsigned long n)
+{
+ unsigned long i;
+
+ for (i = 0; i < n; ++i)
+ buff[i] = table[buff[i]];
+}
+
+#else
+extern inline void
+translate_bytes (const void *table, void *buff, unsigned long n)
+{
+ __asm__ ("cld\n"
+ "1:\tlodsb\n\t"
+ "xlatb\n\t"
+ "stosb\n\t"
+ "loop 1b\n\t":
+ :"b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff)
+ :"bx", "cx", "di", "si", "ax");
+}
+
+#endif
+
+int
+audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ int c, p, l;
+ int err;
+ int dev_type = dev & 0x0f;
+
+ dev = dev >> 4;
+
+ p = 0;
+ c = count;
+
+ if (audio_mode[dev] == AM_READ) /* Direction changed */
+ {
+ wr_buff_no[dev] = -1;
+ }
+
+ audio_mode[dev] = AM_WRITE;
+
+ if (!count) /* Flush output */
+ {
+ if (wr_buff_no[dev] >= 0)
+ {
+ DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+ wr_buff_no[dev] = -1;
+ }
+ return 0;
+ }
+
+ while (c)
+ { /* Perform output blocking */
+ if (wr_buff_no[dev] < 0) /* There is no incomplete buffers */
+ {
+ if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev], &wr_buff_size[dev])) < 0)
+ return wr_buff_no[dev];
+ wr_buff_ptr[dev] = 0;
+ }
+
+ l = c;
+ if (l > (wr_buff_size[dev] - wr_buff_ptr[dev]))
+ l = (wr_buff_size[dev] - wr_buff_ptr[dev]);
+
+ if (!dsp_devs[dev]->copy_from_user)
+ { /* No device specific copy routine */
+ COPY_FROM_USER (&wr_dma_buf[dev][wr_buff_ptr[dev]], buf, p, l);
+ }
+ else
+ dsp_devs[dev]->copy_from_user (dev,
+ wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l);
+
+
+ /* Insert local processing here */
+
+ if (dev_type == SND_DEV_AUDIO)
+ {
+#ifdef linux
+ /* This just allows interrupts while the conversion is running */
+ __asm__ ("sti");
+#endif
+ translate_bytes (ulaw_dsp, (unsigned char *) &wr_dma_buf[dev][wr_buff_ptr[dev]], l);
+ }
+
+ c -= l;
+ p += l;
+ wr_buff_ptr[dev] += l;
+
+ if (wr_buff_ptr[dev] >= wr_buff_size[dev])
+ {
+ if ((err = DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev])) < 0)
+ return err;
+
+ wr_buff_no[dev] = -1;
+ }
+
+ }
+
+ return count;
+}
+
+int
+audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ int c, p, l;
+ char *dmabuf;
+ int buff_no;
+ int dev_type = dev & 0x0f;
+
+ dev = dev >> 4;
+ p = 0;
+ c = count;
+
+ if (audio_mode[dev] == AM_WRITE)
+ {
+ if (wr_buff_no[dev] >= 0)
+ {
+ DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+ wr_buff_no[dev] = -1;
+ }
+ }
+
+ audio_mode[dev] = AM_READ;
+
+ while (c)
+ {
+ if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l)) < 0)
+ return buff_no;
+
+ if (l > c)
+ l = c;
+
+ /* Insert any local processing here. */
+
+ if (dev_type == SND_DEV_AUDIO)
+ {
+#ifdef linux
+ /* This just allows interrupts while the conversion is running */
+ __asm__ ("sti");
+#endif
+
+ translate_bytes (dsp_ulaw, (unsigned char *) dmabuf, l);
+ }
+
+ COPY_TO_USER (buf, p, dmabuf, l);
+
+ DMAbuf_rmchars (dev, buff_no, l);
+
+ p += l;
+ c -= l;
+ }
+
+ return count - c;
+}
+
+int
+audio_ioctl (int dev, struct fileinfo *file,
+ unsigned int cmd, unsigned int arg)
+{
+ int dev_type = dev & 0x0f;
+
+ dev = dev >> 4;
+
+ switch (cmd)
+ {
+ case SNDCTL_DSP_SYNC:
+ if (wr_buff_no[dev] >= 0)
+ {
+ DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+ wr_buff_no[dev] = -1;
+ }
+ return DMAbuf_ioctl (dev, cmd, arg, 0);
+ break;
+
+ case SNDCTL_DSP_POST:
+ if (wr_buff_no[dev] >= 0)
+ {
+ DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+ wr_buff_no[dev] = -1;
+ }
+ return 0;
+ break;
+
+ case SNDCTL_DSP_RESET:
+ wr_buff_no[dev] = -1;
+ return DMAbuf_ioctl (dev, cmd, arg, 0);
+ break;
+
+ default:
+ if (dev_type == SND_DEV_AUDIO)
+ return RET_ERROR (EIO);
+
+ return DMAbuf_ioctl (dev, cmd, arg, 0);
+ }
+}
+
+long
+audio_init (long mem_start)
+{
+ return mem_start;
+}
+
+#else
+/* Stub versions */
+
+int
+audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ return RET_ERROR (EIO);
+}
+
+int
+audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ return RET_ERROR (EIO);
+}
+
+int
+audio_open (int dev, struct fileinfo *file)
+{
+ return RET_ERROR (ENXIO);
+}
+
+void
+audio_release (int dev, struct fileinfo *file)
+{
+};
+int
+audio_ioctl (int dev, struct fileinfo *file,
+ unsigned int cmd, unsigned int arg)
+{
+ return RET_ERROR (EIO);
+}
+
+int
+audio_lseek (int dev, struct fileinfo *file, off_t offset, int orig)
+{
+ return RET_ERROR (EIO);
+}
+
+long
+audio_init (long mem_start)
+{
+ return mem_start;
+}
+
+#endif
+
+#endif
diff --git a/sys/i386/isa/sound/dev_table.c b/sys/i386/isa/sound/dev_table.c
new file mode 100644
index 0000000..7f7cae1
--- /dev/null
+++ b/sys/i386/isa/sound/dev_table.c
@@ -0,0 +1,217 @@
+/*
+ * sound/dev_table.c
+ *
+ * Device call tables.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#define _DEV_TABLE_C_
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+long
+sndtable_init (long mem_start)
+{
+ int i, n = sizeof (supported_drivers) / sizeof (struct card_info);
+
+ for (i = 0; i < (n - 1); i++)
+ if (supported_drivers[i].enabled)
+ if (supported_drivers[i].probe (&supported_drivers[i].config))
+ {
+#ifndef SHORT_BANNERS
+ printk ("snd%d",
+ supported_drivers[i].card_type);
+#endif
+
+ mem_start = supported_drivers[i].attach (mem_start, &supported_drivers[i].config);
+#ifndef SHORT_BANNERS
+ printk (" at 0x%x irq %d drq %d\n",
+ supported_drivers[i].config.io_base,
+ supported_drivers[i].config.irq,
+ supported_drivers[i].config.dma);
+#endif
+ }
+ else
+ supported_drivers[i].enabled = 0; /* Mark as not detected */
+ return mem_start;
+}
+
+int
+sndtable_probe (int unit, struct address_info *hw_config)
+{
+ int i, n = sizeof (supported_drivers) / sizeof (struct card_info);
+
+ if (!unit)
+ return TRUE;
+
+ for (i = 0; i < (n - 1); i++)
+ if (supported_drivers[i].card_type == unit)
+ {
+ supported_drivers[i].config.io_base = hw_config->io_base;
+ supported_drivers[i].config.irq = hw_config->irq;
+ supported_drivers[i].config.dma = hw_config->dma;
+ if (supported_drivers[i].probe (hw_config))
+ return 1;
+ supported_drivers[i].enabled = 0; /* Mark as not detected */
+ return 0;
+ }
+
+ return FALSE;
+}
+
+int
+sndtable_init_card (int unit, struct address_info *hw_config)
+{
+ int i, n = sizeof (supported_drivers) / sizeof (struct card_info);
+
+ if (!unit)
+ {
+ if (sndtable_init (0) != 0)
+ panic ("snd: Invalid memory allocation\n");
+ return TRUE;
+ }
+
+ for (i = 0; i < (n - 1); i++)
+ if (supported_drivers[i].card_type == unit)
+ {
+ supported_drivers[i].config.io_base = hw_config->io_base;
+ supported_drivers[i].config.irq = hw_config->irq;
+ supported_drivers[i].config.dma = hw_config->dma;
+
+ if (supported_drivers[i].attach (0, hw_config) != 0)
+ panic ("snd#: Invalid memory allocation\n");
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+int
+sndtable_get_cardcount (void)
+{
+ return num_dspdevs + num_mixers + num_synths + num_midis;
+}
+
+#ifdef linux
+void
+sound_setup (char *str, int *ints)
+{
+ int i, n = sizeof (supported_drivers) / sizeof (struct card_info);
+
+ /*
+ * First disable all drivers
+ */
+
+ for (i = 0; i < n; i++)
+ supported_drivers[i].enabled = 0;
+
+ if (ints[0] == 0 || ints[1] == 0)
+ return;
+ /*
+ * Then enable them one by time
+ */
+
+ for (i = 1; i <= ints[0]; i++)
+ {
+ int card_type, ioaddr, irq, dma, ptr, j;
+ unsigned int val;
+
+ val = (unsigned int) ints[i];
+
+ card_type = (val & 0x0ff00000) >> 20;
+
+ if (card_type > 127)
+ {
+ /* Add any future extensions here */
+ return;
+ }
+
+ ioaddr = (val & 0x000fff00) >> 8;
+ irq = (val & 0x000000f0) >> 4;
+ dma = (val & 0x0000000f);
+
+ ptr = -1;
+ for (j = 0; j < n && ptr == -1; j++)
+ if (supported_drivers[j].card_type == card_type)
+ ptr = j;
+
+ if (ptr == -1)
+ printk ("Sound: Invalid setup parameter 0x%08x\n", val);
+ else
+ {
+ supported_drivers[ptr].enabled = 1;
+ supported_drivers[ptr].config.io_base = ioaddr;
+ supported_drivers[ptr].config.irq = irq;
+ supported_drivers[ptr].config.dma = dma;
+ }
+ }
+}
+
+#else
+void
+sound_chconf (int card_type, int ioaddr, int irq, int dma)
+{
+ int i, n = sizeof (supported_drivers) / sizeof (struct card_info);
+
+ int ptr, j;
+
+ ptr = -1;
+ for (j = 0; j < n && ptr == -1; j++)
+ if (supported_drivers[j].card_type == card_type)
+ ptr = j;
+
+ if (ptr != -1)
+ {
+ supported_drivers[ptr].enabled = 1;
+ if (ioaddr)
+ supported_drivers[ptr].config.io_base = ioaddr;
+ if (irq)
+ supported_drivers[ptr].config.irq = irq;
+ if (dma)
+ supported_drivers[ptr].config.dma = dma;
+ }
+}
+
+#endif
+
+struct address_info *
+sound_getconf (int card_type)
+{
+ int j, ptr;
+ int n = sizeof (supported_drivers) / sizeof (struct card_info);
+
+ ptr = -1;
+ for (j = 0; j < n && ptr == -1; j++)
+ if (supported_drivers[j].card_type == card_type)
+ ptr = j;
+
+ if (ptr == -1)
+ return (struct address_info *) NULL;
+
+ return &supported_drivers[ptr].config;
+}
+
+#endif
diff --git a/sys/i386/isa/sound/dev_table.h b/sys/i386/isa/sound/dev_table.h
new file mode 100644
index 0000000..4b656ba
--- /dev/null
+++ b/sys/i386/isa/sound/dev_table.h
@@ -0,0 +1,273 @@
+/*
+ * dev_table.h
+ *
+ * Global definitions for device call tables
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+
+*/
+
+#ifndef _DEV_TABLE_H_
+#define _DEV_TABLE_H_
+
+/*
+ * NOTE! NOTE! NOTE! NOTE!
+ *
+ * If you modify this file, please check the dev_table.c also.
+ *
+ * NOTE! NOTE! NOTE! NOTE!
+ */
+
+struct card_info {
+ int card_type; /* From soundcard.c */
+ char *name;
+ long (*attach) (long mem_start, struct address_info *hw_config);
+ int (*probe) (struct address_info *hw_config);
+ struct address_info config;
+ int enabled;
+};
+
+/** UWM -- new MIDI structure here.. **/
+
+struct generic_midi_info{
+ char *name; /* Name of the MIDI device.. */
+ long (*attach) (long mem_start);
+};
+
+struct audio_operations {
+ char name[32];
+ int flags;
+#define NOTHING_SPECIAL 0
+#define NEEDS_RESTART 1
+ int (*open) (int dev, int mode);
+ void (*close) (int dev);
+ void (*output_block) (int dev, unsigned long buf,
+ int count, int intrflag, int dma_restart);
+ void (*start_input) (int dev, unsigned long buf,
+ int count, int intrflag, int dma_restart);
+ int (*ioctl) (int dev, unsigned int cmd, unsigned int arg, int local);
+ int (*prepare_for_input) (int dev, int bufsize, int nbufs);
+ int (*prepare_for_output) (int dev, int bufsize, int nbufs);
+ void (*reset) (int dev);
+ void (*halt_xfer) (int dev);
+ int (*has_output_drained)(int dev);
+ void (*copy_from_user)(int dev, char *localbuf, int localoffs,
+ snd_rw_buf *userbuf, int useroffs, int len);
+};
+
+struct mixer_operations {
+ int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
+};
+
+struct synth_operations {
+ struct synth_info *info;
+ int synth_type;
+ int synth_subtype;
+
+ int (*open) (int dev, int mode);
+ void (*close) (int dev);
+ int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
+ int (*kill_note) (int dev, int voice, int velocity);
+ int (*start_note) (int dev, int voice, int note, int velocity);
+ int (*set_instr) (int dev, int voice, int instr);
+ void (*reset) (int dev);
+ void (*hw_control) (int dev, unsigned char *event);
+ int (*load_patch) (int dev, int format, snd_rw_buf *addr,
+ int offs, int count, int pmgr_flag);
+ void (*aftertouch) (int dev, int voice, int pressure);
+ void (*controller) (int dev, int voice, int ctrl_num, int value);
+ void (*panning) (int dev, int voice, int value);
+ void (*volume_method) (int dev, int mode);
+ int (*pmgr_interface) (int dev, struct patmgr_info *info);
+};
+
+struct midi_operations {
+ struct midi_info info;
+ int (*open) (int dev, int mode,
+ void (*inputintr)(int dev, unsigned char data),
+ void (*outputintr)(int dev)
+ );
+ void (*close) (int dev);
+ int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
+ int (*putc) (int dev, unsigned char data);
+ int (*start_read) (int dev);
+ int (*end_read) (int dev);
+ void (*kick)(int dev);
+ int (*command) (int dev, unsigned char data);
+ int (*buffer_status) (int dev);
+};
+
+/** UWM -- new structure for MIDI **/
+
+struct generic_midi_operations {
+ struct midi_info info;
+ int (*open) (int dev, int mode);
+ void (*close) (int dev);
+ int (*write) (int dev, snd_rw_buf *data);
+ int (*read) (int dev, snd_rw_buf *data);
+};
+
+#ifndef ALL_EXTERNAL_TO_ME
+
+#ifdef _MIDI_TABLE_C_
+
+/** UWM **/
+ struct generic_midi_operations * generic_midi_devs[MAX_MIDI_DEV] = {NULL};
+ int num_generic_midis = 0, pro_midi_dev = 0;
+
+ struct generic_midi_info midi_supported[] = {
+
+#ifndef EXCLUDE_PRO_MIDI
+ {"ProAudioSpectrum MV101",pro_midi_attach}
+#endif
+ };
+
+ int num_midi_drivers =
+ sizeof (midi_supported) / sizeof(struct generic_midi_info);
+
+#endif
+
+
+#ifdef _DEV_TABLE_C_
+ struct audio_operations * dsp_devs[MAX_DSP_DEV] = {NULL}; int num_dspdevs = 0;
+ struct mixer_operations * mixer_devs[MAX_MIXER_DEV] = {NULL}; int num_mixers = 0;
+ struct synth_operations * synth_devs[MAX_SYNTH_DEV] = {NULL}; int num_synths = 0;
+ struct midi_operations * midi_devs[MAX_MIDI_DEV] = {NULL}; int num_midis = 0;
+
+
+# ifndef EXCLUDE_MPU401
+ int mpu401_dev = 0;
+# endif
+
+/*
+ * Note! The detection order is significant. Don't change it.
+ */
+
+ struct card_info supported_drivers[] = {
+#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
+ {SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401,
+ {MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
+#endif
+
+#ifndef EXCLUDE_PAS
+ {SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas,
+ {PAS_BASE, PAS_IRQ, PAS_DMA}, SND_DEFAULT_ENABLE},
+#endif
+
+#ifndef EXCLUDE_SB
+ {SNDCARD_SB, "SoundBlaster", attach_sb_card, probe_sb,
+ {SBC_BASE, SBC_IRQ, SBC_DMA}, SND_DEFAULT_ENABLE},
+#endif
+
+#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO)
+#ifndef EXCLUDE_AUDIO
+ {SNDCARD_SB16, "SoundBlaster16", sb16_dsp_init, sb16_dsp_detect,
+ {SBC_BASE, SBC_IRQ, SB16_DMA}, SND_DEFAULT_ENABLE},
+#endif
+#ifndef EXCLUDE_MIDI
+ {SNDCARD_SB16MIDI,"SB16 MPU-401", attach_sb16midi, probe_sb16midi,
+ {SB16MIDI_BASE, SBC_IRQ, 0}, SND_DEFAULT_ENABLE},
+#endif
+#endif
+
+#ifndef EXCLUDE_GUS
+ {SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus,
+ {GUS_BASE, GUS_IRQ, GUS_DMA}, SND_DEFAULT_ENABLE},
+#endif
+
+#ifndef EXCLUDE_YM3812
+ {SNDCARD_ADLIB, "AdLib", attach_adlib_card, probe_adlib,
+ {FM_MONO, 0, 0}, SND_DEFAULT_ENABLE},
+#endif
+ {0, "*?*", NULL, 0}
+ };
+
+ int num_sound_drivers =
+ sizeof(supported_drivers) / sizeof (struct card_info);
+
+
+# ifndef EXCLUDE_AUDIO
+ int sound_buffcounts[MAX_DSP_DEV] = {0};
+ long sound_buffsizes[MAX_DSP_DEV] = {0};
+ int sound_dsp_dmachan[MAX_DSP_DEV] = {0};
+ int sound_dma_automode[MAX_DSP_DEV] = {0};
+# endif
+#else
+ extern struct audio_operations * dsp_devs[MAX_DSP_DEV]; int num_dspdevs;
+ extern struct mixer_operations * mixer_devs[MAX_MIXER_DEV]; extern int num_mixers;
+ extern struct synth_operations * synth_devs[MAX_SYNTH_DEV]; extern int num_synths;
+ extern struct midi_operations * midi_devs[MAX_MIDI_DEV]; extern int num_midis;
+# ifndef EXCLUDE_MPU401
+ extern int mpu401_dev;
+# endif
+
+ extern struct card_info supported_drivers[];
+ extern int num_sound_drivers;
+
+# ifndef EXCLUDE_AUDIO
+ extern int sound_buffcounts[MAX_DSP_DEV];
+ extern long sound_buffsizes[MAX_DSP_DEV];
+ extern int sound_dsp_dmachan[MAX_DSP_DEV];
+ extern int sound_dma_automode[MAX_DSP_DEV];
+# endif
+
+#endif
+
+long sndtable_init(long mem_start);
+int sndtable_get_cardcount (void);
+long CMIDI_init(long mem_start); /* */
+struct address_info *sound_getconf(int card_type);
+void sound_chconf(int card_type, int ioaddr, int irq, int dma);
+#endif
+
+#endif
+
+/* If external to me.... :) */
+
+#ifdef ALL_EXTERNAL_TO_ME
+
+ extern struct audio_operations * dsp_devs[MAX_DSP_DEV]; int num_dspdevs;
+ extern struct mixer_operations * mixer_devs[MAX_MIXER_DEV]; extern int num_mixers;
+ extern struct synth_operations * synth_devs[MAX_SYNTH_DEV]; extern int num_synths;
+ extern struct midi_operations * midi_devs[MAX_MIDI_DEV]; extern int num_midis;
+ extern struct generic_midi_operations *generic_midi_devs[];
+ extern int num_generic_midis, pro_midi_dev;
+
+#ifndef EXCLUDE_MPU401
+ extern int mpu401_dev;
+#endif
+
+ extern struct generic_midi_info midi_supported[];
+ extern struct card_info supported_drivers[];
+ extern int num_sound_drivers;
+ extern int num_midi_drivers;
+#ifndef EXCLUDE_AUDIO
+ extern int sound_buffcounts[MAX_DSP_DEV];
+ extern long sound_buffsizes[MAX_DSP_DEV];
+ extern int sound_dsp_dmachan[MAX_DSP_DEV];
+ extern int sound_dma_automode[MAX_DSP_DEV];
+#endif
+
+#endif
diff --git a/sys/i386/isa/sound/dmabuf.c b/sys/i386/isa/sound/dmabuf.c
new file mode 100644
index 0000000..851a70a1
--- /dev/null
+++ b/sys/i386/isa/sound/dmabuf.c
@@ -0,0 +1,902 @@
+/*
+ * sound/dmabuf.c
+ *
+ * The DMA buffer manager for digitized voice applications
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+#include "sound_calls.h"
+
+#if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_GUS)
+
+#define MAX_SUB_BUFFERS (32*MAX_REALTIME_FACTOR)
+
+/*
+ * The DSP channel can be used either for input or output. Variable
+ * 'dma_mode' will be set when the program calls read or write first time
+ * after open. Current version doesn't support mode changes without closing
+ * and reopening the device. Support for this feature may be implemented in a
+ * future version of this driver.
+ */
+
+#define DMODE_NONE 0
+#define DMODE_OUTPUT 1
+#define DMODE_INPUT 2
+
+DEFINE_WAIT_QUEUES (dev_sleeper[MAX_DSP_DEV], dev_sleep_flag[MAX_DSP_DEV]);
+
+static int dma_mode[MAX_DSP_DEV] =
+{0}; /* DMODE_INPUT, DMODE_OUTPUT or DMODE_NONE */
+
+static volatile int dmabuf_interrupted[MAX_DSP_DEV] =
+{0};
+
+/*
+ * Pointers to raw buffers
+ */
+
+char *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT] =
+{
+ {NULL}};
+unsigned long snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT];
+int snd_raw_count[MAX_DSP_DEV];
+
+/*
+ * Device state tables
+ */
+
+static int dev_busy[MAX_DSP_DEV];
+static int dev_needs_restart[MAX_DSP_DEV];
+static int dev_modes[MAX_DSP_DEV];
+static int dev_active[MAX_DSP_DEV];
+static int dev_started[MAX_DSP_DEV];
+static int dev_qlen[MAX_DSP_DEV];
+static int dev_qhead[MAX_DSP_DEV];
+static int dev_qtail[MAX_DSP_DEV];
+static int dev_underrun[MAX_DSP_DEV];
+static int bufferalloc_done[MAX_DSP_DEV] =
+{0};
+
+/*
+ * Logical buffers for each devices
+ */
+
+static int dev_nbufs[MAX_DSP_DEV]; /* # of logical buffers ( >=
+
+ * sound_buffcounts[dev] */
+static int dev_counts[MAX_DSP_DEV][MAX_SUB_BUFFERS];
+static int dev_subdivision[MAX_DSP_DEV];
+static unsigned long dev_buf_phys[MAX_DSP_DEV][MAX_SUB_BUFFERS];
+static char *dev_buf[MAX_DSP_DEV][MAX_SUB_BUFFERS] =
+{
+ {NULL}};
+static int dev_buffsize[MAX_DSP_DEV];
+
+static void
+reorganize_buffers (int dev)
+{
+ /*
+ * This routine breaks the physical device buffers to logical ones.
+ */
+
+ unsigned i, p, n;
+ unsigned sr, nc, sz, bsz;
+
+ sr = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_RATE, 0, 1);
+ nc = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_CHANNELS, 0, 1);
+ sz = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_BITS, 0, 1);
+
+ if (sr < 1 || nc < 1 || sz < 1)
+ {
+ printk ("SOUND: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", dev, sr, nc, sz);
+ sr = DSP_DEFAULT_SPEED;
+ nc = 1;
+ sz = 8;
+ }
+
+ sz /= 8; /* Convert # of bits -> # of bytes */
+
+ sz = sr * nc * sz;
+
+ /*
+ * Compute a buffer size not exeeding 1 second.
+ */
+
+ bsz = sound_buffsizes[dev];
+
+ while (bsz > sz)
+ bsz >>= 1; /* Divide by 2 */
+
+ if (sound_buffcounts[dev] == 1 && bsz == sound_buffsizes[dev])
+ bsz >>= 1; /* Need at least 2 buffers */
+
+ if (dev_subdivision[dev] == 0)
+ dev_subdivision[dev] = 1; /* Default value */
+
+ bsz /= dev_subdivision[dev]; /* Use smaller buffers */
+
+ if (bsz == 0)
+ bsz = 4096; /* Just a sanity check */
+
+ while ((sound_buffsizes[dev] * sound_buffcounts[dev]) / bsz > MAX_SUB_BUFFERS)
+ bsz <<= 1; /* Too much buffers */
+
+ dev_buffsize[dev] = bsz;
+ n = 0;
+
+ /*
+ * Now computing addresses for the logical buffers
+ */
+
+ for (i = 0; i < snd_raw_count[dev]; i++)
+ {
+ p = 0;
+
+ while ((p + bsz) <= sound_buffsizes[dev])
+ {
+ dev_buf[dev][n] = snd_raw_buf[dev][i] + p;
+ dev_buf_phys[dev][n] = snd_raw_buf_phys[dev][i] + p;
+ p += bsz;
+ n++;
+ }
+ }
+
+ dev_nbufs[dev] = n;
+
+ for (i = 0; i < dev_nbufs[dev]; i++)
+ {
+ dev_counts[dev][i] = 0;
+ }
+
+ bufferalloc_done[dev] = 1;
+}
+
+static void
+dma_init_buffers (int dev)
+{
+ RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
+ dev_underrun[dev] = 0;
+
+ dev_busy[dev] = 1;
+
+ bufferalloc_done[dev] = 0;
+
+ dev_active[dev] = dev_qlen[dev] = dev_qtail[dev] = dev_qhead[dev] = 0;
+ dev_needs_restart[dev] = dev_started[dev] = 0;
+ dma_mode[dev] = DMODE_NONE;
+}
+
+int
+DMAbuf_open (int dev, int mode)
+{
+ int retval;
+
+ if (dev >= num_dspdevs)
+ {
+ printk ("PCM device %d not installed.\n", dev);
+ return RET_ERROR (ENXIO);
+ }
+
+ if (dev_busy[dev])
+ return RET_ERROR (EBUSY);
+
+ if (!dsp_devs[dev])
+ {
+ printk ("DSP device %d not initialized\n", dev);
+ return RET_ERROR (ENXIO);
+ }
+
+#ifdef USE_RUNTIME_DMAMEM
+ sound_dma_malloc (dev);
+#endif
+
+ if (snd_raw_buf[dev][0] == NULL)
+ return RET_ERROR (ENOSPC); /* Memory allocation failed during boot */
+
+ if ((retval = dsp_devs[dev]->open (dev, mode)) < 0)
+ return retval;
+
+ dev_modes[dev] = mode;
+ dev_subdivision[dev] = 0;
+
+ dma_init_buffers (dev);
+ dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_BITS, 8, 1);
+ dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_CHANNELS, 1, 1);
+ dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_RATE, DSP_DEFAULT_SPEED, 1);
+
+ return 0;
+}
+
+static void
+dma_reset (int dev)
+{
+ int retval;
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+ dsp_devs[dev]->reset (dev);
+ dsp_devs[dev]->close (dev);
+
+ if ((retval = dsp_devs[dev]->open (dev, dev_modes[dev])) < 0)
+ printk ("Sound: Reset failed - Can't reopen device\n");
+ RESTORE_INTR (flags);
+
+ dma_init_buffers (dev);
+ reorganize_buffers (dev);
+}
+
+static int
+dma_sync (int dev)
+{
+ unsigned long flags;
+
+ if (dma_mode[dev] == DMODE_OUTPUT)
+ {
+ DISABLE_INTR (flags);
+
+ while ((!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||
+ dmabuf_interrupted[dev]))
+ && dev_qlen[dev])
+ {
+ DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 10 * HZ);
+ if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
+ return dev_qlen[dev];
+ }
+ RESTORE_INTR (flags);
+
+ /*
+ * Some devices such as GUS have huge amount of on board RAM for the
+ * audio data. We have to wait util the device has finished playing.
+ */
+
+ DISABLE_INTR (flags);
+ if (dsp_devs[dev]->has_output_drained) /* Device has hidden buffers */
+ {
+ while (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||
+ dmabuf_interrupted[dev])
+ && !dsp_devs[dev]->has_output_drained (dev))
+ {
+ DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], HZ / 4);
+ }
+ }
+ RESTORE_INTR (flags);
+ }
+ return dev_qlen[dev];
+}
+
+int
+DMAbuf_release (int dev, int mode)
+{
+
+ if (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) ||
+ dmabuf_interrupted[dev])
+ && (dma_mode[dev] == DMODE_OUTPUT))
+ {
+ dma_sync (dev);
+ }
+
+#ifdef USE_RUNTIME_DMAMEM
+ sound_dma_free (dev);
+#endif
+
+ dsp_devs[dev]->reset (dev);
+
+ dsp_devs[dev]->close (dev);
+
+ dma_mode[dev] = DMODE_NONE;
+ dev_busy[dev] = 0;
+
+ return 0;
+}
+
+int
+DMAbuf_getrdbuffer (int dev, char **buf, int *len)
+{
+ unsigned long flags;
+ int err = EIO;
+
+ DISABLE_INTR (flags);
+ if (!dev_qlen[dev])
+ {
+ if (dev_needs_restart[dev])
+ {
+ dma_reset (dev);
+ dev_needs_restart[dev] = 0;
+ }
+
+ if (dma_mode[dev] == DMODE_OUTPUT) /* Was output -> direction change */
+ {
+ dma_sync (dev);
+ dma_reset (dev);
+ dma_mode[dev] = DMODE_NONE;
+ }
+
+ if (!bufferalloc_done[dev])
+ reorganize_buffers (dev);
+
+ if (!dma_mode[dev])
+ {
+ int err;
+
+ if ((err = dsp_devs[dev]->prepare_for_input (dev,
+ dev_buffsize[dev], dev_nbufs[dev])) < 0)
+ {
+ RESTORE_INTR (flags);
+ return err;
+ }
+ dma_mode[dev] = DMODE_INPUT;
+ }
+
+ if (!dev_active[dev])
+ {
+ dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]],
+ dev_buffsize[dev], 0,
+ !sound_dma_automode[dev] ||
+ !dev_started[dev]);
+ dev_active[dev] = 1;
+ dev_started[dev] = 1;
+ }
+
+ /* Wait for the next block */
+ DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ);
+ if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
+ {
+ printk ("Sound: DMA timed out - IRQ/DRQ config error?\n");
+ err = EIO;
+ SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);
+ }
+ else
+ err = EINTR;
+ }
+ RESTORE_INTR (flags);
+
+ if (!dev_qlen[dev])
+ return RET_ERROR (err);
+
+ *buf = &dev_buf[dev][dev_qhead[dev]][dev_counts[dev][dev_qhead[dev]]];
+ *len = dev_buffsize[dev] - dev_counts[dev][dev_qhead[dev]];
+
+ return dev_qhead[dev];
+}
+
+int
+DMAbuf_rmchars (int dev, int buff_no, int c)
+{
+ int p = dev_counts[dev][dev_qhead[dev]] + c;
+
+ if (p >= dev_buffsize[dev])
+ { /* This buffer is now empty */
+ dev_counts[dev][dev_qhead[dev]] = 0;
+ dev_qlen[dev]--;
+ dev_qhead[dev] = (dev_qhead[dev] + 1) % dev_nbufs[dev];
+ }
+ else
+ dev_counts[dev][dev_qhead[dev]] = p;
+
+ return 0;
+}
+
+int
+DMAbuf_read (int dev, snd_rw_buf * user_buf, int count)
+{
+ char *dmabuf;
+ int buff_no, c, err;
+
+ /*
+ * This routine returns at most 'count' bytes from the dsp input buffers.
+ * Returns negative value if there is an error.
+ */
+
+ if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &c)) < 0)
+ return buff_no;
+
+ if (c > count)
+ c = count;
+
+ COPY_TO_USER (user_buf, 0, dmabuf, c);
+
+ if ((err = DMAbuf_rmchars (dev, buff_no, c)) < 0)
+ return err;
+ return c;
+
+}
+
+int
+DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+{
+ switch (cmd)
+ {
+ case SNDCTL_DSP_RESET:
+ dma_reset (dev);
+ return 0;
+ break;
+
+ case SNDCTL_DSP_SYNC:
+ dma_sync (dev);
+ dma_reset (dev);
+ return 0;
+ break;
+
+ case SNDCTL_DSP_GETBLKSIZE:
+ if (!bufferalloc_done[dev])
+ reorganize_buffers (dev);
+
+ return IOCTL_OUT (arg, dev_buffsize[dev]);
+ break;
+
+ case SNDCTL_DSP_SUBDIVIDE:
+ {
+ int fact = IOCTL_IN (arg);
+
+ if (fact == 0)
+ {
+ fact = dev_subdivision[dev];
+ if (fact == 0)
+ fact = 1;
+ return IOCTL_OUT (arg, fact);
+ }
+
+ if (dev_subdivision[dev] != 0) /* Too late to change */
+ return RET_ERROR (EINVAL);
+
+ if (fact > MAX_REALTIME_FACTOR)
+ return RET_ERROR (EINVAL);
+
+ if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16)
+ return RET_ERROR (EINVAL);
+
+ dev_subdivision[dev] = fact;
+ return IOCTL_OUT (arg, fact);
+ }
+ break;
+
+ default:
+ return dsp_devs[dev]->ioctl (dev, cmd, arg, local);
+ }
+
+ /* NOTREACHED */
+ return RET_ERROR (EIO);
+}
+
+int
+DMAbuf_getwrbuffer (int dev, char **buf, int *size)
+{
+ unsigned long flags;
+ int err = EIO;
+
+ if (dma_mode[dev] == DMODE_INPUT) /* Was input -> Direction change */
+ {
+ dma_reset (dev);
+ dma_mode[dev] = DMODE_NONE;
+ }
+ else if (dev_needs_restart[dev]) /* Restart buffering */
+ {
+ dma_sync (dev);
+ dma_reset (dev);
+ }
+
+ dev_needs_restart[dev] = 0;
+
+ if (!bufferalloc_done[dev])
+ reorganize_buffers (dev);
+
+ if (!dma_mode[dev])
+ {
+ int err;
+
+ dma_mode[dev] = DMODE_OUTPUT;
+ if ((err = dsp_devs[dev]->prepare_for_output (dev,
+ dev_buffsize[dev], dev_nbufs[dev])) < 0)
+ return err;
+ }
+
+
+ DISABLE_INTR (flags);
+
+ RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]);
+
+ if (dev_qlen[dev] == dev_nbufs[dev])
+ {
+ if (!dev_active[dev])
+ {
+ printk ("Soundcard warning: DMA not activated %d/%d\n",
+ dev_qlen[dev], dev_nbufs[dev]);
+ return RET_ERROR (EIO);
+ }
+
+ /* Wait for free space */
+ DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ);
+ if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev]))
+ {
+ printk ("Sound: DMA timed out - IRQ/DRQ config error?\n");
+ err = EIO;
+ SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]);
+ }
+ else if (PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]))
+ err = EINTR;
+ }
+ RESTORE_INTR (flags);
+
+ if (dev_qlen[dev] == dev_nbufs[dev])
+ return RET_ERROR (err); /* We have got signal (?) */
+
+ *buf = dev_buf[dev][dev_qtail[dev]];
+ *size = dev_buffsize[dev];
+ dev_counts[dev][dev_qtail[dev]] = 0;
+
+ return dev_qtail[dev];
+}
+
+int
+DMAbuf_start_output (int dev, int buff_no, int l)
+{
+ if (buff_no != dev_qtail[dev])
+ printk ("Soundcard warning: DMA buffers out of sync %d != %d\n", buff_no, dev_qtail[dev]);
+
+ dev_qlen[dev]++;
+
+ dev_counts[dev][dev_qtail[dev]] = l;
+
+ dev_needs_restart[dev] = (l != dev_buffsize[dev]) &&
+ (sound_dma_automode[dev] || dsp_devs[dev]->flags & NEEDS_RESTART);
+
+ dev_qtail[dev] = (dev_qtail[dev] + 1) % dev_nbufs[dev];
+
+ if (!dev_active[dev])
+ {
+ dev_active[dev] = 1;
+ dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]],
+ dev_counts[dev][dev_qhead[dev]], 0,
+ !sound_dma_automode[dev] || !dev_started[dev]);
+ dev_started[dev] = 1;
+ }
+
+ return 0;
+}
+
+int
+DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
+{
+ int chan = sound_dsp_dmachan[dev];
+ unsigned long flags;
+
+ /*
+ * This function is not as portable as it should be.
+ */
+
+ /*
+ * The count must be one less than the actual size. This is handled by
+ * set_dma_addr()
+ */
+
+ if (sound_dma_automode[dev])
+ { /* Auto restart mode. Transfer the whole
+ * buffer */
+#ifdef linux
+ DISABLE_INTR (flags);
+ disable_dma (chan);
+ clear_dma_ff (chan);
+ set_dma_mode (chan, dma_mode | DMA_AUTOINIT);
+ set_dma_addr (chan, snd_raw_buf_phys[dev][0]);
+ set_dma_count (chan, sound_buffsizes[dev]);
+ enable_dma (chan);
+ RESTORE_INTR (flags);
+#else /* linux */
+
+#ifdef __386BSD__
+ printk ("sound: Invalid DMA mode for device %d\n", dev);
+
+ isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE,
+ (caddr_t)snd_raw_buf_phys[dev][0],
+ sound_buffsizes[dev],
+ chan);
+#else /* __386BSD__ */
+#if defined(ISC) || defined(SCO) || defined(SVR42)
+#ifndef DMAMODE_AUTO
+ printk ("sound: Invalid DMA mode for device %d\n", dev);
+#endif /* DMAMODE_AUTO */
+ dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode)
+#ifdef DMAMODE_AUTO
+ | DMAMODE_AUTO
+#endif /* DMAMODE_AUTO */
+ ,
+ snd_raw_buf_phys[dev][0], count);
+ dma_enable (chan);
+#else /* SYSV */
+#error This routine is not valid for this OS.
+#endif /* SYSV */
+#endif /* __386BSD__ */
+
+#endif /* linux */
+ }
+ else
+ {
+#ifdef linux
+ DISABLE_INTR (flags);
+ disable_dma (chan);
+ clear_dma_ff (chan);
+ set_dma_mode (chan, dma_mode);
+ set_dma_addr (chan, physaddr);
+ set_dma_count (chan, count);
+ enable_dma (chan);
+ RESTORE_INTR (flags);
+#else /* linux */
+#ifdef __386BSD__
+ isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE,
+ (caddr_t)physaddr,
+ count,
+ chan);
+#else /* __386BSD__ */
+
+#if defined(ISC) || defined(SCO) || defined(SVR42)
+ dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode),
+ physaddr, count);
+ dma_enable (chan);
+#else /* SYSV */
+#error This routine is not valid for this OS.
+#endif /* SYSV */
+#endif /* __386BSD__ */
+
+#endif /* linux */
+ }
+
+ return count;
+}
+
+long
+DMAbuf_init (long mem_start)
+{
+ int i;
+
+ /*
+ * In this version the DMA buffer allocation is done by sound_mem_init()
+ * which is called by init/main.c
+ */
+
+ for (i = 0; i < MAX_DSP_DEV; i++)
+ {
+ dev_qlen[i] = 0;
+ dev_qhead[i] = 0;
+ dev_qtail[i] = 0;
+ dev_active[i] = 0;
+ dev_busy[i] = 0;
+ bufferalloc_done[i] = 0;
+ }
+
+ return mem_start;
+}
+
+void
+DMAbuf_outputintr (int dev, int underrun_flag)
+{
+ unsigned long flags;
+
+ dev_qlen[dev]--;
+ dev_qhead[dev] = (dev_qhead[dev] + 1) % dev_nbufs[dev];
+ dev_active[dev] = 0;
+
+ if (dev_qlen[dev])
+ {
+ dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]],
+ dev_counts[dev][dev_qhead[dev]], 1,
+ !sound_dma_automode[dev]);
+ dev_active[dev] = 1;
+ }
+ else if (underrun_flag)
+ {
+ dev_underrun[dev]++;
+ dsp_devs[dev]->halt_xfer (dev);
+ dev_needs_restart[dev] = (sound_dma_automode[dev] ||
+ dsp_devs[dev]->flags & NEEDS_RESTART);
+ }
+
+ DISABLE_INTR (flags);
+ if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
+ {
+ WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
+ }
+ RESTORE_INTR (flags);
+}
+
+void
+DMAbuf_inputintr (int dev)
+{
+ unsigned long flags;
+
+ if (!dev_busy[dev])
+ {
+ dsp_devs[dev]->close (dev);
+ }
+ else if (dev_qlen[dev] == (dev_nbufs[dev] - 1))
+ {
+ printk ("Sound: Recording overrun\n");
+ dev_underrun[dev]++;
+ dsp_devs[dev]->halt_xfer (dev);
+ dev_active[dev] = 0;
+ dev_needs_restart[dev] = sound_dma_automode[dev];
+ }
+ else
+ {
+ dev_qlen[dev]++;
+ dev_qtail[dev] = (dev_qtail[dev] + 1) % dev_nbufs[dev];
+
+ dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]],
+ dev_buffsize[dev], 1,
+ !sound_dma_automode[dev]);
+ dev_active[dev] = 1;
+ }
+
+ DISABLE_INTR (flags);
+ if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev]))
+ {
+ WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]);
+ }
+ RESTORE_INTR (flags);
+}
+
+int
+DMAbuf_open_dma (int dev)
+{
+ unsigned long flags;
+ int chan = sound_dsp_dmachan[dev];
+
+ if (ALLOC_DMA_CHN (chan))
+ {
+ printk ("Unable to grab DMA%d for the audio driver\n", chan);
+ return 0;
+ }
+
+ DISABLE_INTR (flags);
+#ifdef linux
+ disable_dma (chan);
+ clear_dma_ff (chan);
+#endif
+ RESTORE_INTR (flags);
+
+ return 1;
+}
+
+void
+DMAbuf_close_dma (int dev)
+{
+ int chan = sound_dsp_dmachan[dev];
+
+ DMAbuf_reset_dma (chan);
+ RELEASE_DMA_CHN (chan);
+}
+
+void
+DMAbuf_reset_dma (int chan)
+{
+}
+
+/*
+ * The sound_mem_init() is called by mem_init() immediately after mem_map is
+ * initialized and before free_page_list is created.
+ *
+ * This routine allocates DMA buffers at the end of available physical memory (
+ * <16M) and marks pages reserved at mem_map.
+ */
+
+#else
+/* Stub versions if audio services not included */
+
+int
+DMAbuf_open (int dev, int mode)
+{
+ return RET_ERROR (ENXIO);
+}
+
+int
+DMAbuf_release (int dev, int mode)
+{
+ return 0;
+}
+
+int
+DMAbuf_read (int dev, snd_rw_buf * user_buf, int count)
+{
+ return RET_ERROR (EIO);
+}
+
+int
+DMAbuf_getwrbuffer (int dev, char **buf, int *size)
+{
+ return RET_ERROR (EIO);
+}
+
+int
+DMAbuf_getrdbuffer (int dev, char **buf, int *len)
+{
+ return RET_ERROR (EIO);
+}
+
+int
+DMAbuf_rmchars (int dev, int buff_no, int c)
+{
+ return RET_ERROR (EIO);
+}
+
+int
+DMAbuf_start_output (int dev, int buff_no, int l)
+{
+ return RET_ERROR (EIO);
+}
+
+int
+DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+{
+ return RET_ERROR (EIO);
+}
+
+long
+DMAbuf_init (long mem_start)
+{
+ return mem_start;
+}
+
+int
+DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode)
+{
+ return RET_ERROR (EIO);
+}
+
+int
+DMAbuf_open_dma (int chan)
+{
+ return RET_ERROR (ENXIO);
+}
+
+void
+DMAbuf_close_dma (int chan)
+{
+ return;
+}
+
+void
+DMAbuf_reset_dma (int chan)
+{
+ return;
+}
+
+void
+DMAbuf_inputintr (int dev)
+{
+ return;
+}
+
+void
+DMAbuf_outputintr (int dev, int underrun_flag)
+{
+ return;
+}
+
+#endif
+
+#endif
diff --git a/sys/i386/isa/sound/finetune.h b/sys/i386/isa/sound/finetune.h
new file mode 100644
index 0000000..b86a0eb
--- /dev/null
+++ b/sys/i386/isa/sound/finetune.h
@@ -0,0 +1,49 @@
+#ifdef SEQUENCER_C
+/*
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+ unsigned short finetune_table[128] =
+ {
+/* 0 */ 9439, 9447, 9456, 9464, 9473, 9481, 9490, 9499,
+/* 8 */ 9507, 9516, 9524, 9533, 9542, 9550, 9559, 9567,
+/* 16 */ 9576, 9585, 9593, 9602, 9611, 9619, 9628, 9637,
+/* 24 */ 9645, 9654, 9663, 9672, 9680, 9689, 9698, 9707,
+/* 32 */ 9715, 9724, 9733, 9742, 9750, 9759, 9768, 9777,
+/* 40 */ 9786, 9795, 9803, 9812, 9821, 9830, 9839, 9848,
+/* 48 */ 9857, 9866, 9874, 9883, 9892, 9901, 9910, 9919,
+/* 56 */ 9928, 9937, 9946, 9955, 9964, 9973, 9982, 9991,
+/* 64 */ 10000, 10009, 10018, 10027, 10036, 10045, 10054, 10063,
+/* 72 */ 10072, 10082, 10091, 10100, 10109, 10118, 10127, 10136,
+/* 80 */ 10145, 10155, 10164, 10173, 10182, 10191, 10201, 10210,
+/* 88 */ 10219, 10228, 10237, 10247, 10256, 10265, 10274, 10284,
+/* 96 */ 10293, 10302, 10312, 10321, 10330, 10340, 10349, 10358,
+/* 104 */ 10368, 10377, 10386, 10396, 10405, 10415, 10424, 10433,
+/* 112 */ 10443, 10452, 10462, 10471, 10481, 10490, 10499, 10509,
+/* 120 */ 10518, 10528, 10537, 10547, 10556, 10566, 10576, 10585
+ };
+#else
+ extern unsigned short finetune_table[128];
+#endif
diff --git a/sys/i386/isa/sound/gus_card.c b/sys/i386/isa/sound/gus_card.c
new file mode 100644
index 0000000..c7cfc0a
--- /dev/null
+++ b/sys/i386/isa/sound/gus_card.c
@@ -0,0 +1,142 @@
+/*
+ * sound/gus_card.c
+ *
+ * Detection routine for the Gravis Ultrasound.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
+
+#include "gus_hw.h"
+
+void gusintr (int);
+
+int gus_base, gus_irq, gus_dma;
+
+long
+attach_gus_card (long mem_start, struct address_info *hw_config)
+{
+ int io_addr;
+
+ snd_set_irq_handler (hw_config->irq, gusintr);
+
+ if (gus_wave_detect (hw_config->io_base)) /* Try first the default */
+ {
+ mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma);
+#ifndef EXCLUDE_MIDI
+ mem_start = gus_midi_init (mem_start);
+#endif
+ return mem_start;
+ }
+
+#ifndef EXCLUDE_GUS_IODETECT
+
+ /*
+ * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6)
+ */
+
+ for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10)
+ if (io_addr != hw_config->io_base) /* Already tested */
+ if (gus_wave_detect (io_addr))
+ {
+ printk (" WARNING! GUS found at %x, config was %x ", io_addr, hw_config->io_base);
+ mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma);
+#ifndef EXCLUDE_MIDI
+ mem_start = gus_midi_init (mem_start);
+#endif
+ return mem_start;
+ }
+
+#endif
+
+ return mem_start; /* Not detected */
+}
+
+int
+probe_gus (struct address_info *hw_config)
+{
+ int io_addr;
+
+ if (gus_wave_detect (hw_config->io_base))
+ return 1;
+
+#ifndef EXCLUDE_GUS_IODETECT
+
+ /*
+ * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6)
+ */
+
+ for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10)
+ if (io_addr != hw_config->io_base) /* Already tested */
+ if (gus_wave_detect (io_addr))
+ return 1;
+
+#endif
+
+ return 0;
+}
+
+void
+gusintr (int unit)
+{
+ unsigned char src;
+
+#ifdef linux
+ sti ();
+#endif
+
+ while (1)
+ {
+ if (!(src = INB (u_IrqStatus)))
+ return;
+
+ if (src & DMA_TC_IRQ)
+ {
+ guswave_dma_irq ();
+ }
+
+ if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ))
+ {
+#ifndef EXCLUDE_MIDI
+ gus_midi_interrupt (0);
+#endif
+ }
+
+ if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ))
+ {
+ printk ("T");
+ gus_write8 (0x45, 0); /* Timer control */
+ }
+
+ if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ))
+ {
+ gus_voice_irq ();
+ }
+ }
+}
+
+#endif
diff --git a/sys/i386/isa/sound/gus_hw.h b/sys/i386/isa/sound/gus_hw.h
new file mode 100644
index 0000000..f97a0b8
--- /dev/null
+++ b/sys/i386/isa/sound/gus_hw.h
@@ -0,0 +1,50 @@
+
+/*
+ * I/O addresses
+ */
+
+#define u_Base (gus_base + 0x000)
+#define u_Mixer u_Base
+#define u_Status (gus_base + 0x006)
+#define u_TimerControl (gus_base + 0x008)
+#define u_TimerData (gus_base + 0x009)
+#define u_IRQDMAControl (gus_base + 0x00b)
+#define u_MidiControl (gus_base + 0x100)
+#define MIDI_RESET 0x03
+#define MIDI_ENABLE_XMIT 0x20
+#define MIDI_ENABLE_RCV 0x80
+#define u_MidiStatus u_MidiControl
+#define MIDI_RCV_FULL 0x01
+#define MIDI_XMIT_EMPTY 0x02
+#define MIDI_FRAME_ERR 0x10
+#define MIDI_OVERRUN 0x20
+#define MIDI_IRQ_PEND 0x80
+#define u_MidiData (gus_base + 0x101)
+#define u_Voice (gus_base + 0x102)
+#define u_Command (gus_base + 0x103)
+#define u_DataLo (gus_base + 0x104)
+#define u_DataHi (gus_base + 0x105)
+#define u_MixData (gus_base + 0x106) /* Rev. 3.7+ mixing */
+#define u_MixSelect (gus_base + 0x506) /* registers. */
+#define u_IrqStatus u_Status
+# define MIDI_TX_IRQ 0x01 /* pending MIDI xmit IRQ */
+# define MIDI_RX_IRQ 0x02 /* pending MIDI recv IRQ */
+# define GF1_TIMER1_IRQ 0x04 /* general purpose timer */
+# define GF1_TIMER2_IRQ 0x08 /* general purpose timer */
+# define WAVETABLE_IRQ 0x20 /* pending wavetable IRQ */
+# define ENVELOPE_IRQ 0x40 /* pending volume envelope IRQ */
+# define DMA_TC_IRQ 0x80 /* pending dma tc IRQ */
+
+#define ICS2101 1
+# define ICS_MIXDEVS 6
+# define DEV_MIC 0
+# define DEV_LINE 1
+# define DEV_CD 2
+# define DEV_GF1 3
+# define DEV_UNUSED 4
+# define DEV_VOL 5
+
+# define CHN_LEFT 0
+# define CHN_RIGHT 1
+#define CS4231 2
+#define u_DRAMIO (gus_base + 0x107)
diff --git a/sys/i386/isa/sound/gus_linearvol.h b/sys/i386/isa/sound/gus_linearvol.h
new file mode 100644
index 0000000..7ad0c30
--- /dev/null
+++ b/sys/i386/isa/sound/gus_linearvol.h
@@ -0,0 +1,18 @@
+static unsigned short gus_linearvol[128] = {
+ 0x0000, 0x08ff, 0x09ff, 0x0a80, 0x0aff, 0x0b40, 0x0b80, 0x0bc0,
+ 0x0bff, 0x0c20, 0x0c40, 0x0c60, 0x0c80, 0x0ca0, 0x0cc0, 0x0ce0,
+ 0x0cff, 0x0d10, 0x0d20, 0x0d30, 0x0d40, 0x0d50, 0x0d60, 0x0d70,
+ 0x0d80, 0x0d90, 0x0da0, 0x0db0, 0x0dc0, 0x0dd0, 0x0de0, 0x0df0,
+ 0x0dff, 0x0e08, 0x0e10, 0x0e18, 0x0e20, 0x0e28, 0x0e30, 0x0e38,
+ 0x0e40, 0x0e48, 0x0e50, 0x0e58, 0x0e60, 0x0e68, 0x0e70, 0x0e78,
+ 0x0e80, 0x0e88, 0x0e90, 0x0e98, 0x0ea0, 0x0ea8, 0x0eb0, 0x0eb8,
+ 0x0ec0, 0x0ec8, 0x0ed0, 0x0ed8, 0x0ee0, 0x0ee8, 0x0ef0, 0x0ef8,
+ 0x0eff, 0x0f04, 0x0f08, 0x0f0c, 0x0f10, 0x0f14, 0x0f18, 0x0f1c,
+ 0x0f20, 0x0f24, 0x0f28, 0x0f2c, 0x0f30, 0x0f34, 0x0f38, 0x0f3c,
+ 0x0f40, 0x0f44, 0x0f48, 0x0f4c, 0x0f50, 0x0f54, 0x0f58, 0x0f5c,
+ 0x0f60, 0x0f64, 0x0f68, 0x0f6c, 0x0f70, 0x0f74, 0x0f78, 0x0f7c,
+ 0x0f80, 0x0f84, 0x0f88, 0x0f8c, 0x0f90, 0x0f94, 0x0f98, 0x0f9c,
+ 0x0fa0, 0x0fa4, 0x0fa8, 0x0fac, 0x0fb0, 0x0fb4, 0x0fb8, 0x0fbc,
+ 0x0fc0, 0x0fc4, 0x0fc8, 0x0fcc, 0x0fd0, 0x0fd4, 0x0fd8, 0x0fdc,
+ 0x0fe0, 0x0fe4, 0x0fe8, 0x0fec, 0x0ff0, 0x0ff4, 0x0ff8, 0x0ffc
+};
diff --git a/sys/i386/isa/sound/gus_midi.c b/sys/i386/isa/sound/gus_midi.c
new file mode 100644
index 0000000..935c5c9
--- /dev/null
+++ b/sys/i386/isa/sound/gus_midi.c
@@ -0,0 +1,283 @@
+/*
+ * sound/gus2_midi.c
+ *
+ * The low level driver for the GUS Midi Interface.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+#include "gus_hw.h"
+
+#if !defined(EXCLUDE_GUS) && !defined(EXCLUDE_MIDI)
+
+static int midi_busy = 0, input_opened = 0;
+static int my_dev;
+static int output_used = 0;
+static volatile unsigned char gus_midi_control;
+
+static void (*midi_input_intr) (int dev, unsigned char data);
+
+static unsigned char tmp_queue[256];
+static volatile int qlen;
+static volatile unsigned char qhead, qtail;
+extern int gus_base, gus_irq, gus_dma;
+
+#define GUS_MIDI_STATUS() INB(u_MidiStatus)
+
+static int
+gus_midi_open (int dev, int mode,
+ void (*input) (int dev, unsigned char data),
+ void (*output) (int dev)
+)
+{
+
+ if (midi_busy)
+ {
+ printk ("GUS: Midi busy\n");
+ return RET_ERROR (EBUSY);
+ }
+
+ OUTB (MIDI_RESET, u_MidiControl);
+ gus_delay ();
+
+ gus_midi_control = 0;
+ input_opened = 0;
+
+ if (mode == OPEN_READ || mode == OPEN_READWRITE)
+ {
+ gus_midi_control |= MIDI_ENABLE_RCV;
+ input_opened = 1;
+ }
+
+ if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
+ {
+ gus_midi_control |= MIDI_ENABLE_XMIT;
+ }
+
+ OUTB (gus_midi_control, u_MidiControl); /* Enable */
+
+ midi_busy = 1;
+ qlen = qhead = qtail = output_used = 0;
+ midi_input_intr = input;
+
+ return 0;
+}
+
+static int
+dump_to_midi (unsigned char midi_byte)
+{
+ unsigned long flags;
+ int ok = 0;
+
+ output_used = 1;
+
+ DISABLE_INTR (flags);
+
+ if (GUS_MIDI_STATUS () & MIDI_XMIT_EMPTY)
+ {
+ ok = 1;
+ OUTB (midi_byte, u_MidiData);
+ }
+ else
+ {
+ /* Enable Midi xmit interrupts (again) */
+ gus_midi_control |= MIDI_ENABLE_XMIT;
+ OUTB (gus_midi_control, u_MidiControl);
+ }
+
+ RESTORE_INTR (flags);
+ return ok;
+}
+
+static void
+gus_midi_close (int dev)
+{
+ /* Reset FIFO pointers, disable intrs */
+
+ OUTB (MIDI_RESET, u_MidiControl);
+ midi_busy = 0;
+}
+
+static int
+gus_midi_out (int dev, unsigned char midi_byte)
+{
+
+ unsigned long flags;
+
+ /*
+ * Drain the local queue first
+ */
+
+ DISABLE_INTR (flags);
+
+ while (qlen && dump_to_midi (tmp_queue[qhead]))
+ {
+ qlen--;
+ qhead++;
+ }
+
+ RESTORE_INTR (flags);
+
+ /*
+ * Output the byte if the local queue is empty.
+ */
+
+ if (!qlen)
+ if (dump_to_midi (midi_byte))
+ return 1; /* OK */
+
+ /*
+ * Put to the local queue
+ */
+
+ if (qlen >= 256)
+ return 0; /* Local queue full */
+
+ DISABLE_INTR (flags);
+
+ tmp_queue[qtail] = midi_byte;
+ qlen++;
+ qtail++;
+
+ RESTORE_INTR (flags);
+
+ return 1;
+}
+
+static int
+gus_midi_start_read (int dev)
+{
+ return 0;
+}
+
+static int
+gus_midi_end_read (int dev)
+{
+ return 0;
+}
+
+static int
+gus_midi_ioctl (int dev, unsigned cmd, unsigned arg)
+{
+ return RET_ERROR (EINVAL);
+}
+
+static void
+gus_midi_kick (int dev)
+{
+}
+
+static int
+gus_midi_buffer_status (int dev)
+{
+ unsigned long flags;
+
+ if (!output_used)
+ return 0;
+
+ DISABLE_INTR (flags);
+
+ if (qlen && dump_to_midi (tmp_queue[qhead]))
+ {
+ qlen--;
+ qhead++;
+ }
+
+ RESTORE_INTR (flags);
+
+ return (qlen > 0) | !(GUS_MIDI_STATUS () & MIDI_XMIT_EMPTY);
+}
+
+static struct midi_operations gus_midi_operations =
+{
+ {"Gravis UltraSound", 0, 0, SNDCARD_GUS},
+ gus_midi_open,
+ gus_midi_close,
+ gus_midi_ioctl,
+ gus_midi_out,
+ gus_midi_start_read,
+ gus_midi_end_read,
+ gus_midi_kick,
+ NULL, /* command */
+ gus_midi_buffer_status
+};
+
+long
+gus_midi_init (long mem_start)
+{
+ OUTB (MIDI_RESET, u_MidiControl);
+
+ my_dev = num_midis;
+ midi_devs[num_midis++] = &gus_midi_operations;
+ return mem_start;
+}
+
+void
+gus_midi_interrupt (int dummy)
+{
+ unsigned char stat, data;
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+
+ stat = GUS_MIDI_STATUS ();
+
+ if (stat & MIDI_RCV_FULL)
+ {
+ data = INB (u_MidiData);
+ if (input_opened)
+ midi_input_intr (my_dev, data);
+ }
+
+ if (stat & MIDI_XMIT_EMPTY)
+ {
+ while (qlen && dump_to_midi (tmp_queue[qhead]))
+ {
+ qlen--;
+ qhead++;
+ }
+
+ if (!qlen)
+ {
+ /* Disable Midi output interrupts, since no data in the buffer */
+ gus_midi_control &= ~MIDI_ENABLE_XMIT;
+ OUTB (gus_midi_control, u_MidiControl);
+ }
+ }
+
+ if (stat & MIDI_FRAME_ERR)
+ printk ("Midi framing error\n");
+ if (stat & MIDI_OVERRUN && input_opened)
+ printk ("GUS: Midi input overrun\n");
+
+ RESTORE_INTR (flags);
+}
+
+#endif
+
+#endif
diff --git a/sys/i386/isa/sound/gus_vol.c b/sys/i386/isa/sound/gus_vol.c
new file mode 100644
index 0000000..055a117
--- /dev/null
+++ b/sys/i386/isa/sound/gus_vol.c
@@ -0,0 +1,147 @@
+/*
+ * gus_vol.c - Compute volume for GUS.
+ *
+ * Greg Lee 1993.
+ */
+#include "sound_config.h"
+#ifndef EXCLUDE_GUS
+#include "gus_linearvol.h"
+
+#define GUS_VOLUME gus_wave_volume
+
+
+extern int gus_wave_volume;
+
+/*
+ * Calculate gus volume from note velocity, main volume, expression, and
+ * intrinsic patch volume given in patch library. Expression is multiplied
+ * in, so it emphasizes differences in note velocity, while main volume is
+ * added in -- I don't know whether this is right, but it seems reasonable to
+ * me. (In the previous stage, main volume controller messages were changed
+ * to expression controller messages, if they were found to be used for
+ * dynamic volume adjustments, so here, main volume can be assumed to be
+ * constant throughout a song.)
+ *
+ * Intrinsic patch volume is added in, but if over 64 is also multiplied in, so
+ * we can give a big boost to very weak voices like nylon guitar and the
+ * basses. The normal value is 64. Strings are assigned lower values.
+ */
+unsigned short
+gus_adagio_vol (int vel, int mainv, int xpn, int voicev)
+{
+ int i, m, n, x;
+
+
+ /*
+ * A voice volume of 64 is considered neutral, so adjust the main volume if
+ * something other than this neutral value was assigned in the patch
+ * library.
+ */
+ x = 256 + 6 * (voicev - 64);
+
+ /*
+ * Boost expression by voice volume above neutral.
+ */
+ if (voicev > 65)
+ xpn += voicev - 64;
+ xpn += (voicev - 64) / 2;
+
+ /*
+ * Combine multiplicative and level components.
+ */
+ x = vel * xpn * 6 + (voicev / 4) * x;
+
+#ifdef GUS_VOLUME
+ /*
+ * Further adjustment by installation-specific master volume control
+ * (default 60).
+ */
+ x = (x * GUS_VOLUME * GUS_VOLUME) / 10000;
+#endif
+
+#ifdef GUS_USE_CHN_MAIN_VOLUME
+ /*
+ * Experimental support for the channel main volume
+ */
+
+ mainv = (mainv / 2) + 64; /* Scale to 64 to 127 */
+ x = (x * mainv * mainv) / 16384;
+#endif
+
+ if (x < 2)
+ return (0);
+ else if (x >= 65535)
+ return ((15 << 8) | 255);
+
+ /*
+ * Convert to gus's logarithmic form with 4 bit exponent i and 8 bit
+ * mantissa m.
+ */
+ n = x;
+ i = 7;
+ if (n < 128)
+ {
+ while (i > 0 && n < (1 << i))
+ i--;
+ }
+ else
+ while (n > 255)
+ {
+ n >>= 1;
+ i++;
+ }
+ /*
+ * Mantissa is part of linear volume not expressed in exponent. (This is
+ * not quite like real logs -- I wonder if it's right.)
+ */
+ m = x - (1 << i);
+
+ /*
+ * Adjust mantissa to 8 bits.
+ */
+ if (m > 0)
+ {
+ if (i > 8)
+ m >>= i - 8;
+ else if (i < 8)
+ m <<= 8 - i;
+ }
+
+ return ((i << 8) + m);
+}
+
+/*
+ * Volume-values are interpreted as linear values. Volume is based on the
+ * value supplied with SEQ_START_NOTE(), channel main volume (if compiled in)
+ * and the volume set by the mixer-device (default 60%).
+ */
+
+unsigned short
+gus_linear_vol (int vol, int mainvol)
+{
+ int mixer_mainvol;
+
+ if (vol <= 0)
+ vol = 0;
+ else if (vol >= 127)
+ vol = 127;
+
+#ifdef GUS_VOLUME
+ mixer_mainvol = GUS_VOLUME;
+#else
+ mixer_mainvol = 100;
+#endif
+
+#ifdef GUS_USE_CHN_MAIN_VOLUME
+ if (mainvol <= 0)
+ mainvol = 0;
+ else if (mainvol >= 127)
+ mainvol = 127;
+#else
+ mainvol = 128;
+#endif
+
+ return gus_linearvol[(((vol * mainvol) / 128) * mixer_mainvol) / 100];
+}
+
+#endif
diff --git a/sys/i386/isa/sound/gus_wave.c b/sys/i386/isa/sound/gus_wave.c
new file mode 100644
index 0000000..9f6442e
--- /dev/null
+++ b/sys/i386/isa/sound/gus_wave.c
@@ -0,0 +1,3575 @@
+/*
+ * sound/gus_wave.c
+ *
+ * Driver for the Gravis UltraSound wave table synth.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+#ifdef __FreeBSD__
+#include <machine/ultrasound.h>
+#else
+#include "ultrasound.h"
+#endif
+#include "gus_hw.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
+
+#define MAX_SAMPLE 128
+#define MAX_PATCH 256
+
+struct voice_info
+ {
+ unsigned long orig_freq;
+ unsigned long current_freq;
+ unsigned long mode;
+ int bender;
+ int bender_range;
+ int panning;
+ int midi_volume;
+ unsigned int initial_volume;
+ unsigned int current_volume;
+ int loop_irq_mode, loop_irq_parm;
+#define LMODE_FINISH 1
+#define LMODE_PCM 2
+#define LMODE_PCM_STOP 3
+ int volume_irq_mode, volume_irq_parm;
+#define VMODE_HALT 1
+#define VMODE_ENVELOPE 2
+#define VMODE_START_NOTE 3
+
+ int env_phase;
+ unsigned char env_rate[6];
+ unsigned char env_offset[6];
+
+ /*
+ * Volume computation parameters for gus_adagio_vol()
+ */
+ int main_vol, expression_vol, patch_vol;
+
+ /* Variables for "Ultraclick" removal */
+ int dev_pending, note_pending, volume_pending, sample_pending;
+ char kill_pending;
+ long offset_pending;
+
+ };
+
+extern int gus_base;
+extern int gus_irq, gus_dma;
+extern char *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT];
+extern unsigned long snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT];
+extern int snd_raw_count[MAX_DSP_DEV];
+static long gus_mem_size = 0;
+static long free_mem_ptr = 0;
+static int gus_busy = 0;
+static int nr_voices = 0;
+static int gus_devnum = 0;
+static int volume_base, volume_scale, volume_method;
+static int gus_line_vol = 100, gus_mic_vol = 0;
+static int gus_recmask = SOUND_MASK_MIC;
+static int recording_active = 0;
+
+int gus_wave_volume = 60;
+int gus_pcm_volume = 80;
+static unsigned char mix_image = 0x00;
+
+/*
+ * Current version of this driver doesn't allow synth and PCM functions
+ * at the same time. The active_device specifies the active driver
+ */
+static int active_device = 0;
+
+#define GUS_DEV_WAVE 1 /*
+ * * * Wave table synth */
+#define GUS_DEV_PCM_DONE 2 /*
+ * * * PCM device, transfer done */
+#define GUS_DEV_PCM_CONTINUE 3 /*
+ * * * PCM device, transfer the
+ * second * * * chn */
+
+static int gus_sampling_speed;
+static int gus_sampling_channels;
+static int gus_sampling_bits;
+
+DEFINE_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);
+
+/*
+ * Variables and buffers for PCM output
+ */
+#define MAX_PCM_BUFFERS (32*MAX_REALTIME_FACTOR) /*
+ * * * Don't
+ * * * change
+ *
+ */
+
+static int pcm_bsize, /*
+ * Current blocksize
+ */
+ pcm_nblk, /*
+ * Current # of blocks
+ */
+ pcm_banksize; /*
+
+
+ * * * * # bytes allocated for channels */
+static int pcm_datasize[MAX_PCM_BUFFERS]; /*
+
+
+ * * * * Actual # of bytes
+ * in blk * */
+static volatile int pcm_head, pcm_tail, pcm_qlen; /*
+
+
+ * * * * DRAM queue
+ * */
+static volatile int pcm_active;
+static int pcm_opened = 0;
+static int pcm_current_dev;
+static int pcm_current_block;
+static unsigned long pcm_current_buf;
+static int pcm_current_count;
+static int pcm_current_intrflag;
+
+struct voice_info voices[32];
+
+static int freq_div_table[] =
+{
+ 44100, /*
+ * 14
+ */
+ 41160, /*
+ * 15
+ */
+ 38587, /*
+ * 16
+ */
+ 36317, /*
+ * 17
+ */
+ 34300, /*
+ * 18
+ */
+ 32494, /*
+ * 19
+ */
+ 30870, /*
+ * 20
+ */
+ 29400, /*
+ * 21
+ */
+ 28063, /*
+ * 22
+ */
+ 26843, /*
+ * 23
+ */
+ 25725, /*
+ * 24
+ */
+ 24696, /*
+ * 25
+ */
+ 23746, /*
+ * 26
+ */
+ 22866, /*
+ * 27
+ */
+ 22050, /*
+ * 28
+ */
+ 21289, /*
+ * 29
+ */
+ 20580, /*
+ * 30
+ */
+ 19916, /*
+ * 31
+ */
+ 19293 /*
+ * 32
+ */
+};
+
+static struct patch_info *samples;
+static long sample_ptrs[MAX_SAMPLE + 1];
+static int sample_map[32];
+static int free_sample;
+
+
+static int patch_table[MAX_PATCH];
+static int patch_map[32];
+
+static struct synth_info gus_info =
+{"Gravis UltraSound", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, 0, 16, 0, MAX_PATCH};
+
+static void gus_poke (long addr, unsigned char data);
+static void compute_and_set_volume (int voice, int volume, int ramp_time);
+extern unsigned short gus_adagio_vol (int vel, int mainv, int xpn, int voicev);
+extern unsigned short gus_linear_vol (int vol, int mainvol);
+static void compute_volume (int voice, int volume);
+static void do_volume_irq (int voice);
+static void set_input_volumes (void);
+
+#define INSTANT_RAMP -1 /*
+ * * * Dont use ramping */
+#define FAST_RAMP 0 /*
+ * * * Fastest possible ramp */
+
+static void
+reset_sample_memory (void)
+{
+ int i;
+
+ for (i = 0; i <= MAX_SAMPLE; i++)
+ sample_ptrs[i] = -1;
+ for (i = 0; i < 32; i++)
+ sample_map[i] = -1;
+ for (i = 0; i < 32; i++)
+ patch_map[i] = -1;
+
+ gus_poke (0, 0); /*
+ * Put silence here
+ */
+ gus_poke (1, 0);
+
+ free_mem_ptr = 2;
+ free_sample = 0;
+
+ for (i = 0; i < MAX_PATCH; i++)
+ patch_table[i] = -1;
+}
+
+void
+gus_delay (void)
+{
+ int i;
+
+ for (i = 0; i < 7; i++)
+ INB (u_DRAMIO);
+}
+
+static void
+gus_poke (long addr, unsigned char data)
+{
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+ OUTB (0x43, u_Command);
+ OUTB (addr & 0xff, u_DataLo);
+ OUTB ((addr >> 8) & 0xff, u_DataHi);
+
+ OUTB (0x44, u_Command);
+ OUTB ((addr >> 16) & 0xff, u_DataHi);
+ OUTB (data, u_DRAMIO);
+ RESTORE_INTR (flags);
+}
+
+static unsigned char
+gus_peek (long addr)
+{
+ unsigned long flags;
+ unsigned char tmp;
+
+ DISABLE_INTR (flags);
+ OUTB (0x43, u_Command);
+ OUTB (addr & 0xff, u_DataLo);
+ OUTB ((addr >> 8) & 0xff, u_DataHi);
+
+ OUTB (0x44, u_Command);
+ OUTB ((addr >> 16) & 0xff, u_DataHi);
+ tmp = INB (u_DRAMIO);
+ RESTORE_INTR (flags);
+
+ return tmp;
+}
+
+void
+gus_write8 (int reg, unsigned int data)
+{
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+
+ OUTB (reg, u_Command);
+ OUTB ((unsigned char) (data & 0xff), u_DataHi);
+
+ RESTORE_INTR (flags);
+}
+
+unsigned char
+gus_read8 (int reg)
+{
+ unsigned long flags;
+ unsigned char val;
+
+ DISABLE_INTR (flags);
+ OUTB (reg | 0x80, u_Command);
+ val = INB (u_DataHi);
+ RESTORE_INTR (flags);
+
+ return val;
+}
+
+unsigned char
+gus_look8 (int reg)
+{
+ unsigned long flags;
+ unsigned char val;
+
+ DISABLE_INTR (flags);
+ OUTB (reg, u_Command);
+ val = INB (u_DataHi);
+ RESTORE_INTR (flags);
+
+ return val;
+}
+
+void
+gus_write16 (int reg, unsigned int data)
+{
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+
+ OUTB (reg, u_Command);
+
+ OUTB ((unsigned char) (data & 0xff), u_DataLo);
+ OUTB ((unsigned char) ((data >> 8) & 0xff), u_DataHi);
+
+ RESTORE_INTR (flags);
+}
+
+unsigned short
+gus_read16 (int reg)
+{
+ unsigned long flags;
+ unsigned char hi, lo;
+
+ DISABLE_INTR (flags);
+
+ OUTB (reg | 0x80, u_Command);
+
+ lo = INB (u_DataLo);
+ hi = INB (u_DataHi);
+
+ RESTORE_INTR (flags);
+
+ return ((hi << 8) & 0xff00) | lo;
+}
+
+void
+gus_write_addr (int reg, unsigned long address, int is16bit)
+{
+ unsigned long hold_address;
+
+ if (is16bit)
+ {
+ /*
+ * Special processing required for 16 bit patches
+ */
+
+ hold_address = address;
+ address = address >> 1;
+ address &= 0x0001ffffL;
+ address |= (hold_address & 0x000c0000L);
+ }
+
+ gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
+ gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));
+ /* Could writing twice fix problems with GUS_VOICE_POS() ? Lets try... */
+ gus_delay ();
+ gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
+ gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));
+}
+
+static void
+gus_select_voice (int voice)
+{
+ if (voice < 0 || voice > 31)
+ return;
+
+ OUTB (voice, u_Voice);
+}
+
+static void
+gus_select_max_voices (int nvoices)
+{
+ if (nvoices < 14)
+ nvoices = 14;
+ if (nvoices > 32)
+ nvoices = 32;
+
+ nr_voices = nvoices;
+
+ gus_write8 (0x0e, (nvoices - 1) | 0xc0);
+}
+
+static void
+gus_voice_on (unsigned int mode)
+{
+ gus_write8 (0x00, (unsigned char) (mode & 0xfc));
+ gus_delay ();
+ gus_write8 (0x00, (unsigned char) (mode & 0xfc));
+}
+
+static void
+gus_voice_off (void)
+{
+ gus_write8 (0x00, gus_read8 (0x00) | 0x03);
+}
+
+static void
+gus_voice_mode (unsigned int m)
+{
+ unsigned char mode = (unsigned char) (m & 0xff);
+
+ gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc)); /*
+ * Don't
+ * start
+ * or
+ * stop
+ * *
+ * voice
+ */
+ gus_delay ();
+ gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc));
+}
+
+static void
+gus_voice_freq (unsigned long freq)
+{
+ unsigned long divisor = freq_div_table[nr_voices - 14];
+ unsigned short fc;
+
+ fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor);
+ fc = fc << 1;
+
+ gus_write16 (0x01, fc);
+}
+
+static void
+gus_voice_volume (unsigned int vol)
+{
+ gus_write8 (0x0d, 0x03); /*
+ * Stop ramp before setting volume
+ */
+ gus_write16 (0x09, (unsigned short) (vol << 4));
+}
+
+static void
+gus_voice_balance (unsigned int balance)
+{
+ gus_write8 (0x0c, (unsigned char) (balance & 0xff));
+}
+
+static void
+gus_ramp_range (unsigned int low, unsigned int high)
+{
+ gus_write8 (0x07, (unsigned char) ((low >> 4) & 0xff));
+ gus_write8 (0x08, (unsigned char) ((high >> 4) & 0xff));
+}
+
+static void
+gus_ramp_rate (unsigned int scale, unsigned int rate)
+{
+ gus_write8 (0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f)));
+}
+
+static void
+gus_rampon (unsigned int m)
+{
+ unsigned char mode = (unsigned char) (m & 0xff);
+
+ gus_write8 (0x0d, mode & 0xfc);
+ gus_delay ();
+ gus_write8 (0x0d, mode & 0xfc);
+}
+
+static void
+gus_ramp_mode (unsigned int m)
+{
+ unsigned char mode = (unsigned char) (m & 0xff);
+
+ gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc)); /*
+ * Don't
+ * start
+ * or
+ * stop
+ * *
+ * ramping
+ */
+ gus_delay ();
+ gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc));
+}
+
+static void
+gus_rampoff (void)
+{
+ gus_write8 (0x0d, 0x03);
+}
+
+static void
+gus_set_voice_pos (int voice, long position)
+{
+ int sample_no;
+
+ if ((sample_no = sample_map[voice]) != -1)
+ if (position < samples[sample_no].len)
+ if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
+ voices[voice].offset_pending = position;
+ else
+ gus_write_addr (0x0a, sample_ptrs[sample_no] + position,
+ samples[sample_no].mode & WAVE_16_BITS);
+}
+
+static void
+gus_voice_init (int voice)
+{
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_voice_volume (0);
+ gus_write_addr (0x0a, 0, 0); /*
+ * Set current position to 0
+ */
+ gus_write8 (0x00, 0x03); /*
+ * Voice off
+ */
+ gus_write8 (0x0d, 0x03); /*
+ * Ramping off
+ */
+ RESTORE_INTR (flags);
+
+}
+
+static void
+gus_voice_init2 (int voice)
+{
+ voices[voice].panning = 0;
+ voices[voice].mode = 0;
+ voices[voice].orig_freq = 20000;
+ voices[voice].current_freq = 20000;
+ voices[voice].bender = 0;
+ voices[voice].bender_range = 200;
+ voices[voice].initial_volume = 0;
+ voices[voice].current_volume = 0;
+ voices[voice].loop_irq_mode = 0;
+ voices[voice].loop_irq_parm = 0;
+ voices[voice].volume_irq_mode = 0;
+ voices[voice].volume_irq_parm = 0;
+ voices[voice].env_phase = 0;
+ voices[voice].main_vol = 127;
+ voices[voice].patch_vol = 127;
+ voices[voice].expression_vol = 127;
+ voices[voice].sample_pending = -1;
+}
+
+static void
+step_envelope (int voice)
+{
+ unsigned vol, prev_vol, phase;
+ unsigned char rate;
+ long int flags;
+
+ if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2)
+ {
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_rampoff ();
+ RESTORE_INTR (flags);
+ return; /*
+ * Sustain
+ */
+ }
+
+ if (voices[voice].env_phase >= 5)
+ {
+ /*
+ * Shoot the voice off
+ */
+
+ gus_voice_init (voice);
+ return;
+ }
+
+ prev_vol = voices[voice].current_volume;
+ phase = ++voices[voice].env_phase;
+ compute_volume (voice, voices[voice].midi_volume);
+ vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255;
+ rate = voices[voice].env_rate[phase];
+
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+
+ gus_voice_volume (prev_vol);
+
+
+ gus_write8 (0x06, rate); /*
+ * Ramping rate
+ */
+
+ voices[voice].volume_irq_mode = VMODE_ENVELOPE;
+
+ if (((vol - prev_vol) / 64) == 0) /*
+ * No significant volume change
+ */
+ {
+ RESTORE_INTR (flags);
+ step_envelope (voice); /*
+ * Continue with the next phase
+ */
+ return;
+ }
+
+ if (vol > prev_vol)
+ {
+ if (vol >= (4096 - 64))
+ vol = 4096 - 65;
+ gus_ramp_range (0, vol);
+ gus_rampon (0x20); /*
+ * Increasing, irq
+ */
+ }
+ else
+ {
+ if (vol <= 64)
+ vol = 65;
+ gus_ramp_range (vol, 4030);
+ gus_rampon (0x60); /*
+ * Decreasing, irq
+ */
+ }
+ voices[voice].current_volume = vol;
+ RESTORE_INTR (flags);
+}
+
+static void
+init_envelope (int voice)
+{
+ voices[voice].env_phase = -1;
+ voices[voice].current_volume = 64;
+
+ step_envelope (voice);
+}
+
+static void
+start_release (int voice, long int flags)
+{
+ if (gus_read8 (0x00) & 0x03)
+ return; /*
+ * Voice already stopped
+ */
+
+ voices[voice].env_phase = 2; /*
+ * Will be incremented by step_envelope
+ */
+
+ voices[voice].current_volume =
+ voices[voice].initial_volume =
+ gus_read16 (0x09) >> 4; /*
+ * Get current volume
+ */
+
+ voices[voice].mode &= ~WAVE_SUSTAIN_ON;
+ gus_rampoff ();
+ RESTORE_INTR (flags);
+ step_envelope (voice);
+}
+
+static void
+gus_voice_fade (int voice)
+{
+ int instr_no = sample_map[voice], is16bits;
+ long int flags;
+
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+
+ if (instr_no < 0 || instr_no > MAX_SAMPLE)
+ {
+ gus_write8 (0x00, 0x03); /*
+ * Hard stop
+ */
+ RESTORE_INTR (flags);
+ return;
+ }
+
+ is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /*
+ * 8 or 16
+ * bit
+ * samples
+ */
+
+ if (voices[voice].mode & WAVE_ENVELOPES)
+ {
+ start_release (voice, flags);
+ return;
+ }
+
+ /*
+ * Ramp the volume down but not too quickly.
+ */
+ if ((gus_read16 (0x09) >> 4) < 100) /*
+ * Get current volume
+ */
+ {
+ gus_voice_off ();
+ gus_rampoff ();
+ gus_voice_init (voice);
+ return;
+ }
+
+ gus_ramp_range (65, 4030);
+ gus_ramp_rate (2, 4);
+ gus_rampon (0x40 | 0x20); /*
+ * Down, once, irq
+ */
+ voices[voice].volume_irq_mode = VMODE_HALT;
+ RESTORE_INTR (flags);
+}
+
+static void
+gus_reset (void)
+{
+ int i;
+
+ gus_select_max_voices (24);
+ volume_base = 3071;
+ volume_scale = 4;
+ volume_method = VOL_METHOD_ADAGIO;
+
+ for (i = 0; i < 32; i++)
+ {
+ gus_voice_init (i); /*
+ * Turn voice off
+ */
+ gus_voice_init2 (i);
+ }
+
+ INB (u_Status); /*
+ * Touch the status register
+ */
+
+ gus_look8 (0x41); /*
+ * Clear any pending DMA IRQs
+ */
+ gus_look8 (0x49); /*
+ * Clear any pending sample IRQs
+ */
+ gus_read8 (0x0f); /*
+ * Clear pending IRQs
+ */
+
+}
+
+static void
+gus_initialize (void)
+{
+ unsigned long flags;
+ register unsigned char dma_image, irq_image, tmp;
+
+ static unsigned char gus_irq_map[16] =
+ {0, 0, 1, 3, 0, 2, 0, 4, 0, 0, 0, 5, 6, 0, 0, 7};
+
+ static unsigned char gus_dma_map[8] =
+ {0, 1, 0, 2, 0, 3, 4, 5};
+
+ DISABLE_INTR (flags);
+
+ gus_write8 (0x4c, 0); /*
+ * Reset GF1
+ */
+ gus_delay ();
+ gus_delay ();
+
+ gus_write8 (0x4c, 1); /*
+ * Release Reset
+ */
+ gus_delay ();
+ gus_delay ();
+
+ /*
+ * Clear all interrupts
+ */
+
+ gus_write8 (0x41, 0); /*
+ * DMA control
+ */
+ gus_write8 (0x45, 0); /*
+ * Timer control
+ */
+ gus_write8 (0x49, 0); /*
+ * Sample control
+ */
+
+ gus_select_max_voices (24);
+
+ INB (u_Status); /*
+ * Touch the status register
+ */
+
+ gus_look8 (0x41); /*
+ * Clear any pending DMA IRQs
+ */
+ gus_look8 (0x49); /*
+ * Clear any pending sample IRQs
+ */
+ gus_read8 (0x0f); /*
+ * Clear pending IRQs
+ */
+
+ gus_reset (); /*
+ * Resets all voices
+ */
+
+ gus_look8 (0x41); /*
+ * Clear any pending DMA IRQs
+ */
+ gus_look8 (0x49); /*
+ * Clear any pending sample IRQs
+ */
+ gus_read8 (0x0f); /*
+ * Clear pending IRQs
+ */
+
+ gus_write8 (0x4c, 7); /*
+ * Master reset | DAC enable | IRQ enable
+ */
+
+ /*
+ * Set up for Digital ASIC
+ */
+
+ OUTB (0x05, gus_base + 0x0f);
+
+ mix_image |= 0x02; /*
+ * Disable line out
+ */
+ OUTB (mix_image, u_Mixer);
+
+ OUTB (0x00, u_IRQDMAControl);
+
+ OUTB (0x00, gus_base + 0x0f);
+
+ /*
+ * Now set up the DMA and IRQ interface
+ *
+ * The GUS supports two IRQs and two DMAs.
+ *
+ * Just one DMA channel is used. This prevents simultaneous ADC and DAC.
+ * Adding this support requires significant changes to the dmabuf.c, dsp.c
+ * and audio.c also.
+ */
+
+ irq_image = 0;
+ tmp = gus_irq_map[gus_irq];
+ if (!tmp)
+ printk ("Warning! GUS IRQ not selected\n");
+ irq_image |= tmp;
+ irq_image |= 0x40; /*
+ * Combine IRQ1 (GF1) and IRQ2 (Midi)
+ */
+
+ dma_image = 0x40; /*
+ * Combine DMA1 (DRAM) and IRQ2 (ADC)
+ */
+ tmp = gus_dma_map[gus_dma];
+ if (!tmp)
+ printk ("Warning! GUS DMA not selected\n");
+ dma_image |= tmp;
+
+ /*
+ * For some reason the IRQ and DMA addresses must be written twice
+ */
+
+ /*
+ * Doing it first time
+ */
+
+ OUTB (mix_image, u_Mixer); /*
+ * Select DMA control
+ */
+ OUTB (dma_image | 0x80, u_IRQDMAControl); /*
+ * Set DMA address
+ */
+
+ OUTB (mix_image | 0x40, u_Mixer); /*
+ * Select IRQ control
+ */
+ OUTB (irq_image, u_IRQDMAControl); /*
+ * Set IRQ address
+ */
+
+ /*
+ * Doing it second time
+ */
+
+ OUTB (mix_image, u_Mixer); /*
+ * Select DMA control
+ */
+ OUTB (dma_image, u_IRQDMAControl); /*
+ * Set DMA address
+ */
+
+ OUTB (mix_image | 0x40, u_Mixer); /*
+ * Select IRQ control
+ */
+ OUTB (irq_image, u_IRQDMAControl); /*
+ * Set IRQ address
+ */
+
+ gus_select_voice (0); /*
+ * This disables writes to IRQ/DMA reg
+ */
+
+ mix_image &= ~0x02; /*
+ * Enable line out
+ */
+ mix_image |= 0x08; /*
+ * Enable IRQ
+ */
+ OUTB (mix_image, u_Mixer); /*
+ * Turn mixer channels on
+ * Note! Mic in is left off.
+ */
+
+ gus_select_voice (0); /*
+ * This disables writes to IRQ/DMA reg
+ */
+
+ gusintr (0); /*
+ * Serve pending interrupts
+ */
+ RESTORE_INTR (flags);
+}
+
+int
+gus_wave_detect (int baseaddr)
+{
+ unsigned long i;
+ unsigned long loc;
+
+ gus_base = baseaddr;
+
+ gus_write8 (0x4c, 0); /* Reset GF1 */
+ gus_delay ();
+ gus_delay ();
+
+ gus_write8 (0x4c, 1); /* Release Reset */
+ gus_delay ();
+ gus_delay ();
+
+ /* See if there is first block there.... */
+ gus_poke (0L, 0xaa);
+ if (gus_peek (0L) != 0xaa)
+ return (0);
+
+ /* Now zero it out so that I can check for mirroring .. */
+ gus_poke (0L, 0x00);
+ for (i = 1L; i < 1024L; i++)
+ {
+ int n, failed;
+
+ /* check for mirroring ... */
+ if (gus_peek (0L) != 0)
+ break;
+ loc = i << 10;
+
+ for (n = loc - 1, failed = 0; n <= loc; n++)
+ {
+ gus_poke (loc, 0xaa);
+ if (gus_peek (loc) != 0xaa)
+ failed = 1;
+
+ gus_poke (loc, 0x55);
+ if (gus_peek (loc) != 0x55)
+ failed = 1;
+ }
+
+ if (failed)
+ break;
+ }
+ gus_mem_size = i << 10;
+ return 1;
+}
+
+static int
+guswave_ioctl (int dev,
+ unsigned int cmd, unsigned int arg)
+{
+
+ switch (cmd)
+ {
+ case SNDCTL_SYNTH_INFO:
+ gus_info.nr_voices = nr_voices;
+ IOCTL_TO_USER ((char *) arg, 0, &gus_info, sizeof (gus_info));
+ return 0;
+ break;
+
+ case SNDCTL_SEQ_RESETSAMPLES:
+ reset_sample_memory ();
+ return 0;
+ break;
+
+ case SNDCTL_SEQ_PERCMODE:
+ return 0;
+ break;
+
+ case SNDCTL_SYNTH_MEMAVL:
+ return gus_mem_size - free_mem_ptr - 32;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+}
+
+static int
+guswave_set_instr (int dev, int voice, int instr_no)
+{
+ int sample_no;
+
+ if (instr_no < 0 || instr_no > MAX_PATCH)
+ return RET_ERROR (EINVAL);
+
+ if (voice < 0 || voice > 31)
+ return RET_ERROR (EINVAL);
+
+ if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
+ {
+ voices[voice].sample_pending = instr_no;
+ return 0;
+ }
+
+ sample_no = patch_table[instr_no];
+ patch_map[voice] = -1;
+
+ if (sample_no < 0)
+ {
+ printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice);
+ return RET_ERROR (EINVAL);/*
+ * Patch not defined
+ */
+ }
+
+ if (sample_ptrs[sample_no] == -1) /*
+ * Sample not loaded
+ */
+ {
+ printk ("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice);
+ return RET_ERROR (EINVAL);
+ }
+
+ sample_map[voice] = sample_no;
+ patch_map[voice] = instr_no;
+ return 0;
+}
+
+static int
+#ifdef FUTURE_VERSION
+guswave_kill_note (int dev, int voice, int note, int velocity)
+#else
+guswave_kill_note (int dev, int voice, int velocity)
+#endif
+{
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+ if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
+ {
+ voices[voice].kill_pending = 1;
+ RESTORE_INTR (flags);
+ }
+ else
+ {
+ RESTORE_INTR (flags);
+ gus_voice_fade (voice);
+ }
+
+ return 0;
+}
+
+static void
+guswave_aftertouch (int dev, int voice, int pressure)
+{
+ short lo_limit, hi_limit;
+ unsigned long flags;
+
+ return; /*
+ * Currently disabled
+ */
+
+ if (voice < 0 || voice > 31)
+ return;
+
+ if (voices[voice].mode & WAVE_ENVELOPES && voices[voice].env_phase != 2)
+ return; /*
+ * Don't mix with envelopes
+ */
+
+ if (pressure < 32)
+ {
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_rampoff ();
+ compute_and_set_volume (voice, 255, 0); /*
+ * Back to original volume
+ */
+ RESTORE_INTR (flags);
+ return;
+ }
+
+ hi_limit = voices[voice].current_volume;
+ lo_limit = hi_limit * 99 / 100;
+ if (lo_limit < 65)
+ lo_limit = 65;
+
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ if (hi_limit > (4095 - 65))
+ {
+ hi_limit = 4095 - 65;
+ gus_voice_volume (hi_limit);
+ }
+ gus_ramp_range (lo_limit, hi_limit);
+ gus_ramp_rate (3, 8);
+ gus_rampon (0x58); /*
+ * Bidirectional, Down, Loop
+ */
+ RESTORE_INTR (flags);
+}
+
+static void
+guswave_panning (int dev, int voice, int value)
+{
+ if (voice >= 0 || voice < 32)
+ voices[voice].panning = value;
+}
+
+static void
+guswave_volume_method (int dev, int mode)
+{
+ if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO)
+ volume_method = mode;
+}
+
+static void
+compute_volume (int voice, int volume)
+{
+ if (volume < 128)
+ voices[voice].midi_volume = volume;
+
+ switch (volume_method)
+ {
+ case VOL_METHOD_ADAGIO:
+ voices[voice].initial_volume =
+ gus_adagio_vol (voices[voice].midi_volume, voices[voice].main_vol,
+ voices[voice].expression_vol,
+ voices[voice].patch_vol);
+ break;
+
+ case VOL_METHOD_LINEAR: /* Totally ignores patch-volume and expression */
+ voices[voice].initial_volume =
+ gus_linear_vol (volume, voices[voice].main_vol);
+ break;
+
+ default:
+ voices[voice].initial_volume = volume_base +
+ (voices[voice].midi_volume * volume_scale);
+ }
+
+ if (voices[voice].initial_volume > 4030)
+ voices[voice].initial_volume = 4030;
+}
+
+static void
+compute_and_set_volume (int voice, int volume, int ramp_time)
+{
+ int current, target, rate;
+ unsigned long flags;
+
+ compute_volume (voice, volume);
+ voices[voice].current_volume = voices[voice].initial_volume;
+
+ DISABLE_INTR (flags);
+ /*
+ * CAUTION! Interrupts disabled. Enable them before returning
+ */
+
+ gus_select_voice (voice);
+
+ current = gus_read16 (0x09) >> 4;
+ target = voices[voice].initial_volume;
+
+ if (ramp_time == INSTANT_RAMP)
+ {
+ gus_rampoff ();
+ gus_voice_volume (target);
+ RESTORE_INTR (flags);
+ return;
+ }
+
+ if (ramp_time == FAST_RAMP)
+ rate = 63;
+ else
+ rate = 16;
+ gus_ramp_rate (0, rate);
+
+ if ((target - current) / 64 == 0) /*
+ * Too close
+ */
+ {
+ gus_rampoff ();
+ gus_voice_volume (target);
+ RESTORE_INTR (flags);
+ return;
+ }
+
+ if (target > current)
+ {
+ if (target > (4095 - 65))
+ target = 4095 - 65;
+ gus_ramp_range (current, target);
+ gus_rampon (0x00); /*
+ * Ramp up, once, no irq
+ */
+ }
+ else
+ {
+ if (target < 65)
+ target = 65;
+
+ gus_ramp_range (target, current);
+ gus_rampon (0x40); /*
+ * Ramp down, once, no irq
+ */
+ }
+ RESTORE_INTR (flags);
+}
+
+static void
+dynamic_volume_change (int voice)
+{
+ unsigned char status;
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ status = gus_read8 (0x00); /*
+ * Voice status
+ */
+ RESTORE_INTR (flags);
+
+ if (status & 0x03)
+ return; /*
+ * Voice not started
+ */
+
+ if (!(voices[voice].mode & WAVE_ENVELOPES))
+ {
+ compute_and_set_volume (voice, voices[voice].midi_volume, 1);
+ return;
+ }
+
+ /*
+ * Voice is running and has envelopes.
+ */
+
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ status = gus_read8 (0x0d); /*
+ * Ramping status
+ */
+ RESTORE_INTR (flags);
+
+ if (status & 0x03) /*
+ * Sustain phase?
+ */
+ {
+ compute_and_set_volume (voice, voices[voice].midi_volume, 1);
+ return;
+ }
+
+ if (voices[voice].env_phase < 0)
+ return;
+
+ compute_volume (voice, voices[voice].midi_volume);
+
+#if 0 /*
+ * * * Is this really required */
+ voices[voice].current_volume =
+ gus_read16 (0x09) >> 4; /*
+ * Get current volume
+ */
+
+ voices[voice].env_phase--;
+ step_envelope (voice);
+#endif
+}
+
+static void
+guswave_controller (int dev, int voice, int ctrl_num, int value)
+{
+ unsigned long flags;
+ unsigned long freq;
+
+ if (voice < 0 || voice > 31)
+ return;
+
+ switch (ctrl_num)
+ {
+ case CTRL_PITCH_BENDER:
+ voices[voice].bender = value;
+
+ if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
+ {
+ freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range);
+ voices[voice].current_freq = freq;
+
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_voice_freq (freq);
+ RESTORE_INTR (flags);
+ }
+ break;
+
+ case CTRL_PITCH_BENDER_RANGE:
+ voices[voice].bender_range = value;
+ break;
+#ifdef FUTURE_VERSION
+ case CTL_EXPRESSION:
+ value /= 128;
+#endif
+ case CTRL_EXPRESSION:
+ if (volume_method == VOL_METHOD_ADAGIO)
+ {
+ voices[voice].expression_vol = value;
+ if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
+ dynamic_volume_change (voice);
+ }
+ break;
+
+#ifdef FUTURE_VERSION
+ case CTL_PAN:
+ voices[voice].panning = (value * 2) - 128;
+ break;
+
+ case CTL_MAIN_VOLUME:
+ value = (value * 100) / 16383;
+#endif
+
+ case CTRL_MAIN_VOLUME:
+ voices[voice].main_vol = value;
+ if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
+ dynamic_volume_change (voice);
+ break;
+
+ default: /*
+ * Ignore
+ */
+ break;
+ }
+}
+
+static int
+guswave_start_note2 (int dev, int voice, int note_num, int volume)
+{
+ int sample, best_sample, best_delta, delta_freq;
+ int is16bits, samplep, patch, pan;
+ unsigned long note_freq, base_note, freq, flags;
+ unsigned char mode = 0;
+
+ if (voice < 0 || voice > 31)
+ {
+ printk ("GUS: Invalid voice\n");
+ return RET_ERROR (EINVAL);
+ }
+
+ if (note_num == 255)
+ {
+ if (voices[voice].mode & WAVE_ENVELOPES)
+ {
+ voices[voice].midi_volume = volume;
+ dynamic_volume_change (voice);
+ return 0;
+ }
+
+ compute_and_set_volume (voice, volume, 1);
+ return 0;
+ }
+
+ if ((patch = patch_map[voice]) == -1)
+ {
+ return RET_ERROR (EINVAL);
+ }
+
+ if ((samplep = patch_table[patch]) == -1)
+ {
+ return RET_ERROR (EINVAL);
+ }
+
+ note_freq = note_to_freq (note_num);
+
+ /*
+ * Find a sample within a patch so that the note_freq is between low_note
+ * and high_note.
+ */
+ sample = -1;
+
+ best_sample = samplep;
+ best_delta = 1000000;
+ while (samplep >= 0 && sample == -1)
+ {
+ delta_freq = note_freq - samples[samplep].base_note;
+ if (delta_freq < 0)
+ delta_freq = -delta_freq;
+ if (delta_freq < best_delta)
+ {
+ best_sample = samplep;
+ best_delta = delta_freq;
+ }
+ if (samples[samplep].low_note <= note_freq && note_freq <= samples[samplep].high_note)
+ sample = samplep;
+ else
+ samplep = samples[samplep].key; /*
+ * Follow link
+ */
+ }
+ if (sample == -1)
+ sample = best_sample;
+
+ if (sample == -1)
+ {
+ printk ("GUS: Patch %d not defined for note %d\n", patch, note_num);
+ return 0; /*
+ * Should play default patch ???
+ */
+ }
+
+ is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; /*
+ * 8 or 16
+ * bit
+ * samples
+ */
+ voices[voice].mode = samples[sample].mode;
+ voices[voice].patch_vol = samples[sample].volume;
+
+ if (voices[voice].mode & WAVE_ENVELOPES)
+ {
+ int i;
+
+ for (i = 0; i < 6; i++)
+ {
+ voices[voice].env_rate[i] = samples[sample].env_rate[i];
+ voices[voice].env_offset[i] = samples[sample].env_offset[i];
+ }
+ }
+
+ sample_map[voice] = sample;
+
+ base_note = samples[sample].base_note / 100; /*
+ * To avoid overflows
+ */
+ note_freq /= 100;
+
+ freq = samples[sample].base_freq * note_freq / base_note;
+
+ voices[voice].orig_freq = freq;
+
+ /*
+ * Since the pitch bender may have been set before playing the note, we
+ * have to calculate the bending now.
+ */
+
+ freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range);
+ voices[voice].current_freq = freq;
+
+ pan = (samples[sample].panning + voices[voice].panning) / 32;
+ pan += 7;
+ if (pan < 0)
+ pan = 0;
+ if (pan > 15)
+ pan = 15;
+
+ if (samples[sample].mode & WAVE_16_BITS)
+ {
+ mode |= 0x04; /*
+ * 16 bits
+ */
+ if ((sample_ptrs[sample] >> 18) !=
+ ((sample_ptrs[sample] + samples[sample].len) >> 18))
+ printk ("GUS: Sample address error\n");
+ }
+
+ /*************************************************************************
+ * CAUTION! Interrupts disabled. Don't return before enabling
+ *************************************************************************/
+
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_voice_off (); /*
+ * It may still be running
+ */
+ gus_rampoff ();
+
+ RESTORE_INTR (flags);
+
+ if (voices[voice].mode & WAVE_ENVELOPES)
+ {
+ compute_volume (voice, volume);
+ init_envelope (voice);
+ }
+ else
+ compute_and_set_volume (voice, volume, 0);
+
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+
+ if (samples[sample].mode & WAVE_LOOP_BACK)
+ gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len -
+ voices[voice].offset_pending, is16bits); /* Sample
+ * start=end */
+ else
+ gus_write_addr (0x0a, sample_ptrs[sample] + voices[voice].offset_pending,
+ is16bits); /* Sample start=begin */
+
+ if (samples[sample].mode & WAVE_LOOPING)
+ {
+ mode |= 0x08; /*
+ * Looping on
+ */
+
+ if (samples[sample].mode & WAVE_BIDIR_LOOP)
+ mode |= 0x10; /*
+ * Bidirectional looping on
+ */
+
+ if (samples[sample].mode & WAVE_LOOP_BACK)
+ {
+ gus_write_addr (0x0a,
+ sample_ptrs[sample] + samples[sample].loop_end -
+ voices[voice].offset_pending, is16bits);
+ mode |= 0x40;
+ }
+
+ gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start, is16bits); /*
+ * Loop
+ * start
+ * location
+ */
+ gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end, is16bits); /*
+ * Loop
+ * end
+ * location
+ */
+ }
+ else
+ {
+ mode |= 0x20; /*
+ * Loop irq at the end
+ */
+ voices[voice].loop_irq_mode = LMODE_FINISH; /*
+ * Ramp it down at
+ * the * end
+ */
+ voices[voice].loop_irq_parm = 1;
+ gus_write_addr (0x02, sample_ptrs[sample], is16bits); /*
+ * Loop start
+ * location
+ */
+ gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len - 1, is16bits); /*
+ * Loop
+ * end
+ * location
+ */
+ }
+ gus_voice_freq (freq);
+ gus_voice_balance (pan);
+ gus_voice_on (mode);
+ RESTORE_INTR (flags);
+
+ return 0;
+}
+
+/*
+ * * New guswave_start_note by Andrew J. Robinson attempts to minimize
+ * clicking * when the note playing on the voice is changed. It uses volume
+ * ramping. */
+
+static int
+guswave_start_note (int dev, int voice, int note_num, int volume)
+{
+ long int flags;
+ int mode;
+ int ret_val = 0;
+
+ DISABLE_INTR (flags);
+ if (note_num == 255)
+ {
+ if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
+ voices[voice].volume_pending = volume;
+ else
+ {
+ RESTORE_INTR (flags);
+ ret_val = guswave_start_note2 (dev, voice, note_num, volume);
+ }
+ }
+ else
+ {
+ gus_select_voice (voice);
+ mode = gus_read8 (0x00);
+ if (mode & 0x20)
+ gus_write8 (0x00, mode & 0xdf); /* No interrupt! */
+
+ voices[voice].offset_pending = 0;
+ voices[voice].kill_pending = 0;
+ voices[voice].volume_irq_mode = 0;
+ voices[voice].loop_irq_mode = 0;
+
+ if (voices[voice].sample_pending >= 0)
+ {
+ RESTORE_INTR (flags);
+ guswave_set_instr (voices[voice].dev_pending, voice,
+ voices[voice].sample_pending);
+ voices[voice].sample_pending = -1;
+ DISABLE_INTR (flags);
+ }
+
+ if ((mode & 0x01) || ((gus_read16 (0x09) >> 4) < 2065))
+ {
+ ret_val = guswave_start_note2 (dev, voice, note_num, volume);
+ }
+ else
+ {
+ voices[voice].dev_pending = dev;
+ voices[voice].note_pending = note_num;
+ voices[voice].volume_pending = volume;
+ voices[voice].volume_irq_mode = VMODE_START_NOTE;
+
+ gus_rampoff ();
+ gus_ramp_range (2000, 4065);
+ gus_ramp_rate (0, 63);/* Fastest possible rate */
+ gus_rampon (0x20 | 0x40); /* Ramp down, once, irq */
+ RESTORE_INTR (flags);
+ }
+ }
+ return ret_val;
+}
+
+static void
+guswave_reset (int dev)
+{
+ int i;
+
+ for (i = 0; i < 32; i++)
+ {
+ gus_voice_init (i);
+ gus_voice_init2 (i);
+ }
+}
+
+static int
+guswave_open (int dev, int mode)
+{
+ int err;
+
+ if (gus_busy)
+ return RET_ERROR (EBUSY);
+
+ gus_initialize ();
+
+ if ((err = DMAbuf_open_dma (gus_devnum)))
+ return err;
+
+ RESET_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);
+ gus_busy = 1;
+ active_device = GUS_DEV_WAVE;
+
+ gus_reset ();
+
+ return 0;
+}
+
+static void
+guswave_close (int dev)
+{
+ gus_busy = 0;
+ active_device = 0;
+ gus_reset ();
+
+ DMAbuf_close_dma (gus_devnum);
+}
+
+static int
+guswave_load_patch (int dev, int format, snd_rw_buf * addr,
+ int offs, int count, int pmgr_flag)
+{
+ struct patch_info patch;
+ int instr;
+ long sizeof_patch;
+
+ unsigned long blk_size, blk_end, left, src_offs, target;
+
+ sizeof_patch = (long) &patch.data[0] - (long) &patch; /*
+ * Size of
+ * the header
+ * * info
+ */
+
+ if (format != GUS_PATCH)
+ {
+ printk ("GUS Error: Invalid patch format (key) 0x%x\n", format);
+ return RET_ERROR (EINVAL);
+ }
+
+ if (count < sizeof_patch)
+ {
+ printk ("GUS Error: Patch header too short\n");
+ return RET_ERROR (EINVAL);
+ }
+
+ count -= sizeof_patch;
+
+ if (free_sample >= MAX_SAMPLE)
+ {
+ printk ("GUS: Sample table full\n");
+ return RET_ERROR (ENOSPC);
+ }
+
+ /*
+ * Copy the header from user space but ignore the first bytes which have
+ * been transferred already.
+ */
+
+ COPY_FROM_USER (&((char *) &patch)[offs], addr, offs, sizeof_patch - offs);
+
+ instr = patch.instr_no;
+
+ if (instr < 0 || instr > MAX_PATCH)
+ {
+ printk ("GUS: Invalid patch number %d\n", instr);
+ return RET_ERROR (EINVAL);
+ }
+
+ if (count < patch.len)
+ {
+ printk ("GUS Warning: Patch record too short (%d<%d)\n",
+ count, (int) patch.len);
+ patch.len = count;
+ }
+
+ if (patch.len <= 0 || patch.len > gus_mem_size)
+ {
+ printk ("GUS: Invalid sample length %d\n", (int) patch.len);
+ return RET_ERROR (EINVAL);
+ }
+
+ if (patch.mode & WAVE_LOOPING)
+ {
+ if (patch.loop_start < 0 || patch.loop_start >= patch.len)
+ {
+ printk ("GUS: Invalid loop start\n");
+ return RET_ERROR (EINVAL);
+ }
+
+ if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len)
+ {
+ printk ("GUS: Invalid loop end\n");
+ return RET_ERROR (EINVAL);
+ }
+ }
+
+ free_mem_ptr = (free_mem_ptr + 31) & ~31; /*
+ * Alignment 32 bytes
+ */
+
+#define GUS_BANK_SIZE (256*1024)
+
+ if (patch.mode & WAVE_16_BITS)
+ {
+ /*
+ * 16 bit samples must fit one 256k bank.
+ */
+ if (patch.len >= GUS_BANK_SIZE)
+ {
+ printk ("GUS: Sample (16 bit) too long %d\n", (int) patch.len);
+ return RET_ERROR (ENOSPC);
+ }
+
+ if ((free_mem_ptr / GUS_BANK_SIZE) !=
+ ((free_mem_ptr + patch.len) / GUS_BANK_SIZE))
+ {
+ unsigned long tmp_mem = /*
+ * Align to 256K*N
+ */
+ ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;
+
+ if ((tmp_mem + patch.len) > gus_mem_size)
+ return RET_ERROR (ENOSPC);
+
+ free_mem_ptr = tmp_mem; /*
+ * This leaves unusable memory
+ */
+ }
+ }
+
+ if ((free_mem_ptr + patch.len) > gus_mem_size)
+ return RET_ERROR (ENOSPC);
+
+ sample_ptrs[free_sample] = free_mem_ptr;
+
+ /*
+ * Tremolo is not possible with envelopes
+ */
+
+ if (patch.mode & WAVE_ENVELOPES)
+ patch.mode &= ~WAVE_TREMOLO;
+
+ memcpy ((char *) &samples[free_sample], &patch, sizeof_patch);
+
+ /*
+ * Link this_one sample to the list of samples for patch 'instr'.
+ */
+
+ samples[free_sample].key = patch_table[instr];
+ patch_table[instr] = free_sample;
+
+ /*
+ * Use DMA to transfer the wave data to the DRAM
+ */
+
+ left = patch.len;
+ src_offs = 0;
+ target = free_mem_ptr;
+
+ while (left) /*
+ * Not all moved
+ */
+ {
+ blk_size = sound_buffsizes[gus_devnum];
+ if (blk_size > left)
+ blk_size = left;
+
+ /*
+ * DMA cannot cross 256k bank boundaries. Check for that.
+ */
+ blk_end = target + blk_size;
+
+ if ((target >> 18) != (blk_end >> 18))
+ { /*
+ * Have to split the block
+ */
+
+ blk_end &= ~(256 * 1024 - 1);
+ blk_size = blk_end - target;
+ }
+
+#if defined(GUS_NO_DMA) || defined(GUS_PATCH_NO_DMA)
+ /*
+ * For some reason the DMA is not possible. We have to use PIO.
+ */
+ {
+ long i;
+ unsigned char data;
+
+ for (i = 0; i < blk_size; i++)
+ {
+ GET_BYTE_FROM_USER (data, addr, sizeof_patch + i);
+ if (patch.mode & WAVE_UNSIGNED)
+
+ if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
+ data ^= 0x80; /*
+ * Convert to signed
+ */
+ gus_poke (target + i, data);
+ }
+ }
+#else /*
+ * * * GUS_NO_DMA */
+ {
+ unsigned long address, hold_address;
+ unsigned char dma_command;
+ unsigned long flags;
+
+ /*
+ * OK, move now. First in and then out.
+ */
+
+ COPY_FROM_USER (snd_raw_buf[gus_devnum][0],
+ addr, sizeof_patch + src_offs,
+ blk_size);
+
+ DISABLE_INTR (flags); /******** INTERRUPTS DISABLED NOW ********/
+ gus_write8 (0x41, 0); /*
+ * Disable GF1 DMA
+ */
+ DMAbuf_start_dma (gus_devnum, snd_raw_buf_phys[gus_devnum][0],
+ blk_size, DMA_MODE_WRITE);
+
+ /*
+ * Set the DRAM address for the wave data
+ */
+
+ address = target;
+
+ if (sound_dsp_dmachan[gus_devnum] > 3)
+ {
+ hold_address = address;
+ address = address >> 1;
+ address &= 0x0001ffffL;
+ address |= (hold_address & 0x000c0000L);
+ }
+
+ gus_write16 (0x42, (address >> 4) & 0xffff); /*
+ * DRAM DMA address
+ */
+
+ /*
+ * Start the DMA transfer
+ */
+
+ dma_command = 0x21; /*
+ * IRQ enable, DMA start
+ */
+ if (patch.mode & WAVE_UNSIGNED)
+ dma_command |= 0x80; /*
+ * Invert MSB
+ */
+ if (patch.mode & WAVE_16_BITS)
+ dma_command |= 0x40; /*
+ * 16 bit _DATA_
+ */
+ if (sound_dsp_dmachan[gus_devnum] > 3)
+ dma_command |= 0x04; /*
+ * 16 bit DMA channel
+ */
+
+ gus_write8 (0x41, dma_command); /*
+ * Let's go luteet (=bugs)
+ */
+
+ /*
+ * Sleep here until the DRAM DMA done interrupt is served
+ */
+ active_device = GUS_DEV_WAVE;
+
+ DO_SLEEP (dram_sleeper, dram_sleep_flag, HZ);
+ if (TIMED_OUT (dram_sleeper, dram_sleep_flag))
+ printk ("GUS: DMA Transfer timed out\n");
+ RESTORE_INTR (flags);
+ }
+#endif /*
+ * * * GUS_NO_DMA */
+
+ /*
+ * Now the next part
+ */
+
+ left -= blk_size;
+ src_offs += blk_size;
+ target += blk_size;
+
+ gus_write8 (0x41, 0); /*
+ * Stop DMA
+ */
+ }
+
+ free_mem_ptr += patch.len;
+
+ if (!pmgr_flag)
+ pmgr_inform (dev, PM_E_PATCH_LOADED, instr, free_sample, 0, 0);
+ free_sample++;
+ return 0;
+}
+
+static void
+guswave_hw_control (int dev, unsigned char *event)
+{
+ int voice, cmd;
+ unsigned short p1, p2;
+ unsigned long plong, flags;
+
+ cmd = event[2];
+ voice = event[3];
+ p1 = *(unsigned short *) &event[4];
+ p2 = *(unsigned short *) &event[6];
+ plong = *(unsigned long *) &event[4];
+
+ if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) &&
+ (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS))
+ do_volume_irq (voice);
+
+ switch (cmd)
+ {
+
+ case _GUS_NUMVOICES:
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_select_max_voices (p1);
+ RESTORE_INTR (flags);
+ break;
+
+ case _GUS_VOICESAMPLE:
+ guswave_set_instr (dev, voice, p1);
+ break;
+
+ case _GUS_VOICEON:
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ p1 &= ~0x20; /*
+ * Disable intr
+ */
+ gus_voice_on (p1);
+ RESTORE_INTR (flags);
+ break;
+
+ case _GUS_VOICEOFF:
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_voice_off ();
+ RESTORE_INTR (flags);
+ break;
+
+ case _GUS_VOICEFADE:
+ gus_voice_fade (voice);
+ break;
+
+ case _GUS_VOICEMODE:
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ p1 &= ~0x20; /*
+ * Disable intr
+ */
+ gus_voice_mode (p1);
+ RESTORE_INTR (flags);
+ break;
+
+ case _GUS_VOICEBALA:
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_voice_balance (p1);
+ RESTORE_INTR (flags);
+ break;
+
+ case _GUS_VOICEFREQ:
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_voice_freq (plong);
+ RESTORE_INTR (flags);
+ break;
+
+ case _GUS_VOICEVOL:
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_voice_volume (p1);
+ RESTORE_INTR (flags);
+ break;
+
+ case _GUS_VOICEVOL2: /*
+ * Just update the voice value
+ */
+ voices[voice].initial_volume =
+ voices[voice].current_volume = p1;
+ break;
+
+ case _GUS_RAMPRANGE:
+ if (voices[voice].mode & WAVE_ENVELOPES)
+ break; /*
+ * NO-NO
+ */
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_ramp_range (p1, p2);
+ RESTORE_INTR (flags);
+ break;
+
+ case _GUS_RAMPRATE:
+ if (voices[voice].mode & WAVE_ENVELOPES)
+ break; /*
+ * NO-NO
+ */
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_ramp_rate (p1, p2);
+ RESTORE_INTR (flags);
+ break;
+
+ case _GUS_RAMPMODE:
+ if (voices[voice].mode & WAVE_ENVELOPES)
+ break; /*
+ * NO-NO
+ */
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ p1 &= ~0x20; /*
+ * Disable intr
+ */
+ gus_ramp_mode (p1);
+ RESTORE_INTR (flags);
+ break;
+
+ case _GUS_RAMPON:
+ if (voices[voice].mode & WAVE_ENVELOPES)
+ break; /*
+ * NO-NO
+ */
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ p1 &= ~0x20; /*
+ * Disable intr
+ */
+ gus_rampon (p1);
+ RESTORE_INTR (flags);
+ break;
+
+ case _GUS_RAMPOFF:
+ if (voices[voice].mode & WAVE_ENVELOPES)
+ break; /*
+ * NO-NO
+ */
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_rampoff ();
+ RESTORE_INTR (flags);
+ break;
+
+ case _GUS_VOLUME_SCALE:
+ volume_base = p1;
+ volume_scale = p2;
+ break;
+
+ case _GUS_VOICE_POS:
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_set_voice_pos (voice, plong);
+ RESTORE_INTR (flags);
+ break;
+
+ default:;
+ }
+}
+
+static int
+gus_sampling_set_speed (int speed)
+{
+ if (speed <= 0)
+ return gus_sampling_speed;
+
+ if (speed > 44100)
+ speed = 44100;
+
+ gus_sampling_speed = speed;
+ return speed;
+}
+
+static int
+gus_sampling_set_channels (int channels)
+{
+ if (!channels)
+ return gus_sampling_channels;
+ if (channels > 2)
+ channels = 2;
+ if (channels < 1)
+ channels = 1;
+ gus_sampling_channels = channels;
+ return channels;
+}
+
+static int
+gus_sampling_set_bits (int bits)
+{
+ if (!bits)
+ return gus_sampling_bits;
+
+ if (bits != 8 && bits != 16)
+ bits = 8;
+
+ gus_sampling_bits = bits;
+ return bits;
+}
+
+static int
+gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+{
+ switch (cmd)
+ {
+ case SOUND_PCM_WRITE_RATE:
+ if (local)
+ return gus_sampling_set_speed (arg);
+ return IOCTL_OUT (arg, gus_sampling_set_speed (IOCTL_IN (arg)));
+ break;
+
+ case SOUND_PCM_READ_RATE:
+ if (local)
+ return gus_sampling_speed;
+ return IOCTL_OUT (arg, gus_sampling_speed);
+ break;
+
+ case SNDCTL_DSP_STEREO:
+ if (local)
+ return gus_sampling_set_channels (arg + 1) - 1;
+ return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg) + 1) - 1);
+ break;
+
+ case SOUND_PCM_WRITE_CHANNELS:
+ if (local)
+ return gus_sampling_set_channels (arg);
+ return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg)));
+ break;
+
+ case SOUND_PCM_READ_CHANNELS:
+ if (local)
+ return gus_sampling_channels;
+ return IOCTL_OUT (arg, gus_sampling_channels);
+ break;
+
+ case SNDCTL_DSP_SAMPLESIZE:
+ if (local)
+ return gus_sampling_set_bits (arg);
+ return IOCTL_OUT (arg, gus_sampling_set_bits (IOCTL_IN (arg)));
+ break;
+
+ case SOUND_PCM_READ_BITS:
+ if (local)
+ return gus_sampling_bits;
+ return IOCTL_OUT (arg, gus_sampling_bits);
+
+ case SOUND_PCM_WRITE_FILTER: /*
+ * NOT YET IMPLEMENTED
+ */
+ return IOCTL_OUT (arg, RET_ERROR (EINVAL));
+ break;
+
+ case SOUND_PCM_READ_FILTER:
+ return IOCTL_OUT (arg, RET_ERROR (EINVAL));
+ break;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+ return RET_ERROR (EINVAL);
+}
+
+static void
+gus_sampling_reset (int dev)
+{
+}
+
+static int
+gus_sampling_open (int dev, int mode)
+{
+#ifdef GUS_NO_DMA
+ printk ("GUS: DMA mode not enabled. Device not supported\n");
+ return RET_ERROR (ENXIO);
+#endif
+
+ if (gus_busy)
+ return RET_ERROR (EBUSY);
+
+ gus_initialize ();
+
+ gus_busy = 1;
+ active_device = 0;
+
+ gus_reset ();
+ reset_sample_memory ();
+ gus_select_max_voices (14);
+
+ pcm_active = 0;
+ pcm_opened = 1;
+ if (mode & OPEN_READ)
+ {
+ recording_active = 1;
+ set_input_volumes ();
+ }
+
+ return 0;
+}
+
+static void
+gus_sampling_close (int dev)
+{
+ gus_reset ();
+ gus_busy = 0;
+ pcm_opened = 0;
+ active_device = 0;
+
+ if (recording_active)
+ set_input_volumes ();
+
+ recording_active = 0;
+}
+
+static void
+gus_sampling_update_volume (void)
+{
+ unsigned long flags;
+ int voice;
+
+ DISABLE_INTR (flags);
+ if (pcm_active && pcm_opened)
+ for (voice = 0; voice < gus_sampling_channels; voice++)
+ {
+ gus_select_voice (voice);
+ gus_rampoff ();
+ gus_voice_volume (1530 + (25 * gus_pcm_volume));
+ gus_ramp_range (65, 1530 + (25 * gus_pcm_volume));
+ }
+ RESTORE_INTR (flags);
+}
+
+static void
+play_next_pcm_block (void)
+{
+ unsigned long flags;
+ int speed = gus_sampling_speed;
+ int this_one, is16bits, chn;
+ unsigned long dram_loc;
+ unsigned char mode[2], ramp_mode[2];
+
+ if (!pcm_qlen)
+ return;
+
+ this_one = pcm_head;
+
+ for (chn = 0; chn < gus_sampling_channels; chn++)
+ {
+ mode[chn] = 0x00;
+ ramp_mode[chn] = 0x03; /*
+ * Ramping and rollover off
+ */
+
+ if (chn == 0)
+ {
+ mode[chn] |= 0x20; /*
+ * Loop irq
+ */
+ voices[chn].loop_irq_mode = LMODE_PCM;
+ }
+
+ if (gus_sampling_bits != 8)
+ {
+ is16bits = 1;
+ mode[chn] |= 0x04; /*
+ * 16 bit data
+ */
+ }
+ else
+ is16bits = 0;
+
+ dram_loc = this_one * pcm_bsize;
+ dram_loc += chn * pcm_banksize;
+
+ if (this_one == (pcm_nblk - 1)) /*
+ * Last of the DRAM buffers
+ */
+ {
+ mode[chn] |= 0x08; /*
+ * Enable loop
+ */
+ ramp_mode[chn] = 0x03;/*
+ * Disable rollover
+ */
+ }
+ else
+ {
+ if (chn == 0)
+ ramp_mode[chn] = 0x04; /*
+ * Enable rollover bit
+ */
+ }
+
+ DISABLE_INTR (flags);
+ gus_select_voice (chn);
+ gus_voice_freq (speed);
+
+ if (gus_sampling_channels == 1)
+ gus_voice_balance (7); /*
+ * mono
+ */
+ else if (chn == 0)
+ gus_voice_balance (0); /*
+ * left
+ */
+ else
+ gus_voice_balance (15); /*
+ * right
+ */
+
+ if (!pcm_active) /*
+ * Voice not started yet
+ */
+ {
+ /*
+ * The playback was not started yet (or there has been a pause).
+ * Start the voice (again) and ask for a rollover irq at the end of
+ * this_one block. If this_one one is last of the buffers, use just
+ * the normal loop with irq.
+ */
+
+ gus_voice_off (); /*
+ * It could already be running
+ */
+ gus_rampoff ();
+ gus_voice_volume (1530 + (25 * gus_pcm_volume));
+ gus_ramp_range (65, 1530 + (25 * gus_pcm_volume));
+
+ gus_write_addr (0x0a, dram_loc, is16bits); /*
+ * Starting position
+ */
+ gus_write_addr (0x02, chn * pcm_banksize, is16bits); /*
+ * Loop start
+ * location
+ */
+
+ if (chn != 0)
+ gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk),
+ is16bits); /*
+ * Loop end location
+ */
+ }
+
+ if (chn == 0)
+ gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /*
+ * Loop
+ * end
+ * location
+ */
+ else
+ mode[chn] |= 0x08; /*
+ * Enable loop
+ */
+
+ if (pcm_datasize[this_one] != pcm_bsize)
+ {
+ /*
+ * Incomplete block. Possibly the last one.
+ */
+ if (chn == 0)
+ {
+ mode[chn] &= ~0x08; /*
+ * Disable loop
+ */
+ mode[chn] |= 0x20;/*
+ * Enable loop IRQ
+ */
+ voices[0].loop_irq_mode = LMODE_PCM_STOP;
+ ramp_mode[chn] = 0x03; /*
+ * No rollover bit
+ */
+ }
+ else
+ {
+ gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /*
+ * Loop
+ * end
+ * location
+ */
+ mode[chn] &= ~0x08; /*
+ * Disable loop
+ */
+ }
+ }
+
+ RESTORE_INTR (flags);
+ }
+
+ for (chn = 0; chn < gus_sampling_channels; chn++)
+ {
+ DISABLE_INTR (flags);
+ gus_select_voice (chn);
+ gus_write8 (0x0d, ramp_mode[chn]);
+ gus_voice_on (mode[chn]);
+ RESTORE_INTR (flags);
+ }
+
+ pcm_active = 1;
+}
+
+static void
+gus_transfer_output_block (int dev, unsigned long buf,
+ int total_count, int intrflag, int chn)
+{
+ /*
+ * This routine transfers one block of audio data to the DRAM. In mono mode
+ * it's called just once. When in stereo mode, this_one routine is called
+ * once for both channels.
+ *
+ * The left/mono channel data is transferred to the beginning of dram and the
+ * right data to the area pointed by gus_page_size.
+ */
+
+ int this_one, count;
+ unsigned long flags;
+ unsigned char dma_command;
+ unsigned long address, hold_address;
+
+ DISABLE_INTR (flags);
+
+ count = total_count / gus_sampling_channels;
+
+ if (chn == 0)
+ {
+ if (pcm_qlen >= pcm_nblk)
+ printk ("GUS Warning: PCM buffers out of sync\n");
+
+ this_one = pcm_current_block = pcm_tail;
+ pcm_qlen++;
+ pcm_tail = (pcm_tail + 1) % pcm_nblk;
+ pcm_datasize[this_one] = count;
+ }
+ else
+ this_one = pcm_current_block;
+
+ gus_write8 (0x41, 0); /*
+ * Disable GF1 DMA
+ */
+ DMAbuf_start_dma (dev, buf + (chn * count), count, DMA_MODE_WRITE);
+
+ address = this_one * pcm_bsize;
+ address += chn * pcm_banksize;
+
+ if (sound_dsp_dmachan[dev] > 3)
+ {
+ hold_address = address;
+ address = address >> 1;
+ address &= 0x0001ffffL;
+ address |= (hold_address & 0x000c0000L);
+ }
+
+ gus_write16 (0x42, (address >> 4) & 0xffff); /*
+ * DRAM DMA address
+ */
+
+ dma_command = 0x21; /*
+ * IRQ enable, DMA start
+ */
+
+ if (gus_sampling_bits != 8)
+ dma_command |= 0x40; /*
+ * 16 bit _DATA_
+ */
+ else
+ dma_command |= 0x80; /*
+ * Invert MSB
+ */
+
+ if (sound_dsp_dmachan[dev] > 3)
+ dma_command |= 0x04; /*
+ * 16 bit DMA channel
+ */
+
+ gus_write8 (0x41, dma_command); /*
+ * Kick on
+ */
+
+ if (chn == (gus_sampling_channels - 1)) /*
+ * Last channel
+ */
+ {
+ /*
+ * Last (right or mono) channel data
+ */
+ active_device = GUS_DEV_PCM_DONE;
+ if (!pcm_active && (pcm_qlen > 2 || count < pcm_bsize))
+ {
+ play_next_pcm_block ();
+ }
+ }
+ else /*
+ * * * Left channel data. The right channel
+ * is * * * transferred after DMA interrupt */
+ active_device = GUS_DEV_PCM_CONTINUE;
+
+ RESTORE_INTR (flags);
+}
+
+static void
+gus_sampling_output_block (int dev, unsigned long buf, int total_count,
+ int intrflag, int restart_dma)
+{
+ pcm_current_buf = buf;
+ pcm_current_count = total_count;
+ pcm_current_intrflag = intrflag;
+ pcm_current_dev = dev;
+ gus_transfer_output_block (dev, buf, total_count, intrflag, 0);
+}
+
+static void
+gus_sampling_start_input (int dev, unsigned long buf, int count,
+ int intrflag, int restart_dma)
+{
+ unsigned long flags;
+ unsigned char mode;
+
+ DISABLE_INTR (flags);
+
+ DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
+
+ mode = 0xa0; /*
+ * DMA IRQ enable, invert MSB
+ */
+
+ if (sound_dsp_dmachan[dev] > 3)
+ mode |= 0x04; /*
+ * 16 bit DMA channel
+ */
+ if (gus_sampling_channels > 1)
+ mode |= 0x02; /*
+ * Stereo
+ */
+ mode |= 0x01; /*
+ * DMA enable
+ */
+
+ gus_write8 (0x49, mode);
+
+ RESTORE_INTR (flags);
+}
+
+static int
+gus_sampling_prepare_for_input (int dev, int bsize, int bcount)
+{
+ unsigned int rate;
+
+ rate = (9878400 / (gus_sampling_speed + 2)) / 16;
+
+ gus_write8 (0x48, rate & 0xff); /*
+ * Set sampling frequency
+ */
+
+ if (gus_sampling_bits != 8)
+ {
+ printk ("GUS Error: 16 bit recording not supported\n");
+ return RET_ERROR (EINVAL);
+ }
+
+ return 0;
+}
+
+static int
+gus_sampling_prepare_for_output (int dev, int bsize, int bcount)
+{
+ int i;
+
+ long mem_ptr, mem_size;
+
+ mem_ptr = 0;
+ mem_size = gus_mem_size / gus_sampling_channels;
+
+ if (mem_size > (256 * 1024))
+ mem_size = 256 * 1024;
+
+ pcm_bsize = bsize / gus_sampling_channels;
+ pcm_head = pcm_tail = pcm_qlen = 0;
+
+ pcm_nblk = MAX_PCM_BUFFERS;
+ if ((pcm_bsize * pcm_nblk) > mem_size)
+ pcm_nblk = mem_size / pcm_bsize;
+
+ for (i = 0; i < pcm_nblk; i++)
+ pcm_datasize[i] = 0;
+
+ pcm_banksize = pcm_nblk * pcm_bsize;
+
+ if (gus_sampling_bits != 8 && pcm_banksize == (256 * 1024))
+ pcm_nblk--;
+
+ return 0;
+}
+
+static int
+gus_has_output_drained (int dev)
+{
+ return !pcm_qlen;
+}
+
+static void
+gus_copy_from_user (int dev, char *localbuf, int localoffs,
+ snd_rw_buf * userbuf, int useroffs, int len)
+{
+ if (gus_sampling_channels == 1)
+ {
+ COPY_FROM_USER (&localbuf[localoffs], userbuf, useroffs, len);
+ }
+ else if (gus_sampling_bits == 8)
+ {
+ int in_left = useroffs;
+ int in_right = useroffs + 1;
+ char *out_left, *out_right;
+ int i;
+
+ len /= 2;
+ localoffs /= 2;
+ out_left = &localbuf[localoffs];
+ out_right = out_left + pcm_bsize;
+
+ for (i = 0; i < len; i++)
+ {
+ GET_BYTE_FROM_USER (*out_left++, userbuf, in_left);
+ in_left += 2;
+ GET_BYTE_FROM_USER (*out_right++, userbuf, in_right);
+ in_right += 2;
+ }
+ }
+ else
+ {
+ int in_left = useroffs;
+ int in_right = useroffs + 1;
+ short *out_left, *out_right;
+ int i;
+
+ len /= 4;
+ localoffs /= 4;
+
+ out_left = (short *) &localbuf[localoffs];
+ out_right = out_left + (pcm_bsize / 2);
+
+ for (i = 0; i < len; i++)
+ {
+ GET_SHORT_FROM_USER (*out_left++, (short *) userbuf, in_left);
+ in_left += 2;
+ GET_SHORT_FROM_USER (*out_right++, (short *) userbuf, in_right);
+ in_right += 2;
+ }
+ }
+}
+
+static struct audio_operations gus_sampling_operations =
+{
+ "Gravis UltraSound",
+ NEEDS_RESTART,
+ gus_sampling_open,
+ gus_sampling_close,
+ gus_sampling_output_block,
+ gus_sampling_start_input,
+ gus_sampling_ioctl,
+ gus_sampling_prepare_for_input,
+ gus_sampling_prepare_for_output,
+ gus_sampling_reset,
+ gus_sampling_reset,
+ gus_has_output_drained,
+ gus_copy_from_user
+};
+
+#ifdef FUTURE_VERSION
+static void
+guswave_bender (int dev, int voice, int value)
+{
+ int freq;
+ unsigned long flags;
+
+ voices[voice].bender = value - 8192;
+ freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range);
+ voices[voice].current_freq = freq;
+
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+ gus_voice_freq (freq);
+ RESTORE_INTR (flags);
+}
+
+#endif
+
+static int
+guswave_patchmgr (int dev, struct patmgr_info *rec)
+{
+ int i, n;
+
+ switch (rec->command)
+ {
+ case PM_GET_DEVTYPE:
+ rec->parm1 = PMTYPE_WAVE;
+ return 0;
+ break;
+
+ case PM_GET_NRPGM:
+ rec->parm1 = MAX_PATCH;
+ return 0;
+ break;
+
+ case PM_GET_PGMMAP:
+ rec->parm1 = MAX_PATCH;
+
+ for (i = 0; i < MAX_PATCH; i++)
+ {
+ int ptr = patch_table[i];
+
+ rec->data.data8[i] = 0;
+
+ while (ptr >= 0 && ptr < free_sample)
+ {
+ rec->data.data8[i]++;
+ ptr = samples[ptr].key; /*
+ * Follow link
+ */
+ }
+ }
+ return 0;
+ break;
+
+ case PM_GET_PGM_PATCHES:
+ {
+ int ptr = patch_table[rec->parm1];
+
+ n = 0;
+
+ while (ptr >= 0 && ptr < free_sample)
+ {
+ rec->data.data32[n++] = ptr;
+ ptr = samples[ptr].key; /*
+ * Follow link
+ */
+ }
+ }
+ rec->parm1 = n;
+ return 0;
+ break;
+
+ case PM_GET_PATCH:
+ {
+ int ptr = rec->parm1;
+ struct patch_info *pat;
+
+ if (ptr < 0 || ptr >= free_sample)
+ return RET_ERROR (EINVAL);
+
+ memcpy (rec->data.data8, (char *) &samples[ptr],
+ sizeof (struct patch_info));
+
+ pat = (struct patch_info *) rec->data.data8;
+
+ pat->key = GUS_PATCH; /*
+ * Restore patch type
+ */
+ rec->parm1 = sample_ptrs[ptr]; /*
+ * DRAM address
+ */
+ rec->parm2 = sizeof (struct patch_info);
+ }
+ return 0;
+ break;
+
+ case PM_SET_PATCH:
+ {
+ int ptr = rec->parm1;
+ struct patch_info *pat;
+
+ if (ptr < 0 || ptr >= free_sample)
+ return RET_ERROR (EINVAL);
+
+ pat = (struct patch_info *) rec->data.data8;
+
+ if (pat->len > samples[ptr].len) /*
+ * Cannot expand sample
+ */
+ return RET_ERROR (EINVAL);
+
+ pat->key = samples[ptr].key; /*
+ * Ensure the link is correct
+ */
+
+ memcpy ((char *) &samples[ptr], rec->data.data8,
+ sizeof (struct patch_info));
+
+ pat->key = GUS_PATCH;
+ }
+ return 0;
+ break;
+
+ case PM_READ_PATCH: /*
+ * Returns a block of wave data from the DRAM
+ */
+ {
+ int sample = rec->parm1;
+ int n;
+ long offs = rec->parm2;
+ int l = rec->parm3;
+
+ if (sample < 0 || sample >= free_sample)
+ return RET_ERROR (EINVAL);
+
+ if (offs < 0 || offs >= samples[sample].len)
+ return RET_ERROR (EINVAL); /*
+ * Invalid offset
+ */
+
+ n = samples[sample].len - offs; /*
+ * Nr of bytes left
+ */
+
+ if (l > n)
+ l = n;
+
+ if (l > sizeof (rec->data.data8))
+ l = sizeof (rec->data.data8);
+
+ if (l <= 0)
+ return RET_ERROR (EINVAL); /*
+ * Was there a bug?
+ */
+
+ offs += sample_ptrs[sample]; /*
+ * Begin offsess + offset to DRAM
+ */
+
+ for (n = 0; n < l; n++)
+ rec->data.data8[n] = gus_peek (offs++);
+ rec->parm1 = n; /*
+ * Nr of bytes copied
+ */
+ }
+ return 0;
+ break;
+
+ case PM_WRITE_PATCH: /*
+ * Writes a block of wave data to the DRAM
+ */
+ {
+ int sample = rec->parm1;
+ int n;
+ long offs = rec->parm2;
+ int l = rec->parm3;
+
+ if (sample < 0 || sample >= free_sample)
+ return RET_ERROR (EINVAL);
+
+ if (offs < 0 || offs >= samples[sample].len)
+ return RET_ERROR (EINVAL); /*
+ * Invalid offset
+ */
+
+ n = samples[sample].len - offs; /*
+ * Nr of bytes left
+ */
+
+ if (l > n)
+ l = n;
+
+ if (l > sizeof (rec->data.data8))
+ l = sizeof (rec->data.data8);
+
+ if (l <= 0)
+ return RET_ERROR (EINVAL); /*
+ * Was there a bug?
+ */
+
+ offs += sample_ptrs[sample]; /*
+ * Begin offsess + offset to DRAM
+ */
+
+ for (n = 0; n < l; n++)
+ gus_poke (offs++, rec->data.data8[n]);
+ rec->parm1 = n; /*
+ * Nr of bytes copied
+ */
+ }
+ return 0;
+ break;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+}
+
+static struct synth_operations guswave_operations =
+{
+ &gus_info,
+#ifdef FUTURE_VERSION
+ 0,
+#endif
+ SYNTH_TYPE_SAMPLE,
+ SAMPLE_TYPE_GUS,
+ guswave_open,
+ guswave_close,
+ guswave_ioctl,
+ guswave_kill_note,
+ guswave_start_note,
+ guswave_set_instr,
+ guswave_reset,
+ guswave_hw_control,
+ guswave_load_patch,
+ guswave_aftertouch,
+ guswave_controller,
+ guswave_panning,
+ guswave_volume_method,
+ guswave_patchmgr,
+#ifdef FUTURE_VERSION
+ guswave_bender
+#endif
+};
+
+static void
+set_input_volumes (void)
+{
+ unsigned long flags;
+ unsigned char mask = 0xff & ~0x06; /* Just line out enabled */
+
+ DISABLE_INTR (flags);
+
+ /*
+ * Enable channels having vol > 10%
+ * Note! bit 0x01 means line in DISABLED while 0x04 means
+ * mic in ENABLED.
+ */
+ if (gus_line_vol > 10)
+ mask &= ~0x01;
+ if (gus_mic_vol > 10)
+ mask |= 0x04;
+
+ if (recording_active)
+ {
+ /*
+ * Disable channel, if not selected for recording
+ */
+ if (!(gus_recmask & SOUND_MASK_LINE))
+ mask |= 0x01;
+ if (!(gus_recmask & SOUND_MASK_MIC))
+ mask &= ~0x04;
+ }
+
+ mix_image &= ~0x07;
+ mix_image |= mask & 0x07;
+ OUTB (mix_image, u_Mixer);
+
+ RESTORE_INTR (flags);
+}
+
+int
+gus_default_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
+{
+#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \
+ SOUND_MASK_SYNTH|SOUND_MASK_PCM)
+ if (((cmd >> 8) & 0xff) == 'M')
+ {
+ if (cmd & IOC_IN)
+ switch (cmd & 0xff)
+ {
+ case SOUND_MIXER_RECSRC:
+ gus_recmask = IOCTL_IN (arg) & MIX_DEVS;
+ if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE)))
+ gus_recmask = SOUND_MASK_MIC;
+ /* Note! Input volumes are updated during next open for recording */
+ return IOCTL_OUT (arg, gus_recmask);
+ break;
+
+ case SOUND_MIXER_MIC:
+ {
+ int vol = IOCTL_IN (arg) & 0xff;
+
+ if (vol < 0)
+ vol = 0;
+ if (vol > 100)
+ vol = 100;
+ gus_mic_vol = vol;
+ set_input_volumes ();
+ return IOCTL_OUT (arg, vol | (vol << 8));
+ }
+ break;
+
+ case SOUND_MIXER_LINE:
+ {
+ int vol = IOCTL_IN (arg) & 0xff;
+
+ if (vol < 0)
+ vol = 0;
+ if (vol > 100)
+ vol = 100;
+ gus_line_vol = vol;
+ set_input_volumes ();
+ return IOCTL_OUT (arg, vol | (vol << 8));
+ }
+ break;
+
+ case SOUND_MIXER_PCM:
+ gus_pcm_volume = IOCTL_IN (arg) & 0xff;
+ if (gus_pcm_volume < 0)
+ gus_pcm_volume = 0;
+ if (gus_pcm_volume > 100)
+ gus_pcm_volume = 100;
+ gus_sampling_update_volume ();
+ return IOCTL_OUT (arg, gus_pcm_volume | (gus_pcm_volume << 8));
+ break;
+
+ case SOUND_MIXER_SYNTH:
+ {
+ int voice;
+
+ gus_wave_volume = IOCTL_IN (arg) & 0xff;
+
+ if (gus_wave_volume < 0)
+ gus_wave_volume = 0;
+ if (gus_wave_volume > 100)
+ gus_wave_volume = 100;
+
+ if (active_device == GUS_DEV_WAVE)
+ for (voice = 0; voice < nr_voices; voice++)
+ dynamic_volume_change (voice); /*
+ * Apply the new
+ * volume
+ */
+
+ return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8));
+ }
+ break;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+ else
+ switch (cmd & 0xff) /*
+ * Return parameters
+ */
+ {
+
+ case SOUND_MIXER_RECSRC:
+ return IOCTL_OUT (arg, gus_recmask);
+ break;
+
+ case SOUND_MIXER_DEVMASK:
+ return IOCTL_OUT (arg, MIX_DEVS);
+ break;
+
+ case SOUND_MIXER_STEREODEVS:
+ return IOCTL_OUT (arg, 0);
+ break;
+
+ case SOUND_MIXER_RECMASK:
+ return IOCTL_OUT (arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
+ break;
+
+ case SOUND_MIXER_CAPS:
+ return IOCTL_OUT (arg, 0);
+ break;
+
+ case SOUND_MIXER_MIC:
+ return IOCTL_OUT (arg, gus_mic_vol | (gus_mic_vol << 8));
+ break;
+
+ case SOUND_MIXER_LINE:
+ return IOCTL_OUT (arg, gus_line_vol | (gus_line_vol << 8));
+ break;
+
+ case SOUND_MIXER_PCM:
+ return IOCTL_OUT (arg, gus_pcm_volume | (gus_pcm_volume << 8));
+ break;
+
+ case SOUND_MIXER_SYNTH:
+ return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8));
+ break;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+ }
+ else
+ return RET_ERROR (EINVAL);
+}
+
+static struct mixer_operations gus_mixer_operations =
+{
+ gus_default_mixer_ioctl
+};
+
+static long
+gus_default_mixer_init (long mem_start)
+{
+ if (num_mixers < MAX_MIXER_DEV) /*
+ * Don't install if there is another
+ * mixer
+ */
+ mixer_devs[num_mixers++] = &gus_mixer_operations;
+
+ return mem_start;
+}
+
+long
+gus_wave_init (long mem_start, int irq, int dma)
+{
+ unsigned long flags;
+ unsigned char val;
+ char *model_num = "2.4";
+ int gus_type = 0x24; /* 2.4 */
+ int mixer_type = 0;
+
+ /*
+ * Try to identify the GUS model.
+ *
+ * Versions < 3.6 don't have the digital ASIC. Try to probe it first.
+ */
+
+ DISABLE_INTR (flags);
+ OUTB (0x20, gus_base + 0x0f);
+ val = INB (gus_base + 0x0f);
+ RESTORE_INTR (flags);
+
+ if (val != 0xff && (val & 0x06)) /* Should be 0x02? */
+ {
+ /*
+ * It has the digital ASIC so the card is at least v3.4.
+ * Next try to detect the true model.
+ */
+
+ val = INB (u_MixSelect);
+
+ /*
+ * Value 255 means pre-3.7 which don't have mixer.
+ * Values 5 thru 9 mean v3.7 which has a ICS2101 mixer.
+ * 10 and above is GUS MAX which has the CS4231 codec/mixer.
+ *
+ * Sorry. No GUS max support yet but it should be available
+ * soon after the SDK for GUS MAX is available.
+ */
+
+ if (val == 255 || val < 5)
+ {
+ model_num = "3.4";
+ gus_type = 0x34;
+ }
+ else if (val < 10)
+ {
+ model_num = "3.7";
+ gus_type = 0x37;
+ mixer_type = ICS2101;
+ }
+ else
+ {
+ model_num = "MAX";
+ gus_type = 0x40;
+ mixer_type = CS4231;
+ }
+ }
+ else
+ {
+ /*
+ * ASIC not detected so the card must be 2.2 or 2.4.
+ * There could still be the 16-bit/mixer daughter card.
+ * It has the same codec/mixer than MAX.
+ * At this time there is no support for it but it will appear soon.
+ */
+ }
+
+
+#ifdef __FreeBSD__
+ printk ("snd4: <Gravis UltraSound %s (%dk)>", model_num, (int) gus_mem_size / 1024);
+#else
+ printk (" <Gravis UltraSound %s (%dk)>", model_num, (int) gus_mem_size / 1024);
+#endif
+
+#ifndef SCO
+ sprintf (gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024);
+#endif
+
+ if (irq < 0 || irq > 15)
+ {
+ printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq);
+ return mem_start;
+ }
+
+ if (dma < 0 || dma > 7)
+ {
+ printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma);
+ return mem_start;
+ }
+
+ gus_irq = irq;
+ gus_dma = dma;
+
+ if (num_synths >= MAX_SYNTH_DEV)
+ printk ("GUS Error: Too many synthesizers\n");
+ else
+ synth_devs[num_synths++] = &guswave_operations;
+
+ PERMANENT_MALLOC (struct patch_info *, samples,
+ (MAX_SAMPLE + 1) * sizeof (*samples), mem_start);
+
+ reset_sample_memory ();
+
+ gus_initialize ();
+
+ if (num_dspdevs < MAX_DSP_DEV)
+ {
+ dsp_devs[gus_devnum = num_dspdevs++] = &gus_sampling_operations;
+ sound_dsp_dmachan[gus_devnum] = dma;
+ sound_buffcounts[gus_devnum] = DSP_BUFFCOUNT;
+ sound_buffsizes[gus_devnum] = DSP_BUFFSIZE;
+ sound_dma_automode[gus_devnum] = 0;
+ }
+ else
+ printk ("GUS: Too many PCM devices available\n");
+
+ /*
+ * Mixer dependent initialization.
+ */
+
+ switch (mixer_type)
+ {
+ case ICS2101:
+ gus_line_vol=gus_mic_vol=gus_wave_volume = gus_pcm_volume = 100;
+ return ics2101_mixer_init (mem_start);
+
+ case CS4231:
+ /* Available soon */
+ default:
+ return gus_default_mixer_init (mem_start);
+ }
+
+ return mem_start;
+}
+
+static void
+do_loop_irq (int voice)
+{
+ unsigned char tmp;
+ int mode, parm;
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+ gus_select_voice (voice);
+
+ tmp = gus_read8 (0x00);
+ tmp &= ~0x20; /*
+ * Disable wave IRQ for this_one voice
+ */
+ gus_write8 (0x00, tmp);
+
+ mode = voices[voice].loop_irq_mode;
+ voices[voice].loop_irq_mode = 0;
+ parm = voices[voice].loop_irq_parm;
+
+ switch (mode)
+ {
+
+ case LMODE_FINISH: /*
+ * Final loop finished, shoot volume down
+ */
+
+ if ((gus_read16 (0x09) >> 4) < 100) /*
+ * Get current volume
+ */
+ {
+ gus_voice_off ();
+ gus_rampoff ();
+ gus_voice_init (voice);
+ break;
+ }
+ gus_ramp_range (65, 4065);
+ gus_ramp_rate (0, 63); /*
+ * Fastest possible rate
+ */
+ gus_rampon (0x20 | 0x40); /*
+ * Ramp down, once, irq
+ */
+ voices[voice].volume_irq_mode = VMODE_HALT;
+ break;
+
+ case LMODE_PCM_STOP:
+ pcm_active = 0; /*
+ * Requires extensive processing
+ */
+ case LMODE_PCM:
+ {
+ int orig_qlen = pcm_qlen;
+
+ pcm_qlen--;
+ pcm_head = (pcm_head + 1) % pcm_nblk;
+ if (pcm_qlen)
+ {
+ play_next_pcm_block ();
+ }
+ else
+ { /*
+ * Out of data. Just stop the voice
+ */
+ gus_voice_off ();
+ gus_rampoff ();
+ pcm_active = 0;
+ }
+
+ if (orig_qlen == pcm_nblk)
+ {
+ DMAbuf_outputintr (gus_devnum, 0);
+ }
+ }
+ break;
+
+ default:;
+ }
+ RESTORE_INTR (flags);
+}
+
+static void
+do_volume_irq (int voice)
+{
+ unsigned char tmp;
+ int mode, parm;
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+
+ gus_select_voice (voice);
+
+ tmp = gus_read8 (0x0d);
+ tmp &= ~0x20; /*
+ * Disable volume ramp IRQ
+ */
+ gus_write8 (0x0d, tmp);
+
+ mode = voices[voice].volume_irq_mode;
+ voices[voice].volume_irq_mode = 0;
+ parm = voices[voice].volume_irq_parm;
+
+ switch (mode)
+ {
+ case VMODE_HALT: /*
+ * Decay phase finished
+ */
+ RESTORE_INTR (flags);
+ gus_voice_init (voice);
+ break;
+
+ case VMODE_ENVELOPE:
+ gus_rampoff ();
+ RESTORE_INTR (flags);
+ step_envelope (voice);
+ break;
+
+ case VMODE_START_NOTE:
+ RESTORE_INTR (flags);
+ guswave_start_note2 (voices[voice].dev_pending, voice,
+ voices[voice].note_pending, voices[voice].volume_pending);
+ if (voices[voice].kill_pending)
+ guswave_kill_note (voices[voice].dev_pending, voice, 0);
+ if (voices[voice].sample_pending >= 0)
+ {
+ guswave_set_instr (voices[voice].dev_pending, voice,
+ voices[voice].sample_pending);
+ voices[voice].sample_pending = -1;
+ }
+ break;
+
+ default:;
+ }
+}
+
+void
+gus_voice_irq (void)
+{
+ unsigned long wave_ignore = 0, volume_ignore = 0;
+ unsigned long voice_bit;
+
+ unsigned char src, voice;
+
+ while (1)
+ {
+ src = gus_read8 (0x0f); /*
+ * Get source info
+ */
+ voice = src & 0x1f;
+ src &= 0xc0;
+
+ if (src == (0x80 | 0x40))
+ return; /*
+ * No interrupt
+ */
+
+ voice_bit = 1 << voice;
+
+ if (!(src & 0x80)) /*
+ * Wave IRQ pending
+ */
+ if (!(wave_ignore & voice_bit) && voice < nr_voices) /*
+ * Not done
+ * yet
+ */
+ {
+ wave_ignore |= voice_bit;
+ do_loop_irq (voice);
+ }
+
+ if (!(src & 0x40)) /*
+ * Volume IRQ pending
+ */
+ if (!(volume_ignore & voice_bit) && voice < nr_voices) /*
+ * Not done
+ * yet
+ */
+ {
+ volume_ignore |= voice_bit;
+ do_volume_irq (voice);
+ }
+ }
+}
+
+void
+guswave_dma_irq (void)
+{
+ unsigned char status;
+
+ status = gus_look8 (0x41); /*
+ * Get DMA IRQ Status
+ */
+ if (status & 0x40) /*
+ * DMA Irq pending
+ */
+ switch (active_device)
+ {
+ case GUS_DEV_WAVE:
+ if (SOMEONE_WAITING (dram_sleeper, dram_sleep_flag))
+ WAKE_UP (dram_sleeper, dram_sleep_flag);
+ break;
+
+ case GUS_DEV_PCM_CONTINUE:
+ gus_transfer_output_block (pcm_current_dev, pcm_current_buf,
+ pcm_current_count,
+ pcm_current_intrflag, 1);
+ break;
+
+ case GUS_DEV_PCM_DONE:
+ if (pcm_qlen < pcm_nblk)
+ {
+ DMAbuf_outputintr (gus_devnum, pcm_qlen == 0);
+ }
+ break;
+
+ default:;
+ }
+
+ status = gus_look8 (0x49); /*
+ * Get Sampling IRQ Status
+ */
+ if (status & 0x40) /*
+ * Sampling Irq pending
+ */
+ {
+ DMAbuf_inputintr (gus_devnum);
+ }
+
+}
+
+#endif
diff --git a/sys/i386/isa/sound/gustest/Makefile b/sys/i386/isa/sound/gustest/Makefile
new file mode 100644
index 0000000..d161e5b
--- /dev/null
+++ b/sys/i386/isa/sound/gustest/Makefile
@@ -0,0 +1,16 @@
+all: gustest gusload gmod midithru
+
+gustest: gustest.c
+ $(CC) -o gustest gustest.c -lm
+
+gusload: gusload.c
+ $(CC) -o gusload gusload.c
+
+gmod: gmod.c
+ $(CC) -o gmod gmod.c
+
+midithru: midithru.c
+ $(CC) -o midithru midithru.c
+
+clean:
+ rm -f gusload gustest gmod midithru *.o
diff --git a/sys/i386/isa/sound/gustest/Readme b/sys/i386/isa/sound/gustest/Readme
new file mode 100644
index 0000000..7640bf8
--- /dev/null
+++ b/sys/i386/isa/sound/gustest/Readme
@@ -0,0 +1,67 @@
+The programs in this directory are more or less incompletely implemented.
+I have used them for debugging purposes while developing the driver.
+
+Files in this directory:
+
+
+../ultrasound.h (sys/ultrasound.h)
+ This file contains some macros which are similar than
+ the procedures provided by GUSUNIT.PAS. See gustest.c
+ for more information.
+ INSTALL THIS FILE TO YOUR /usr/include/sys !!!!!!!!!!!!
+
+gusload.c This program can be used to load patches (samples) to
+ the DRAM of GUS. It understands the format used in the
+ .pat files shipped with GUS.
+
+ Usage: gusload pgm# patchfile.
+ or gusload reset #Removes all patches from memory.
+
+ You should load just the patches you will need to play
+ a Midi file, since the memory capacity of GUS is rather
+ limited (256k-1M).
+
+ Example:
+
+ gusload 0 acpiano.pat
+ gusload 1 britepno.pat
+ gusload 19 church.pat
+
+ This program is not required if the adagio package is
+ used. It can do the patch uploading itself.
+
+gmod.c This is a simple module player which demonstrates
+ programming with GUS. It doesn't try to interpret
+ most of the effect commands. In fact this program
+ may interpret the modules incorrectly since I am
+ not a module player expert.
+ This version plays .MOD, .STM and .669 modules.
+
+midithru.c This program reads messages from the Midi interface
+ and plays the notes with an internal synthesizer
+ (FM or GUS). The program accepts one argument, the
+ synthesizer device number. In addition to the note on
+ and note off messages it interprets also program changes
+ and channel pressure messages.
+ If you need an example on programming the /dev/sequencer,
+ this is a good one. The voice allocation algorithm is
+ not good so don't look at it.
+
+ NOTE! This program is useful with gmod. Jus load
+ a module with gmod. Wait until the module has
+ finished or hit ^C. Now you can play the samples
+ with the midithru program.
+
+ NOTE2! You need a Midi keyboard to use this program. In
+ addition the Midi interface of GUS is not supported
+ yet which means you need also PAS16 or MPU-401.
+
+pmtest.c
+gpatinfo.c ******* For information only *******
+ These programs demonstrate the patch manager interface
+ which will be included to some later driver version.
+ This interface is not complete in version 1.99.9.
+ Using pmtest will hang your system sooner or later.
+
+Hannu Savolainen
+hsavolai@cs.helsinki.fi
diff --git a/sys/i386/isa/sound/gustest/gmidi.h b/sys/i386/isa/sound/gustest/gmidi.h
new file mode 100644
index 0000000..ab951e7
--- /dev/null
+++ b/sys/i386/isa/sound/gustest/gmidi.h
@@ -0,0 +1,131 @@
+ char patch_names[][9] =
+ {
+ /* 0 */ "acpiano",
+ /* 1 */ "britepno",
+ /* 2 */ "synpiano",
+ /* 3 */ "honktonk",
+ /* 4 */ "epiano1",
+ /* 5 */ "epiano2",
+ /* 6 */ "hrpschrd",
+ /* 7 */ "clavinet",
+ /* 8 */ "celeste",
+ /* 9 */ "glocken",
+ /* 10 */ "musicbox",
+ /* 11 */ "vibes",
+ /* 12 */ "marimba",
+ /* 13 */ "xylophon",
+ /* 14 */ "tubebell",
+ /* 15 */ "santur",
+ /* 16 */ "homeorg",
+ /* 17 */ "percorg",
+ /* 18 */ "rockorg",
+ /* 19 */ "church",
+ /* 20 */ "reedorg",
+ /* 21 */ "accordn",
+ /* 22 */ "harmonca",
+ /* 23 */ "concrtna",
+ /* 24 */ "nyguitar",
+ /* 25 */ "acguitar",
+ /* 26 */ "jazzgtr",
+ /* 27 */ "cleangtr",
+ /* 28 */ "mutegtr",
+ /* 29 */ "odguitar",
+ /* 30 */ "distgtr",
+ /* 31 */ "gtrharm",
+ /* 32 */ "acbass",
+ /* 33 */ "fngrbass",
+ /* 34 */ "pickbass",
+ /* 35 */ "fretless",
+ /* 36 */ "slapbas1",
+ /* 37 */ "slapbas2",
+ /* 38 */ "synbass1",
+ /* 39 */ "synbass2",
+ /* 40 */ "violin",
+ /* 41 */ "viola",
+ /* 42 */ "cello",
+ /* 43 */ "contraba",
+ /* 44 */ "marcato",
+ /* 45 */ "pizzcato",
+ /* 46 */ "harp",
+ /* 47 */ "timpani",
+ /* 48 */ "marcato",
+ /* 49 */ "slowstr",
+ /* 50 */ "synstr1",
+ /* 51 */ "synstr2",
+ /* 52 */ "choir",
+ /* 53 */ "doo",
+ /* 54 */ "voices",
+ /* 55 */ "orchhit",
+ /* 56 */ "trumpet",
+ /* 57 */ "trombone",
+ /* 58 */ "tuba",
+ /* 59 */ "mutetrum",
+ /* 60 */ "frenchrn",
+ /* 61 */ "hitbrass",
+ /* 62 */ "synbras1",
+ /* 63 */ "synbras2",
+ /* 64 */ "sprnosax",
+ /* 65 */ "altosax",
+ /* 66 */ "tenorsax",
+ /* 67 */ "barisax",
+ /* 68 */ "oboe",
+ /* 69 */ "englhorn",
+ /* 70 */ "bassoon",
+ /* 71 */ "clarinet",
+ /* 72 */ "piccolo",
+ /* 73 */ "flute",
+ /* 74 */ "recorder",
+ /* 75 */ "woodflut",
+ /* 76 */ "bottle",
+ /* 77 */ "shakazul",
+ /* 78 */ "whistle",
+ /* 79 */ "ocarina",
+ /* 80 */ "sqrwave",
+ /* 81 */ "sawwave",
+ /* 82 */ "calliope",
+ /* 83 */ "chiflead",
+ /* 84 */ "voxlead",
+ /* 85 */ "voxlead",
+ /* 86 */ "lead5th",
+ /* 87 */ "basslead",
+ /* 88 */ "fantasia",
+ /* 89 */ "warmpad",
+ /* 90 */ "polysyn",
+ /* 91 */ "ghostie",
+ /* 92 */ "bowglass",
+ /* 93 */ "metalpad",
+ /* 94 */ "halopad",
+ /* 95 */ "sweeper",
+ /* 96 */ "aurora",
+ /* 97 */ "soundtrk",
+ /* 98 */ "crystal",
+ /* 99 */ "atmosphr",
+ /* 100 */ "freshair",
+ /* 101 */ "unicorn",
+ /* 102 */ "sweeper",
+ /* 103 */ "startrak",
+ /* 104 */ "sitar",
+ /* 105 */ "banjo",
+ /* 106 */ "shamisen",
+ /* 107 */ "koto",
+ /* 108 */ "kalimba",
+ /* 109 */ "bagpipes",
+ /* 110 */ "fiddle",
+ /* 111 */ "Shannai",
+ /* 112 */ "carillon",
+ /* 113 */ "agogo",
+ /* 114 */ "steeldrm",
+ /* 115 */ "woodblk",
+ /* 116 */ "taiko",
+ /* 117 */ "toms",
+ /* 118 */ "syntom",
+ /* 119 */ "revcym",
+ /* 120 */ "fx-fret",
+ /* 121 */ "fx-blow",
+ /* 122 */ "seashore",
+ /* 123 */ "jungle",
+ /* 124 */ "telephon",
+ /* 125 */ "helicptr",
+ /* 126 */ "applause",
+ /* 127 */ "ringwhsl"
+ };
diff --git a/sys/i386/isa/sound/gustest/gmod.c b/sys/i386/isa/sound/gustest/gmod.c
new file mode 100644
index 0000000..a1184a0
--- /dev/null
+++ b/sys/i386/isa/sound/gustest/gmod.c
@@ -0,0 +1,1588 @@
+/*
+ * gmod.c - Module player for GUS and Linux.
+ * (C) Hannu Savolainen, 1993
+ *
+ * NOTE! This program doesn't try to be a complete module player.
+ * It's just a too I used while developing the driver. In
+ * addition it can be used as an example on programming
+ * the LInux Sound Driver with GUS.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <machine/ultrasound.h>
+#include <fcntl.h>
+#include <math.h>
+#include <string.h>
+
+#define CMD_ARPEG 0x00
+#define CMD_SLIDEUP 0x01
+#define CMD_SLIDEDOWN 0x02
+#define CMD_SLIDETO 0x03
+#define SLIDE_SIZE 8
+#define CMD_VOLSLIDE 0x0a
+#define CMD_JUMP 0x0b
+#define CMD_VOLUME 0x0c
+#define CMD_BREAK 0x0d
+#define CMD_SPEED 0x0f
+#define CMD_NOP 0xfe
+#define CMD_NONOTE 0xff
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+#define MAX_TRACK 8
+#define MAX_PATTERN 128
+#define MAX_POSITION 128
+
+struct note_info
+ {
+ unsigned char note;
+ unsigned char vol;
+ unsigned char sample;
+ unsigned char command;
+ short parm1, parm2;
+ };
+
+struct voice_info
+ {
+ int sample;
+ int note;
+ int volume;
+ int pitchbender;
+
+ /* Pitch sliding */
+
+ int slide_pitch;
+ int slide_goal;
+ int slide_rate;
+
+ int volslide;
+ };
+
+typedef struct note_info pattern[MAX_TRACK][64];
+int pattern_len[MAX_POSITION];
+int pattern_tempo[MAX_POSITION];
+pattern *pattern_table[MAX_PATTERN];
+
+struct voice_info voices[MAX_TRACK];
+
+int nr_channels, nr_patterns, songlength;
+int tune[MAX_POSITION];
+double tick_duration;
+
+int period_table[] =
+{
+ 856, 808, 762, 720, 678, 640, 604, 570, 538, 508, 480, 453,
+ 428, 404, 381, 360, 339, 320, 302, 285, 269, 254, 240, 226,
+ 214, 202, 190, 180, 170, 160, 151, 143, 135, 127, 120, 113
+};
+
+SEQ_DEFINEBUF (2048);
+
+int seqfd;
+int sample_ok[128], sample_vol[128];
+int tmp, gus_dev;
+double this_time, next_time;
+int ticks_per_division;
+double clock_rate; /* HZ */
+
+/*
+ * The function seqbuf_dump() must always be provided
+ */
+
+void play_module (char *name);
+int load_module (char *name);
+int play_note (int channel, struct note_info *pat);
+void lets_play_voice (int channel, struct voice_info *v);
+
+void
+seqbuf_dump ()
+{
+ if (_seqbufptr)
+ if (write (seqfd, _seqbuf, _seqbufptr) == -1)
+ {
+ perror ("write /dev/sequencer");
+ exit (-1);
+ }
+ _seqbufptr = 0;
+}
+
+void
+init_voices ()
+{
+ int i;
+
+ for (i = 0; i < MAX_TRACK; i++)
+ {
+ voices[i].sample = 0;
+ voices[i].note = 0;
+ voices[i].volume = 64;
+
+ voices[i].slide_pitch = 0;
+ voices[i].slide_goal = 0;
+ voices[i].slide_rate = 0;
+ voices[i].pitchbender = 0;
+
+ voices[i].volslide = 0;
+ }
+}
+
+int
+main (int argc, char *argv[])
+{
+ int i, n, j;
+ struct synth_info info;
+
+ if ((seqfd = open ("/dev/sequencer", O_WRONLY, 0)) == -1)
+ {
+ perror ("/dev/sequencer");
+ exit (-1);
+ }
+
+ if (ioctl (seqfd, SNDCTL_SEQ_NRSYNTHS, &n) == -1)
+ {
+ perror ("/dev/sequencer");
+ exit (-1);
+ }
+
+ for (i = 0; i < n; i++)
+ {
+ info.device = i;
+
+ if (ioctl (seqfd, SNDCTL_SYNTH_INFO, &info) == -1)
+ {
+ perror ("/dev/sequencer");
+ exit (-1);
+ }
+
+ if (info.synth_type == SYNTH_TYPE_SAMPLE
+ && info.synth_subtype == SAMPLE_TYPE_GUS)
+ gus_dev = i;
+ }
+
+ if (gus_dev == -1)
+ {
+ fprintf (stderr, "Gravis Ultrasound not detected\n");
+ exit (-1);
+ }
+
+ GUS_NUMVOICES (gus_dev, 14);
+
+ for (i = 1; i < argc; i++)
+ {
+ for (j = 0; j < MAX_PATTERN; j++)
+ pattern_table[j] = NULL;
+
+ if (load_module (argv[i]))
+ {
+ tick_duration = 100.0 / clock_rate;
+ play_module (argv[i]);
+ }
+
+ }
+
+ SEQ_DUMPBUF ();
+ close (seqfd);
+
+ exit (0);
+}
+
+unsigned short
+intelize (unsigned short v)
+{
+ return ((v & 0xff) << 8) | ((v >> 8) & 0xff);
+}
+
+unsigned long
+intelize4 (unsigned long v)
+{
+ return
+ (((v >> 16) & 0xff) << 8) | (((v >> 16) >> 8) & 0xff) |
+ (((v & 0xff) << 8) | ((v >> 8) & 0xff) << 16);
+}
+
+int
+load_stm_module (int mod_fd, char *name)
+{
+
+ struct sample_header
+ {
+ char name[12];
+ unsigned char instr_disk;
+ unsigned short reserved1;
+ unsigned short length; /* In bytes */
+ unsigned short loop_start;
+ unsigned short loop_end;
+ unsigned char volume;
+ unsigned char reserved2;
+ unsigned short C2_speed;
+ unsigned short reserved3;
+
+ };
+
+ int i, total_mem;
+ int sample_ptr;
+
+ int position;
+
+ unsigned char *tune_ptr; /* array 0-127 */
+
+ char header[1105], sname[21];
+
+ int nr_samples; /* 16 or 32 samples (or 64 or ???) */
+ int slen, npat;
+
+ fprintf (stderr, "Loading .STM module: %s\n", name);
+
+ if (read (mod_fd, header, sizeof (header)) != sizeof (header))
+ {
+ fprintf (stderr, "%s: Short file (header)\n", name);
+ close (mod_fd);
+ return 0;
+ }
+
+ strncpy (sname, header, 20);
+
+ fprintf (stderr, "\nModule: %s - ", sname);
+
+ if (header[28] != 0x1a)
+ {
+ fprintf (stderr, "Not a STM module\n");
+ close (mod_fd);
+ return 0;
+ }
+
+ npat = header[33];
+ slen = 0;
+ tune_ptr = &header[48 + (31 * 32)];
+
+ for (i = 0; i < 64; i++)
+ {
+ tune[i] = tune_ptr[i];
+ if (tune[i] < npat)
+ slen = i;
+ }
+
+ fprintf (stderr, "Song lenght %d, %d patterns.\n", slen, npat);
+
+ nr_samples = 31;
+
+ sample_ptr = 48 + (31 * 32) + 64 + (npat * 1024); /* Location where the
+ * first sample is
+ * stored */
+ total_mem = 0;
+
+ for (i = 0; i < 32; i++)
+ sample_ok[i] = 0;
+
+ for (i = 0; i < nr_samples; i++)
+ {
+ int len, loop_start, loop_end, base_freq;
+ unsigned short loop_flags = 0;
+
+ struct sample_header *sample;
+
+ struct patch_info *patch;
+
+ sample = (struct sample_header *) &header[48 + (i * 32)];
+
+ len = sample->length;
+ loop_start = sample->loop_start;
+ loop_end = sample->loop_end;
+ base_freq = sample->C2_speed;
+
+ if (strlen (sample->name) > 21)
+ {
+ fprintf (stderr, "\nInvalid name for sample #%d\n", i);
+ close (mod_fd);
+ return 0;
+ }
+
+ if (len > 0)
+ {
+ int x;
+
+ if (loop_end > len)
+ loop_end = 1;
+ else if (loop_end < loop_start)
+ {
+ loop_start = 0;
+ loop_end = 0;
+ }
+ else
+ loop_flags = WAVE_LOOPING;
+
+ total_mem += len;
+ patch = (struct patch_info *) malloc (sizeof (*patch) + len);
+
+ patch->key = GUS_PATCH;
+ patch->device_no = gus_dev;
+ patch->instr_no = i;
+ patch->mode = loop_flags;
+ patch->len = len;
+ patch->loop_start = loop_start;
+ patch->loop_end = loop_end;
+ patch->base_freq = base_freq;
+ patch->base_note = 261630; /* Mid C */
+ patch->low_note = 0;
+ patch->high_note = 0x7fffffff;
+ patch->volume = 120;
+
+ if (lseek (mod_fd, sample_ptr, 0) == -1)
+ {
+ perror (name);
+ close (mod_fd);
+ free (patch);
+ return 0;
+ }
+
+ sample_ptr += len;
+
+ if ((x = read (mod_fd, patch->data, len)) != len)
+ {
+ fprintf (stderr, "Short file (sample at %d (%d!=%d)\n", sample_ptr, x, len);
+ close (mod_fd);
+ free (patch);
+ return 0;
+ }
+
+ fprintf (stderr, "Sample %02d: %05d, %05d, %05d, %07d %s\n",
+ i,
+ len,
+ loop_start,
+ loop_end,
+ base_freq,
+ sample->name);
+
+ if (write (seqfd, patch, sizeof (*patch) + len) == -1)
+ {
+ perror ("ioctl /dev/sequencer");
+ exit (-1);
+ }
+ else
+ sample_ok[i] = 1;
+
+ free (patch);
+ }
+ }
+
+ nr_patterns = slen;
+ songlength = slen;
+ nr_channels = 4;
+
+ for (position = 0; position < npat; position++)
+ {
+ unsigned char patterns[64][4][4];
+ int pat, channel, x;
+
+ int pp = 1104 + (position * 1024);
+
+ if ((pattern_table[position] = (pattern *) malloc (sizeof (struct note_info) * 64 * nr_channels)) == NULL)
+ {
+ fprintf (stderr, "Can't allocate memory for a pattern\n");
+ return 0;
+ }
+
+ if (lseek (mod_fd, pp, 0) == -1)
+ {
+ perror (name);
+ close (mod_fd);
+ return 0;
+ }
+
+ if ((x = read (mod_fd, patterns, 1024)) != 1024)
+ {
+ fprintf (stderr, "Short file (pattern at %d), %d!=%d\n", pp, x, 1024);
+ close (mod_fd);
+ return 0;
+ }
+
+ for (pat = 0; pat < 64; pat++)
+ {
+
+ for (channel = 0; channel < 4; channel++)
+ {
+ unsigned char *p;
+
+ unsigned vol, note, octave, sample, effect, params;
+
+ p = &patterns[pat][channel][0];
+
+ if (p[0] < 251)
+ {
+ note = p[0] & 15;
+ octave = p[0] / 16;
+
+ note = 48 + octave * 12 + note;
+
+ sample = p[1] / 8;
+ vol = (p[1] & 7) + (p[2] / 2);
+ effect = p[2] & 0xF;
+ params = p[3];
+ }
+ else
+ {
+ note = 0;
+ octave = 0;
+
+ sample = 0;
+ vol = 0;
+ effect = CMD_NONOTE;
+ params = 0;
+ }
+
+ (*pattern_table[position])[channel][pat].note = note;
+ (*pattern_table[position])[channel][pat].sample = sample;
+ (*pattern_table[position])[channel][pat].command = effect;
+ (*pattern_table[position])[channel][pat].parm1 = params;
+ (*pattern_table[position])[channel][pat].parm2 = 0;
+ (*pattern_table[position])[channel][pat].vol = vol;
+ }
+
+ }
+
+ }
+
+ close (mod_fd);
+ return 1;
+}
+
+int
+load_669_module (int mod_fd, char *name)
+{
+ struct sample_header
+ {
+ char name[13];
+ unsigned long length; /* In bytes */
+ unsigned long loop_start;
+ unsigned long loop_end;
+ };
+
+ int i, total_mem;
+ int sample_ptr;
+
+ int position;
+
+ unsigned char *tune_ptr, *len_ptr, *tempo_ptr; /* array 0-127 */
+
+ char header[1084];
+ char msg[110];
+
+ int nr_samples; /* 16 or 32 samples */
+ int slen, npat;
+
+ clock_rate = 25.0;
+
+ fprintf (stderr, "Loading .669 module: %s\n", name);
+
+ if (read (mod_fd, header, sizeof (header)) != sizeof (header))
+ {
+ fprintf (stderr, "%s: Short file (header)\n", name);
+ close (mod_fd);
+ return 0;
+ }
+
+ if (*(unsigned short *) &header[0] != 0x6669)
+ {
+ fprintf (stderr, "Not a 669 file\n");
+ close (mod_fd);
+ return 0;
+ }
+
+ strncpy (msg, &header[2], 108);
+
+ for (i = 0; i < strlen (msg); i++)
+ if ((msg[i] >= ' ' && msg[i] <= 'z') || msg[i] == '\n')
+ printf ("%c", msg[i]);
+ printf ("\n");
+
+ npat = header[0x6f];
+
+ tune_ptr = &header[0x71];
+
+ for (slen = 0; slen < 128 && tune_ptr[slen] != 0xff; slen++);
+ slen--;
+
+ for (i = 0; i < slen; i++)
+ tune[i] = tune_ptr[i];
+
+ len_ptr = &header[0x171];
+ for (i = 0; i < slen; i++)
+ pattern_len[i] = len_ptr[i] - 1;
+
+ tempo_ptr = &header[0xf1];
+ for (i = 0; i < slen; i++)
+ pattern_tempo[i] = tempo_ptr[i];
+
+ nr_samples = header[0x6e];
+
+ fprintf (stderr, "Song lenght %d, %d patterns, %d samples.\n", slen, npat, nr_samples);
+
+ sample_ptr = 0x1f1 + (nr_samples * 0x19) + (npat * 0x600); /* Location where the
+ * first sample is
+ * stored */
+ total_mem = 0;
+
+ for (i = 0; i < 64; i++)
+ sample_ok[i] = 0;
+
+ for (i = 0; i < nr_samples; i++)
+ {
+ int len, loop_start, loop_end;
+ unsigned short loop_flags = 0;
+
+ struct sample_header *sample;
+ char sname[14];
+
+ struct patch_info *patch;
+
+ sample = (struct sample_header *) &header[0x1f1 + (i * 0x19)];
+
+ len = *(unsigned long *) &sample->name[13];
+ loop_start = *(unsigned long *) &sample->name[17];
+ loop_end = *(unsigned long *) &sample->name[21];
+ if (loop_end > len)
+ loop_end = 1;
+ else if (loop_end == len)
+ loop_end--;
+
+ if (loop_end < loop_start)
+ {
+ loop_start = 0;
+ loop_end = 0;
+ }
+
+ strncpy (sname, sample->name, 13);
+
+ if (len > 0 && len < 200000)
+ {
+ total_mem += len;
+
+ fprintf (stderr, "Sample %02d: %05d, %05d, %05d %s\n",
+ i,
+ len,
+ loop_start,
+ loop_end,
+ sname);
+
+ patch = (struct patch_info *) malloc (sizeof (*patch) + len);
+
+ if (loop_end == 0)
+ loop_end = 1;
+ if (loop_end >= len)
+ loop_end = 1;
+
+ if (loop_end > 1) loop_flags = WAVE_LOOPING;
+
+ patch->key = GUS_PATCH;
+ patch->device_no = gus_dev;
+ patch->instr_no = i;
+ patch->mode = WAVE_UNSIGNED | loop_flags;
+ patch->len = len;
+ patch->loop_start = loop_start;
+ patch->loop_end = loop_end;
+ patch->base_freq = 8448;
+ patch->base_note = 261630;
+ patch->low_note = 1000;
+ patch->high_note = 0x7fffffff;
+ patch->volume = 120;
+
+ if (lseek (mod_fd, sample_ptr, 0) == -1)
+ {
+ fprintf (stderr, "Seek failed\n");
+ perror (name);
+ close (mod_fd);
+ free (patch);
+ return 0;
+ }
+
+ sample_ptr += len;
+
+ if (read (mod_fd, patch->data, len) != len)
+ {
+ fprintf (stderr, "Short file (sample at %d)\n", sample_ptr);
+ close (mod_fd);
+ free (patch);
+ return 0;
+ }
+
+ if (write (seqfd, patch, sizeof (*patch) + len) == -1)
+ {
+ perror ("ioctl /dev/sequencer");
+ /* exit (-1); */
+ }
+ else
+ sample_ok[i] = 1;
+
+ free (patch);
+ }
+ }
+
+ nr_patterns = slen;
+ songlength = slen;
+ nr_channels = 8;
+
+ for (position = 0; position < npat; position++)
+ {
+ unsigned char patterns[0x600];
+ int pat, channel, x;
+
+ int pp = 0x1f1 + (nr_samples * 0x19) + (position * 0x600);
+
+ if ((pattern_table[position] = (pattern *) malloc (sizeof (struct note_info) * 64 * nr_channels)) == NULL)
+ {
+ fprintf (stderr, "Can't allocate memory for a pattern\n");
+ return 0;
+ }
+
+
+ if (lseek (mod_fd, pp, 0) == -1)
+ {
+ perror (name);
+ close (mod_fd);
+ return 0;
+ }
+
+ if ((x = read (mod_fd, patterns, 1024)) != 1024)
+ {
+ fprintf (stderr, "Short file (pattern at %d) %d!=1024\n", pp, x);
+ close (mod_fd);
+ return 0;
+ }
+
+ for (pat = 0; pat < 64; pat++)
+ {
+
+ for (channel = 0; channel < 8; channel++)
+ {
+ unsigned char *p;
+
+ unsigned vol, period, sample, effect, params;
+
+ p = &patterns[pat * 24 + channel * 3];
+
+ if (p[0] >= 0xfe ||
+ (p[0] == 0xff && p[1] == 0xff && p[2] == 0xff) ||
+ (p[0] == 0 && p[1] == 0 && p[2] == 0) ||
+ *(int *) p == -1)
+ {
+ period = 0;
+ effect = CMD_NONOTE;
+ sample = 0;
+ vol = 0;
+ params = 0;
+
+ if (p[0] == 0)
+ {
+ effect = CMD_BREAK;
+ params = -2;
+ }
+ }
+ else
+ {
+ period = (p[0] >> 2) + 48;
+ effect = (p[2] >> 4);
+ params = p[2] & 0x0f;
+ vol = p[1] & 0x0f;
+
+ if (p[2] == 0xfe)
+ {
+ effect = CMD_VOLUME;
+ params = vol;
+ }
+ else if (p[2] == 0xff)
+ {
+ effect = CMD_NOP;
+ }
+ else
+ switch (effect)
+ {
+ case 0: /* a - Portamento up */
+ effect = CMD_SLIDEUP;
+ break;
+
+ case 1: /* b - Portamento down */
+ effect = CMD_SLIDEDOWN;
+ break;
+
+ case 2: /* c - Port to note */
+ effect = CMD_SLIDETO;
+ break;
+
+ case 3: /* d - Frequency adjust */
+ effect = CMD_NOP; /* To be implemented */
+ break;
+
+ case 4: /* e - Frequency vibrato */
+ effect = CMD_NOP; /* To be implemented */
+ break;
+
+ case 5: /* f - Set tempo */
+ effect = CMD_SPEED;
+ break;
+
+ default:
+ effect = CMD_NOP;
+ }
+
+ sample = (((p[0] << 4) & 0x30) | ((p[1] >> 4) & 0x0f)) + 1;
+ }
+
+ (*pattern_table[position])[channel][pat].note = period;
+ (*pattern_table[position])[channel][pat].sample = sample;
+ (*pattern_table[position])[channel][pat].command = effect;
+ (*pattern_table[position])[channel][pat].parm1 = params;
+ (*pattern_table[position])[channel][pat].parm2 = 0;
+ (*pattern_table[position])[channel][pat].vol = vol;
+ }
+
+ }
+
+ }
+
+ close (mod_fd);
+ return 1;
+}
+
+int
+load_mmd0_module (int mod_fd, char *name)
+{
+
+ struct sample_header
+ {
+ unsigned short loop_start;
+ unsigned short loop_end;
+ unsigned char midich;
+ unsigned char midipreset;
+ unsigned char volume;
+ unsigned char strans;
+ };
+
+ int i, total_mem;
+ int sample_ptr;
+
+ int position;
+
+ unsigned char *tune_ptr; /* array 0-127 */
+
+ char header[1105];
+
+ int nr_samples; /* 16 or 32 samples (or 64 or ???) */
+ int slen, npat;
+
+ fprintf (stderr, "Loading .MED module: %s\n", name);
+
+ if (read (mod_fd, header, sizeof (header)) != sizeof (header))
+ {
+ fprintf (stderr, "%s: Short file (header)\n", name);
+ close (mod_fd);
+ return 0;
+ }
+
+ if (strncmp (header, "MMD0", 4))
+ {
+ fprintf (stderr, "Not a MED module\n");
+ close (mod_fd);
+ return 0;
+ }
+
+ printf ("Module len %d\n", intelize4 (*(long *) &header[4]));
+ printf ("Song info %d\n", intelize4 (*(long *) &header[8]));
+ printf ("Song len %d\n", intelize4 (*(long *) &header[12]));
+ printf ("Blockarr %x\n", intelize4 (*(long *) &header[16]));
+ printf ("Blockarr len %d\n", intelize4 (*(long *) &header[20]));
+ printf ("Sample array %x\n", intelize4 (*(long *) &header[24]));
+ printf ("Sample array len %d\n", intelize4 (*(long *) &header[28]));
+ printf ("Exp data %x\n", intelize4 (*(long *) &header[32]));
+ printf ("Exp size %d\n", intelize4 (*(long *) &header[36]));
+ printf ("Pstate %d\n", intelize (*(long *) &header[40]));
+ printf ("Pblock %d\n", intelize (*(long *) &header[42]));
+
+ return 0;
+
+ npat = header[33];
+ slen = 0;
+ tune_ptr = &header[48 + (31 * 32)];
+
+ for (i = 0; i < 64; i++)
+ {
+ tune[i] = tune_ptr[i];
+ if (tune[i] < npat)
+ slen = i;
+ }
+
+ fprintf (stderr, "Song lenght %d, %d patterns.\n", slen, npat);
+
+ nr_samples = 31;
+
+ sample_ptr = 48 + (31 * 32) + 64 + (npat * 1024); /* Location where the
+ * first sample is
+ * stored */
+ total_mem = 0;
+
+ for (i = 0; i < 32; i++)
+ sample_ok[i] = 0;
+
+ for (i = 0; i < nr_samples; i++)
+ {
+ int len, loop_start, loop_end, base_freq;
+ unsigned short loop_flags = 0;
+
+ struct sample_header *sample;
+
+ struct patch_info *patch;
+
+ sample = (struct sample_header *) &header[48 + (i * 32)];
+
+ /*
+ * len = sample->length; loop_start = sample->loop_start; loop_end =
+ * sample->loop_end; base_freq = sample->C2_speed;
+ *
+ * if (strlen (sample->name) > 21) { fprintf (stderr, "\nInvalid name for
+ * sample #%d\n", i); close (mod_fd); return 0; }
+ */
+ if (len > 0)
+ {
+ int x;
+
+ if (loop_end > len)
+ loop_end = 1;
+
+ if (loop_end < loop_start)
+ {
+ loop_start = 0;
+ loop_end = 0;
+ }
+
+ if (loop_end > 2) loop_flags = WAVE_LOOPING;
+
+ total_mem += len;
+ patch = (struct patch_info *) malloc (sizeof (*patch) + len);
+
+ patch->key = GUS_PATCH;
+ patch->device_no = gus_dev;
+ patch->instr_no = i;
+ patch->mode = loop_flags;
+ patch->len = len;
+ patch->loop_start = loop_start;
+ patch->loop_end = loop_end;
+ patch->base_freq = base_freq;
+ patch->base_note = 261630; /* Mid C */
+ patch->low_note = 0;
+ patch->high_note = 0x7fffffff;
+ patch->volume = 120;
+
+ if (lseek (mod_fd, sample_ptr, 0) == -1)
+ {
+ perror (name);
+ close (mod_fd);
+ free (patch);
+ return 0;
+ }
+
+ sample_ptr += len;
+
+ if ((x = read (mod_fd, patch->data, len)) != len)
+ {
+ fprintf (stderr, "Short file (sample at %d (%d!=%d)\n", sample_ptr, x, len);
+ close (mod_fd);
+ free (patch);
+ return 0;
+ }
+ /*
+ * fprintf (stderr, "Sample %02d: %05d, %05d, %05d, %07d %s\n", i,
+ * len, loop_start, loop_end, base_freq, sample->name);
+ */
+ if (write (seqfd, patch, sizeof (*patch) + len) == -1)
+ {
+ perror ("ioctl /dev/sequencer");
+ exit (-1);
+ }
+ else
+ sample_ok[i] = 1;
+
+ free (patch);
+ }
+ }
+
+ nr_patterns = slen;
+ songlength = slen;
+ nr_channels = 4;
+
+ for (position = 0; position < npat; position++)
+ {
+ unsigned char patterns[64][4][4];
+ int pat, channel, x;
+
+ int pp = 1104 + (position * 1024);
+
+ if ((pattern_table[position] = (pattern *) malloc (sizeof (struct note_info) * 64 * nr_channels)) == NULL)
+ {
+ fprintf (stderr, "Can't allocate memory for a pattern\n");
+ return 0;
+ }
+
+ if (lseek (mod_fd, pp, 0) == -1)
+ {
+ perror (name);
+ close (mod_fd);
+ return 0;
+ }
+
+ if ((x = read (mod_fd, patterns, 1024)) != 1024)
+ {
+ fprintf (stderr, "Short file (pattern at %d), %d!=%d\n", pp, x, 1024);
+ close (mod_fd);
+ return 0;
+ }
+
+ for (pat = 0; pat < 64; pat++)
+ {
+
+ for (channel = 0; channel < 4; channel++)
+ {
+ unsigned char *p;
+
+ unsigned vol, note, octave, sample, effect, params;
+
+ p = &patterns[pat][channel][0];
+
+ if (p[0] < 251)
+ {
+ note = p[0] & 15;
+ octave = p[0] / 16;
+
+ note = 48 + octave * 12 + note;
+
+ sample = p[1] / 8;
+ vol = (p[1] & 7) + (p[2] / 2);
+ effect = p[2] & 0xF;
+ params = p[3];
+ }
+ else
+ {
+ note = 0;
+ octave = 0;
+
+ sample = 0;
+ vol = 0;
+ effect = CMD_NONOTE;
+ params = 0;
+ }
+
+ (*pattern_table[position])[channel][pat].note = note;
+ (*pattern_table[position])[channel][pat].sample = sample;
+ (*pattern_table[position])[channel][pat].command = effect;
+ (*pattern_table[position])[channel][pat].parm1 = params;
+ (*pattern_table[position])[channel][pat].parm2 = 0;
+ (*pattern_table[position])[channel][pat].vol = vol;
+ }
+
+ }
+
+ }
+
+ close (mod_fd);
+ return 1;
+}
+
+int
+load_module (char *name)
+{
+
+ struct sample_header
+ {
+ char name[22];
+ unsigned short length; /* In words */
+
+ unsigned char finetune;
+ unsigned char volume;
+
+ unsigned short repeat_point; /* In words */
+ unsigned short repeat_length; /* In words */
+ };
+
+ int i, mod_fd, total_mem;
+ int sample_ptr, pattern_loc;
+
+ int position;
+
+ unsigned char *tune_ptr; /* array 0-127 */
+
+ char header[1084];
+
+ int nr_samples; /* 16 or 32 samples */
+ int slen, npat;
+ char mname[23];
+
+ ioctl (seqfd, SNDCTL_SEQ_SYNC, 0);
+ ioctl (seqfd, SNDCTL_SEQ_RESETSAMPLES, &gus_dev);
+
+ clock_rate = 50.0;
+
+ for (i = 0; i < MAX_POSITION; i++)
+ pattern_len[i] = 64;
+
+ for (i = 0; i < MAX_POSITION; i++)
+ pattern_tempo[i] = 0;
+
+ if ((mod_fd = open (name, O_RDONLY, 0)) == -1)
+ {
+ perror (name);
+ return 0;
+ }
+
+ if (read (mod_fd, header, sizeof (header)) != sizeof (header))
+ {
+ fprintf (stderr, "%s: Short file (header)\n", name);
+ close (mod_fd);
+ return 0;
+ }
+
+ if (lseek (mod_fd, 0, 0) == -1)
+ {
+ perror (name);
+ close (mod_fd);
+ return 0;
+ }
+
+ if (header[28] == 0x1a)
+ return load_stm_module (mod_fd, name);
+
+ if (*(unsigned short *) &header[0] == 0x6669)
+ return load_669_module (mod_fd, name);
+
+ if (!strncmp (header, "MMD0", 4))
+ return load_mmd0_module (mod_fd, name);
+
+ fprintf (stderr, "Loading .MOD module: %s\n", name);
+
+ strncpy (mname, header, 22);
+ fprintf (stderr, "\nModule: %s - ", mname);
+
+ if (!strncmp (&header[1080], "M.K.", 4) || !strncmp (&header[1080], "FLT8", 4))
+ {
+ fprintf (stderr, "31 samples\n");
+ nr_samples = 31;
+ }
+ else
+ {
+ fprintf (stderr, "15 samples\n");
+ nr_samples = 15;
+ }
+
+ if (nr_samples == 31)
+ {
+ sample_ptr = pattern_loc = 1084;
+ slen = header[950];
+ tune_ptr = (unsigned char *) &header[952];
+ }
+ else
+ {
+ sample_ptr = pattern_loc = 600;
+ slen = header[470];
+ tune_ptr = (unsigned char *) &header[472];
+ }
+
+ npat = 0;
+ for (i = 0; i < 128; i++)
+ {
+ tune[i] = tune_ptr[i];
+
+ if (tune_ptr[i] > npat)
+ npat = tune_ptr[i];
+ }
+ npat++;
+
+ fprintf (stderr, "Song lenght %d, %d patterns.\n", slen, npat);
+
+ sample_ptr += (npat * 1024); /* Location where the first sample is stored */
+ total_mem = 0;
+
+ for (i = 0; i < 32; i++)
+ sample_ok[i] = 0;
+
+ for (i = 0; i < nr_samples; i++)
+ {
+ int len, loop_start, loop_end;
+ unsigned short loop_flags = 0;
+ char pname[22];
+
+ struct sample_header *sample;
+
+ struct patch_info *patch;
+
+ sample = (struct sample_header *) &header[20 + (i * 30)];
+
+ len = intelize (sample->length) * 2;
+ loop_start = intelize (sample->repeat_point) * 2;
+ loop_end = loop_start + (intelize (sample->repeat_length) * 2);
+
+ if (loop_start > len)
+ loop_start = 0;
+ if (loop_end > len)
+ loop_end = len;
+
+ if (loop_end <= loop_start)
+ loop_end = loop_start + 1;
+
+ if (loop_end > 2 && loop_end > loop_start)
+ loop_flags = WAVE_LOOPING;
+
+ strncpy (pname, sample->name, 20);
+
+ if (len > 0)
+ {
+ fprintf (stderr, "Sample %02d: L%05d, S%05d, E%05d V%02d %s\n",
+ i,
+ len,
+ loop_start,
+ loop_end,
+ sample->volume,
+ pname);
+
+ total_mem += len;
+
+ patch = (struct patch_info *) malloc (sizeof (*patch) + len);
+
+ patch->key = GUS_PATCH;
+ patch->device_no = gus_dev;
+ patch->instr_no = i;
+ patch->mode = loop_flags;
+ patch->len = len;
+ patch->loop_start = loop_start;
+ patch->loop_end = loop_end;
+ patch->base_note = 261630; /* Middle C */
+ patch->base_freq = 8448;
+ patch->low_note = 0;
+ patch->high_note = 20000000;
+ patch->volume = 120;
+ patch->panning = 0;
+
+ if (lseek (mod_fd, sample_ptr, 0) == -1)
+ {
+ perror (name);
+ close (mod_fd);
+ free (patch);
+ return 0;
+ }
+
+ sample_ptr += len;
+
+ if (read (mod_fd, patch->data, len) != len)
+ {
+ fprintf (stderr, "Short file (sample) %d\n", sample_ptr);
+ close (mod_fd);
+ free (patch);
+ return 0;
+ }
+
+ SEQ_WRPATCH (patch, sizeof (*patch) + len);
+
+ sample_ok[i] = 1;
+ if (sample->volume == 0) sample->volume = 64;
+ sample_vol[i] = sample->volume;
+
+ free (patch);
+ }
+ }
+
+ nr_patterns = npat;
+ songlength = slen;
+ nr_channels = 4;
+
+ for (position = 0; position < npat; position++)
+ {
+ unsigned char patterns[64][4][4];
+ int pat, channel;
+
+ int pp = pattern_loc + (position * 1024);
+
+ if (lseek (mod_fd, pp, 0) == -1)
+ {
+ perror (name);
+ close (mod_fd);
+ return 0;
+ }
+
+ if (read (mod_fd, patterns, 1024) != 1024)
+ {
+ fprintf (stderr, "Short file (pattern %d) %d\n", tune[position], pp);
+ close (mod_fd);
+ return 0;
+ }
+
+ if ((pattern_table[position] = (pattern *) malloc (sizeof (struct note_info) * 64 * nr_channels)) == NULL)
+ {
+ fprintf (stderr, "Can't allocate memory for a pattern\n");
+ return 0;
+ }
+
+ for (pat = 0; pat < 64; pat++)
+ {
+ for (channel = 0; channel < 4; channel++)
+ {
+ unsigned short tmp;
+ unsigned char *p;
+
+ unsigned period, sample, effect, params, note, vol;
+
+ p = &patterns[pat][channel][0];
+
+ tmp = (p[0] << 8) | p[1];
+ sample = (tmp >> 8) & 0x10;
+ period =
+ MIN (tmp & 0xFFF, 1023);
+ tmp = (p[2] << 8) | p[3];
+ sample |= tmp >> 12;
+ effect = (tmp >> 8) & 0xF;
+ params = tmp & 0xFF;
+
+ note = 0;
+
+ if (period)
+ {
+ /*
+ * Convert period to a Midi note number
+ */
+
+ for (note = 0; note < 37 && period != period_table[note]; note++);
+ if (note >= 37)
+ note = 0;
+
+ note += 48;
+ }
+
+ vol = 64;
+
+ if (sample)
+ if (effect == 0xc)
+ {
+ vol = params;
+ }
+ else
+ vol = sample_vol[sample - 1];
+
+ vol *= 2;
+ if (vol>64)vol--;
+
+ (*pattern_table[position])[channel][pat].note = note;
+ (*pattern_table[position])[channel][pat].sample = sample;
+ (*pattern_table[position])[channel][pat].command = effect;
+ (*pattern_table[position])[channel][pat].parm1 = params;
+ (*pattern_table[position])[channel][pat].parm2 = 0;
+ (*pattern_table[position])[channel][pat].vol = vol;
+ }
+ }
+ }
+
+ close (mod_fd);
+ return 1;
+}
+
+int
+panning (int ch)
+{
+ static int panning_tab[] =
+ {-110, 110, 110, -110};
+
+ return panning_tab[ch % 4];
+}
+
+void
+set_speed (int parm)
+{
+ if (!parm)
+ parm = 1;
+
+ if (parm < 32)
+ {
+ ticks_per_division = parm;
+ }
+ else
+ {
+ tick_duration = (60.0 / parm) * 10.0;
+ }
+
+}
+
+void
+play_module (char *name)
+{
+ int i, position, jump_to_pos;
+
+ init_voices ();
+
+ SEQ_START_TIMER ();
+#if 1
+ for (i=0;i<32;i++)
+ {
+ SEQ_EXPRESSION(gus_dev, i, 127);
+ SEQ_MAIN_VOLUME(gus_dev, i, 100);
+ }
+#endif
+ next_time = 0.0;
+
+ set_speed (6);
+
+ for (position = 0; position < songlength; position++)
+ {
+ int tick, pattern, channel, pos, go_to;
+
+ pos = tune[position];
+ if (pattern_tempo[position])
+ set_speed (pattern_tempo[position]);
+
+ jump_to_pos = -1;
+ for (pattern = 0; pattern < pattern_len[position] && jump_to_pos == -1; pattern++)
+ {
+ this_time = 0.0;
+
+ for (channel = 0; channel < nr_channels; channel++)
+ {
+ if ((go_to = play_note (channel, &(*pattern_table[pos])[channel][pattern])) != -1)
+ jump_to_pos = go_to;
+
+ }
+
+ next_time += tick_duration;
+
+ for (tick = 1; tick < ticks_per_division; tick++)
+ {
+ for (channel = 0; channel < nr_channels; channel++)
+ lets_play_voice (channel, &voices[channel]);
+ next_time += tick_duration;
+ }
+
+ }
+
+ if (jump_to_pos >= 0)
+ position = jump_to_pos;
+ }
+
+ SEQ_WAIT_TIME ((int) next_time + 200); /* Wait extra 2 secs */
+
+ for (i = 0; i < nr_channels; i++)
+ SEQ_STOP_NOTE (gus_dev, i, 0, 127);
+ SEQ_DUMPBUF ();
+
+ for (i = 0; i < nr_patterns; i++)
+ free (pattern_table[i]);
+}
+
+void
+sync_time ()
+{
+ if (next_time > this_time)
+ {
+ SEQ_WAIT_TIME ((long) next_time);
+ this_time = next_time;
+ }
+}
+
+void
+set_volslide (int channel, struct note_info *pat)
+{
+ int n;
+
+ voices[channel].volslide = 0;
+
+ if ((n = (pat->parm1 & 0xf0) >> 4))
+ voices[channel].volslide = n;
+ else
+ voices[channel].volslide = pat->parm1 & 0xf;
+}
+
+void
+set_slideto (int channel, struct note_info *pat)
+{
+ int size, rate, dir, range = 200;
+
+ rate = pat->parm1;
+ size = voices[channel].note - pat->note;
+ if (!size)
+ return;
+
+ if (size < 0)
+ {
+ size *= -1;
+ dir = -1;
+ }
+ else
+ dir = 1;
+
+ if (size > 2)
+ {
+ range = size * 100;
+ rate = rate * size / 200;
+ }
+
+ rate = pat->parm1 * dir / 30;
+ if (!rate)
+ rate = 1;
+
+ voices[channel].slide_pitch = 1;
+ voices[channel].slide_goal = (dir * 8192 * 200 * 2 / size) / range;
+ voices[channel].pitchbender = 0;
+ voices[channel].slide_rate = rate;
+ SEQ_BENDER_RANGE (gus_dev, channel, range);
+}
+
+int
+play_note (int channel, struct note_info *pat)
+{
+ int jump = -1;
+ int sample;
+
+ if (pat->sample == 0x3f)
+ pat->sample = 0;
+
+ if (pat->command == CMD_NONOTE)
+ return -1; /* Undefined */
+
+ sample = pat->sample;
+
+ if (sample && !pat->note)
+ {
+ pat->note = voices[channel].note;
+ }
+
+ if (sample)
+ voices[channel].sample = sample;
+ else
+ sample = voices[channel].sample;
+
+ sample--;
+
+ if (pat->note && pat->command != 3) /* Have a note -> play */
+ {
+ if (sample < 0)
+ sample = voices[channel].sample - 1;
+
+ if (!sample_ok[sample])
+ sample = voices[channel].sample - 1;
+
+ if (sample < 0)
+ sample = 0;
+
+ if (sample_ok[sample])
+ {
+ sync_time ();
+
+ if (pat->vol > 127) pat->vol=127;
+ SEQ_SET_PATCH (gus_dev, channel, sample);
+ SEQ_PANNING (gus_dev, channel, panning (channel));
+ SEQ_PITCHBEND (gus_dev, channel, 0);
+ SEQ_START_NOTE (gus_dev, channel, pat->note, pat->vol);
+
+ voices[channel].volume = pat->vol;
+ voices[channel].note = pat->note;
+ voices[channel].slide_pitch = 0;
+ }
+ else
+ SEQ_STOP_NOTE (gus_dev, channel, pat->note, pat->vol);
+ }
+
+ switch (pat->command)
+ {
+
+ case CMD_NOP:;
+ break;
+
+ case CMD_JUMP:
+ jump = pat->parm1;
+ break;
+
+ case CMD_BREAK:
+ jump = -2;
+ break;
+
+ case CMD_SPEED:
+ set_speed (pat->parm1);
+ break;
+
+ case CMD_SLIDEUP:
+ voices[channel].slide_pitch = 1;
+ voices[channel].slide_goal = 8191;
+ voices[channel].pitchbender = 0;
+ voices[channel].slide_rate = pat->parm1 * SLIDE_SIZE;
+ SEQ_BENDER_RANGE (gus_dev, channel, 200);
+ break;
+
+ case CMD_SLIDEDOWN:
+ voices[channel].slide_pitch = 1;
+ voices[channel].slide_goal = -8192;
+ voices[channel].pitchbender = 0;
+ voices[channel].slide_rate = -pat->parm1 * SLIDE_SIZE;
+ SEQ_BENDER_RANGE (gus_dev, channel, 200);
+ break;
+
+ case CMD_SLIDETO:
+ set_slideto (channel, pat);
+ break;
+
+ case CMD_VOLUME:
+ {
+ int vol = pat->parm1*2;
+ if (vol>127) vol=127;
+ if (pat->note && pat->command != 3)
+ break;
+ SEQ_START_NOTE (gus_dev, channel, 255, vol);
+ }
+ break;
+
+ case CMD_ARPEG:
+ break;
+
+ case 0x0e:
+ /* printf ("Cmd 0xE%02x\n", pat->parm1); */
+ break;
+
+ case CMD_VOLSLIDE:
+ set_slideto (channel, pat);
+ break;
+
+ default:
+ /* printf ("Command %x %02x\n", pat->command, pat->parm1); */
+ }
+
+ return jump;
+}
+
+void
+lets_play_voice (int channel, struct voice_info *v)
+{
+ if (v->slide_pitch)
+ {
+ v->pitchbender += v->slide_rate;
+ if (v->slide_goal < 0)
+ {
+ if (v->pitchbender <= v->slide_goal)
+ {
+ v->pitchbender = v->slide_goal;
+ v->slide_pitch = 0; /* Stop */
+ }
+ }
+ else
+ {
+ if (v->pitchbender >= v->slide_goal)
+ {
+ v->pitchbender = v->slide_goal;
+ v->slide_pitch = 0; /* Stop */
+ }
+ }
+
+ sync_time ();
+ SEQ_PITCHBEND (gus_dev, channel, v->pitchbender);
+ }
+
+ if (v->volslide)
+ {
+ v->volume += v->volslide;
+ sync_time ();
+
+ if (v->volume > 127) v->volume = 127;
+ SEQ_START_NOTE (gus_dev, channel, 255, v->volume);
+ }
+}
diff --git a/sys/i386/isa/sound/gustest/gpatinfo.c b/sys/i386/isa/sound/gustest/gpatinfo.c
new file mode 100644
index 0000000..121020d
--- /dev/null
+++ b/sys/i386/isa/sound/gustest/gpatinfo.c
@@ -0,0 +1,175 @@
+/*
+ * gpatinfo.c: This program demonstrates the patch management
+ * interface of the GUS driver.
+ *
+ * NOTE! The patch manager interface is highly device dependent,
+ * currently incompletely implemented prototype and
+ * will change before final implementation.
+ *
+ */
+
+#include <stdio.h>
+#include <machine/ultrasound.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "gmidi.h"
+
+#define GUS_DEV gus_dev
+
+#define patch_access(cmd, rec) \
+ rec.command = cmd;\
+ rec.device = gus_dev;\
+ if (ioctl(seqfd, SNDCTL_PMGR_IFACE, &rec)==-1)\
+ {\
+ perror("/dev/sequencer(SNDCTL_PMGR_IFACE/" #cmd ")");\
+ exit(-1);\
+ }
+
+SEQ_DEFINEBUF (2048);
+
+int seqfd;
+
+int gus_dev = -1;
+
+/*
+ * The function seqbuf_dump() must always be provided
+ */
+
+void
+seqbuf_dump ()
+{
+ if (_seqbufptr)
+ if (write (seqfd, _seqbuf, _seqbufptr) == -1)
+ {
+ perror ("write /dev/sequencer");
+ exit (-1);
+ }
+ _seqbufptr = 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int i, j, n;
+ struct synth_info info;
+ struct patch_info *patch;
+ struct patmgr_info mgr, mgr2, mgr3;
+
+ if ((seqfd = open ("/dev/sequencer", O_WRONLY, 0)) == -1)
+ {
+ perror ("/dev/sequencer");
+ exit (-1);
+ }
+
+ if (ioctl (seqfd, SNDCTL_SEQ_NRSYNTHS, &n) == -1)
+ {
+ perror ("/dev/sequencer");
+ exit (-1);
+ }
+
+/*
+ * First locate the GUS device
+ */
+
+ for (i = 0; i < n; i++)
+ {
+ info.device = i;
+
+ if (ioctl (seqfd, SNDCTL_SYNTH_INFO, &info) == -1)
+ {
+ perror ("/dev/sequencer");
+ exit (-1);
+ }
+
+ if (info.synth_type == SYNTH_TYPE_SAMPLE
+ && info.synth_subtype == SAMPLE_TYPE_GUS)
+ gus_dev = i;
+ }
+
+ if (gus_dev == -1)
+ {
+ fprintf (stderr, "Error: Gravis Ultrasound not detected\n");
+ exit (-1);
+ }
+
+ printf("Gravis UltraSound device = %d\n", gus_dev);
+
+ /*
+ * Get type of the Patch Manager interface of the GUS device
+ */
+
+ patch_access(PM_GET_DEVTYPE, mgr);
+ printf("Patch manager type: %d\n", mgr.parm1);
+
+ if (mgr.parm1 != PMTYPE_WAVE)
+ {
+ fprintf(stderr, "Hups, this program seems to be obsolete\n");
+ exit(-1);
+ }
+
+ /*
+ * The GUS driver supports up to 256 different midi program numbers but
+ * this limit can be changed before compiling the driver. The following
+ * call returns the value compiled to the driver.
+ */
+
+ patch_access(PM_GET_PGMMAP, mgr);
+ printf("Device supports %d midi programs.\n", mgr.parm1);
+
+ /*
+ * Each program can be undefined or it may have one or more patches.
+ * A patch consists of header and the waveform data. If there is more
+ * than one patch in a program, the right one is selected by checking the
+ * note number when the program is played.
+ *
+ * The following call reads an array indexed by program number. Each
+ * element defines the number of patches defined for the corresponding
+ * program.
+ */
+ printf("Loaded programs:\n");
+
+ for (i=0;i<mgr.parm1;i++)
+ if (mgr.data.data8[i])
+ {
+ printf("%03d: %2d patches\n", i, mgr.data.data8[i]);
+
+ /*
+ * Next get the magic keys of the patches associated with this program.
+ * This key can be used to access the patc data.
+ */
+ mgr2.parm1=i;
+ patch_access(PM_GET_PGM_PATCHES, mgr2);
+ for (j = 0;j<mgr2.parm1;j++)
+ {
+ printf("\tPatch %d: %3d ", j, mgr2.data.data32[j]);
+
+ /*
+ * The last step is to read the patch header (without wave data).
+ * The header is returned in the mgr3.data. The field parm1 returns
+ * address of the wave data in tge GUS DRAM. Parm2 returns
+ * size of the struct patch_info in the kernel.
+ *
+ * There is also the PM_SET_PATCH call which allows modification of the
+ * header data. The only limitation is that the sample len cannot be
+ * increased.
+ */
+ mgr3.parm1 = mgr2.data.data32[j];
+ patch_access(PM_GET_PATCH, mgr3);
+ patch = (struct patch_info *)&mgr3.data; /* Pointer to the patch hdr */
+
+ printf("DRAM ptr = %7d, sample len =%6d bytes.\n",
+ mgr3.parm1, patch->len);
+
+ }
+ }
+
+ i = gus_dev;
+
+ if (ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &i)==-1) exit(-1);
+ printf("%d bytes of DRAM available for wave data\n", i);
+
+
+ exit(0);
+}
diff --git a/sys/i386/isa/sound/gustest/gusload.c b/sys/i386/isa/sound/gustest/gusload.c
new file mode 100644
index 0000000..1e04a7d
--- /dev/null
+++ b/sys/i386/isa/sound/gustest/gusload.c
@@ -0,0 +1,349 @@
+/*
+ * patutil.c - A sample program which loads patches to the Gravis
+ * Ultrasound
+ *
+ */
+
+#ifndef PATCH_PATH
+#define PATCH_PATH "/D/ultrasnd/midi"
+#endif
+
+#include <stdio.h>
+#include <machine/ultrasound.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "gmidi.h"
+
+struct pat_header
+ {
+ char magic[12];
+ char version[10];
+ char description[60];
+ unsigned char instruments;
+ char voices;
+ char channels;
+ unsigned short nr_waveforms;
+ unsigned short master_volume;
+ unsigned long data_size;
+ };
+
+struct sample_header
+ {
+ char name[7];
+ unsigned char fractions;
+ long len;
+ long loop_start;
+ long loop_end;
+ unsigned short base_freq;
+ long low_note;
+ long high_note;
+ long base_note;
+ short detune;
+ unsigned char panning;
+
+ unsigned char envelope_rate[6];
+ unsigned char envelope_offset[6];
+
+ unsigned char tremolo_sweep;
+ unsigned char tremolo_rate;
+ unsigned char tremolo_depth;
+
+ unsigned char vibrato_sweep;
+ unsigned char vibrato_rate;
+ unsigned char vibrato_depth;
+
+ char modes;
+
+ short scale_frequency;
+ unsigned short scale_factor;
+ };
+
+#define GUS_DEV gus_dev
+
+SEQ_DEFINEBUF (2048);
+
+int seqfd;
+
+int gus_dev = -1;
+
+struct patch_info *patch;
+
+/*
+ * The function seqbuf_dump() must always be provided
+ */
+
+void
+seqbuf_dump ()
+{
+ if (_seqbufptr)
+ if (write (seqfd, _seqbuf, _seqbufptr) == -1)
+ {
+ perror ("write /dev/sequencer");
+ exit (-1);
+ }
+ _seqbufptr = 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int i, n, patfd, pgm, print_only = 0;
+ struct synth_info info;
+ struct pat_header header;
+ struct sample_header sample;
+ char buf[256];
+ char name[256];
+ long offset;
+
+ if ((seqfd = open ("/dev/sequencer", O_WRONLY, 0)) == -1)
+ {
+ perror ("/dev/sequencer");
+ exit (-1);
+ }
+
+ if (ioctl (seqfd, SNDCTL_SEQ_NRSYNTHS, &n) == -1)
+ {
+ perror ("/dev/sequencer");
+ exit (-1);
+ }
+
+
+ for (i = 0; i < n; i++)
+ {
+ info.device = i;
+
+ if (ioctl (seqfd, SNDCTL_SYNTH_INFO, &info) == -1)
+ {
+ perror ("/dev/sequencer");
+ exit (-1);
+ }
+
+ if (info.synth_type == SYNTH_TYPE_SAMPLE
+ && info.synth_subtype == SAMPLE_TYPE_GUS)
+ gus_dev = i;
+ }
+
+ if (gus_dev == -1)
+ {
+ fprintf (stderr, "Error: Gravis Ultrasound not detected\n");
+ exit (-1);
+ }
+
+ if (argc == 2)
+ {
+ if (!strcmp (argv[1], "reset"))
+ if (ioctl (seqfd, SNDCTL_SEQ_RESETSAMPLES, &gus_dev) == -1)
+ perror ("Sample reset");
+ exit (0);
+ }
+
+ if (argc != 3)
+ {
+ fprintf (stderr, "Usage: %s pgm# patchfile\n", argv[0]);
+ fprintf (stderr, " or : %s pgm# GM\n", argv[0]);
+ fprintf (stderr, " or : %s pgm# -l\n", argv[0]);
+ fprintf (stderr, " or : %s reset\n", argv[0]);
+ fprintf (stderr, " or : %s -l patchfile\n", argv[0]);
+ exit (-1);
+ }
+
+ pgm = atoi (argv[1]);
+ strcpy (name, argv[2]);
+
+ if (strcmp (name, "GM") == 0 || strcmp(name, "-l")==0)
+ {
+ if (strcmp (name, "-l") == 0) print_only = 1;
+ if (pgm < 0 || pgm > 127)
+ {
+ fprintf (stderr, "pgm# must be between 0 and 127\n");
+ exit (-1);
+ }
+
+ sprintf (name, PATCH_PATH "/%s.pat", patch_names[pgm]);
+
+ if (!print_only)
+ fprintf (stderr, "Loading program %d from %s\n", pgm, name);
+ }
+ else if (strcmp (argv[1], "-l") == 0)
+ print_only = 1;
+
+ if ((patfd = open (name, O_RDONLY, 0)) == -1)
+ {
+ perror (name);
+ exit (-1);
+ }
+
+ if (read (patfd, buf, 0xef) != 0xef)
+ {
+ fprintf (stderr, "%s: Short file\n", name);
+ exit (-1);
+ }
+
+ memcpy ((char *) &header, buf, sizeof (header));
+
+ if (strncmp (header.magic, "GF1PATCH110", 12))
+ {
+ fprintf (stderr, "%s: Not a patch file\n", name);
+ exit (-1);
+ }
+
+ if (strncmp (header.version, "ID#000002", 10))
+ {
+ fprintf (stderr, "%s: Incompatible patch file version\n", name);
+ exit (-1);
+ }
+
+ header.nr_waveforms = *(unsigned short *) &buf[85];
+ header.master_volume = *(unsigned short *) &buf[87];
+
+ if (print_only)
+ {
+ printf ("Patch file: %s contains %d samples\n\n", name, header.nr_waveforms);
+ printf ("Master volume: %d\n", header.master_volume);
+ }
+
+ offset = 0xef;
+
+ for (i = 0; i < header.nr_waveforms; i++)
+ {
+ if (lseek (patfd, offset, 0) == -1)
+ {
+ perror (name);
+ exit (-1);
+ }
+
+ if (read (patfd, &buf, sizeof (sample)) != sizeof (sample))
+ {
+ fprintf (stderr, "%s: Short file\n", name);
+ exit (-1);
+ }
+
+ memcpy ((char *) &sample, buf, sizeof (sample));
+
+ /*
+ * Since some fields of the patch record are not 32bit aligned, we must
+ * handle them specially.
+ */
+ sample.low_note = *(long *) &buf[22];
+ sample.high_note = *(long *) &buf[26];
+ sample.base_note = *(long *) &buf[30];
+ sample.detune = *(short *) &buf[34];
+ sample.panning = (unsigned char) buf[36];
+
+ memcpy (sample.envelope_rate, &buf[37], 6);
+ memcpy (sample.envelope_offset, &buf[43], 6);
+
+ sample.tremolo_sweep = (unsigned char) buf[49];
+ sample.tremolo_rate = (unsigned char) buf[50];
+ sample.tremolo_depth = (unsigned char) buf[51];
+
+ sample.vibrato_sweep = (unsigned char) buf[52];
+ sample.vibrato_rate = (unsigned char) buf[53];
+ sample.vibrato_depth = (unsigned char) buf[54];
+ sample.modes = (unsigned char) buf[55];
+ sample.scale_frequency = *(short *) &buf[56];
+ sample.scale_factor = *(unsigned short *) &buf[58];
+
+ if (print_only)
+ {
+ printf("\nSample: %03d / %s\n", i, sample.name);
+ printf ("Len: %d, Loop start: %d, Loop end: %d\n", sample.len, sample.loop_start, sample.loop_end);
+ printf ("Flags: ");
+ if (sample.modes & WAVE_16_BITS)
+ printf ("16 bit ");
+ if (sample.modes & WAVE_UNSIGNED)
+ printf ("unsigned ");
+ if (sample.modes & WAVE_LOOP_BACK)
+ printf("reverse ");
+ if (sample.modes & WAVE_BIDIR_LOOP)
+ printf("bidir ");
+ if (sample.modes & WAVE_LOOPING)
+ printf ("looping "); else printf("one_shot" );
+ if (sample.modes & WAVE_SUSTAIN_ON)
+ printf ("sustain ");
+ if (sample.modes & WAVE_ENVELOPES)
+ printf ("enveloped ");
+ printf ("\n");
+
+ if (sample.modes & WAVE_ENVELOPES)
+ {
+ int i;
+
+ printf ("Envelope info: ");
+ for (i = 0; i < 6; i++)
+ {
+ printf ("%d/%d ", sample.envelope_rate[i],
+ sample.envelope_offset[i]);
+ }
+ printf ("\n");
+ }
+
+ printf("Tremolo: sweep=%d, rate=%d, depth=%d\n",
+ sample.tremolo_sweep,
+ sample.tremolo_rate,
+ sample.tremolo_depth);
+
+ printf("Vibrato: sweep=%d, rate=%d, depth=%d\n",
+ sample.vibrato_sweep,
+ sample.vibrato_rate,
+ sample.vibrato_depth);
+ }
+
+ offset = offset + 96;
+ patch = (struct patch_info *) malloc (sizeof (*patch) + sample.len);
+
+ patch->key = GUS_PATCH;
+ patch->device_no = GUS_DEV;
+ patch->instr_no = pgm;
+ patch->mode = sample.modes | WAVE_TREMOLO |
+ WAVE_VIBRATO | WAVE_SCALE;
+ patch->len = sample.len;
+ patch->loop_start = sample.loop_start;
+ patch->loop_end = sample.loop_end;
+ patch->base_note = sample.base_note;
+ patch->high_note = sample.high_note;
+ patch->low_note = sample.low_note;
+ patch->base_freq = sample.base_freq;
+ patch->detuning = sample.detune;
+ patch->panning = (sample.panning - 7) * 16;
+
+ memcpy (patch->env_rate, sample.envelope_rate, 6);
+ memcpy (patch->env_offset, sample.envelope_offset, 6);
+
+ patch->tremolo_sweep = sample.tremolo_sweep;
+ patch->tremolo_rate = sample.tremolo_rate;
+ patch->tremolo_depth = sample.tremolo_depth;
+
+ patch->vibrato_sweep = sample.vibrato_sweep;
+ patch->vibrato_rate = sample.vibrato_rate;
+ patch->vibrato_depth = sample.vibrato_depth;
+
+ patch->scale_frequency = sample.scale_frequency;
+ patch->scale_factor = sample.scale_factor;
+
+ patch->volume = header.master_volume;
+
+ if (lseek (patfd, offset, 0) == -1)
+ {
+ perror (name);
+ exit (-1);
+ }
+
+ if (!print_only)
+ {
+ if (read (patfd, patch->data, sample.len) != sample.len)
+ {
+ fprintf (stderr, "%s: Short file\n", name);
+ exit (-1);
+ }
+
+ SEQ_WRPATCH (patch, sizeof (*patch) + sample.len);
+ }
+
+ offset = offset + sample.len;
+ }
+
+ exit (0);
+}
diff --git a/sys/i386/isa/sound/gustest/midithru.c b/sys/i386/isa/sound/gustest/midithru.c
new file mode 100644
index 0000000..78f58c1
--- /dev/null
+++ b/sys/i386/isa/sound/gustest/midithru.c
@@ -0,0 +1,325 @@
+#include <stdio.h>
+#include <machine/soundcard.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/errno.h>
+
+SEQ_DEFINEBUF (2048);
+SEQ_PM_DEFINES;
+
+int seqfd, dev = 0;
+unsigned char buf[100];
+int bufp;
+
+/* LRU list for free operators */
+
+unsigned char free_list[256];
+int fhead=0, ftail=0, flen=0;
+
+/* LRU list for still playing notes */
+
+unsigned char note_list[256];
+int nhead=0, ntail=0, nlen=0;
+unsigned char oper_note[32];
+
+int pgm = 0;
+int num_voices;
+int bender = 0; /* Initially off */
+
+void
+seqbuf_dump ()
+{
+ if (_seqbufptr)
+ if (write (seqfd, _seqbuf, _seqbufptr) == -1)
+ {
+ perror ("write /dev/sequencer");
+ exit (-1);
+ }
+ _seqbufptr = 0;
+}
+
+void
+stop_note(int note, int velocity)
+{
+ int i, op;
+
+ op=255;
+
+ for (i=0;i<num_voices && op==255;i++)
+ {
+ if (oper_note[i]== note) op=i;
+ }
+
+ if (op==255)
+ {
+ fprintf(stderr, "Note %d off, note not started\n", note);
+ fprintf(stderr, "%d, %d\n", flen, nlen);
+ return; /* Has already been killed ??? */
+ }
+
+ SEQ_STOP_NOTE(dev, op, note, velocity);
+ SEQ_DUMPBUF();
+
+ oper_note[op] = 255;
+
+ free_list[ftail]=op;
+ flen++;
+ ftail = (ftail+1) % num_voices;
+
+ for (i=0;i<16;i++)
+ if (note_list[i] == op) note_list[i] = 255;
+
+ while (nlen && note_list[nhead] == 255)
+ {
+ nlen--;
+ /* printf("Remove from note queue %d, len %d\n", nhead, nlen); */
+ nhead = (nhead+1) % 256;
+ }
+}
+
+void
+kill_one_note()
+{
+ int oldest;
+
+ if (!nlen) {fprintf(stderr, "Free list empty but no notes playing\n");return;} /* No notes playing */
+
+ oldest = note_list[nhead];
+ nlen--;
+ nhead = (nhead+1) % 256;
+
+ fprintf(stderr, "Killing oper %d, note %d\n", oldest, oper_note[oldest]);
+
+ if (oldest== 255) return; /* Was already stopped. Why? */
+
+ stop_note(oper_note[oldest], 127);
+}
+
+void
+start_note(int note, int velocity)
+{
+ int free;
+
+ if (!flen) kill_one_note();
+
+ if (!flen) {printf("** no free voices\n");return;} /* Panic??? */
+
+ free = free_list[fhead];
+ flen--;
+ fhead = (fhead+1) % num_voices;
+
+ note_list[ntail] = free;
+
+ if (nlen>255)
+ {
+#if 0
+ fprintf(stderr, "Note list overflow %d, %d, %d\n",
+ nlen, nhead, ntail);
+#endif
+ nlen=0; /* Overflow -> hard reset */
+ }
+ nlen++;
+ ntail = (ntail+1) % 256;
+
+ oper_note[free] = note;
+
+ SEQ_SET_PATCH(dev, free, pgm);
+ SEQ_PITCHBEND(dev, free, bender);
+ SEQ_START_NOTE(dev, free, note, velocity);
+ SEQ_DUMPBUF();
+}
+
+void
+channel_pressure(int ch, int pressure)
+{
+ int i;
+
+ for (i=0;i<num_voices;i++)
+ {
+ if (oper_note[i] != 255)
+ {
+#if 1
+ SEQ_CHN_PRESSURE(dev, i, pressure);
+#else
+ SEQ_EXPRESSION(dev, i, pressure);
+#endif
+ SEQ_DUMPBUF();
+ }
+ }
+}
+
+void
+pitch_bender(int ch, int value)
+{
+ int i;
+
+ value -= 8192;
+
+ bender = value;
+
+ for (i=0;i<num_voices;i++)
+ {
+ if (oper_note[i] != 255)
+ {
+ bender = value;
+ SEQ_PITCHBEND(dev, i, value);
+ SEQ_DUMPBUF();
+ }
+ }
+}
+
+void
+do_buf()
+{
+ int ch = buf[0] & 0x0f;
+ int value;
+
+ switch (buf[0] & 0xf0)
+ {
+ case 0x90: /* Note on */
+ if (bufp < 3) break;
+ /* printf("Note on %d %d %d\n", ch, buf[1], buf[2]); */
+ if (buf[2])
+ start_note(buf[1], buf[2]);
+ else
+ stop_note(buf[1], buf[2]);
+ bufp=1;
+ break;
+
+ case 0xb0: /* Control change */
+ if (bufp < 3) break;
+ /* printf("Control change %d %d %d\n", ch, buf[1], buf[2]); */
+ bufp=1;
+ break;
+
+ case 0x80: /* Note off */
+ if (bufp < 3) break;
+ /* printf("Note off %d %d %d\n", ch, buf[1], buf[2]); */
+ stop_note(buf[1], buf[2]);
+ bufp=1;
+ break;
+
+ case 0xe0: /* Pitch bender */
+ if (bufp < 3) break;
+ value = ((buf[2] & 0x7f) << 7) | (buf[1] & 0x7f);
+ /* printf("Pitch bender %d %d\n", ch, value >> 7); */
+ pitch_bender(ch, value);
+ bufp=1;
+ break;
+
+ case 0xc0: /* Pgm change */
+ if (bufp < 2) break;
+ /* printf("Pgm change %d %d\n", ch, buf[1]); */
+ pgm = buf[1];
+ if (PM_LOAD_PATCH(dev, 0, pgm) < 0)
+ if (errno != ESRCH) /* No such process */
+ perror("PM_LOAD_PATCH");
+ bufp=0;
+ break;
+
+ case 0xd0: /* Channel pressure */
+ if (bufp < 2) break;
+ /* printf("Channel pressure %d %d\n", ch, buf[1]); */
+ channel_pressure(ch, buf[1]);
+ bufp=1;
+ break;
+
+ default:
+ bufp=0;
+ }
+}
+
+int
+main (int argc, char *argv[])
+{
+ int i, n, max_voice = 999;
+
+ struct synth_info info;
+
+ unsigned char ev[4], *p;
+
+ if (argc >= 2) dev = atoi(argv[1]);
+
+ for (i=0;i<16;i++) oper_note[i] = 255;
+
+ if ((seqfd = open ("/dev/sequencer", O_RDWR, 0)) == -1)
+ {
+ perror ("open /dev/sequencer");
+ exit (-1);
+ }
+
+ if (argc >= 3)
+ {
+ int d = dev;
+ ioctl(seqfd, SNDCTL_FM_4OP_ENABLE, &d);
+ }
+
+ info.device = dev;
+
+ if (ioctl(seqfd, SNDCTL_SYNTH_INFO, &info)==-1)
+ {
+ perror ("info /dev/sequencer");
+ exit (-1);
+ }
+
+ num_voices = info.nr_voices;
+ if (num_voices>max_voice)num_voices = max_voice;
+ fprintf(stderr, "Output to synth device %d (%s)\n", dev, info.name);
+ fprintf(stderr, "%d voices available\n", num_voices);
+
+ for (i=0;i<num_voices;i++)
+ {
+ flen++;
+ free_list[fhead] = i;
+ fhead = (fhead+1) % num_voices;
+ }
+
+ bufp = 0;
+ if (PM_LOAD_PATCH(dev, 0, 0) < 0) /* Load the default instrument */
+ if (errno != ESRCH) /* No such process */
+ perror("PM_LOAD_PATCH");
+
+ while (1)
+ {
+ if ((n = read (seqfd, ev, sizeof (ev))) == -1)
+ {
+ perror ("read /dev/sequencer");
+ exit (-1);
+ }
+
+ for (i = 0; i <= (n / 4); i++)
+ {
+ p = &ev[i * 4];
+
+ if (p[0] == SEQ_MIDIPUTC && p[2] == 0 /* Midi if# == 0 */)
+ {
+/* printf("%02x ", p[1]);fflush(stdout); */
+ if (p[1] & 0x80) /* Status */
+ {
+ if (bufp)
+ do_buf ();
+ buf[0] = p[1];
+ bufp = 1;
+ }
+ else if (bufp)
+ {
+ buf[bufp++] = p[1];
+ if ((buf[0] & 0xf0) == 0x90 || (buf[0] & 0xf0) == 0x80 || (buf[0] & 0xf0) == 0xb0 ||
+ (buf[0] & 0xf0) == 0xe0)
+ {
+ if (bufp == 3)
+ do_buf ();
+ }
+ else
+ if ((buf[0] & 0xf0) == 0xc0 || (buf[0] & 0xf0) == 0xd0)
+ {
+ if (bufp == 2) do_buf();
+ }
+ }
+ }
+ }
+ }
+
+ exit (0);
+}
diff --git a/sys/i386/isa/sound/gustest/pmtest.c b/sys/i386/isa/sound/gustest/pmtest.c
new file mode 100644
index 0000000..05b5b9e
--- /dev/null
+++ b/sys/i386/isa/sound/gustest/pmtest.c
@@ -0,0 +1,409 @@
+/*
+ * CAUTION! This program is just an incompletely implemented version
+ * of the patch manager daemon for GUS. Using this program
+ * with the driver version 1.99.9 will hang your system
+ * completely (sooner or later).
+ *
+ * This program is for information only. The final
+ * implementation of the patch manager will not be
+ * compatible with this one.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <machine/ultrasound.h>
+#include <strings.h>
+#include <sys/errno.h>
+#include "gmidi.h"
+
+#ifndef PATCH_PATH
+#define PATCH_PATH "/D/ultrasnd/midi"
+#endif
+
+char loadmap[256] =
+{0}; /* 1 if the patch is already loaded */
+
+struct pat_header
+ {
+ char magic[12];
+ char version[10];
+ char description[60];
+ unsigned char instruments;
+ char voices;
+ char channels;
+ unsigned short nr_waveforms;
+ unsigned short master_volume;
+ unsigned long data_size;
+ };
+
+struct sample_header
+ {
+ char name[7];
+ unsigned char fractions;
+ long len;
+ long loop_start;
+ long loop_end;
+ unsigned short base_freq;
+ long low_note;
+ long high_note;
+ long base_note;
+ short detune;
+ unsigned char panning;
+
+ unsigned char envelope_rate[6];
+ unsigned char envelope_offset[6];
+
+ unsigned char tremolo_sweep;
+ unsigned char tremolo_rate;
+ unsigned char tremolo_depth;
+
+ unsigned char vibrato_sweep;
+ unsigned char vibrato_rate;
+ unsigned char vibrato_depth;
+
+ char modes;
+
+ short scale_frequency;
+ unsigned short scale_factor;
+ };
+int seqfd = 0, gus_dev = -1;
+
+struct patch_info *patch;
+
+int
+do_load_patch (struct patmgr_info *rec)
+{
+ int i, patfd, pgm, print_only = 0;
+ struct pat_header header;
+ struct sample_header sample;
+ char buf[256];
+ char name[256];
+ long offset;
+
+ pgm = rec->data.data8[0];
+
+ if (loadmap[pgm])
+ return 0; /* Already loaded */
+
+ sprintf (name, PATCH_PATH "/%s.pat", patch_names[pgm]);
+
+ if ((patfd = open (name, O_RDONLY, 0)) == -1)
+ {
+ perror (name);
+ return errno;
+ }
+
+ if (read (patfd, buf, 0xef) != 0xef)
+ {
+ fprintf (stderr, "%s: Short file\n", name);
+ return EIO;
+ }
+
+ memcpy ((char *) &header, buf, sizeof (header));
+
+ if (strncmp (header.magic, "GF1PATCH110", 12))
+ {
+ fprintf (stderr, "%s: Not a patch file\n", name);
+ return EINVAL;
+ }
+
+ if (strncmp (header.version, "ID#000002", 10))
+ {
+ fprintf (stderr, "%s: Incompatible patch file version\n", name);
+ return EINVAL;
+ }
+
+ header.nr_waveforms = *(unsigned short *) &buf[85];
+ header.master_volume = *(unsigned short *) &buf[87];
+
+ printf ("GUS: Loading: %s\n", name);
+
+ offset = 0xef;
+
+ for (i = 0; i < header.nr_waveforms; i++)
+ {
+ if (lseek (patfd, offset, 0) == -1)
+ {
+ perror (name);
+ return errno;
+ }
+
+ if (read (patfd, &buf, sizeof (sample)) != sizeof (sample))
+ {
+ fprintf (stderr, "%s: Short file\n", name);
+ return EIO;
+ }
+
+ memcpy ((char *) &sample, buf, sizeof (sample));
+
+ /*
+ * Since some fields of the patch record are not 32bit aligned, we must
+ * handle them specially.
+ */
+ sample.low_note = *(long *) &buf[22];
+ sample.high_note = *(long *) &buf[26];
+ sample.base_note = *(long *) &buf[30];
+ sample.detune = *(short *) &buf[34];
+ sample.panning = (unsigned char) buf[36];
+
+ memcpy (sample.envelope_rate, &buf[37], 6);
+ memcpy (sample.envelope_offset, &buf[43], 6);
+
+ sample.tremolo_sweep = (unsigned char) buf[49];
+ sample.tremolo_rate = (unsigned char) buf[50];
+ sample.tremolo_depth = (unsigned char) buf[51];
+
+ sample.vibrato_sweep = (unsigned char) buf[52];
+ sample.vibrato_rate = (unsigned char) buf[53];
+ sample.vibrato_depth = (unsigned char) buf[54];
+ sample.modes = (unsigned char) buf[55];
+ sample.scale_frequency = *(short *) &buf[56];
+ sample.scale_factor = *(unsigned short *) &buf[58];
+
+ if (print_only)
+ {
+ printf ("\nSample: %03d / %s\n", i, sample.name);
+ printf ("Len: %d, Loop start: %d, Loop end: %d\n", sample.len, sample.loop_start, sample.loop_end);
+ printf ("Flags: ");
+ if (sample.modes & WAVE_16_BITS)
+ printf ("16 bit ");
+ if (sample.modes & WAVE_UNSIGNED)
+ printf ("unsigned ");
+ if (sample.modes & WAVE_LOOP_BACK)
+ printf ("reverse ");
+ if (sample.modes & WAVE_BIDIR_LOOP)
+ printf ("bidir ");
+ if (sample.modes & WAVE_LOOPING)
+ printf ("looping ");
+ else
+ printf ("one_shot");
+ if (sample.modes & WAVE_SUSTAIN_ON)
+ printf ("sustain ");
+ if (sample.modes & WAVE_ENVELOPES)
+ printf ("enveloped ");
+ printf ("\n");
+
+ if (sample.modes & WAVE_ENVELOPES)
+ {
+ int i;
+
+ printf ("Envelope info: ");
+ for (i = 0; i < 6; i++)
+ {
+ printf ("%d/%d ", sample.envelope_rate[i],
+ sample.envelope_offset[i]);
+ }
+ printf ("\n");
+ }
+
+ printf ("Tremolo: sweep=%d, rate=%d, depth=%d\n",
+ sample.tremolo_sweep,
+ sample.tremolo_rate,
+ sample.tremolo_depth);
+
+ printf ("Vibrato: sweep=%d, rate=%d, depth=%d\n",
+ sample.vibrato_sweep,
+ sample.vibrato_rate,
+ sample.vibrato_depth);
+ }
+
+ offset = offset + 96;
+ patch = (struct patch_info *) malloc (sizeof (*patch) + sample.len);
+
+ patch->key = GUS_PATCH;
+ patch->device_no = gus_dev;
+ patch->instr_no = pgm;
+ patch->mode = sample.modes | WAVE_TREMOLO |
+ WAVE_VIBRATO | WAVE_SCALE;
+ patch->len = sample.len;
+ patch->loop_start = sample.loop_start;
+ patch->loop_end = sample.loop_end;
+ patch->base_note = sample.base_note;
+ patch->high_note = sample.high_note;
+ patch->low_note = sample.low_note;
+ patch->base_freq = sample.base_freq;
+ patch->detuning = sample.detune;
+ patch->panning = (sample.panning - 7) * 16;
+
+ memcpy (patch->env_rate, sample.envelope_rate, 6);
+ memcpy (patch->env_offset, sample.envelope_offset, 6);
+
+ patch->tremolo_sweep = sample.tremolo_sweep;
+ patch->tremolo_rate = sample.tremolo_rate;
+ patch->tremolo_depth = sample.tremolo_depth;
+
+ patch->vibrato_sweep = sample.vibrato_sweep;
+ patch->vibrato_rate = sample.vibrato_rate;
+ patch->vibrato_depth = sample.vibrato_depth;
+
+ patch->scale_frequency = sample.scale_frequency;
+ patch->scale_factor = sample.scale_factor;
+
+ patch->volume = header.master_volume;
+
+ if (lseek (patfd, offset, 0) == -1)
+ {
+ perror (name);
+ return errno;
+ }
+
+ if (!print_only)
+ {
+ if (read (patfd, patch->data, sample.len) != sample.len)
+ {
+ fprintf (stderr, "%s: Short file\n", name);
+ return EIO;
+ }
+
+ if (write (seqfd, patch, sizeof (*patch) + sample.len) == -1)
+ {
+ perror ("/dev/pmgr0");
+ return errno;
+ }
+ }
+
+ offset = offset + sample.len;
+ }
+
+ loadmap[pgm] = 1;
+ return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+ struct patmgr_info inf;
+ int err, i, n;
+ struct synth_info info;
+
+ if ((seqfd = open ("/dev/patmgr0", O_RDWR, 0)) == -1)
+ {
+ fprintf (stderr, "Cannot open\n");
+ perror ("/dev/patmgr0");
+ exit (-1);
+ }
+
+ if (ioctl (seqfd, SNDCTL_SEQ_NRSYNTHS, &n) == -1)
+ {
+ perror ("NRSYNTH: /dev/patmgr0");
+ exit (-1);
+ }
+
+ for (i = 0; i < n; i++)
+ {
+ info.device = i;
+
+ if (ioctl (seqfd, SNDCTL_SYNTH_INFO, &info) == -1)
+ {
+ perror ("SYNTH_INFO: /dev/patmgr0");
+ exit (-1);
+ }
+
+ if (info.synth_type == SYNTH_TYPE_SAMPLE
+ && info.synth_subtype == SAMPLE_TYPE_GUS)
+ gus_dev = i;
+ }
+
+ if (gus_dev == -1)
+ {
+ fprintf (stderr, "Error: Gravis Ultrasound not detected\n");
+ exit (-1);
+ }
+
+ if (ioctl (seqfd, SNDCTL_SEQ_RESETSAMPLES, &gus_dev) == -1)
+ perror ("Sample reset");
+
+ for (i = 0; i < 256; i++)
+ loadmap[i] = 0;
+
+ while (1)
+ {
+ if (read (seqfd, (char *) &inf, sizeof (inf)) != sizeof (inf))
+ {
+ perror ("Read");
+ exit (-1);
+ }
+
+ if (inf.key == PM_K_EVENT)
+ switch (inf.command)
+ {
+ case PM_E_OPENED:
+ printf ("Opened\n");
+ break;
+
+ case PM_E_CLOSED:
+ printf ("Closed\n");
+ if (ioctl (seqfd, SNDCTL_SEQ_RESETSAMPLES, &gus_dev) == -1)
+ perror ("Sample reset");
+ for (i = 0; i < 256; i++)
+ loadmap[i] = 0;
+ break;
+
+ case PM_E_PATCH_RESET:
+ printf ("Patch reset called\n");
+ for (i = 0; i < 256; i++)
+ loadmap[i] = 0;
+ break;
+
+ case PM_E_PATCH_LOADED:
+ printf ("Patch loaded by client\n");
+ break;
+
+ default:
+ printf ("Unknown event %d\n", inf.command);
+ inf.key = PM_ERROR;
+ inf.parm1 = EINVAL;
+ }
+ else if (inf.key == PM_K_COMMAND)
+ switch (inf.command)
+ {
+ case _PM_LOAD_PATCH:
+ if ((err = do_load_patch (&inf)))
+ if (err == ENOSPC)
+ {
+ if (ioctl (seqfd, SNDCTL_SEQ_RESETSAMPLES, &gus_dev) == -1)
+ {
+ perror ("Sample reset");
+ return errno;
+ }
+
+ for (i = 0; i < 256; i++)
+ loadmap[i] = 0;
+ err = do_load_patch (&inf);
+ }
+
+ if (err)
+ {
+ inf.key = PM_ERROR;
+ inf.parm1 = err;
+ printf("Error = %d\n", err);
+ }
+ else
+ {
+ inf.key = PM_K_COMMAND;
+ inf.parm1 = 0;
+ }
+ break;
+
+ default:
+ printf ("Unknown command %d\n", inf.command);
+ inf.key = PM_ERROR;
+ inf.parm1 = EINVAL;
+ }
+ else
+ {
+ printf ("Unknown event %d/%d\n", inf.key, inf.command);
+ inf.key = PM_ERROR;
+ inf.parm1 = EINVAL;
+ }
+
+ if (write (seqfd, (char *) &inf, sizeof (inf)) != sizeof (inf))
+ {
+ perror ("write");
+ exit (-1);
+ }
+ }
+
+ exit (0);
+}
diff --git a/sys/i386/isa/sound/ics2101.c b/sys/i386/isa/sound/ics2101.c
new file mode 100644
index 0000000..0e54c60
--- /dev/null
+++ b/sys/i386/isa/sound/ics2101.c
@@ -0,0 +1,265 @@
+/*
+ * sound/ics2101.c
+ *
+ * Driver for the ICS2101 mixer of GUS v3.7.
+ *
+ * Copyright by Hannu Savolainen 1994
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
+
+#ifdef __FreeBSD__
+#include <machine/ultrasound.h>
+#else
+#include "ultrasound.h"
+#endif
+#include "gus_hw.h"
+
+#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \
+ SOUND_MASK_SYNTH| \
+ SOUND_MASK_CD | SOUND_MASK_VOLUME)
+
+extern int gus_base;
+static int volumes[ICS_MIXDEVS];
+static int left_fix[ICS_MIXDEVS] =
+{1, 1, 1, 2, 1, 2};
+static int right_fix[ICS_MIXDEVS] =
+{2, 2, 2, 1, 2, 1};
+
+static int
+scale_vol(int vol)
+{
+#if 1
+/*
+ * Experimental volume scaling by Risto Kankkunen.
+ * This should give smoother volume response than just
+ * a plain multiplication.
+ */
+ int e;
+
+ if (vol < 0)
+ vol = 0;
+ if (vol > 100)
+ vol = 100;
+ vol = (31 * vol + 50) / 100;
+ e = 0;
+ if (vol) {
+ while (vol < 16) {
+ vol <<= 1;
+ e--;
+ }
+ vol -= 16;
+ e += 7;
+ }
+ return ((e << 4) + vol);
+#else
+ return ((vol*127)+50)/100;
+#endif
+}
+
+static void
+write_mix (int dev, int chn, int vol)
+{
+ int *selector;
+ unsigned long flags;
+ int ctrl_addr = dev << 3;
+ int attn_addr = dev << 3;
+
+ vol=scale_vol(vol);
+
+ if (chn == CHN_LEFT)
+ {
+ selector = left_fix;
+ ctrl_addr |= 0x00;
+ attn_addr |= 0x02;
+ }
+ else
+ {
+ selector = right_fix;
+ ctrl_addr |= 0x01;
+ attn_addr |= 0x03;
+ }
+
+ DISABLE_INTR (flags);
+ OUTB (ctrl_addr, u_MixSelect);
+ OUTB (selector[dev], u_MixData);
+ OUTB (attn_addr, u_MixSelect);
+ OUTB ((unsigned char) vol, u_MixData);
+ RESTORE_INTR (flags);
+}
+
+static int
+set_volumes (int dev, int vol)
+{
+ int left = vol & 0x00ff;
+ int right = (vol >> 8) & 0x00ff;
+
+ if (left < 0)
+ left = 0;
+ if (left > 100)
+ left = 100;
+ if (right < 0)
+ right = 0;
+ if (right > 100)
+ right = 100;
+
+ write_mix (dev, CHN_LEFT, left);
+ write_mix (dev, CHN_RIGHT, right);
+
+ vol = left + (right << 8);
+ volumes[dev] = vol;
+ return vol;
+}
+
+static int
+ics2101_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
+{
+ if (((cmd >> 8) & 0xff) == 'M')
+ {
+ if (cmd & IOC_IN)
+ switch (cmd & 0xff)
+ {
+ case SOUND_MIXER_RECSRC:
+ return gus_default_mixer_ioctl (dev, cmd, arg);
+ break;
+
+ case SOUND_MIXER_MIC:
+ return IOCTL_OUT (arg, set_volumes (DEV_MIC, IOCTL_IN (arg)));
+ break;
+
+ case SOUND_MIXER_CD:
+ return IOCTL_OUT (arg, set_volumes (DEV_CD, IOCTL_IN (arg)));
+ break;
+
+ case SOUND_MIXER_LINE:
+ return IOCTL_OUT (arg, set_volumes (DEV_LINE, IOCTL_IN (arg)));
+ break;
+
+ case SOUND_MIXER_SYNTH:
+ return IOCTL_OUT (arg, set_volumes (DEV_GF1, IOCTL_IN (arg)));
+ break;
+
+ case SOUND_MIXER_VOLUME:
+ return IOCTL_OUT (arg, set_volumes (DEV_VOL, IOCTL_IN (arg)));
+ break;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+ else
+ switch (cmd & 0xff) /*
+ * Return parameters
+ */
+ {
+
+ case SOUND_MIXER_RECSRC:
+ return gus_default_mixer_ioctl (dev, cmd, arg);
+ break;
+
+ case SOUND_MIXER_DEVMASK:
+ return IOCTL_OUT (arg, MIX_DEVS);
+ break;
+
+ case SOUND_MIXER_STEREODEVS:
+ return IOCTL_OUT (arg, SOUND_MASK_LINE | SOUND_MASK_CD |
+ SOUND_MASK_SYNTH | SOUND_MASK_VOLUME|
+ SOUND_MASK_MIC);
+ break;
+
+ case SOUND_MIXER_RECMASK:
+ return IOCTL_OUT (arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
+ break;
+
+ case SOUND_MIXER_CAPS:
+ return IOCTL_OUT (arg, 0);
+ break;
+
+ case SOUND_MIXER_MIC:
+ return IOCTL_OUT (arg, volumes[DEV_MIC]);
+ break;
+
+ case SOUND_MIXER_LINE:
+ return IOCTL_OUT (arg, volumes[DEV_LINE]);
+ break;
+
+ case SOUND_MIXER_CD:
+ return IOCTL_OUT (arg, volumes[DEV_CD]);
+ break;
+
+ case SOUND_MIXER_VOLUME:
+ return IOCTL_OUT (arg, volumes[DEV_VOL]);
+ break;
+
+ case SOUND_MIXER_SYNTH:
+ return IOCTL_OUT (arg, volumes[DEV_GF1]);
+ break;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+ }
+
+ return RET_ERROR (EINVAL);
+}
+
+static struct mixer_operations ics2101_mixer_operations =
+{
+ ics2101_mixer_ioctl
+};
+
+long
+ics2101_mixer_init (long mem_start)
+{
+ int i;
+
+ if (num_mixers < MAX_MIXER_DEV)
+ {
+ mixer_devs[num_mixers++] = &ics2101_mixer_operations;
+
+ /*
+ * Some GUS v3.7 cards had some channels flipped. Disable
+ * the flipping feature if the model id is other than 5.
+ */
+
+ if (INB (u_MixSelect) != 5)
+ {
+ for (i = 0; i < ICS_MIXDEVS; i++)
+ left_fix[i] = 1;
+ for (i = 0; i < ICS_MIXDEVS; i++)
+ right_fix[i] = 2;
+ }
+
+ set_volumes (DEV_GF1, 0x5a5a);
+ set_volumes (DEV_CD, 0x5a5a);
+ set_volumes (DEV_MIC, 0x0000);
+ set_volumes (DEV_LINE, 0x5a5a);
+ set_volumes (DEV_VOL, 0x5a5a);
+ set_volumes (DEV_UNUSED, 0x0000);
+ }
+
+ return mem_start;
+}
+
+#endif
diff --git a/sys/i386/isa/sound/local.h b/sys/i386/isa/sound/local.h
new file mode 100644
index 0000000..36092e3
--- /dev/null
+++ b/sys/i386/isa/sound/local.h
@@ -0,0 +1,15 @@
+/* for FreeBSD */
+#include "snd.h"
+
+#if NSND > 0
+#define KERNEL_SOUNDCARD
+#endif
+
+#define DSP_BUFFSIZE 65536
+#define NO_AUTODMA /* still */
+#define SELECTED_SOUND_OPTIONS 0xffffffff
+#define SOUND_VERSION_STRING "2.5"
+#define SOUND_CONFIG_DATE "Sat Apr 23 07:45:17 MSD 1994"
+#define SOUND_CONFIG_BY "ache"
+#define SOUND_CONFIG_HOST "dream.demos.su"
+#define SOUND_CONFIG_DOMAIN ""
diff --git a/sys/i386/isa/sound/midi.c b/sys/i386/isa/sound/midi.c
new file mode 100644
index 0000000..6ea51b0
--- /dev/null
+++ b/sys/i386/isa/sound/midi.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright by UWM - comments to soft-eng@cs.uwm.edu
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#define _MIDI_TABLE_C_
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+#ifndef EXCLUDE_CHIP_MIDI
+
+
+static int generic_midi_busy[MAX_MIDI_DEV];
+
+long
+CMIDI_init (long mem_start)
+{
+
+ int i;
+ int n = num_midi_drivers;
+
+ /*
+ * int n = sizeof (midi_supported) / sizeof( struct generic_midi_info );
+ */
+ for (i = 0; i < n; i++)
+ {
+ if (midi_supported[i].attach (mem_start))
+ {
+ printk ("MIDI: Successfully attached %s\n", midi_supported[i].name);
+ }
+
+ }
+ return (mem_start);
+}
+
+
+int
+CMIDI_open (int dev, struct fileinfo *file)
+{
+
+ int mode, err, retval;
+
+ dev = dev >> 4;
+
+ mode = file->mode & O_ACCMODE;
+
+
+ if (generic_midi_busy[dev])
+ return (RET_ERROR (EBUSY));
+
+
+ if (dev >= num_generic_midis)
+ {
+ printk (" MIDI device %d not installed.\n", dev);
+ return (ENXIO);
+ }
+
+ if (!generic_midi_devs[dev])
+ {
+ printk (" MIDI device %d not initialized\n", dev);
+ return (ENXIO);
+ }
+
+ /* If all good and healthy, go ahead and issue call! */
+
+
+ retval = generic_midi_devs[dev]->open (dev, mode);
+
+ /* If everything ok, set device as busy */
+
+ if (retval >= 0)
+ generic_midi_busy[dev] = 1;
+
+ return (retval);
+
+}
+
+int
+CMIDI_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+
+ int retval;
+
+ dev = dev >> 4;
+
+ if (dev >= num_generic_midis)
+ {
+ printk (" MIDI device %d not installed.\n", dev);
+ return (ENXIO);
+ }
+
+ /*
+ * Make double sure of healthiness -- doubt Need we check this again??
+ *
+ */
+
+ if (!generic_midi_devs[dev])
+ {
+ printk (" MIDI device %d not initialized\n", dev);
+ return (ENXIO);
+ }
+
+ /* If all good and healthy, go ahead and issue call! */
+
+
+ retval = generic_midi_devs[dev]->write (dev, buf);
+
+ return (retval);
+
+}
+
+int
+CMIDI_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ int retval;
+
+ dev = dev >> 4;
+
+ if (dev >= num_generic_midis)
+ {
+ printk (" MIDI device %d not installed.\n", dev);
+ return (ENXIO);
+ }
+
+ /*
+ * Make double sure of healthiness -- doubt Need we check this again??
+ *
+ */
+
+ if (!generic_midi_devs[dev])
+ {
+ printk (" MIDI device %d not initialized\n", dev);
+ return (ENXIO);
+ }
+
+ /* If all good and healthy, go ahead and issue call! */
+
+
+ retval = generic_midi_devs[dev]->read (dev, buf);
+
+ return (retval);
+
+}
+
+int
+CMIDI_close (int dev, struct fileinfo *file)
+{
+
+ int retval;
+
+ dev = dev >> 4;
+
+ if (dev >= num_generic_midis)
+ {
+ printk (" MIDI device %d not installed.\n", dev);
+ return (ENXIO);
+ }
+
+ /*
+ * Make double sure of healthiness -- doubt Need we check this again??
+ *
+ */
+
+ if (!generic_midi_devs[dev])
+ {
+ printk (" MIDI device %d not initialized\n", dev);
+ return (ENXIO);
+ }
+
+ /* If all good and healthy, go ahead and issue call! */
+
+
+ generic_midi_devs[dev]->close (dev);
+
+ generic_midi_busy[dev] = 0; /* Free the device */
+
+ return (0);
+
+}
+
+#endif
+
+#endif
diff --git a/sys/i386/isa/sound/midibuf.c b/sys/i386/isa/sound/midibuf.c
new file mode 100644
index 0000000..7dadb3f
--- /dev/null
+++ b/sys/i386/isa/sound/midibuf.c
@@ -0,0 +1,123 @@
+/*
+ * sound/midibuf.c
+ *
+ * Device file manager for /dev/midi
+ *
+ * NOTE! This part of the driver is currently just a stub.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MPU401)
+
+#if 0
+#include "midiioctl.h"
+#include "midivar.h"
+#endif
+
+static int midibuf_busy = 0;
+
+int
+MIDIbuf_open (int dev, struct fileinfo *file)
+{
+ int mode, err;
+
+ dev = dev >> 4;
+ mode = file->mode & O_ACCMODE;
+
+ if (midibuf_busy)
+ return RET_ERROR (EBUSY);
+
+ if (!mpu401_dev)
+ {
+ printk ("Midi: MPU-401 compatible Midi interface not present\n");
+ return RET_ERROR (ENXIO);
+ }
+
+ if ((err = midi_devs[mpu401_dev]->open (mpu401_dev, mode, NULL, NULL)) < 0)
+ return err;
+
+ midibuf_busy = 1;
+
+ return RET_ERROR (ENXIO);
+}
+
+void
+MIDIbuf_release (int dev, struct fileinfo *file)
+{
+ int mode;
+
+ dev = dev >> 4;
+ mode = file->mode & O_ACCMODE;
+
+ midi_devs[mpu401_dev]->close (mpu401_dev);
+ midibuf_busy = 0;
+}
+
+int
+MIDIbuf_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+
+ dev = dev >> 4;
+
+ return count;
+}
+
+
+int
+MIDIbuf_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ dev = dev >> 4;
+
+ return RET_ERROR (EIO);
+}
+
+int
+MIDIbuf_ioctl (int dev, struct fileinfo *file,
+ unsigned int cmd, unsigned int arg)
+{
+ dev = dev >> 4;
+
+ switch (cmd)
+ {
+
+ default:
+ return midi_devs[0]->ioctl (dev, cmd, arg);
+ }
+}
+
+void
+MIDIbuf_bytes_received (int dev, unsigned char *buf, int count)
+{
+}
+
+long
+MIDIbuf_init (long mem_start)
+{
+ return mem_start;
+}
+
+#endif
diff --git a/sys/i386/isa/sound/mpu401.c b/sys/i386/isa/sound/mpu401.c
new file mode 100644
index 0000000..38ba486
--- /dev/null
+++ b/sys/i386/isa/sound/mpu401.c
@@ -0,0 +1,282 @@
+/*
+ * sound/mpu401.c
+ *
+ * The low level driver for Roland MPU-401 compatible Midi cards.
+ *
+ * This version supports just the DUMB UART mode.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
+
+#define DATAPORT (mpu401_base)/* MPU-401 Data I/O Port on IBM */
+#define COMDPORT (mpu401_base+1) /* MPU-401 Command Port on IBM */
+#define STATPORT (mpu401_base+1) /* MPU-401 Status Port on IBM */
+
+#define mpu401_status() INB(STATPORT)
+#define input_avail() (!(mpu401_status()&INPUT_AVAIL))
+#define output_ready() (!(mpu401_status()&OUTPUT_READY))
+#define mpu401_cmd(cmd) OUTB(cmd, COMDPORT)
+#define mpu401_read() INB(DATAPORT)
+#define mpu401_write(byte) OUTB(byte, DATAPORT)
+
+#define OUTPUT_READY 0x40 /* Mask for Data Read Redy Bit */
+#define INPUT_AVAIL 0x80 /* Mask for Data Send Ready Bit */
+#define MPU_ACK 0xFE /* MPU-401 Acknowledge Response */
+#define MPU_RESET 0xFF /* MPU-401 Total Reset Command */
+#define UART_MODE_ON 0x3F /* MPU-401 "Dumb UART Mode" */
+
+static int mpu401_opened = 0;
+static int mpu401_base = 0x330;
+static int mpu401_irq;
+static int mpu401_detected = 0;
+static int my_dev;
+
+static int reset_mpu401 (void);
+static void (*midi_input_intr) (int dev, unsigned char data);
+
+void
+mpuintr (int unit)
+{
+ while (input_avail ())
+ {
+ unsigned char c = mpu401_read ();
+
+ if (mpu401_opened & OPEN_READ)
+ midi_input_intr (my_dev, c);
+ }
+}
+
+static int
+mpu401_open (int dev, int mode,
+ void (*input) (int dev, unsigned char data),
+ void (*output) (int dev)
+)
+{
+ if (mpu401_opened)
+ {
+ printk ("MPU-401: Midi busy\n");
+ return RET_ERROR (EBUSY);
+ }
+
+ mpuintr (0);
+
+ midi_input_intr = input;
+ mpu401_opened = mode;
+
+ return 0;
+}
+
+static void
+mpu401_close (int dev)
+{
+ mpu401_opened = 0;
+}
+
+static int
+mpu401_out (int dev, unsigned char midi_byte)
+{
+ int timeout;
+ unsigned long flags;
+
+ /*
+ * Test for input since pending input seems to block the output.
+ */
+
+ DISABLE_INTR (flags);
+
+ if (input_avail ())
+ mpuintr (0);
+
+ RESTORE_INTR (flags);
+
+ /*
+ * Sometimes it takes about 13000 loops before the output becomes ready
+ * (After reset). Normally it takes just about 10 loops.
+ */
+
+ for (timeout = 30000; timeout > 0 && !output_ready (); timeout--); /* Wait */
+
+ if (!output_ready ())
+ {
+ printk ("MPU-401: Timeout\n");
+ return 0;
+ }
+
+ mpu401_write (midi_byte);
+ return 1;
+}
+
+static int
+mpu401_command (int dev, unsigned char midi_byte)
+{
+ return 1;
+}
+
+static int
+mpu401_start_read (int dev)
+{
+ return 0;
+}
+
+static int
+mpu401_end_read (int dev)
+{
+ return 0;
+}
+
+static int
+mpu401_ioctl (int dev, unsigned cmd, unsigned arg)
+{
+ return RET_ERROR (EINVAL);
+}
+
+static void
+mpu401_kick (int dev)
+{
+}
+
+static int
+mpu401_buffer_status (int dev)
+{
+ return 0; /* No data in buffers */
+}
+
+static struct midi_operations mpu401_operations =
+{
+ {"MPU-401", 0, 0, SNDCARD_MPU401},
+ mpu401_open,
+ mpu401_close,
+ mpu401_ioctl,
+ mpu401_out,
+ mpu401_start_read,
+ mpu401_end_read,
+ mpu401_kick,
+ mpu401_command,
+ mpu401_buffer_status
+};
+
+
+long
+attach_mpu401 (long mem_start, struct address_info *hw_config)
+{
+ int ok, timeout;
+ unsigned long flags;
+
+ mpu401_base = hw_config->io_base;
+ mpu401_irq = hw_config->irq;
+
+ if (!mpu401_detected)
+ return RET_ERROR (EIO);
+
+ DISABLE_INTR (flags);
+ for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* Wait */
+ mpu401_cmd (UART_MODE_ON);
+
+ ok = 0;
+ for (timeout = 50000; timeout > 0 && !ok; timeout--)
+ if (input_avail ())
+ if (mpu401_read () == MPU_ACK)
+ ok = 1;
+
+ RESTORE_INTR (flags);
+
+#ifdef __FreeBSD__
+ printk ("snd5: <Roland MPU-401>");
+#else
+ printk (" <Roland MPU-401>");
+#endif
+
+ my_dev = num_midis;
+ mpu401_dev = num_midis;
+ midi_devs[num_midis++] = &mpu401_operations;
+ return mem_start;
+}
+
+static int
+reset_mpu401 (void)
+{
+ unsigned long flags;
+ int ok, timeout, n;
+
+ /*
+ * Send the RESET command. Try again if no success at the first time.
+ */
+
+ ok = 0;
+
+ DISABLE_INTR (flags);
+
+ for (n = 0; n < 2 && !ok; n++)
+ {
+ for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* Wait */
+ mpu401_cmd (MPU_RESET); /* Send MPU-401 RESET Command */
+
+ /*
+ * Wait at least 25 msec. This method is not accurate so let's make the
+ * loop bit longer. Cannot sleep since this is called during boot.
+ */
+
+ for (timeout = 50000; timeout > 0 && !ok; timeout--)
+ if (input_avail ())
+ if (mpu401_read () == MPU_ACK)
+ ok = 1;
+
+ }
+
+ mpu401_opened = 0;
+ if (ok)
+ mpuintr (0); /* Flush input before enabling interrupts */
+
+ RESTORE_INTR (flags);
+
+ return ok;
+}
+
+
+int
+probe_mpu401 (struct address_info *hw_config)
+{
+ int ok = 0;
+
+ mpu401_base = hw_config->io_base;
+ mpu401_irq = hw_config->irq;
+
+ if (snd_set_irq_handler (mpu401_irq, mpuintr) < 0)
+ return 0;
+
+ ok = reset_mpu401 ();
+
+ mpu401_detected = ok;
+ return ok;
+}
+
+#endif
+
+#endif
diff --git a/sys/i386/isa/sound/opl3.c b/sys/i386/isa/sound/opl3.c
new file mode 100644
index 0000000..6e3dcca
--- /dev/null
+++ b/sys/i386/isa/sound/opl3.c
@@ -0,0 +1,960 @@
+/*
+ * sound/opl3.c
+ *
+ * A low level driver for Yamaha YM3812 and OPL-3 -chips
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/* Major improvements to the FM handling 30AUG92 by Rob Hooft, */
+/* hooft@chem.ruu.nl */
+
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_YM3812)
+
+#include "opl3.h"
+
+#define MAX_VOICE 18
+#define OFFS_4OP 11 /* Definitions for the operators OP3 and OP4
+ * begin here */
+
+static int opl3_enabled = 0;
+static int left_address = 0x388, right_address = 0x388, both_address = 0;
+
+static int nr_voices = 9;
+static int logical_voices[MAX_VOICE] =
+{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
+
+struct voice_info
+ {
+ unsigned char keyon_byte;
+ long bender;
+ long bender_range;
+ unsigned long orig_freq;
+ unsigned long current_freq;
+ int mode;
+ };
+
+static struct voice_info voices[MAX_VOICE];
+
+static struct sbi_instrument *instrmap;
+static struct sbi_instrument *active_instrument[MAX_VOICE] =
+{NULL};
+
+static struct synth_info fm_info =
+{"AdLib", 0, SYNTH_TYPE_FM, FM_TYPE_ADLIB, 0, 9, 0, SBFM_MAXINSTR, 0};
+
+static int already_initialized = 0;
+
+static int opl3_ok = 0;
+static int opl3_busy = 0;
+static int fm_model = 0; /* 0=no fm, 1=mono, 2=SB Pro 1, 3=SB Pro 2 */
+
+static int store_instr (int instr_no, struct sbi_instrument *instr);
+static void freq_to_fnum (int freq, int *block, int *fnum);
+static void opl3_command (int io_addr, unsigned int addr, unsigned int val);
+static int opl3_kill_note (int dev, int voice, int velocity);
+static unsigned char connection_mask = 0x00;
+
+void
+enable_opl3_mode (int left, int right, int both)
+{
+ if (opl3_enabled)
+ return;
+
+ opl3_enabled = 1;
+ left_address = left;
+ right_address = right;
+ both_address = both;
+ fm_info.capabilities = SYNTH_CAP_OPL3;
+ fm_info.synth_subtype = FM_TYPE_OPL3;
+}
+
+static void
+enter_4op_mode (void)
+{
+ int i;
+ static int voices_4op[MAX_VOICE] =
+ {0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17};
+
+ connection_mask = 0x3f;
+ opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x3f); /* Select all 4-OP
+ * voices */
+ for (i = 0; i < 3; i++)
+ physical_voices[i].voice_mode = 4;
+ for (i = 3; i < 6; i++)
+ physical_voices[i].voice_mode = 0;
+
+ for (i = 9; i < 12; i++)
+ physical_voices[i].voice_mode = 4;
+ for (i = 12; i < 15; i++)
+ physical_voices[i].voice_mode = 0;
+
+ for (i = 0; i < 12; i++)
+ logical_voices[i] = voices_4op[i];
+ nr_voices = 12;
+}
+
+static int
+opl3_ioctl (int dev,
+ unsigned int cmd, unsigned int arg)
+{
+ switch (cmd)
+ {
+
+ case SNDCTL_FM_LOAD_INSTR:
+ {
+ struct sbi_instrument ins;
+
+ IOCTL_FROM_USER ((char *) &ins, (char *) arg, 0, sizeof (ins));
+
+ if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR)
+ {
+ printk ("FM Error: Invalid instrument number %d\n", ins.channel);
+ return RET_ERROR (EINVAL);
+ }
+
+ pmgr_inform (dev, PM_E_PATCH_LOADED, ins.channel, 0, 0, 0);
+ return store_instr (ins.channel, &ins);
+ }
+ break;
+
+ case SNDCTL_SYNTH_INFO:
+ fm_info.nr_voices = (nr_voices == 12) ? 6 : nr_voices;
+
+ IOCTL_TO_USER ((char *) arg, 0, &fm_info, sizeof (fm_info));
+ return 0;
+ break;
+
+ case SNDCTL_SYNTH_MEMAVL:
+ return 0x7fffffff;
+ break;
+
+ case SNDCTL_FM_4OP_ENABLE:
+ if (opl3_enabled)
+ enter_4op_mode ();
+ return 0;
+ break;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+
+}
+
+int
+opl3_detect (int ioaddr)
+{
+ /*
+ * This function returns 1 if the FM chicp is present at the given I/O port
+ * The detection algorithm plays with the timer built in the FM chip and
+ * looks for a change in the status register.
+ *
+ * Note! The timers of the FM chip are not connected to AdLib (and compatible)
+ * boards.
+ *
+ * Note2! The chip is initialized if detected.
+ */
+
+ unsigned char stat1, stat2;
+ int i;
+
+ if (already_initialized)
+ {
+ return 0; /* Do avoid duplicate initializations */
+ }
+
+ if (opl3_enabled)
+ ioaddr = left_address;
+
+ opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); /* Reset timers 1 and 2 */
+ opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); /* Reset the IRQ of FM
+ * chicp */
+
+ stat1 = INB (ioaddr); /* Read status register */
+
+ if ((stat1 & 0xE0) != 0x00)
+ {
+ return 0; /* Should be 0x00 */
+ }
+
+ opl3_command (ioaddr, TIMER1_REGISTER, 0xff); /* Set timer 1 to 0xff */
+ opl3_command (ioaddr, TIMER_CONTROL_REGISTER,
+ TIMER2_MASK | TIMER1_START); /* Unmask and start timer 1 */
+
+ /*
+ * Now we have to delay at least 80 msec
+ */
+
+ for (i = 0; i < 50; i++)
+ tenmicrosec (); /* To be sure */
+
+ stat2 = INB (ioaddr); /* Read status after timers have expired */
+
+ /* Stop the timers */
+
+ opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); /* Reset timers 1 and 2 */
+ opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); /* Reset the IRQ of FM
+ * chicp */
+
+ if ((stat2 & 0xE0) != 0xc0)
+ {
+ return 0; /* There is no YM3812 */
+ }
+
+ /* There is a FM chicp in this address. Now set some default values. */
+
+ for (i = 0; i < 9; i++)
+ opl3_command (ioaddr, KEYON_BLOCK + i, 0); /* Note off */
+
+ opl3_command (ioaddr, TEST_REGISTER, ENABLE_WAVE_SELECT);
+ opl3_command (ioaddr, PERCUSSION_REGISTER, 0x00); /* Melodic mode. */
+
+ return 1;
+}
+
+static int
+opl3_kill_note (int dev, int voice, int velocity)
+{
+ struct physical_voice_info *map;
+
+ if (voice < 0 || voice >= nr_voices)
+ return 0;
+
+ map = &physical_voices[logical_voices[voice]];
+
+ DEB (printk ("Kill note %d\n", voice));
+
+ if (map->voice_mode == 0)
+ return 0;
+
+ opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, voices[voice].keyon_byte & ~0x20);
+
+ voices[voice].keyon_byte = 0;
+ voices[voice].bender = 0;
+ voices[voice].bender_range = 200; /* 200 cents = 2 semitones */
+ voices[voice].orig_freq = 0;
+ voices[voice].current_freq = 0;
+ voices[voice].mode = 0;
+
+ return 0;
+}
+
+#define HIHAT 0
+#define CYMBAL 1
+#define TOMTOM 2
+#define SNARE 3
+#define BDRUM 4
+#define UNDEFINED TOMTOM
+#define DEFAULT TOMTOM
+
+static int
+store_instr (int instr_no, struct sbi_instrument *instr)
+{
+
+ if (instr->key != FM_PATCH && (instr->key != OPL3_PATCH || !opl3_enabled))
+ printk ("FM warning: Invalid patch format field (key) 0x%x\n", instr->key);
+ memcpy ((char *) &(instrmap[instr_no]), (char *) instr, sizeof (*instr));
+
+ return 0;
+}
+
+static int
+opl3_set_instr (int dev, int voice, int instr_no)
+{
+ if (voice < 0 || voice >= nr_voices)
+ return 0;
+
+ if (instr_no < 0 || instr_no >= SBFM_MAXINSTR)
+ return 0;
+
+ active_instrument[voice] = &instrmap[instr_no];
+ return 0;
+}
+
+/*
+ * The next table looks magical, but it certainly is not. Its values have
+ * been calculated as table[i]=8*log(i/64)/log(2) with an obvious exception
+ * for i=0. This log-table converts a linear volume-scaling (0..127) to a
+ * logarithmic scaling as present in the FM-synthesizer chips. so : Volume
+ * 64 = 0 db = relative volume 0 and: Volume 32 = -6 db = relative
+ * volume -8 it was implemented as a table because it is only 128 bytes and
+ * it saves a lot of log() calculations. (RH)
+ */
+char fm_volume_table[128] =
+{-64, -48, -40, -35, -32, -29, -27, -26, /* 0 - 7 */
+ -24, -23, -21, -20, -19, -18, -18, -17, /* 8 - 15 */
+ -16, -15, -15, -14, -13, -13, -12, -12, /* 16 - 23 */
+ -11, -11, -10, -10, -10, -9, -9, -8, /* 24 - 31 */
+ -8, -8, -7, -7, -7, -6, -6, -6,/* 32 - 39 */
+ -5, -5, -5, -5, -4, -4, -4, -4,/* 40 - 47 */
+ -3, -3, -3, -3, -2, -2, -2, -2,/* 48 - 55 */
+ -2, -1, -1, -1, -1, 0, 0, 0, /* 56 - 63 */
+ 0, 0, 0, 1, 1, 1, 1, 1, /* 64 - 71 */
+ 1, 2, 2, 2, 2, 2, 2, 2, /* 72 - 79 */
+ 3, 3, 3, 3, 3, 3, 3, 4, /* 80 - 87 */
+ 4, 4, 4, 4, 4, 4, 4, 5, /* 88 - 95 */
+ 5, 5, 5, 5, 5, 5, 5, 5, /* 96 - 103 */
+ 6, 6, 6, 6, 6, 6, 6, 6, /* 104 - 111 */
+ 6, 7, 7, 7, 7, 7, 7, 7, /* 112 - 119 */
+ 7, 7, 7, 8, 8, 8, 8, 8}; /* 120 - 127 */
+
+static void
+calc_vol (unsigned char *regbyte, int volume)
+{
+ int level = (~*regbyte & 0x3f);
+
+ if (level)
+ level += fm_volume_table[volume];
+
+ if (level > 0x3f)
+ level = 0x3f;
+ if (level < 0)
+ level = 0;
+
+ *regbyte = (*regbyte & 0xc0) | (~level & 0x3f);
+}
+
+static void
+set_voice_volume (int voice, int volume)
+{
+ unsigned char vol1, vol2, vol3, vol4;
+ struct sbi_instrument *instr;
+ struct physical_voice_info *map;
+
+ if (voice < 0 || voice >= nr_voices)
+ return;
+
+ map = &physical_voices[logical_voices[voice]];
+
+ instr = active_instrument[voice];
+
+ if (!instr)
+ instr = &instrmap[0];
+
+ if (instr->channel < 0)
+ return;
+
+ if (voices[voice].mode == 0)
+ return;
+
+ if (voices[voice].mode == 2)
+ { /* 2 OP voice */
+
+ vol1 = instr->operators[2];
+ vol2 = instr->operators[3];
+
+ if ((instr->operators[10] & 0x01))
+ { /* Additive synthesis */
+ calc_vol (&vol1, volume);
+ calc_vol (&vol2, volume);
+ }
+ else
+ { /* FM synthesis */
+ calc_vol (&vol2, volume);
+ }
+
+ opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); /* Modulator volume */
+ opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2); /* Carrier volume */
+ }
+ else
+ { /* 4 OP voice */
+ int connection;
+
+ vol1 = instr->operators[2];
+ vol2 = instr->operators[3];
+ vol3 = instr->operators[OFFS_4OP + 2];
+ vol4 = instr->operators[OFFS_4OP + 3];
+
+ /*
+ * The connection method for 4 OP voices is defined by the rightmost
+ * bits at the offsets 10 and 10+OFFS_4OP
+ */
+
+ connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01);
+
+ switch (connection)
+ {
+ case 0:
+ calc_vol (&vol4, volume); /* Just the OP 4 is carrier */
+ break;
+
+ case 1:
+ calc_vol (&vol2, volume);
+ calc_vol (&vol4, volume);
+ break;
+
+ case 2:
+ calc_vol (&vol1, volume);
+ calc_vol (&vol4, volume);
+ break;
+
+ case 3:
+ calc_vol (&vol1, volume);
+ calc_vol (&vol3, volume);
+ calc_vol (&vol4, volume);
+ break;
+
+ default:/* Why ?? */ ;
+ }
+
+ opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1);
+ opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2);
+ opl3_command (map->ioaddr, KSL_LEVEL + map->op[2], vol3);
+ opl3_command (map->ioaddr, KSL_LEVEL + map->op[3], vol4);
+ }
+}
+
+static int
+opl3_start_note (int dev, int voice, int note, int volume)
+{
+ unsigned char data, fpc;
+ int block, fnum, freq, voice_mode;
+ struct sbi_instrument *instr;
+ struct physical_voice_info *map;
+
+ if (voice < 0 || voice >= nr_voices)
+ return 0;
+
+ map = &physical_voices[logical_voices[voice]];
+
+ if (map->voice_mode == 0)
+ return 0;
+
+ if (note == 255) /* Just change the volume */
+ {
+ set_voice_volume (voice, volume);
+ return 0;
+ }
+
+ /* Kill previous note before playing */
+ opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], 0xff); /* Carrier volume to min */
+ opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], 0xff); /* Modulator volume to */
+
+ if (map->voice_mode == 4)
+ {
+ opl3_command (map->ioaddr, KSL_LEVEL + map->op[2], 0xff);
+ opl3_command (map->ioaddr, KSL_LEVEL + map->op[3], 0xff);
+ }
+
+ opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, 0x00); /* Note off */
+
+ instr = active_instrument[voice];
+
+ if (!instr)
+ instr = &instrmap[0];
+
+ if (instr->channel < 0)
+ {
+ printk (
+ "OPL3: Initializing voice %d with undefined instrument\n",
+ voice);
+ return 0;
+ }
+
+ if (map->voice_mode == 2 && instr->key == OPL3_PATCH)
+ return 0; /* Cannot play */
+
+ voice_mode = map->voice_mode;
+
+ if (voice_mode == 4)
+ {
+ int voice_shift;
+
+ voice_shift = (map->ioaddr == left_address) ? 0 : 3;
+ voice_shift += map->voice_num;
+
+ if (instr->key != OPL3_PATCH) /* Just 2 OP patch */
+ {
+ voice_mode = 2;
+ connection_mask &= ~(1 << voice_shift);
+ }
+ else
+ {
+ connection_mask |= (1 << voice_shift);
+ }
+
+ opl3_command (right_address, CONNECTION_SELECT_REGISTER, connection_mask);
+ }
+
+ /* Set Sound Characteristics */
+ opl3_command (map->ioaddr, AM_VIB + map->op[0], instr->operators[0]);
+ opl3_command (map->ioaddr, AM_VIB + map->op[1], instr->operators[1]);
+
+ /* Set Attack/Decay */
+ opl3_command (map->ioaddr, ATTACK_DECAY + map->op[0], instr->operators[4]);
+ opl3_command (map->ioaddr, ATTACK_DECAY + map->op[1], instr->operators[5]);
+
+ /* Set Sustain/Release */
+ opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[0], instr->operators[6]);
+ opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[1], instr->operators[7]);
+
+ /* Set Wave Select */
+ opl3_command (map->ioaddr, WAVE_SELECT + map->op[0], instr->operators[8]);
+ opl3_command (map->ioaddr, WAVE_SELECT + map->op[1], instr->operators[9]);
+
+ /* Set Feedback/Connection */
+ fpc = instr->operators[10];
+ if (!(fpc & 0x30))
+ fpc |= 0x30; /* Ensure that at least one chn is enabled */
+ opl3_command (map->ioaddr, FEEDBACK_CONNECTION + map->voice_num,
+ fpc);
+
+ /*
+ * If the voice is a 4 OP one, initialize the operators 3 and 4 also
+ */
+
+ if (voice_mode == 4)
+ {
+
+ /* Set Sound Characteristics */
+ opl3_command (map->ioaddr, AM_VIB + map->op[2], instr->operators[OFFS_4OP + 0]);
+ opl3_command (map->ioaddr, AM_VIB + map->op[3], instr->operators[OFFS_4OP + 1]);
+
+ /* Set Attack/Decay */
+ opl3_command (map->ioaddr, ATTACK_DECAY + map->op[2], instr->operators[OFFS_4OP + 4]);
+ opl3_command (map->ioaddr, ATTACK_DECAY + map->op[3], instr->operators[OFFS_4OP + 5]);
+
+ /* Set Sustain/Release */
+ opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[2], instr->operators[OFFS_4OP + 6]);
+ opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[3], instr->operators[OFFS_4OP + 7]);
+
+ /* Set Wave Select */
+ opl3_command (map->ioaddr, WAVE_SELECT + map->op[2], instr->operators[OFFS_4OP + 8]);
+ opl3_command (map->ioaddr, WAVE_SELECT + map->op[3], instr->operators[OFFS_4OP + 9]);
+
+ /* Set Feedback/Connection */
+ fpc = instr->operators[OFFS_4OP + 10];
+ if (!(fpc & 0x30))
+ fpc |= 0x30; /* Ensure that at least one chn is enabled */
+ opl3_command (map->ioaddr, FEEDBACK_CONNECTION + map->voice_num + 3, fpc);
+ }
+
+ voices[voice].mode = voice_mode;
+
+ set_voice_volume (voice, volume);
+
+ freq = voices[voice].orig_freq = note_to_freq (note) / 1000;
+
+ /*
+ * Since the pitch bender may have been set before playing the note, we
+ * have to calculate the bending now.
+ */
+
+ freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range);
+ voices[voice].current_freq = freq;
+
+ freq_to_fnum (freq, &block, &fnum);
+
+ /* Play note */
+
+ data = fnum & 0xff; /* Least significant bits of fnumber */
+ opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data);
+
+ data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3);
+ voices[voice].keyon_byte = data;
+ opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data);
+ if (voice_mode == 4)
+ opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num + 3, data);
+
+ return 0;
+}
+
+static void
+freq_to_fnum (int freq, int *block, int *fnum)
+{
+ int f, octave;
+
+ /* Converts the note frequency to block and fnum values for the FM chip */
+ /* First try to compute the block -value (octave) where the note belongs */
+
+ f = freq;
+
+ octave = 5;
+
+ if (f == 0)
+ octave = 0;
+ else if (f < 261)
+ {
+ while (f < 261)
+ {
+ octave--;
+ f <<= 1;
+ }
+ }
+ else if (f > 493)
+ {
+ while (f > 493)
+ {
+ octave++;
+ f >>= 1;
+ }
+ }
+
+ if (octave > 7)
+ octave = 7;
+
+ *fnum = freq * (1 << (20 - octave)) / 49716;
+ *block = octave;
+}
+
+static void
+opl3_command (int io_addr, unsigned int addr, unsigned int val)
+{
+ int i;
+
+ /*
+ * The original 2-OP synth requires a quite long delay after writing to a
+ * register. The OPL-3 survives with just two INBs
+ */
+
+ OUTB ((unsigned char) (addr & 0xff), io_addr); /* Select register */
+
+ if (!opl3_enabled)
+ tenmicrosec ();
+ else
+ for (i = 0; i < 2; i++)
+ INB (io_addr);
+
+ OUTB ((unsigned char) (val & 0xff), io_addr + 1); /* Write to register */
+
+ if (!opl3_enabled)
+ {
+ tenmicrosec ();
+ tenmicrosec ();
+ tenmicrosec ();
+ }
+ else
+ for (i = 0; i < 2; i++)
+ INB (io_addr);
+}
+
+static void
+opl3_reset (int dev)
+{
+ int i;
+
+ for (i = 0; i < nr_voices; i++)
+ {
+ opl3_command (physical_voices[logical_voices[i]].ioaddr,
+ KSL_LEVEL + physical_voices[logical_voices[i]].op[0], 0xff); /* OP1 volume to min */
+
+ opl3_command (physical_voices[logical_voices[i]].ioaddr,
+ KSL_LEVEL + physical_voices[logical_voices[i]].op[1], 0xff); /* OP2 volume to min */
+
+ if (physical_voices[logical_voices[i]].voice_mode == 4) /* 4 OP voice */
+ {
+ opl3_command (physical_voices[logical_voices[i]].ioaddr,
+ KSL_LEVEL + physical_voices[logical_voices[i]].op[2], 0xff); /* OP3 volume to min */
+
+ opl3_command (physical_voices[logical_voices[i]].ioaddr,
+ KSL_LEVEL + physical_voices[logical_voices[i]].op[3], 0xff); /* OP4 volume to min */
+ }
+
+ opl3_kill_note (dev, i, 64);
+ }
+
+ if (opl3_enabled)
+ {
+ nr_voices = 18;
+
+ for (i = 0; i < 18; i++)
+ logical_voices[i] = i;
+
+ for (i = 0; i < 18; i++)
+ physical_voices[i].voice_mode = 2;
+
+ }
+
+}
+
+static int
+opl3_open (int dev, int mode)
+{
+ if (!opl3_ok)
+ return RET_ERROR (ENXIO);
+ if (opl3_busy)
+ return RET_ERROR (EBUSY);
+ opl3_busy = 1;
+
+ connection_mask = 0x00; /* Just 2 OP voices */
+ if (opl3_enabled)
+ opl3_command (right_address, CONNECTION_SELECT_REGISTER, connection_mask);
+ return 0;
+}
+
+static void
+opl3_close (int dev)
+{
+ opl3_busy = 0;
+ nr_voices = opl3_enabled ? 18 : 9;
+ fm_info.nr_drums = 0;
+ fm_info.perc_mode = 0;
+
+ opl3_reset (dev);
+}
+
+static void
+opl3_hw_control (int dev, unsigned char *event)
+{
+}
+
+static int
+opl3_load_patch (int dev, int format, snd_rw_buf * addr,
+ int offs, int count, int pmgr_flag)
+{
+ struct sbi_instrument ins;
+
+ if (count < sizeof (ins))
+ {
+ printk ("FM Error: Patch record too short\n");
+ return RET_ERROR (EINVAL);
+ }
+
+ COPY_FROM_USER (&((char *) &ins)[offs], (char *) addr, offs, sizeof (ins) - offs);
+
+ if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR)
+ {
+ printk ("FM Error: Invalid instrument number %d\n", ins.channel);
+ return RET_ERROR (EINVAL);
+ }
+ ins.key = format;
+
+ return store_instr (ins.channel, &ins);
+}
+
+static void
+opl3_panning (int dev, int voice, int pressure)
+{
+}
+
+static void
+opl3_volume_method (int dev, int mode)
+{
+}
+
+#define SET_VIBRATO(cell) { \
+ tmp = instr->operators[(cell-1)+(((cell-1)/2)*OFFS_4OP)]; \
+ if (pressure > 110) \
+ tmp |= 0x40; /* Vibrato on */ \
+ opl3_command (map->ioaddr, AM_VIB + map->op[cell-1], tmp);}
+
+static void
+opl3_aftertouch (int dev, int voice, int pressure)
+{
+ int tmp;
+ struct sbi_instrument *instr;
+ struct physical_voice_info *map;
+
+ if (voice < 0 || voice >= nr_voices)
+ return;
+
+ map = &physical_voices[logical_voices[voice]];
+
+ DEB (printk ("Aftertouch %d\n", voice));
+
+ if (map->voice_mode == 0)
+ return;
+
+ /*
+ * Adjust the amount of vibrato depending the pressure
+ */
+
+ instr = active_instrument[voice];
+
+ if (!instr)
+ instr = &instrmap[0];
+
+ if (voices[voice].mode == 4)
+ {
+ int connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01);
+
+ switch (connection)
+ {
+ case 0:
+ SET_VIBRATO (4);
+ break;
+
+ case 1:
+ SET_VIBRATO (2);
+ SET_VIBRATO (4);
+ break;
+
+ case 2:
+ SET_VIBRATO (1);
+ SET_VIBRATO (4);
+ break;
+
+ case 3:
+ SET_VIBRATO (1);
+ SET_VIBRATO (3);
+ SET_VIBRATO (4);
+ break;
+
+ }
+ /* Not implemented yet */
+ }
+ else
+ {
+ SET_VIBRATO (1);
+
+ if ((instr->operators[10] & 0x01)) /* Additive synthesis */
+ SET_VIBRATO (2);
+ }
+}
+
+#undef SET_VIBRATO
+
+static void
+opl3_controller (int dev, int voice, int ctrl_num, int value)
+{
+ unsigned char data;
+ int block, fnum, freq;
+ struct physical_voice_info *map;
+
+ if (voice < 0 || voice >= nr_voices)
+ return;
+
+ map = &physical_voices[logical_voices[voice]];
+
+ if (map->voice_mode == 0)
+ return;
+
+ switch (ctrl_num)
+ {
+ case CTRL_PITCH_BENDER:
+ voices[voice].bender = value;
+ if (!value)
+ return;
+ if (!(voices[voice].keyon_byte & 0x20))
+ return; /* Not keyed on */
+
+ freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range);
+ voices[voice].current_freq = freq;
+
+ freq_to_fnum (freq, &block, &fnum);
+
+ data = fnum & 0xff; /* Least significant bits of fnumber */
+ opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data);
+
+ data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); /* KEYON|OCTAVE|MS bits
+ * of f-num */
+ voices[voice].keyon_byte = data;
+ opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data);
+ break;
+
+ case CTRL_PITCH_BENDER_RANGE:
+ voices[voice].bender_range = value;
+ break;
+ }
+}
+
+static int
+opl3_patchmgr (int dev, struct patmgr_info *rec)
+{
+ return RET_ERROR (EINVAL);
+}
+
+static struct synth_operations opl3_operations =
+{
+ &fm_info,
+ SYNTH_TYPE_FM,
+ FM_TYPE_ADLIB,
+ opl3_open,
+ opl3_close,
+ opl3_ioctl,
+ opl3_kill_note,
+ opl3_start_note,
+ opl3_set_instr,
+ opl3_reset,
+ opl3_hw_control,
+ opl3_load_patch,
+ opl3_aftertouch,
+ opl3_controller,
+ opl3_panning,
+ opl3_volume_method,
+ opl3_patchmgr
+};
+
+long
+opl3_init (long mem_start)
+{
+ int i;
+
+ PERMANENT_MALLOC (struct sbi_instrument *, instrmap,
+ SBFM_MAXINSTR * sizeof (*instrmap), mem_start);
+
+ synth_devs[num_synths++] = &opl3_operations;
+ fm_model = 0;
+ opl3_ok = 1;
+ if (opl3_enabled)
+ {
+#ifdef __FreeBSD__
+ printk ("snd1: <Yamaha OPL-3 FM>");
+#else
+ printk (" <Yamaha OPL-3 FM>");
+#endif
+ fm_model = 2;
+ nr_voices = 18;
+ fm_info.nr_drums = 0;
+ fm_info.capabilities |= SYNTH_CAP_OPL3;
+#ifndef SCO
+ strcpy (fm_info.name, "Yamaha OPL-3");
+#endif
+
+ for (i = 0; i < 18; i++)
+ if (physical_voices[i].ioaddr == USE_LEFT)
+ physical_voices[i].ioaddr = left_address;
+ else
+ physical_voices[i].ioaddr = right_address;
+
+
+ opl3_command (right_address, OPL3_MODE_REGISTER, OPL3_ENABLE); /* Enable OPL-3 mode */
+ opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x00); /* Select all 2-OP
+ * voices */
+ }
+ else
+ {
+#ifdef __FreeBSD__
+ printk ("snd1: <Yamaha 2-OP FM>");
+#else
+ printk (" <Yamaha 2-OP FM>");
+#endif
+ fm_model = 1;
+ nr_voices = 9;
+ fm_info.nr_drums = 0;
+
+ for (i = 0; i < 18; i++)
+ physical_voices[i].ioaddr = left_address;
+ };
+
+ already_initialized = 1;
+ for (i = 0; i < SBFM_MAXINSTR; i++)
+ instrmap[i].channel = -1;
+
+ return mem_start;
+}
+
+#endif
diff --git a/sys/i386/isa/sound/opl3.h b/sys/i386/isa/sound/opl3.h
new file mode 100644
index 0000000..ea7901f
--- /dev/null
+++ b/sys/i386/isa/sound/opl3.h
@@ -0,0 +1,260 @@
+/*
+ * opl3.h - Definitions of the OPL-3 registers
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * The OPL-3 mode is switched on by writing 0x01, to the offset 5
+ * of the right side.
+ *
+ * Another special register at the right side is at offset 4. It contains
+ * a bit mask defining which voices are used as 4 OP voices.
+ *
+ * The percussive mode is implemented in the left side only.
+ *
+ * With the above exeptions the both sides can be operated independently.
+ *
+ * A 4 OP voice can be created by setting the corresponding
+ * bit at offset 4 of the right side.
+ *
+ * For example setting the rightmost bit (0x01) changes the
+ * first voice on the right side to the 4 OP mode. The fourth
+ * voice is made inaccessible.
+ *
+ * If a voice is set to the 2 OP mode, it works like 2 OP modes
+ * of the original YM3812 (AdLib). In addition the voice can
+ * be connected the left, right or both stereo channels. It can
+ * even be left unconnected. This works with 4 OP voices also.
+ *
+ * The stereo connection bits are located in the FEEDBACK_CONNECTION
+ * register of the voice (0xC0-0xC8). In 4 OP voices these bits are
+ * in the second half of the voice.
+ */
+
+/*
+ * Register numbers for the global registers
+ */
+
+#define TEST_REGISTER 0x01
+#define ENABLE_WAVE_SELECT 0x20
+
+#define TIMER1_REGISTER 0x02
+#define TIMER2_REGISTER 0x03
+#define TIMER_CONTROL_REGISTER 0x04 /* Left side */
+#define IRQ_RESET 0x80
+#define TIMER1_MASK 0x40
+#define TIMER2_MASK 0x20
+#define TIMER1_START 0x01
+#define TIMER2_START 0x02
+
+#define CONNECTION_SELECT_REGISTER 0x04 /* Right side */
+#define RIGHT_4OP_0 0x01
+#define RIGHT_4OP_1 0x02
+#define RIGHT_4OP_2 0x04
+#define LEFT_4OP_0 0x08
+#define LEFT_4OP_1 0x10
+#define LEFT_4OP_2 0x20
+
+#define OPL3_MODE_REGISTER 0x05 /* Right side */
+#define OPL3_ENABLE 0x01
+
+#define KBD_SPLIT_REGISTER 0x08 /* Left side */
+#define COMPOSITE_SINE_WAVE_MODE 0x80 /* Don't use with OPL-3? */
+#define KEYBOARD_SPLIT 0x40
+
+#define PERCUSSION_REGISTER 0xbd /* Left side only */
+#define TREMOLO_DEPTH 0x80
+#define VIBRATO_DEPTH 0x40
+#define PERCUSSION_ENABLE 0x20
+#define BASSDRUM_ON 0x10
+#define SNAREDRUM_ON 0x08
+#define TOMTOM_ON 0x04
+#define CYMBAL_ON 0x02
+#define HIHAT_ON 0x01
+
+/*
+ * Offsets to the register banks for operators. To get the
+ * register number just add the operator offset to the bank offset
+ *
+ * AM/VIB/EG/KSR/Multiple (0x20 to 0x35)
+ */
+ #define AM_VIB 0x20
+ #define TREMOLO_ON 0x80
+ #define VIBRATO_ON 0x40
+ #define SUSTAIN_ON 0x20
+ #define KSR 0x10 /* Key scaling rate */
+ #define MULTIPLE_MASK 0x0f /* Frequency multiplier */
+
+ /*
+ * KSL/Total level (0x40 to 0x55)
+ */
+#define KSL_LEVEL 0x40
+#define KSL_MASK 0xc0 /* Envelope scaling bits */
+#define TOTAL_LEVEL_MASK 0x3f /* Strength (volume) of OP */
+
+/*
+ * Attack / Decay rate (0x60 to 0x75)
+ */
+#define ATTACK_DECAY 0x60
+#define ATTACK_MASK 0xf0
+#define DECAY_MASK 0x0f
+
+/*
+ * Sustain level / Release rate (0x80 to 0x95)
+ */
+#define SUSTAIN_RELEASE 0x80
+#define SUSTAIN_MASK 0xf0
+#define RELEASE_MASK 0x0f
+
+/*
+ * Wave select (0xE0 to 0xF5)
+ */
+#define WAVE_SELECT 0xe0
+
+/*
+ * Offsets to the register banks for voices. Just add to the
+ * voice number to get the register number.
+ *
+ * F-Number low bits (0xA0 to 0xA8).
+ */
+#define FNUM_LOW 0xa0
+
+/*
+ * F-number high bits / Key on / Block (octave) (0xB0 to 0xB8)
+ */
+#define KEYON_BLOCK 0xb0
+#define KEYON_BIT 0x20
+#define BLOCKNUM_MASK 0x1c
+#define FNUM_HIGH_MASK 0x03
+
+/*
+ * Feedback / Connection (0xc0 to 0xc8)
+ *
+ * These registers have two new bits when the OPL-3 mode
+ * is selected. These bits controls connecting the voice
+ * to the stereo channels. For 4 OP voices this bit is
+ * defined in the second half of the voice (add 3 to the
+ * register offset).
+ *
+ * For 4 OP voices the connection bit is used in the
+ * both halfs (gives 4 ways to connect the operators).
+ */
+#define FEEDBACK_CONNECTION 0xc0
+#define FEEDBACK_MASK 0x0e /* Valid just for 1st OP of a voice */
+#define CONNECTION_BIT 0x01
+/*
+ * In the 4 OP mode there is four possible configurations how the
+ * operators can be connected together (in 2 OP modes there is just
+ * AM or FM). The 4 OP connection mode is defined by the rightmost
+ * bit of the FEEDBACK_CONNECTION (0xC0-0xC8) on the both halfs.
+ *
+ * First half Second half Mode
+ *
+ * +---+
+ * v |
+ * 0 0 >+-1-+--2--3--4-->
+ *
+ *
+ *
+ * +---+
+ * | |
+ * 0 1 >+-1-+--2-+
+ * |->
+ * >--3----4-+
+ *
+ * +---+
+ * | |
+ * 1 0 >+-1-+-----+
+ * |->
+ * >--2--3--4-+
+ *
+ * +---+
+ * | |
+ * 1 1 >+-1-+--+
+ * |
+ * >--2--3-+->
+ * |
+ * >--4----+
+ */
+#define STEREO_BITS 0x30 /* OPL-3 only */
+#define VOICE_TO_LEFT 0x10
+#define VOICE_TO_RIGHT 0x20
+
+/*
+ * Definition table for the physical voices
+ */
+
+struct physical_voice_info {
+ unsigned char voice_num;
+ unsigned char voice_mode; /* 0=unavailable, 2=2 OP, 4=4 OP */
+ unsigned short ioaddr; /* I/O port (left or right side) */
+ unsigned char op[4]; /* Operator offsets */
+ };
+
+/*
+ * There is 18 possible 2 OP voices
+ * (9 in the left and 9 in the right).
+ * The first OP is the modulator and 2nd is the carrier.
+ *
+ * The first three voices in the both sides may be connected
+ * with another voice to a 4 OP voice. For example voice 0
+ * can be connected with voice 3. The operators of voice 3 are
+ * used as operators 3 and 4 of the new 4 OP voice.
+ * In this case the 2 OP voice number 0 is the 'first half' and
+ * voice 3 is the second.
+ */
+
+#define USE_LEFT 0
+#define USE_RIGHT 1
+
+static struct physical_voice_info physical_voices[18] =
+{
+/* No Mode Side OP1 OP2 OP3 OP4 */
+/* --------------------------------------------------- */
+ { 0, 2, USE_LEFT, {0x00, 0x03, 0x08, 0x0b}},
+ { 1, 2, USE_LEFT, {0x01, 0x04, 0x09, 0x0c}},
+ { 2, 2, USE_LEFT, {0x02, 0x05, 0x0a, 0x0d}},
+
+ { 3, 2, USE_LEFT, {0x08, 0x0b, 0x00, 0x00}},
+ { 4, 2, USE_LEFT, {0x09, 0x0c, 0x00, 0x00}},
+ { 5, 2, USE_LEFT, {0x0a, 0x0d, 0x00, 0x00}},
+
+ { 6, 2, USE_LEFT, {0x10, 0x13, 0x00, 0x00}}, /* Used by percussive voices */
+ { 7, 2, USE_LEFT, {0x11, 0x14, 0x00, 0x00}}, /* if the percussive mode */
+ { 8, 2, USE_LEFT, {0x12, 0x15, 0x00, 0x00}}, /* is selected */
+
+ { 0, 2, USE_RIGHT, {0x00, 0x03, 0x08, 0x0b}},
+ { 1, 2, USE_RIGHT, {0x01, 0x04, 0x09, 0x0c}},
+ { 2, 2, USE_RIGHT, {0x02, 0x05, 0x0a, 0x0d}},
+
+ { 3, 2, USE_RIGHT, {0x08, 0x0b, 0x00, 0x00}},
+ { 4, 2, USE_RIGHT, {0x09, 0x0c, 0x00, 0x00}},
+ { 5, 2, USE_RIGHT, {0x0a, 0x0d, 0x00, 0x00}},
+
+ { 6, 2, USE_RIGHT, {0x10, 0x13, 0x00, 0x00}},
+ { 7, 2, USE_RIGHT, {0x11, 0x14, 0x00, 0x00}},
+ { 8, 2, USE_RIGHT, {0x12, 0x15, 0x00, 0x00}}
+};
diff --git a/sys/i386/isa/sound/os.h b/sys/i386/isa/sound/os.h
new file mode 100644
index 0000000..c6b688a
--- /dev/null
+++ b/sys/i386/isa/sound/os.h
@@ -0,0 +1,319 @@
+#ifndef _OS_H_
+#define _OS_H_
+/*
+ * OS specific settings for FreeBSD
+ *
+ * Copyright by UWM - comments to soft-eng@cs.uwm.edu
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This chould be used as an example when porting the driver to a new
+ * operating systems.
+ *
+ * What you should do is to rewrite the soundcard.c and os.h (this file).
+ * You should create a new subdirectory and put these two files there.
+ * In addition you have to do a makefile.<OS>.
+ *
+ * If you have to make changes to other than these two files, please contact me
+ * before making the changes. It's possible that I have already made the
+ * change.
+ */
+
+/*
+ * Insert here the includes required by your kernel.
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "proc.h"
+#include "user.h"
+#include "conf.h"
+#include "file.h"
+#include "uio.h"
+#include "kernel.h"
+#include "syslog.h"
+#include "errno.h"
+#include "malloc.h"
+#include "buf.h"
+#include "i386/isa/isa_device.h"
+
+/*
+ * Rest of the file is compiled only if the driver is really required.
+ */
+#ifdef CONFIGURE_SOUNDCARD
+
+/*
+ * select() is currently implemented in Linux specific way. Don't enable.
+ * I don't remember what the SHORT_BANNERS means so forget it.
+ */
+
+#undef ALLOW_SELECT
+#define SHORT_BANNERS
+
+/* The soundcard.h could be in a nonstandard place so inclyde it here. */
+#include <machine/soundcard.h>
+
+/*
+ * Here is the first portability problem. Every OS has it's own way to
+ * pass a pointer to the buffer in read() and write() calls. In Linux it's
+ * just a char*. In BSD it's struct uio. This parameter is passed to
+ * all functions called from read() or write(). Since nothing can be
+ * assumed about this structure, the driver uses set of macros for
+ * accessing the user buffer.
+ *
+ * The driver reads/writes bytes in the user buffer sequentially which
+ * means that calls like uiomove() can be used.
+ *
+ * snd_rw_buf is the type which is passed to the device file specific
+ * read() and write() calls.
+ *
+ * The following macros are used to move date to and from the
+ * user buffer. These macros should be used only when the
+ * target or source parameter has snd_rw_buf type.
+ * The offs parameter is a offset relative to the beginning of
+ * the user buffer. In Linux the offset is required but for example
+ * BSD passes the offset info in the uio structure. It could be usefull
+ * if these macros verify that the offs parameter and the value in
+ * the snd_rw_buf structure are equal.
+ */
+typedef struct uio snd_rw_buf;
+
+/*
+ * Move bytes from the buffer which the application given in a
+ * write() call.
+ * offs is position relative to the beginning of the buffer in
+ * user space. The count is number of bytes to be moved.
+ */
+#define COPY_FROM_USER(target, source, offs, count) \
+ do { if (uiomove(target, count, (struct uio *)source)) { \
+ printf ("sb: Bad copyin()!\n"); \
+ } } while(0)
+/* Like COPY_FOM_USER but for writes. */
+#define COPY_TO_USER(target, offs, source, count) \
+ do { if (uiomove(source, count, (struct uio *)target)) { \
+ printf ("sb: Bad copyout()!\n"); \
+ } } while(0)
+/*
+ * The following macros are like COPY_*_USER but work just with one byte (8bit),
+ * short (16 bit) or long (32 bit) at a time.
+ * The same restrictions apply than for COPY_*_USER
+ */
+#define GET_BYTE_FROM_USER(target, addr, offs) {uiomove((char*)&(target), 1, (struct uio *)addr);}
+#define GET_SHORT_FROM_USER(target, addr, offs) {uiomove((char*)&(target), 2, (struct uio *)addr);}
+#define GET_WORD_FROM_USER(target, addr, offs) {uiomove((char*)&(target), 4, (struct uio *)addr);}
+#define PUT_WORD_TO_USER(addr, offs, data) {uiomove((char*)&(data), 4, (struct uio *)addr);}
+
+/*
+ * The way how the ioctl arguments are passed is another nonportable thing.
+ * In Linux the argument is just a pointer directly to the user segment. On
+ * 386bsd the data is already moved to the kernel space. The following
+ * macros should handle the difference.
+ */
+
+/*
+ * IOCTL_FROM_USER is used to copy a record pointed by the argument to
+ * a buffer in the kernel space. On 386bsd it can be done just by calling
+ * memcpy. With Linux a memcpy_from_fs should be called instead.
+ * Parameters of the following macros are like in the COPY_*_USER macros.
+ */
+
+/*
+ * When the ioctl argument points to a record or array (longer than 32 bits),
+ * the macros IOCTL_*_USER are used. It's assumed that the source and target
+ * parameters are direct memory addresses.
+ */
+#define IOCTL_FROM_USER(target, source, offs, count) {memcpy(target, &((source)[offs]), count);}
+#define IOCTL_TO_USER(target, offs, source, count) {memcpy(&((target)[offs]), source, count);}
+/* The following macros are used if the ioctl argument points to 32 bit int */
+#define IOCTL_IN(arg) (*(int*)arg)
+#define IOCTL_OUT(arg, ret) *(int*)arg = ret
+
+/*
+ * When the driver displays something to the console, printk() will be called.
+ * The name can be changed here.
+ */
+#define printk printf
+
+/*
+ * The following macros define an interface to the process management.
+ */
+
+struct snd_wait {
+ int mode; int aborting;
+ };
+
+/*
+ * DEFINE_WAIT_QUEUE is used where a wait queue is required. It must define
+ * a structure which can be passed as a parameter to a sleep(). The second
+ * parameter is name of a flag variable (must be defined as int).
+ */
+#define DEFINE_WAIT_QUEUE(qname, flag) static int *qname = NULL; \
+ static volatile struct snd_wait flag = {0}
+/* Like the above but defines an array of wait queues and flags */
+#define DEFINE_WAIT_QUEUES(qname, flag) static int *qname = {NULL}; \
+ static volatile struct snd_wait flag = {{0}}
+
+#define RESET_WAIT_QUEUE(q, f) {f.aborting = 0;f.mode = WK_NONE;}
+#define SET_ABORT_FLAG(q, f) f.aborting = 1
+#define TIMED_OUT(q, f) (f.mode & WK_TIMEOUT)
+#define SOMEONE_WAITING(q, f) (f.mode & WK_SLEEP)
+/*
+ * This driver handles interrupts little bit nonstandard way. The following
+ * macro is used to test if the current process has received a signal which
+ * is aborts the process. This macro is called from close() to see if the
+ * buffers should be discarded. If this kind info is not available, a constant
+ * 1 or 0 could be returned (1 should be better than 0).
+ * I'm not sure if the following is correct for FreeBSD.
+ */
+#define PROCESS_ABORTING(q, f) (f.aborting | curproc->p_sig)
+
+/*
+ * The following macro calls sleep. It should be implemented such that
+ * the process is resumed if it receives a signal. The following is propably
+ * not the way how it should be done on 386bsd.
+ * The on_what parameter is a wait_queue defined with DEFINE_WAIT_QUEUE(),
+ * and the second is a workarea parameter. The third is a timeout
+ * in ticks. Zero means no timeout.
+ */
+#define DO_SLEEP(q, f, time_limit) \
+ { \
+ int flag, chn; \
+ f.mode = WK_SLEEP; \
+ q = &chn; \
+ flag=tsleep((caddr_t)&(chn), (PRIBIO-5)|PCATCH, "sndint", time_limit); \
+ if(flag == ERESTART) f.aborting = 1;\
+ else f.aborting = 0;\
+ f.mode &= ~WK_SLEEP; \
+ }
+/* An the following wakes up a process */
+#define WAKE_UP(q, f) {f.mode = WK_WAKEUP;wakeup((caddr_t)q);}
+
+/*
+ * Timing macros. This driver assumes that there is a timer running in the
+ * kernel. The timer should return a value which is increased once at every
+ * timer tick. The macro HZ should return the number of such ticks/sec.
+ */
+
+#ifndef HZ
+extern int hz;
+#define HZ hz
+#endif
+
+/*
+ * GET_TIME() returns current value of the counter incremented at timer
+ * ticks. This can overflow, so the timeout might be real big...
+ *
+ */
+extern unsigned long get_time(void);
+#define GET_TIME() get_time()
+/*#define GET_TIME() (lbolt) */ /* Returns current time (1/HZ secs since boot) */
+
+/*
+ * The following three macros are called before and after atomic
+ * code sequences. The flags parameter has always type of unsigned long.
+ * The macro DISABLE_INTR() should ensure that all interrupts which
+ * may invoke any part of the driver (timer, soundcard interrupts) are
+ * disabled.
+ * RESTORE_INTR() should return the interrupt status back to the
+ * state when DISABLE_INTR() was called. The flags parameter is
+ * a variable which can carry 32 bits of state information between
+ * DISABLE_INTR() and RESTORE_INTR() calls.
+ */
+#define DISABLE_INTR(flags) flags = splhigh()
+#define RESTORE_INTR(flags) splx(flags)
+
+/*
+ * INB() and OUTB() should be obvious. NOTE! The order of
+ * paratemeters of OUTB() is different than on some other
+ * operating systems.
+ */
+
+#define INB inb
+/*
+ * The outb(0, 0x80) is just for slowdown. It's bit unsafe since
+ * this address could be used for something usefull.
+ */
+#define OUTB(addr, data) {outb(data, addr);outb(0, 0x80);}
+
+/* memcpy() was not defined og 386bsd. Lets define it here */
+#define memcpy(d, s, c) bcopy(s, d, c)
+
+/*
+ * When a error (such as EINVAL) is returned by a function,
+ * the following macro is used. The driver assumes that a
+ * error is signalled by returning a negative value.
+ */
+
+#define RET_ERROR(err) -(err)
+
+/*
+ KERNEL_MALLOC() allocates requested number of memory and
+ KERNEL_FREE is used to free it.
+ These macros are never called from interrupt, in addition the
+ nbytes will never be more than 4096 bytes. Generally the driver
+ will allocate memory in blocks of 4k. If the kernel has just a
+ page level memory allocation, 4K can be safely used as the size
+ (the nbytes parameter can be ignored).
+*/
+#define KERNEL_MALLOC(nbytes) malloc(nbytes, M_TEMP, M_WAITOK)
+#define KERNEL_FREE(addr) free(addr, M_TEMP)
+
+/*
+ * The macro PERMANENT_MALLOC(typecast, mem_ptr, size, linux_ptr)
+ * returns size bytes of
+ * (kernel virtual) memory which will never get freed by the driver.
+ * This macro is called only during boot. The linux_ptr is a linux specific
+ * parameter which should be ignored in other operating systems.
+ * The mem_ptr is a pointer variable where the macro assigns pointer to the
+ * memory area. The type is the type of the mem_ptr.
+ */
+#define PERMANENT_MALLOC(typecast, mem_ptr, size, linux_ptr) \
+ (mem_ptr) = (typecast)malloc((size), M_TEMP, M_WAITOK)
+
+/*
+ * The macro DEFINE_TIMER defines variables for the ACTIVATE_TIMER if
+ * required. The name is the variable/name to be used and the proc is
+ * the procedure to be called when the timer expires.
+ */
+
+#define DEFINE_TIMER(name, proc)
+
+/*
+ * The ACTIVATE_TIMER requests system to call 'proc' after 'time' ticks.
+ */
+
+#define ACTIVATE_TIMER(name, proc, time) \
+ timeout((timeout_func_t)proc, 0, time);
+/*
+ * The rest of this file is not complete yet. The functions using these
+ * macros will not work
+ */
+#define ALLOC_DMA_CHN(chn) ({ 0; })
+#define RELEASE_DMA_CHN(chn) ({ 0; })
+#define DMA_MODE_READ 0
+#define DMA_MODE_WRITE 1
+#define RELEASE_IRQ(irq_no)
+
+#endif
+#endif
diff --git a/sys/i386/isa/sound/pas.h b/sys/i386/isa/sound/pas.h
new file mode 100644
index 0000000..9902e03
--- /dev/null
+++ b/sys/i386/isa/sound/pas.h
@@ -0,0 +1,250 @@
+/* */
+/* Port addresses and bit fields for the Media Vision Pro AudioSpectrum second generation sound cards. */
+/* */
+/* Feel free to use this header file in any application you create that has support for the Media Vision */
+/* Pro AudioSpectrum second generation sound cards. Other uses prohibited without prior permission. */
+/* */
+/* - cmetz@thor.tjhsst.edu */
+/* */
+/* Notes: */
+/* */
+/* * All of these ports go into the MVD101 multimedia controller chip, which then signals the other chips to do */
+/* the actual work. Many ports like the FM ones functionally attach directly to the destination chip though */
+/* they don't actually have a direct connection. */
+/* */
+/* * The PAS2 series cards have an MVD101 multimedia controller chip, the original PAS cards don't. The original */
+/* PAS cards are pretty defunct now, so no attempt is made here to support them. */
+/* */
+/* * The PAS2 series cards are all really different at the hardware level, though the MVD101 hides some of the */
+/* incompatibilities, there still are differences that need to be accounted for. */
+/* */
+/* Card CD-ROM interface PCM chip Mixer chip FM chip */
+/* PAS Plus Sony proprietary (Crystal?) 8-bit DAC National OPL3 */
+/* PAS 16 Zilog SCSI MVA416 16-bit Codec MVA508 OPL3 */
+/* CDPC Sony proprietary Sony 16-bit Codec National OPL3 */
+/* Fusion CD 16 Sony proprietary MVA416 16-bit Codec MVA508 OPL3 */
+/* Fusion CD Sony proprietary (Crystal?) 8-bit DAC National OPL3 */
+/* */
+#define PAS_DEFAULT_BASE 0x388
+
+/* Symbolic Name Value R W Subsystem Description */
+#define SPEAKER_CONTROL 0x61 /* W PC speaker Control register */
+#define SPEAKER_CONTROL_GHOST 0x738B /* R W PC speaker Control ghost register */
+#define SPEAKER_TIMER_CONTROL 0x43 /* W PC speaker Timer control register */
+#define SPEAKER_TIMER_CONTROL_GHOST 0x778B /* R W PC speaker Timer control register ghost */
+#define SPEAKER_TIMER_DATA 0x42 /* W PC speaker Timer data register */
+#define SPEAKER_TIMER_DATA_GHOST 0x138A /* R W PC speaker Timer data register ghost */
+
+#define WARM_BOOT 0x41 /* W Control Used to detect system warm boot */
+#define WARM_BOOT_GHOST 0x7789 /* ? W Control Use to get the card to fake warm boot */
+#define MASTER_DECODE 0x9A01 /* W Control Address >> 2 of card base address */
+#define PRESCALE_DIVIDER 0xBF8A /* R W PCM Ration between Codec clock and master clock */
+#define WAIT_STATE 0xBF88 /* R W Control Four-bit bus wait-state count (~140ns ea.) */
+#define BOARD_REV_ID 0x2789 /* R Control Extended Board Revision ID */
+
+#define SYSTEM_CONFIGURATION_1 0x8388 /* R W Control */
+ #define S_C_1_PCS_ENABLE 0x01 /* R W PC speaker 1=enable, 0=disable PC speaker emulation */
+ #define S_C_1_PCM_CLOCK_SELECT 0x02 /* R W PCM 1=14.31818Mhz/12, 0=28.224Mhz master clock */
+ #define S_C_1_FM_EMULATE_CLOCK 0x04 /* R W FM 1=use 28.224Mhz/2, 0=use 14.31818Mhz clock */
+ #define S_C_1_PCS_STEREO 0x10 /* R W PC speaker 1=enable PC speaker stereo effect, 0=disable */
+ #define S_C_1_PCS_REALSOUND 0x20 /* R W PC speaker 1=enable RealSound enhancement, 0=disable */
+ #define S_C_1_FORCE_EXT_RESET 0x40 /* R W Control Force external reset */
+ #define S_C_1_FORCE_INT_RESET 0x80 /* R W Control Force internal reset */
+#define SYSTEM_CONFIGURATION_2 0x8389 /* R W Control */
+ #define S_C_2_PCM_OVERSAMPLING 0x03 /* R W PCM 00=0x, 01=2x, 10=4x, 11=reserved */
+ #define S_C_2_PCM_16_BIT 0x04 /* R W PCM 1=16-bit, 0=8-bit samples */
+#define SYSTEM_CONFIGURATION_3 0x838A /* R W Control */
+ #define S_C_3_PCM_CLOCK_SELECT 0x02 /* R W PCM 1=use 1.008Mhz clock for PCM, 0=don't */
+#define SYSTEM_CONFIGURATION_4 0x838B /* R W Control CD-ROM interface controls */
+
+#define IO_CONFIGURATION_1 0xF388 /* R W Control */
+ #define I_C_1_BOOT_RESET_ENABLE 0x80 /* R W Control 1=reset board on warm boot, 0=don't */
+#define IO_CONFIGURATION_2 0xF389 /* R W Control */
+ #define I_C_2_PCM_DMA_DISABLED 0x00 /* R W PCM PCM DMA disabled */
+#define IO_CONFIGURATION_3 0xF38A /* R W Control */
+ #define I_C_3_PCM_IRQ_DISABLED 0x00 /* R W PCM PCM IRQ disabled */
+
+#define COMPATIBILITY_ENABLE 0xF788 /* R W Control */
+ #define C_E_MPU401_ENABLE 0x01 /* R W MIDI 1=enable, 0=disable MPU401 MIDI emulation */
+ #define C_E_SB_ENABLE 0x02 /* R W PCM 1=enable, 0=disable Sound Blaster emulation */
+ #define C_E_SB_ACTIVE 0x04 /* R PCM "Sound Blaster Interrupt active" */
+ #define C_E_MPU401_ACTIVE 0x08 /* R MIDI "MPU UART mode active" */
+ #define C_E_PCM_COMPRESSION 0x10 /* R W PCM 1=enable, 0=disabled compression */
+#define EMULATION_ADDRESS 0xF789 /* R W Control */
+ #define E_A_SB_BASE 0x0f /* R W PCM bits A4-A7 for SB base port */
+ #define E_A_MPU401_BASE 0xf0 /* R W MIDI bits A4-A7 for MPU401 base port */
+#define EMULATION_CONFIGURATION 0xFB8A /* R W ***** Only valid on newer PAS2 cards (?) ***** */
+ #define E_C_MPU401_IRQ 0x07 /* R W MIDI MPU401 emulation IRQ */
+ #define E_C_SB_IRQ 0x38 /* R W PCM SB emulation IRQ */
+ #define E_C_SB_DMA 0xC0 /* R W PCM SB emulation DMA */
+
+#define OPERATION_MODE_1 0xEF8B /* R Control */
+ #define O_M_1_CDROM_TYPE 0x03 /* R CD-ROM 3=SCSI, 2=Sony, 0=no CD-ROM interface */
+ #define O_M_1_FM_TYPE 0x04 /* R FM 1=sterero, 0=mono FM chip */
+ #define O_M_1_PCM_TYPE 0x08 /* R PCM 1=16-bit Codec, 0=8-bit DAC */
+#define OPERATION_MODE_2 0xFF8B /* R Control */
+ #define O_M_2_PCS_ENABLED 0x02 /* R PC speaker PC speaker emulation 1=enabled, 0=disabled */
+ #define O_M_2_BUS_TIMING 0x10 /* R Control 1=AT bus timing, 0=XT bus timing */
+ #define O_M_2_BOARD_REVISION 0xe0 /* R Control Board revision */
+
+#define INTERRUPT_MASK 0x0B8B /* R W Control */
+ #define I_M_FM_LEFT_IRQ_ENABLE 0x01 /* R W FM Enable FM left interrupt */
+ #define I_M_FM_RIGHT_IRQ_ENABLE 0x02 /* R W FM Enable FM right interrupt */
+ #define I_M_PCM_RATE_IRQ_ENABLE 0x04 /* R W PCM Enable Sample Rate interrupt */
+ #define I_M_PCM_BUFFER_IRQ_ENABLE 0x08 /* R W PCM Enable Sample Buffer interrupt */
+ #define I_M_MIDI_IRQ_ENABLE 0x10 /* R W MIDI Enable MIDI interrupt */
+ #define I_M_BOARD_REV 0xE0 /* R Control Board revision */
+
+#define INTERRUPT_STATUS 0x0B89 /* R W Control */
+ #define I_S_FM_LEFT_IRQ 0x01 /* R W FM Left FM Interrupt Pending */
+ #define I_S_FM_RIGHT_IRQ 0x02 /* R W FM Right FM Interrupt Pending */
+ #define I_S_PCM_SAMPLE_RATE_IRQ 0x04 /* R W PCM Sample Rate Interrupt Pending */
+ #define I_S_PCM_SAMPLE_BUFFER_IRQ 0x08 /* R W PCM Sample Buffer Interrupt Pending */
+ #define I_S_MIDI_IRQ 0x10 /* R W MIDI MIDI Interrupt Pending */
+ #define I_S_PCM_CHANNEL 0x20 /* R W PCM 1=right, 0=left */
+ #define I_S_RESET_ACTIVE 0x40 /* R W Control Reset is active (Timed pulse not finished) */
+ #define I_S_PCM_CLIPPING 0x80 /* R W PCM Clipping has occurred */
+
+#define FILTER_FREQUENCY 0x0B8A /* R W Control */
+ #define F_F_FILTER_DISABLED 0x00 /* R W Mixer No filter */
+#if 0
+ struct { /* R W Mixer Filter translation */
+ unsigned int freq:24;
+ unsigned int value:8;
+ } F_F_FILTER_translate[] =
+ { { 73500, 0x01 }, /* 73500Hz - divide by 16 */
+ { 65333, 0x02 }, /* 65333Hz - divide by 18 */
+ { 49000, 0x09 }, /* 49000Hz - divide by 24 */
+ { 36750, 0x11 }, /* 36750Hz - divide by 32 */
+ { 24500, 0x19 }, /* 24500Hz - divide by 48 */
+ { 18375, 0x07 }, /* 18375Hz - divide by 64 */
+ { 12783, 0x0f }, /* 12783Hz - divide by 92 */
+ { 12250, 0x04 }, /* 12250Hz - divide by 96 */
+ { 9188, 0x17 }, /* 9188Hz - divide by 128 */
+ { 6125, 0x1f }, /* 6125Hz - divide by 192 */
+ };
+#endif
+ #define F_F_MIXER_UNMUTE 0x20 /* R W Mixer 1=disable, 0=enable board mute */
+ #define F_F_PCM_RATE_COUNTER 0x40 /* R W PCM 1=enable, 0=disable sample rate counter */
+ #define F_F_PCM_BUFFER_COUNTER 0x80 /* R W PCM 1=enable, 0=disable sample buffer counter */
+
+#define PAS_NONE 0
+#define PAS_PLUS 1
+#define PAS_CDPC 2
+#define PAS_16 3
+#define PAS_16D 4
+
+#ifdef DEFINE_TRANSLATIONS
+ char I_C_2_PCM_DMA_translate[] = /* R W PCM PCM DMA channel value translations */
+ { 4, 1, 2, 3, 0, 5, 6, 7 };
+ char I_C_3_PCM_IRQ_translate[] = /* R W PCM PCM IRQ level value translation */
+ { 0, 0, 1, 2, 3, 4, 5, 6, 0, 1, 7, 8, 9, 0, 10, 11 };
+ char E_C_MPU401_IRQ_translate[] = /* R W MIDI MPU401 emulation IRQ value translation */
+ { 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x01, 0x05, 0x06, 0x07 };
+ char E_C_SB_IRQ_translate[] = /* R W PCM SB emulation IRQ translate */
+ { 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x08, 0x28, 0x30, 0x38, 0, 0 };
+ char E_C_SB_DMA_translate[] = /* R W PCM SB emulation DMA translate */
+ { 0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0 };
+ char O_M_1_to_card[] = /* R W Control Translate (OM1 & 0x0f) to card type */
+ { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, 0, 2, 3 };
+#else
+ extern char I_C_2_PCM_DMA_translate[]; /* R W PCM PCM DMA channel value translations */
+ extern char I_C_3_PCM_IRQ_translate[]; /* R W PCM PCM IRQ level value translation */
+ extern char E_C_MPU401_IRQ_translate[]; /* R W MIDI MPU401 emulation IRQ value translation */
+ extern char E_C_SB_IRQ_translate[]; /* R W PCM SB emulation IRQ translate */
+ extern char E_C_SB_DMA_translate[]; /* R W PCM SB emulation DMA translate */
+ extern char O_M_1_to_card[]; /* R W Control Translate (OM1 & 0x0f) to card type */
+#endif
+
+#define PARALLEL_MIXER 0x078B /* W Mixer Documented for MVD101 as FM Mono Right decode?? */
+ #define P_M_MV508_ADDRESS 0x80 /* W Mixer MVD508 Address/mixer select */
+ #define P_M_MV508_DATA 0x00
+ #define P_M_MV508_LEFT 0x20 /* W Mixer MVD508 Left channel select */
+ #define P_M_MV508_RIGHT 0x40 /* W Mixer MVD508 Right channel select */
+ #define P_M_MV508_BOTH 0x00 /* W Mixer MVD508 Both channel select */
+ #define P_M_MV508_MIXER 0x10 /* W Mixer MVD508 Select a mixer (rather than a volume) */
+ #define P_M_MV508_VOLUME 0x00
+
+ #define P_M_MV508_INPUTMIX 0x20 /* W Mixer MVD508 Select mixer A */
+ #define P_M_MV508_OUTPUTMIX 0x00 /* W Mixer MVD508 Select mixer B */
+
+ #define P_M_MV508_MASTER_A 0x01 /* W Mixer MVD508 Master volume control A (output) */
+ #define P_M_MV508_MASTER_B 0x02 /* W Mixer MVD508 Master volume control B (DSP input) */
+ #define P_M_MV508_BASS 0x03 /* W Mixer MVD508 Bass control */
+ #define P_M_MV508_TREBLE 0x04 /* W Mixer MVD508 Treble control */
+ #define P_M_MV508_MODE 0x05 /* W Mixer MVD508 Master mode control */
+
+ #define P_M_MV508_LOUDNESS 0x04 /* W Mixer MVD508 Mode control - Loudness filter */
+ #define P_M_MV508_ENHANCE_BITS 0x03
+ #define P_M_MV508_ENHANCE_NONE 0x00 /* W Mixer MVD508 Mode control - No stereo enhancement */
+ #define P_M_MV508_ENHANCE_40 0x01 /* W Mixer MVD508 Mode control - 40% stereo enhancement */
+ #define P_M_MV508_ENHANCE_60 0x02 /* W Mixer MVD508 Mode control - 60% stereo enhancement */
+ #define P_M_MV508_ENHANCE_80 0x03 /* W Mixer MVD508 Mode control - 80% stereo enhancement */
+
+ #define P_M_MV508_FM 0x00 /* W Mixer MVD508 Channel 0 - FM */
+ #define P_M_MV508_IMIXER 0x01 /* W Mixer MVD508 Channel 1 - Input mixer (rec monitor) */
+ #define P_M_MV508_LINE 0x02 /* W Mixer MVD508 Channel 2 - Line in */
+ #define P_M_MV508_CDROM 0x03 /* W Mixer MVD508 Channel 3 - CD-ROM */
+ #define P_M_MV508_MIC 0x04 /* W Mixer MVD508 Channel 4 - Microphone */
+ #define P_M_MV508_PCM 0x05 /* W Mixer MVD508 Channel 5 - PCM */
+ #define P_M_MV508_SPEAKER 0x06 /* W Mixer MVD508 Channel 6 - PC Speaker */
+ #define P_M_MV508_SB 0x07 /* W Mixer MVD508 Channel 7 - SB DSP */
+
+#define SERIAL_MIXER 0xB88 /* R W Control Serial mixer control (used other ways) */
+ #define S_M_PCM_RESET 0x01 /* R W PCM Codec/DSP reset */
+ #define S_M_FM_RESET 0x02 /* R W FM FM chip reset */
+ #define S_M_SB_RESET 0x04 /* R W PCM SB emulation chip reset */
+ #define S_M_MIXER_RESET 0x10 /* R W Mixer Mixer chip reset */
+ #define S_M_INTEGRATOR_ENABLE 0x40 /* R W Speaker Enable PC speaker integrator (FORCE RealSound) */
+ #define S_M_OPL3_DUAL_MONO 0x80 /* R W FM Set the OPL-3 to dual mono mode */
+
+#define PCM_CONTROL 0xF8A /* R W PCM PCM Control Register */
+ #define P_C_MIXER_CROSS_FIELD 0x0f
+ #define P_C_MIXER_CROSS_R_TO_R 0x01 /* R W Mixer Connect Right to Right */
+ #define P_C_MIXER_CROSS_L_TO_R 0x02 /* R W Mixer Connect Left to Right */
+ #define P_C_MIXER_CROSS_R_TO_L 0x04 /* R W Mixer Connect Right to Left */
+ #define P_C_MIXER_CROSS_L_TO_L 0x08 /* R W Mixer Connect Left to Left */
+ #define P_C_PCM_DAC_MODE 0x10 /* R W PCM Playback (DAC) mode */
+ #define P_C_PCM_ADC_MODE 0x00 /* R W PCM Record (ADC) mode */
+ #define P_C_PCM_MONO 0x20 /* R W PCM Mono mode */
+ #define P_C_PCM_STEREO 0x00 /* R W PCM Stereo mode */
+ #define P_C_PCM_ENABLE 0x40 /* R W PCM Enable PCM engine */
+ #define P_C_PCM_DMA_ENABLE 0x80 /* R W PCM Enable DRQ */
+
+#define SAMPLE_COUNTER_CONTROL 0x138B /* R W PCM Sample counter control register */
+ #define S_C_C_SQUARE_WAVE 0x04 /* R W PCM Square wave generator (use for sample rate) */
+ #define S_C_C_RATE 0x06 /* R W PCM Rate generator (use for sample buffer count) */
+ #define S_C_C_LSB_THEN_MSB 0x30 /* R W PCM Change all 16 bits, LSB first, then MSB */
+
+ /* MVD101 and SDK documentations have S_C_C_SAMPLE_RATE and S_C_C_SAMPLE_BUFFER transposed. Only one works :-) */
+ #define S_C_C_SAMPLE_RATE 0x00 /* R W PCM Select sample rate timer */
+ #define S_C_C_SAMPLE_BUFFER 0x40 /* R W PCM Select sample buffer counter */
+
+ #define S_C_C_PC_SPEAKER 0x80 /* R W PCM Select PC speaker counter */
+
+#define SAMPLE_RATE_TIMER 0x1388 /* W PCM Sample rate timer register (PCM wait interval) */
+#define SAMPLE_BUFFER_COUNTER 0x1389 /* R W PCM Sample buffer counter (DMA buffer size) */
+
+#define MIDI_CONTROL 0x178b /* R W MIDI Midi control register */
+ #define M_C_ENA_TSTAMP_IRQ 0x01 /* R W MIDI Enable Time Stamp Interrupts */
+ #define M_C_ENA_TME_COMP_IRQ 0x02 /* R W MIDI Enable time compare interrupts */
+ #define M_C_ENA_INPUT_IRQ 0x04 /* R W MIDI Enable input FIFO interrupts */
+ #define M_C_ENA_OUTPUT_IRQ 0x08 /* R W MIDI Enable output FIFO interrupts */
+ #define M_C_ENA_OUTPUT_HALF_IRQ 0x10 /* R W MIDI Enable output FIFO half full interrupts */
+ #define M_C_RESET_INPUT_FIFO 0x20 /* R W MIDI Reset input FIFO pointer */
+ #define M_C_RESET_OUTPUT_FIFO 0x40 /* R W MIDI Reset output FIFO pointer */
+ #define M_C_ENA_THRU_MODE 0x80 /* R W MIDI Echo input to output (THRU) */
+
+#define MIDI_STATUS 0x1B88 /* R W MIDI Midi (interrupt) status register */
+ #define M_S_TIMESTAMP 0x01 /* R W MIDI Midi time stamp interrupt occurred */
+ #define M_S_COMPARE 0x02 /* R W MIDI Midi compare time interrupt occurred */
+ #define M_S_INPUT_AVAIL 0x04 /* R W MIDI Midi input data available interrupt occurred */
+ #define M_S_OUTPUT_EMPTY 0x08 /* R W MIDI Midi output FIFO empty interrupt occurred */
+ #define M_S_OUTPUT_HALF_EMPTY 0x10 /* R W MIDI Midi output FIFO half empty interrupt occurred */
+ #define M_S_INPUT_OVERRUN 0x20 /* R W MIDI Midi input overrun error occurred */
+ #define M_S_OUTPUT_OVERRUN 0x40 /* R W MIDI Midi output overrun error occurred */
+ #define M_S_FRAMING_ERROR 0x80 /* R W MIDI Midi input framing error occurred */
+
+#define MIDI_FIFO_STATUS 0x1B89 /* R W MIDI Midi fifo status */
+#define MIDI_DATA 0x178A /* R W MIDI Midi data register */
+#define MIDI_INPUT_AVAILABLE 0x0f /* RW MIDI */
diff --git a/sys/i386/isa/sound/pas2_card.c b/sys/i386/isa/sound/pas2_card.c
new file mode 100644
index 0000000..cc99a9e
--- /dev/null
+++ b/sys/i386/isa/sound/pas2_card.c
@@ -0,0 +1,383 @@
+#define _PAS2_CARD_C_
+#define SND_SA_INTERRUPT
+/*
+ * sound/pas2_card.c
+ *
+ * Detection routine for the Pro Audio Spectrum cards.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PAS)
+
+#define DEFINE_TRANSLATIONS
+#include "pas.h"
+
+/*
+ * The Address Translation code is used to convert I/O register addresses to
+ * be relative to the given base -register
+ */
+
+int translat_code;
+static int pas_intr_mask = 0;
+static int pas_irq = 0;
+
+static char pas_model;
+static unsigned char board_rev_id;
+#define PAS_REVD_BOARD_ID 127
+static char *pas_model_names[] =
+{"", "Pro AudioSpectrum+", "CDPC", "Pro AudioSpectrum 16", "Pro AudioSpectrum 16D"};
+
+/* pas_read() and pas_write() are equivalents of INB() and OUTB() */
+/* These routines perform the I/O address translation required */
+/* to support other than the default base address */
+
+unsigned char
+pas_read (int ioaddr)
+{
+ return INB (ioaddr ^ translat_code);
+}
+
+void
+pas_write (unsigned char data, int ioaddr)
+{
+ OUTB (data, ioaddr ^ translat_code);
+}
+
+/*
+ * The Revision D cards have a problem with their MVA508 interface. The
+ * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and
+ * MSBs out of the output byte and to do a 16-bit out to the mixer port -
+ * 1.
+ */
+
+void
+mix_write (unsigned char data, int ioaddr)
+{
+ if (board_rev_id >= PAS_REVD_BOARD_ID) {
+ outw ((ioaddr ^ translat_code) - 1, data | (data << 8));
+ outb (0, 0x80);
+ } else
+ OUTB (data, ioaddr ^ translat_code);
+}
+
+void
+pas2_msg (char *foo)
+{
+ printk (" PAS2: %s.\n", foo);
+}
+
+/******************* Begin of the Interrupt Handler ********************/
+
+void
+pasintr (int unused)
+{
+ int status;
+
+ status = pas_read (INTERRUPT_STATUS);
+ pas_write (status, INTERRUPT_STATUS); /* Clear interrupt */
+
+ if (status & I_S_PCM_SAMPLE_BUFFER_IRQ)
+ {
+#ifndef EXCLUDE_AUDIO
+ pas_pcm_interrupt (status, 1);
+#endif
+ status &= ~I_S_PCM_SAMPLE_BUFFER_IRQ;
+ }
+ if (status & I_S_MIDI_IRQ)
+ {
+#ifndef EXCLUDE_MIDI
+#ifdef EXCLUDE_PRO_MIDI
+ pas_midi_interrupt ();
+#endif
+#endif
+ status &= ~I_S_MIDI_IRQ;
+ }
+
+}
+
+int
+pas_set_intr (int mask)
+{
+ int err;
+
+ if (!mask)
+ return 0;
+
+ if (!pas_intr_mask)
+ {
+ if ((err = snd_set_irq_handler (pas_irq, pasintr)) < 0)
+ return err;
+ }
+ pas_intr_mask |= mask;
+
+ pas_write (pas_intr_mask, INTERRUPT_MASK);
+ return 0;
+}
+
+int
+pas_remove_intr (int mask)
+{
+ if (!mask)
+ return 0;
+
+ pas_intr_mask &= ~mask;
+ pas_write (pas_intr_mask, INTERRUPT_MASK);
+
+ if (!pas_intr_mask)
+ {
+ snd_release_irq (pas_irq);
+ }
+ return 0;
+}
+
+/******************* End of the Interrupt handler **********************/
+
+/******************* Begin of the Initialization Code ******************/
+
+int
+config_pas_hw (struct address_info *hw_config)
+{
+ char ok = 1;
+
+ pas_irq = hw_config->irq;
+
+ pas_write (0x00, INTERRUPT_MASK);
+
+ pas_write (0x36, SAMPLE_COUNTER_CONTROL); /* Local timer control
+ * register */
+
+ pas_write (0x36, SAMPLE_RATE_TIMER); /* Sample rate timer (16 bit) */
+ pas_write (0, SAMPLE_RATE_TIMER);
+
+ pas_write (0x74, SAMPLE_COUNTER_CONTROL); /* Local timer control
+ * register */
+
+ pas_write (0x74, SAMPLE_BUFFER_COUNTER); /* Sample count register (16
+ * bit) */
+ pas_write (0, SAMPLE_BUFFER_COUNTER);
+
+ pas_write (F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER | F_F_MIXER_UNMUTE | 1, FILTER_FREQUENCY);
+ pas_write (P_C_PCM_DMA_ENABLE | P_C_PCM_MONO | P_C_PCM_DAC_MODE | P_C_MIXER_CROSS_L_TO_L | P_C_MIXER_CROSS_R_TO_R, PCM_CONTROL);
+ pas_write (S_M_PCM_RESET | S_M_FM_RESET | S_M_SB_RESET | S_M_MIXER_RESET /* | S_M_OPL3_DUAL_MONO */ , SERIAL_MIXER);
+
+ pas_write (I_C_1_BOOT_RESET_ENABLE, IO_CONFIGURATION_1);
+
+ if (pas_irq < 0 || pas_irq > 15)
+ {
+ printk ("PAS2: Invalid IRQ %d", pas_irq);
+ ok = 0;
+ }
+ else
+ {
+ pas_write (I_C_3_PCM_IRQ_translate[pas_irq], IO_CONFIGURATION_3);
+ if (!I_C_3_PCM_IRQ_translate[pas_irq])
+ {
+ printk ("PAS2: Invalid IRQ %d", pas_irq);
+ ok = 0;
+ }
+ }
+
+ if (hw_config->dma < 0 || hw_config->dma > 7)
+ {
+ printk ("PAS2: Invalid DMA selection %d", hw_config->dma);
+ ok = 0;
+ }
+ else
+ {
+ pas_write (I_C_2_PCM_DMA_translate[hw_config->dma], IO_CONFIGURATION_2);
+ if (!I_C_2_PCM_DMA_translate[hw_config->dma])
+ {
+ printk ("PAS2: Invalid DMA selection %d", hw_config->dma);
+ ok = 0;
+ }
+ }
+
+ /*
+ * This fixes the timing problems of the PAS due to the Symphony chipset
+ * as per Media Vision. Only define this if your PAS doesn't work correctly.
+ */
+#ifdef SYMPHONY_PAS
+ OUTB (0x05, 0xa8);
+ OUTB (0x60, 0xa9);
+#endif
+
+#ifdef BROKEN_BUS_CLOCK
+ pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND | S_C_1_FM_EMULATE_CLOCK, SYSTEM_CONFIGURATION_1);
+#else
+ /* pas_write(S_C_1_PCS_ENABLE, SYSTEM_CONFIGURATION_1); */
+ pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND, SYSTEM_CONFIGURATION_1);
+#endif
+ pas_write (0x18, SYSTEM_CONFIGURATION_3); /* ??? */
+
+ pas_write (F_F_MIXER_UNMUTE | 0x01, FILTER_FREQUENCY); /* Sets mute off and
+ * selects filter rate
+ * of 17.897 kHz */
+
+ if (pas_model == PAS_16 || pas_model == PAS_16D)
+ pas_write (8, PRESCALE_DIVIDER);
+ else
+ pas_write (0, PRESCALE_DIVIDER);
+
+ mix_write (P_M_MV508_ADDRESS | 5, PARALLEL_MIXER);
+ mix_write (5, PARALLEL_MIXER);
+
+#if !defined(EXCLUDE_SB_EMULATION) || !defined(EXCLUDE_SB)
+
+ {
+ struct address_info *sb_config;
+
+ if ((sb_config = sound_getconf (SNDCARD_SB)))
+ {
+ unsigned char irq_dma;
+
+ /* Turn on Sound Blaster compatibility */
+ /* bit 1 = SB emulation */
+ /* bit 0 = MPU401 emulation (CDPC only :-( ) */
+ pas_write (0x02, COMPATIBILITY_ENABLE);
+
+ /* "Emulation address" */
+ pas_write ((sb_config->io_base >> 4) & 0x0f, EMULATION_ADDRESS);
+
+ if (!E_C_SB_DMA_translate[sb_config->dma])
+ printk ("\n\nPAS16 Warning: Invalid SB DMA %d\n\n",
+ sb_config->dma);
+
+ if (!E_C_SB_IRQ_translate[sb_config->irq])
+ printk ("\n\nPAS16 Warning: Invalid SB IRQ %d\n\n",
+ sb_config->irq);
+
+ irq_dma = E_C_SB_DMA_translate[sb_config->dma] |
+ E_C_SB_IRQ_translate[sb_config->irq];
+
+ pas_write (irq_dma, EMULATION_CONFIGURATION);
+ }
+ }
+#endif
+
+ if (!ok)
+ pas2_msg ("Driver not enabled");
+
+ return ok;
+}
+
+int
+detect_pas_hw (struct address_info *hw_config)
+{
+ unsigned char board_id, foo;
+
+ /*
+ * WARNING: Setting an option like W:1 or so that disables warm boot reset
+ * of the card will screw up this detect code something fierce. Adding code
+ * to handle this means possibly interfering with other cards on the bus if
+ * you have something on base port 0x388. SO be forewarned.
+ */
+
+ OUTB (0xBC, MASTER_DECODE); /* Talk to first board */
+ OUTB (hw_config->io_base >> 2, MASTER_DECODE); /* Set base address */
+ translat_code = PAS_DEFAULT_BASE ^ hw_config->io_base;
+ pas_write (1, WAIT_STATE); /* One wait-state */
+
+ board_id = pas_read (INTERRUPT_MASK);
+
+ if (board_id == 0xff)
+ return 0;
+
+ /*
+ * We probably have a PAS-series board, now check for a PAS2-series board
+ * by trying to change the board revision bits. PAS2-series hardware won't
+ * let you do this - the bits are read-only.
+ */
+
+ foo = board_id ^ 0xe0;
+
+ pas_write (foo, INTERRUPT_MASK);
+ foo = INB (INTERRUPT_MASK);
+ pas_write (board_id, INTERRUPT_MASK);
+
+ if (board_id != foo) /* Not a PAS2 */
+ return 0;
+
+ pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f];
+
+ return pas_model;
+}
+
+long
+attach_pas_card (long mem_start, struct address_info *hw_config)
+{
+ pas_irq = hw_config->irq;
+
+ if (detect_pas_hw (hw_config))
+ {
+
+ board_rev_id = pas_read (BOARD_REV_ID);
+ if ((pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f]))
+ {
+#ifdef __FreeBSD__
+ printk ("snd3: <%s rev %d>", pas_model_names[(int) pas_model], board_rev_id);
+#else
+ printk (" <%s rev %d>", pas_model_names[(int) pas_model], board_rev_id);
+#endif
+ }
+
+ if (config_pas_hw (hw_config))
+ {
+
+#ifndef EXCLUDE_AUDIO
+ mem_start = pas_pcm_init (mem_start, hw_config);
+#endif
+
+#if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB)
+
+ sb_dsp_disable_midi (); /* The SB emulation don't support
+ * midi */
+#endif
+
+#ifndef EXCLUDE_YM3812
+ enable_opl3_mode (0x388, 0x38a, 0);
+#endif
+
+#ifndef EXCLUDE_MIDI
+#ifdef EXCLUDE_PRO_MIDI
+ mem_start = pas_midi_init (mem_start);
+#endif
+#endif
+
+ pas_init_mixer ();
+ }
+ }
+
+ return mem_start;
+}
+
+int
+probe_pas (struct address_info *hw_config)
+{
+ return detect_pas_hw (hw_config);
+}
+
+#endif
diff --git a/sys/i386/isa/sound/pas2_midi.c b/sys/i386/isa/sound/pas2_midi.c
new file mode 100644
index 0000000..4a07b0b
--- /dev/null
+++ b/sys/i386/isa/sound/pas2_midi.c
@@ -0,0 +1,295 @@
+/*
+ * sound/pas2_midi.c
+ *
+ * The low level driver for the PAS Midi Interface.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+#include "pas.h"
+
+#if !defined(EXCLUDE_PAS) && !defined(EXCLUDE_MIDI) && defined(EXCLUDE_PRO_MIDI)
+
+static int midi_busy = 0, input_opened = 0;
+static int my_dev;
+static volatile int ofifo_bytes = 0;
+
+static unsigned char tmp_queue[256];
+static volatile int qlen;
+static volatile unsigned char qhead, qtail;
+
+static void (*midi_input_intr) (int dev, unsigned char data);
+
+static int
+pas_midi_open (int dev, int mode,
+ void (*input) (int dev, unsigned char data),
+ void (*output) (int dev)
+)
+{
+ int err;
+ unsigned long flags;
+ unsigned char ctrl;
+
+
+ if (midi_busy)
+ {
+ printk ("PAS2: Midi busy\n");
+ return RET_ERROR (EBUSY);
+ }
+
+ /* Reset input and output FIFO pointers */
+ pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO,
+ MIDI_CONTROL);
+
+ DISABLE_INTR (flags);
+
+ if ((err = pas_set_intr (I_M_MIDI_IRQ_ENABLE)) < 0)
+ return err;
+
+ /* Enable input available and output FIFO empty interrupts */
+
+ ctrl = 0;
+ input_opened = 0;
+ midi_input_intr = input;
+
+ if (mode == OPEN_READ || mode == OPEN_READWRITE)
+ {
+ ctrl |= M_C_ENA_INPUT_IRQ;/* Enable input */
+ input_opened = 1;
+ }
+
+ if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
+ {
+ ctrl |= M_C_ENA_OUTPUT_IRQ | /* Enable output */
+ M_C_ENA_OUTPUT_HALF_IRQ;
+ }
+
+ pas_write (ctrl,
+ MIDI_CONTROL);
+
+ /* Acknowledge any pending interrupts */
+
+ pas_write (0xff, MIDI_STATUS);
+ ofifo_bytes = 0;
+
+ RESTORE_INTR (flags);
+
+ midi_busy = 1;
+ qlen = qhead = qtail = 0;
+ return 0;
+}
+
+static void
+pas_midi_close (int dev)
+{
+
+ /* Reset FIFO pointers, disable intrs */
+ pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO, MIDI_CONTROL);
+
+ pas_remove_intr (I_M_MIDI_IRQ_ENABLE);
+ midi_busy = 0;
+}
+
+static int
+dump_to_midi (unsigned char midi_byte)
+{
+ int fifo_space, x;
+
+ fifo_space = ((x = pas_read (MIDI_FIFO_STATUS)) >> 4) & 0x0f;
+
+ if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13)) /* Fifo full */
+ {
+ return 0; /* Upper layer will call again */
+ }
+
+ ofifo_bytes++;
+
+ pas_write (midi_byte, MIDI_DATA);
+
+ return 1;
+}
+
+static int
+pas_midi_out (int dev, unsigned char midi_byte)
+{
+
+ unsigned long flags;
+
+ /*
+ * Drain the local queue first
+ */
+
+ DISABLE_INTR (flags);
+
+ while (qlen && dump_to_midi (tmp_queue[qhead]))
+ {
+ qlen--;
+ qhead++;
+ }
+
+ RESTORE_INTR (flags);
+
+ /*
+ * Output the byte if the local queue is empty.
+ */
+
+ if (!qlen)
+ if (dump_to_midi (midi_byte))
+ return 1; /* OK */
+
+ /*
+ * Put to the local queue
+ */
+
+ if (qlen >= 256)
+ return 0; /* Local queue full */
+
+ DISABLE_INTR (flags);
+
+ tmp_queue[qtail] = midi_byte;
+ qlen++;
+ qtail++;
+
+ RESTORE_INTR (flags);
+
+ return 1;
+}
+
+static int
+pas_midi_start_read (int dev)
+{
+ return 0;
+}
+
+static int
+pas_midi_end_read (int dev)
+{
+ return 0;
+}
+
+static int
+pas_midi_ioctl (int dev, unsigned cmd, unsigned arg)
+{
+ return RET_ERROR (EINVAL);
+}
+
+static void
+pas_midi_kick (int dev)
+{
+ ofifo_bytes = 0;
+}
+
+static int
+pas_buffer_status (int dev)
+{
+ return !qlen;
+}
+
+static struct midi_operations pas_midi_operations =
+{
+ {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS},
+ pas_midi_open,
+ pas_midi_close,
+ pas_midi_ioctl,
+ pas_midi_out,
+ pas_midi_start_read,
+ pas_midi_end_read,
+ pas_midi_kick,
+ NULL, /* command */
+ pas_buffer_status
+};
+
+long
+pas_midi_init (long mem_start)
+{
+ my_dev = num_midis;
+ midi_devs[num_midis++] = &pas_midi_operations;
+ return mem_start;
+}
+
+void
+pas_midi_interrupt (void)
+{
+ unsigned char stat;
+ int i, incount;
+ unsigned long flags;
+
+ stat = pas_read (MIDI_STATUS);
+
+ if (stat & M_S_INPUT_AVAIL) /* Input byte available */
+ {
+ incount = pas_read (MIDI_FIFO_STATUS) & 0x0f; /* Input FIFO count */
+ if (!incount)
+ incount = 16;
+
+ for (i = 0; i < incount; i++)
+ if (input_opened)
+ {
+ midi_input_intr (my_dev, pas_read (MIDI_DATA));
+ }
+ else
+ pas_read (MIDI_DATA); /* Flush */
+ }
+
+ if (stat & (M_S_OUTPUT_EMPTY | M_S_OUTPUT_HALF_EMPTY))
+ {
+ if (!(stat & M_S_OUTPUT_EMPTY))
+ {
+ ofifo_bytes = 8;
+ }
+ else
+ {
+ ofifo_bytes = 0;
+ }
+
+ DISABLE_INTR (flags);
+
+ while (qlen && dump_to_midi (tmp_queue[qhead]))
+ {
+ qlen--;
+ qhead++;
+ }
+
+ RESTORE_INTR (flags);
+ }
+
+ if (stat & M_S_FRAMING_ERROR)
+ printk ("MIDI framing error\n");
+
+ if (stat & M_S_OUTPUT_OVERRUN)
+ {
+ printk ("MIDI output overrun %x,%x,%d \n", pas_read (MIDI_FIFO_STATUS), stat, ofifo_bytes);
+ ofifo_bytes = 100;
+ }
+
+ pas_write (stat, MIDI_STATUS);/* Acknowledge interrupts */
+}
+
+#endif
+
+#endif
diff --git a/sys/i386/isa/sound/pas2_mixer.c b/sys/i386/isa/sound/pas2_mixer.c
new file mode 100644
index 0000000..b386877
--- /dev/null
+++ b/sys/i386/isa/sound/pas2_mixer.c
@@ -0,0 +1,492 @@
+#define _PAS2_MIXER_C_
+
+/*
+ * sound/pas2_mixer.c
+ *
+ * Mixer routines for the Pro Audio Spectrum cards.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PAS)
+
+#include "pas.h"
+
+#define TRACE(what) /* (what) */
+
+extern int translat_code;
+
+static int rec_devices = (SOUND_MASK_MIC); /* Default recording source */
+static int mode_control = 0;
+
+#define POSSIBLE_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
+ SOUND_MASK_CD | SOUND_MASK_ALTPCM)
+
+#define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
+ SOUND_MASK_CD | SOUND_MASK_ALTPCM | SOUND_MASK_IMIX | \
+ SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV | \
+ SOUND_MASK_MUTE | SOUND_MASK_ENHANCE | SOUND_MASK_LOUD)
+
+static unsigned short levels[SOUND_MIXER_NRDEVICES] =
+{
+ 0x3232, /* Master Volume */
+ 0x3232, /* Bass */
+ 0x3232, /* Treble */
+ 0x5050, /* FM */
+ 0x4b4b, /* PCM */
+ 0x3232, /* PC Speaker */
+ 0x4b4b, /* Ext Line */
+ 0x4b4b, /* Mic */
+ 0x4b4b, /* CD */
+ 0x6464, /* Recording monitor */
+ 0x4b4b, /* SB PCM */
+ 0x6464}; /* Recording level */
+
+static int
+mixer_output (int right_vol, int left_vol, int div, int bits,
+ int mixer /* Input or output mixer */ )
+{
+ int left = left_vol * div / 100;
+ int right = right_vol * div / 100;
+
+ if (bits & P_M_MV508_MIXER)
+ { /* Select input or output mixer */
+ left |= mixer;
+ right |= mixer;
+ }
+
+ if (bits == P_M_MV508_BASS || bits == P_M_MV508_TREBLE)
+ { /* Bass and trebble are mono devices */
+ mix_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER);
+ mix_write (left, PARALLEL_MIXER);
+ right_vol = left_vol;
+ }
+ else
+ {
+ mix_write (P_M_MV508_ADDRESS | P_M_MV508_LEFT | bits, PARALLEL_MIXER);
+ mix_write (left, PARALLEL_MIXER);
+ mix_write (P_M_MV508_ADDRESS | P_M_MV508_RIGHT | bits, PARALLEL_MIXER);
+ mix_write (right, PARALLEL_MIXER);
+ }
+
+ return (left_vol | (right_vol << 8));
+}
+
+void
+set_mode (int new_mode)
+{
+ mix_write (P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER);
+ mix_write (new_mode, PARALLEL_MIXER);
+
+ mode_control = new_mode;
+}
+
+static int
+pas_mixer_set (int whichDev, unsigned int level)
+{
+ int left, right, devmask, changed, i, mixer = 0;
+
+ TRACE (printk ("static int pas_mixer_set(int whichDev = %d, unsigned int level = %X)\n", whichDev, level));
+
+ left = level & 0x7f;
+ right = (level & 0x7f00) >> 8;
+
+ if (whichDev < SOUND_MIXER_NRDEVICES)
+ if ((1 << whichDev) & rec_devices)
+ mixer = P_M_MV508_INPUTMIX;
+ else
+ mixer = P_M_MV508_OUTPUTMIX;
+
+ switch (whichDev)
+ {
+ case SOUND_MIXER_VOLUME: /* Master volume (0-63) */
+ levels[whichDev] = mixer_output (right, left, 63, P_M_MV508_MASTER_A, 0);
+ break;
+
+ /*
+ * Note! Bass and Treble are mono devices. Will use just the left
+ * channel.
+ */
+ case SOUND_MIXER_BASS: /* Bass (0-12) */
+ levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_BASS, 0);
+ break;
+ case SOUND_MIXER_TREBLE: /* Treble (0-12) */
+ levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_TREBLE, 0);
+ break;
+
+ case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-31) */
+ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_FM, mixer);
+ break;
+ case SOUND_MIXER_PCM: /* PAS PCM (0-31) */
+ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_PCM, mixer);
+ break;
+ case SOUND_MIXER_ALTPCM: /* SB PCM (0-31) */
+ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SB, mixer);
+ break;
+ case SOUND_MIXER_SPEAKER: /* PC speaker (0-31) */
+ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SPEAKER, mixer);
+ break;
+ case SOUND_MIXER_LINE: /* External line (0-31) */
+ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_LINE, mixer);
+ break;
+ case SOUND_MIXER_CD: /* CD (0-31) */
+ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_CDROM, mixer);
+ break;
+ case SOUND_MIXER_MIC: /* External microphone (0-31) */
+ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_MIC, mixer);
+ break;
+ case SOUND_MIXER_IMIX: /* Recording monitor (0-31) (Only available
+ * on the Output Mixer) */
+ levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_IMIXER,
+ P_M_MV508_OUTPUTMIX);
+ break;
+ case SOUND_MIXER_RECLEV: /* Recording level (0-15) */
+ levels[whichDev] = mixer_output (right, left, 15, P_M_MV508_MASTER_B, 0);
+ break;
+
+ case SOUND_MIXER_MUTE:
+ return 0;
+ break;
+
+ case SOUND_MIXER_ENHANCE:
+ i = 0;
+ level &= 0x7f;
+ if (level)
+ i = (level / 20) - 1;
+
+ mode_control &= ~P_M_MV508_ENHANCE_BITS;
+ mode_control |= P_M_MV508_ENHANCE_BITS;
+ set_mode (mode_control);
+
+ if (i)
+ i = (i + 1) * 20;
+ return i;
+ break;
+
+ case SOUND_MIXER_LOUD:
+ mode_control &= ~P_M_MV508_LOUDNESS;
+ if (level)
+ mode_control |= P_M_MV508_LOUDNESS;
+ set_mode (mode_control);
+ return !!level; /* 0 or 1 */
+ break;
+
+ case SOUND_MIXER_RECSRC:
+ devmask = level & POSSIBLE_RECORDING_DEVICES;
+
+ changed = devmask ^ rec_devices;
+ rec_devices = devmask;
+
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+ if (changed & (1 << i))
+ {
+ pas_mixer_set (i, levels[i]);
+ }
+ return rec_devices;
+ break;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+
+ return (levels[whichDev]);
+}
+
+/*****/
+
+static int
+mixer_set_levels (struct sb_mixer_levels *user_l)
+{
+#define cmix(v) ((((v.r*100+7)/15)<<8)| ((v.l*100+7)/15))
+
+ struct sb_mixer_levels l;
+
+ IOCTL_FROM_USER ((char *) &l, (char *) user_l, 0, sizeof (l));
+
+ if (l.master.l & ~0xF || l.master.r & ~0xF
+ || l.line.l & ~0xF || l.line.r & ~0xF
+ || l.voc.l & ~0xF || l.voc.r & ~0xF
+ || l.fm.l & ~0xF || l.fm.r & ~0xF
+ || l.cd.l & ~0xF || l.cd.r & ~0xF
+ || l.mic & ~0x7)
+ return (RET_ERROR (EINVAL));
+
+ pas_mixer_set (SOUND_MIXER_VOLUME, cmix (l.master));
+ pas_mixer_set (SOUND_MIXER_LINE, cmix (l.line));
+ pas_mixer_set (SOUND_MIXER_PCM, cmix (l.voc));
+ pas_mixer_set (SOUND_MIXER_ALTPCM, cmix (l.voc));
+ pas_mixer_set (SOUND_MIXER_SYNTH, cmix (l.fm));
+ pas_mixer_set (SOUND_MIXER_CD, cmix (l.cd));
+ pas_mixer_set (SOUND_MIXER_MIC, ((l.mic * 100 + 3) / 7) | (((l.mic * 100 + 3) / 7) << 8));
+ return (0);
+}
+
+/*
+ * This sets aspects of the Mixer that are not volume levels. (Recording
+ * source, filter level, I/O filtering, and stereo.)
+ */
+static int
+mixer_set_params (struct sb_mixer_params *user_p)
+{
+ struct sb_mixer_params p;
+ S_BYTE val;
+ int src;
+ unsigned long flags;
+
+ IOCTL_FROM_USER ((char *) &p, (char *) user_p, 0, sizeof (p));
+
+ if (p.record_source != SRC_MIC
+ && p.record_source != SRC_CD
+ && p.record_source != SRC_LINE)
+ return (RET_ERROR (EINVAL));
+
+ /*
+ * I'm not sure if this is The Right Thing. Should stereo be entirely
+ * under control of DSP? I like being able to toggle it while a sound is
+ * playing, so I do this... because I can.
+ */
+
+ DISABLE_INTR (flags);
+
+ val = (pas_read (PCM_CONTROL) & ~P_C_MIXER_CROSS_FIELD) | P_C_MIXER_CROSS_R_TO_R | P_C_MIXER_CROSS_L_TO_L;
+ if (!p.dsp_stereo)
+ val |= (P_C_MIXER_CROSS_R_TO_L | P_C_MIXER_CROSS_L_TO_R); /* Mono */
+ pas_write (val, PCM_CONTROL);
+
+ RESTORE_INTR (flags);
+
+ switch (p.record_source)
+ {
+ case SRC_CD:
+ src = SOUND_MASK_CD;
+ break;
+
+ case SRC_LINE:
+ src = SOUND_MASK_LINE;
+ break;
+
+ default:
+ src = SOUND_MASK_MIC;
+ break;
+ }
+
+ pas_mixer_set (SOUND_MIXER_RECSRC, src);
+
+ /*
+ * setmixer (OUT_FILTER, ((dsp_stereo ? STEREO_DAC : MONO_DAC) |
+ * (p.filter_output ? FILT_ON : FILT_OFF)));
+ */
+ return (0);
+}
+
+static int
+getmixer (int dev, int chn)
+{
+ if (chn == P_M_MV508_RIGHT)
+ {
+ return (levels[dev] >> 8) & 0x7f;
+ }
+ else
+ {
+ return levels[dev] & 0x7f;
+ }
+}
+
+/* Read the current mixer level settings into the user's struct. */
+static int
+mixer_get_levels (struct sb_mixer_levels *user_l)
+{
+
+ struct sb_mixer_levels l;
+
+ l.master.r = ((((levels[SOUND_MIXER_VOLUME] >> 8) & 0x7f) * 15) + 50) / 100; /* Master */
+ l.master.l = (((levels[SOUND_MIXER_VOLUME] & 0x7f) * 15) + 50) / 100; /* Master */
+
+ l.line.r = ((getmixer (SOUND_MIXER_LINE, P_M_MV508_RIGHT) * 15) + 50) / 100; /* Line */
+ l.line.l = ((getmixer (SOUND_MIXER_LINE, P_M_MV508_LEFT) * 15) + 50) / 100;
+
+ l.voc.r = ((getmixer (SOUND_MIXER_PCM, P_M_MV508_RIGHT) * 15) + 50) / 100; /* DAC */
+ l.voc.l = ((getmixer (SOUND_MIXER_PCM, P_M_MV508_LEFT) * 15) + 50) / 100;
+
+ l.fm.r = ((getmixer (SOUND_MIXER_SYNTH, P_M_MV508_RIGHT) * 15) + 50) / 100; /* FM */
+ l.fm.l = ((getmixer (SOUND_MIXER_SYNTH, P_M_MV508_LEFT) * 15) + 50) / 100;
+
+ l.cd.r = ((getmixer (SOUND_MIXER_CD, P_M_MV508_RIGHT) * 15) + 50) / 100; /* CD */
+ l.cd.l = ((getmixer (SOUND_MIXER_CD, P_M_MV508_LEFT) * 15) + 50) / 100;
+
+ l.mic = ((getmixer (SOUND_MIXER_MIC, P_M_MV508_LEFT) * 7) + 50) / 100; /* Microphone */
+
+ IOCTL_TO_USER ((char *) user_l, 0, (char *) &l, sizeof (l));
+ return (0);
+}
+
+/* Read the current mixer parameters into the user's struct. */
+static int
+mixer_get_params (struct sb_mixer_params *user_params)
+{
+ S_BYTE val;
+ struct sb_mixer_params params;
+
+ switch (rec_devices)
+ {
+ case SOUND_MASK_CD:
+ params.record_source = SRC_CD;
+ break;
+
+ case SOUND_MASK_LINE:
+ params.record_source = SRC_LINE;
+ break;
+
+ case SOUND_MASK_MIC:
+ params.record_source = SRC_MIC;
+ break;
+
+ default:
+ params.record_source = SRC_MIC;
+ pas_mixer_set (SOUND_MIXER_RECSRC, SOUND_MASK_MIC); /* Adjust */
+ }
+
+ params.hifreq_filter = OFF;
+ params.filter_input = OFF;
+ params.filter_output = OFF;
+
+ val = INB (PCM_CONTROL);
+ params.dsp_stereo = ((val & P_C_MIXER_CROSS_FIELD) == (P_C_MIXER_CROSS_L_TO_L | P_C_MIXER_CROSS_R_TO_R));
+
+ IOCTL_TO_USER ((char *) user_params, 0, (char *) &params, sizeof (params));
+ return (0);
+}
+
+/*****/
+
+static void
+pas_mixer_reset (void)
+{
+ int foo;
+
+ TRACE (printk ("pas2_mixer.c: void pas_mixer_reset(void)\n"));
+
+ for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++)
+ pas_mixer_set (foo, levels[foo]);
+
+ set_mode (P_M_MV508_LOUDNESS | P_M_MV508_ENHANCE_40);
+}
+
+int
+pas_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
+{
+ TRACE (printk ("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
+
+ if (((cmd >> 8) & 0xff) == 'M')
+ {
+ if (cmd & IOC_IN)
+ return IOCTL_OUT (arg, pas_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
+ else
+ { /* Read parameters */
+
+ switch (cmd & 0xff)
+ {
+
+ case SOUND_MIXER_RECSRC:
+ return IOCTL_OUT (arg, rec_devices);
+ break;
+
+ case SOUND_MIXER_STEREODEVS:
+ return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE));
+ break;
+
+ case SOUND_MIXER_DEVMASK:
+ return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES);
+ break;
+
+ case SOUND_MIXER_RECMASK:
+ return IOCTL_OUT (arg, POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES);
+ break;
+
+ case SOUND_MIXER_CAPS:
+ return IOCTL_OUT (arg, 0); /* No special capabilities */
+ break;
+
+ case SOUND_MIXER_MUTE:
+ return IOCTL_OUT (arg, 0); /* No mute yet */
+ break;
+
+ case SOUND_MIXER_ENHANCE:
+ if (!(mode_control & P_M_MV508_ENHANCE_BITS))
+ return IOCTL_OUT (arg, 0);
+ return IOCTL_OUT (arg, ((mode_control & P_M_MV508_ENHANCE_BITS) + 1) * 20);
+ break;
+
+ case SOUND_MIXER_LOUD:
+ if (mode_control & P_M_MV508_LOUDNESS)
+ return IOCTL_OUT (arg, 1);
+ return IOCTL_OUT (arg, 0);
+ break;
+
+ default:
+ return IOCTL_OUT (arg, levels[cmd & 0xff]);
+ }
+ }
+ }
+ else
+ {
+ switch (cmd)
+ {
+ case MIXER_IOCTL_SET_LEVELS:
+ mixer_set_levels ((struct sb_mixer_levels *) arg);
+ return mixer_get_levels ((struct sb_mixer_levels *) arg);
+ case MIXER_IOCTL_SET_PARAMS:
+ mixer_set_params ((struct sb_mixer_params *) arg);
+ return mixer_get_params ((struct sb_mixer_params *) arg);
+ case MIXER_IOCTL_READ_LEVELS:
+ return mixer_get_levels ((struct sb_mixer_levels *) arg);
+ case MIXER_IOCTL_READ_PARAMS:
+ return mixer_get_params ((struct sb_mixer_params *) arg);
+ case MIXER_IOCTL_RESET:
+ pas_mixer_reset ();
+ return (0);
+ default:
+ return RET_ERROR (EINVAL);
+ }
+ }
+ return RET_ERROR (EINVAL);
+}
+
+static struct mixer_operations pas_mixer_operations =
+{
+ pas_mixer_ioctl
+};
+
+int
+pas_init_mixer (void)
+{
+ pas_mixer_reset ();
+
+ mixer_devs[num_mixers++] = &pas_mixer_operations;
+ return 1;
+}
+
+#endif
diff --git a/sys/i386/isa/sound/pas2_pcm.c b/sys/i386/isa/sound/pas2_pcm.c
new file mode 100644
index 0000000..ec571c5
--- /dev/null
+++ b/sys/i386/isa/sound/pas2_pcm.c
@@ -0,0 +1,429 @@
+#define _PAS2_PCM_C_
+/*
+ * sound/pas2_pcm.c
+ *
+ * The low level driver for the Pro Audio Spectrum ADC/DAC.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+#include "pas.h"
+
+#if !defined(EXCLUDE_PAS) && !defined(EXCLUDE_AUDIO)
+
+#define TRACE(WHAT) /* (WHAT) */
+
+#define PAS_PCM_INTRBITS (0x08)
+/* Sample buffer timer interrupt enable */
+
+#define PCM_NON 0
+#define PCM_DAC 1
+#define PCM_ADC 2
+
+static unsigned long pcm_speed = 0; /* sampling rate */
+static unsigned char pcm_channels = 1; /* channels/sample (1 or 2) */
+static unsigned char pcm_bits = 8; /* bits/sample (8 or 16) */
+static unsigned char pcm_filter = 0; /* filter FLAG */
+static unsigned char pcm_mode = PCM_NON;
+static unsigned long pcm_count = 0;
+static unsigned short pcm_bitsok = 8; /* mask of OK bits */
+static int my_devnum = 0;
+
+int
+pcm_set_speed (int arg)
+{
+ int foo, tmp;
+ unsigned long flags;
+
+ if (arg > 44100)
+ arg = 44100;
+ if (arg < 5000)
+ arg = 5000;
+
+ foo = 1193180 / arg;
+ arg = 1193180 / foo;
+
+ if (pcm_channels & 2)
+ foo = foo >> 1;
+
+ pcm_speed = arg;
+
+ tmp = pas_read (FILTER_FREQUENCY);
+
+ DISABLE_INTR (flags);
+
+ pas_write (tmp & ~(F_F_PCM_RATE_COUNTER | F_F_PCM_BUFFER_COUNTER), FILTER_FREQUENCY);
+ pas_write (S_C_C_SAMPLE_RATE | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
+ pas_write (foo & 0xff, SAMPLE_RATE_TIMER);
+ pas_write ((foo >> 8) & 0xff, SAMPLE_RATE_TIMER);
+ pas_write (tmp, FILTER_FREQUENCY);
+
+ RESTORE_INTR (flags);
+
+ return pcm_speed;
+}
+
+int
+pcm_set_channels (int arg)
+{
+
+ if ((arg != 1) && (arg != 2))
+ return pcm_channels;
+
+ if (arg != pcm_channels)
+ {
+ pas_write (pas_read (PCM_CONTROL) ^ P_C_PCM_MONO, PCM_CONTROL);
+
+ pcm_channels = arg;
+ pcm_set_speed (pcm_speed);/* The speed must be reinitialized */
+ }
+
+ return pcm_channels;
+}
+
+int
+pcm_set_bits (int arg)
+{
+ if ((arg & pcm_bitsok) != arg)
+ return pcm_bits;
+
+ if (arg != pcm_bits)
+ {
+ pas_write (pas_read (SYSTEM_CONFIGURATION_2) ^ S_C_2_PCM_16_BIT, SYSTEM_CONFIGURATION_2);
+
+ pcm_bits = arg;
+ }
+
+ return pcm_bits;
+}
+
+static int
+pas_pcm_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+{
+ TRACE (printk ("pas2_pcm.c: static int pas_pcm_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
+
+ switch (cmd)
+ {
+ case SOUND_PCM_WRITE_RATE:
+ if (local)
+ return pcm_set_speed (arg);
+ return IOCTL_OUT (arg, pcm_set_speed (IOCTL_IN (arg)));
+ break;
+
+ case SOUND_PCM_READ_RATE:
+ if (local)
+ return pcm_speed;
+ return IOCTL_OUT (arg, pcm_speed);
+ break;
+
+ case SNDCTL_DSP_STEREO:
+ if (local)
+ return pcm_set_channels (arg + 1) - 1;
+ return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg) + 1) - 1);
+ break;
+
+ case SOUND_PCM_WRITE_CHANNELS:
+ if (local)
+ return pcm_set_channels (arg);
+ return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg)));
+ break;
+
+ case SOUND_PCM_READ_CHANNELS:
+ if (local)
+ return pcm_channels;
+ return IOCTL_OUT (arg, pcm_channels);
+ break;
+
+ case SNDCTL_DSP_SAMPLESIZE:
+ if (local)
+ return pcm_set_bits (arg);
+ return IOCTL_OUT (arg, pcm_set_bits (IOCTL_IN (arg)));
+ break;
+
+ case SOUND_PCM_READ_BITS:
+ if (local)
+ return pcm_bits;
+ return IOCTL_OUT (arg, pcm_bits);
+
+ case SOUND_PCM_WRITE_FILTER: /* NOT YET IMPLEMENTED */
+ if (IOCTL_IN (arg) > 1)
+ return IOCTL_OUT (arg, RET_ERROR (EINVAL));
+ break;
+
+ pcm_filter = IOCTL_IN (arg);
+ case SOUND_PCM_READ_FILTER:
+ return IOCTL_OUT (arg, pcm_filter);
+ break;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+
+ return RET_ERROR (EINVAL);
+}
+
+static void
+pas_pcm_reset (int dev)
+{
+ TRACE (printk ("pas2_pcm.c: static void pas_pcm_reset(void)\n"));
+
+ pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, PCM_CONTROL);
+}
+
+static int
+pas_pcm_open (int dev, int mode)
+{
+ int err;
+
+ TRACE (printk ("pas2_pcm.c: static int pas_pcm_open(int mode = %X)\n", mode));
+
+ if ((err = pas_set_intr (PAS_PCM_INTRBITS)) < 0)
+ return err;
+
+ if (!DMAbuf_open_dma (dev))
+ {
+ pas_remove_intr (PAS_PCM_INTRBITS);
+ return RET_ERROR (EBUSY);
+ }
+
+ pcm_count = 0;
+
+ return 0;
+}
+
+static void
+pas_pcm_close (int dev)
+{
+ unsigned long flags;
+
+ TRACE (printk ("pas2_pcm.c: static void pas_pcm_close(void)\n"));
+
+ DISABLE_INTR (flags);
+
+ pas_pcm_reset (dev);
+ DMAbuf_close_dma (dev);
+ pas_remove_intr (PAS_PCM_INTRBITS);
+ pcm_mode = PCM_NON;
+
+ RESTORE_INTR (flags);
+}
+
+static void
+pas_pcm_output_block (int dev, unsigned long buf, int count,
+ int intrflag, int restart_dma)
+{
+ unsigned long flags, cnt;
+
+ TRACE (printk ("pas2_pcm.c: static void pas_pcm_output_block(char *buf = %P, int count = %X)\n", buf, count));
+
+ cnt = count;
+ if (sound_dsp_dmachan[dev] > 3)
+ cnt >>= 1;
+
+ if (sound_dma_automode[dev] &&
+ intrflag &&
+ cnt == pcm_count)
+ return; /* Auto mode on. No need to react */
+
+ DISABLE_INTR (flags);
+
+ pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,
+ PCM_CONTROL);
+
+ if (restart_dma)
+ DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
+
+ if (sound_dsp_dmachan[dev] > 3)
+ count >>= 1;
+
+ if (count != pcm_count)
+ {
+ pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
+ pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
+ pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER);
+ pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER);
+ pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
+
+ pcm_count = count;
+ }
+ pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
+ pas_write (pas_read (PCM_CONTROL) | P_C_PCM_ENABLE | P_C_PCM_DAC_MODE, PCM_CONTROL);
+
+ pcm_mode = PCM_DAC;
+
+ RESTORE_INTR (flags);
+}
+
+static void
+pas_pcm_start_input (int dev, unsigned long buf, int count,
+ int intrflag, int restart_dma)
+{
+ unsigned long flags;
+ int cnt;
+
+ TRACE (printk ("pas2_pcm.c: static void pas_pcm_start_input(char *buf = %P, int count = %X)\n", buf, count));
+
+ cnt = count;
+ if (sound_dsp_dmachan[dev] > 3)
+ cnt >>= 1;
+
+ if (sound_dma_automode[my_devnum] &&
+ intrflag &&
+ cnt == pcm_count)
+ return; /* Auto mode on. No need to react */
+
+ DISABLE_INTR (flags);
+
+ if (restart_dma)
+ DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
+
+ if (sound_dsp_dmachan[dev] > 3)
+ count >>= 1;
+
+ if (count != pcm_count)
+ {
+ pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
+ pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL);
+ pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER);
+ pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER);
+ pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY);
+
+ pcm_count = count;
+ }
+ pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY);
+ pas_write ((pas_read (PCM_CONTROL) | P_C_PCM_ENABLE) & ~P_C_PCM_DAC_MODE, PCM_CONTROL);
+
+ pcm_mode = PCM_ADC;
+
+ RESTORE_INTR (flags);
+}
+
+static int
+pas_pcm_prepare_for_input (int dev, int bsize, int bcount)
+{
+ return 0;
+}
+static int
+pas_pcm_prepare_for_output (int dev, int bsize, int bcount)
+{
+ return 0;
+}
+
+static struct audio_operations pas_pcm_operations =
+{
+ "Pro Audio Spectrum",
+ NOTHING_SPECIAL,
+ pas_pcm_open,
+ pas_pcm_close,
+ pas_pcm_output_block,
+ pas_pcm_start_input,
+ pas_pcm_ioctl,
+ pas_pcm_prepare_for_input,
+ pas_pcm_prepare_for_output,
+ pas_pcm_reset,
+ pas_pcm_reset, /* halt_xfer */
+ NULL, /* has_output_drained */
+ NULL /* copy_from_user */
+};
+
+long
+pas_pcm_init (long mem_start, struct address_info *hw_config)
+{
+ TRACE (printk ("pas2_pcm.c: long pas_pcm_init(long mem_start = %X)\n", mem_start));
+
+ pcm_bitsok = 8;
+ if (pas_read (OPERATION_MODE_1) & O_M_1_PCM_TYPE)
+ pcm_bitsok |= 16;
+
+ pcm_set_speed (DSP_DEFAULT_SPEED);
+
+ if (num_dspdevs < MAX_DSP_DEV)
+ {
+ dsp_devs[my_devnum = num_dspdevs++] = &pas_pcm_operations;
+ sound_dsp_dmachan[my_devnum] = hw_config->dma;
+#ifndef NO_AUTODMA
+ if (hw_config->dma > 3)
+ {
+ sound_buffcounts[my_devnum] = 1;
+ sound_buffsizes[my_devnum] = 2 * 65536;
+ sound_dma_automode[my_devnum] = 1;
+ }
+ else
+ {
+ sound_buffcounts[my_devnum] = 1;
+ sound_buffsizes[my_devnum] = DSP_BUFFSIZE;
+ sound_dma_automode[my_devnum] = 1;
+ }
+#else
+ sound_buffcounts[my_devnum] = DSP_BUFFCOUNT;
+ sound_buffsizes[my_devnum] = DSP_BUFFSIZE;
+ sound_dma_automode[my_devnum] = 0;
+#endif
+ }
+ else
+ printk ("PAS2: Too many PCM devices available\n");
+
+ return mem_start;
+}
+
+void
+pas_pcm_interrupt (unsigned char status, int cause)
+{
+ if (cause == 1) /* PCM buffer done */
+ {
+ /*
+ * Halt the PCM first. Otherwise we don't have time to start a new
+ * block before the PCM chip proceeds to the next sample
+ */
+
+ if (!sound_dma_automode[my_devnum])
+ {
+ pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE,
+ PCM_CONTROL);
+ }
+
+ switch (pcm_mode)
+ {
+
+ case PCM_DAC:
+ DMAbuf_outputintr (my_devnum, 1);
+ break;
+
+ case PCM_ADC:
+ DMAbuf_inputintr (my_devnum);
+ break;
+
+ default:
+ printk ("PAS: Unexpected PCM interrupt\n");
+ }
+ }
+}
+
+#endif
+
+#endif
diff --git a/sys/i386/isa/sound/patmgr.c b/sys/i386/isa/sound/patmgr.c
new file mode 100644
index 0000000..042d42d
--- /dev/null
+++ b/sys/i386/isa/sound/patmgr.c
@@ -0,0 +1,262 @@
+/*
+ * sound/patmgr.c
+ *
+ * The patch maneger interface for the /dev/sequencer
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#define PATMGR_C
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SEQUENCER)
+
+DEFINE_WAIT_QUEUES (server_procs[MAX_SYNTH_DEV],
+ server_wait_flag[MAX_SYNTH_DEV]);
+
+static struct patmgr_info *mbox[MAX_SYNTH_DEV] =
+{NULL};
+static volatile int msg_direction[MAX_SYNTH_DEV] =
+{0};
+
+static int pmgr_opened[MAX_SYNTH_DEV] =
+{0};
+
+#define A_TO_S 1
+#define S_TO_A 2
+
+DEFINE_WAIT_QUEUE (appl_proc, appl_wait_flag);
+
+int
+pmgr_open (int dev)
+{
+ if (dev < 0 || dev >= num_synths)
+ return RET_ERROR (ENXIO);
+
+ if (pmgr_opened[dev])
+ return RET_ERROR (EBUSY);
+ pmgr_opened[dev] = 1;
+
+ RESET_WAIT_QUEUE (server_procs[dev], server_wait_flag[dev]);
+
+ return 0;
+}
+
+void
+pmgr_release (int dev)
+{
+
+ if (mbox[dev]) /* Killed in action. Inform the client */
+ {
+
+ mbox[dev]->key = PM_ERROR;
+ mbox[dev]->parm1 = RET_ERROR (EIO);
+
+ if (SOMEONE_WAITING (appl_proc, appl_wait_flag))
+ WAKE_UP (appl_proc, appl_wait_flag);
+ }
+
+ pmgr_opened[dev] = 0;
+}
+
+int
+pmgr_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ unsigned long flags;
+ int ok = 0;
+
+ if (count != sizeof (struct patmgr_info))
+ {
+ printk ("PATMGR%d: Invalid read count\n", dev);
+ return RET_ERROR (EIO);
+ }
+
+ while (!ok && !PROCESS_ABORTING (server_procs[dev], server_wait_flag[dev]))
+ {
+ DISABLE_INTR (flags);
+
+ while (!(mbox[dev] && msg_direction[dev] == A_TO_S) &&
+ !PROCESS_ABORTING (server_procs[dev], server_wait_flag[dev]))
+ {
+ DO_SLEEP (server_procs[dev], server_wait_flag[dev], 0);
+ }
+
+ if (mbox[dev] && msg_direction[dev] == A_TO_S)
+ {
+ COPY_TO_USER (buf, 0, (char *) mbox[dev], count);
+ msg_direction[dev] = 0;
+ ok = 1;
+ }
+
+ RESTORE_INTR (flags);
+
+ }
+
+ if (!ok)
+ return RET_ERROR (EINTR);
+ return count;
+}
+
+int
+pmgr_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ unsigned long flags;
+
+ if (count < 4)
+ {
+ printk ("PATMGR%d: Write count < 4\n", dev);
+ return RET_ERROR (EIO);
+ }
+
+ COPY_FROM_USER (mbox[dev], buf, 0, 4);
+
+ if (*(unsigned char *) mbox[dev] == SEQ_FULLSIZE)
+ {
+ int tmp_dev;
+
+ tmp_dev = ((unsigned short *) mbox[dev])[2];
+ if (tmp_dev != dev)
+ return RET_ERROR (ENXIO);
+
+ return synth_devs[dev]->load_patch (dev, *(unsigned short *) mbox[dev],
+ buf, 4, count, 1);
+ }
+
+ if (count != sizeof (struct patmgr_info))
+ {
+ printk ("PATMGR%d: Invalid write count\n", dev);
+ return RET_ERROR (EIO);
+ }
+
+ /*
+ * If everything went OK, there should be a preallocated buffer in the
+ * mailbox and a client waiting.
+ */
+
+ DISABLE_INTR (flags);
+
+ if (mbox[dev] && !msg_direction[dev])
+ {
+ COPY_FROM_USER (&((char *) mbox[dev])[4], buf, 4, count - 4);
+ msg_direction[dev] = S_TO_A;
+
+ if (SOMEONE_WAITING (appl_proc, appl_wait_flag))
+ {
+ WAKE_UP (appl_proc, appl_wait_flag);
+ }
+ }
+
+ RESTORE_INTR (flags);
+
+ return count;
+}
+
+int
+pmgr_access (int dev, struct patmgr_info *rec)
+{
+ unsigned long flags;
+ int err = 0;
+
+ DISABLE_INTR (flags);
+
+ if (mbox[dev])
+ printk (" PATMGR: Server %d mbox full. Why?\n", dev);
+ else
+ {
+ rec->key = PM_K_COMMAND;
+ mbox[dev] = rec;
+ msg_direction[dev] = A_TO_S;
+
+ if (SOMEONE_WAITING (server_procs[dev], server_wait_flag[dev]))
+ {
+ WAKE_UP (server_procs[dev], server_wait_flag[dev]);
+ }
+
+ DO_SLEEP (appl_proc, appl_wait_flag, 0);
+
+ if (msg_direction[dev] != S_TO_A)
+ {
+ rec->key = PM_ERROR;
+ rec->parm1 = RET_ERROR (EIO);
+ }
+ else if (rec->key == PM_ERROR)
+ {
+ err = rec->parm1;
+ if (err > 0)
+ err = -err;
+ }
+
+ mbox[dev] = NULL;
+ msg_direction[dev] = 0;
+ }
+
+ RESTORE_INTR (flags);
+
+ return err;
+}
+
+int
+pmgr_inform (int dev, int event, unsigned long p1, unsigned long p2,
+ unsigned long p3, unsigned long p4)
+{
+ unsigned long flags;
+ int err = 0;
+
+ if (!pmgr_opened[dev])
+ return 0;
+
+ DISABLE_INTR (flags);
+
+ if (mbox[dev])
+ printk (" PATMGR: Server %d mbox full. Why?\n", dev);
+ else
+ {
+ mbox[dev] =
+ (struct patmgr_info *) KERNEL_MALLOC (sizeof (struct patmgr_info));
+
+ mbox[dev]->key = PM_K_EVENT;
+ mbox[dev]->command = event;
+ mbox[dev]->parm1 = p1;
+ mbox[dev]->parm2 = p2;
+ mbox[dev]->parm3 = p3;
+ msg_direction[dev] = A_TO_S;
+
+ if (SOMEONE_WAITING (server_procs[dev], server_wait_flag[dev]))
+ {
+ WAKE_UP (server_procs[dev], server_wait_flag[dev]);
+ }
+
+ DO_SLEEP (appl_proc, appl_wait_flag, 0);
+ if (mbox[dev])
+ KERNEL_FREE (mbox[dev]);
+ mbox[dev] = NULL;
+ msg_direction[dev] = 0;
+ }
+
+ RESTORE_INTR (flags);
+
+ return err;
+}
+
+#endif
diff --git a/sys/i386/isa/sound/pro_midi.c b/sys/i386/isa/sound/pro_midi.c
new file mode 100644
index 0000000..b9ffa26
--- /dev/null
+++ b/sys/i386/isa/sound/pro_midi.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright by UWM - comments to soft-eng@cs.uwm.edu
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#define ALL_EXTERNAL_TO_ME
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+#include "pas.h"
+#define ESUCCESS 0
+
+#if !defined(EXCLUDE_PRO_MIDI) && !defined(EXCLUDE_CHIP_MIDI)
+
+
+/** Structure for handling operations **/
+
+
+static struct generic_midi_operations pro_midi_operations =
+{
+
+ {"Pro_Audio_Spectrum 16 MV101", 0},
+ pro_midi_open,
+ pro_midi_close,
+ pro_midi_write,
+ pro_midi_read
+};
+
+/*
+ * Note! Note! Note! Follow the same model for any other attach function you
+ * may write
+ */
+
+long
+pro_midi_attach (long mem_start)
+{
+ pro_midi_dev = num_generic_midis;
+ generic_midi_devs[num_generic_midis++] = &pro_midi_operations;
+ return mem_start;
+}
+
+int
+pro_midi_open (int dev, int mode)
+{
+
+ int intr_mask, s;
+
+
+ s = splhigh ();
+
+
+ /* Reset the input and output FIFO pointers */
+
+
+ outb (MIDI_CONTROL, M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO);
+
+ /* Get the interrupt status */
+
+ intr_mask = inb (INTERRUPT_MASK);
+
+
+ /* Enable MIDI IRQ */
+
+ intr_mask |= I_M_MIDI_IRQ_ENABLE;
+ outb (INTERRUPT_MASK, intr_mask);
+
+
+ /* Enable READ/WRITE on MIDI port. This part is quite unsure though */
+
+ outb (MIDI_CONTROL, M_C_ENA_OUTPUT_IRQ | M_C_ENA_INPUT_IRQ);
+
+ /* Acknowledge pending interrupts */
+
+ outb (MIDI_STATUS, 0xff);
+
+
+ splx (s);
+
+ return (ESUCCESS);
+
+
+}
+
+
+void
+pro_midi_close (int dev)
+{
+
+ int intr_mask;
+
+ /* Clean up */
+
+ outb (MIDI_CONTROL, M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO);
+ intr_mask = inb (INTERRUPT_MASK);
+ intr_mask &= ~I_M_MIDI_IRQ_ENABLE;
+ outb (INTERRUPT_MASK, intr_mask);
+
+ return;
+}
+
+int
+pro_midi_write (int dev, struct uio *uio)
+{
+
+ int s;
+ unsigned char data;
+
+ /* printf("midi: Going to do write routine..\n"); */
+ while (uio->uio_resid)
+ {
+
+ if (uiomove (&data, 1, uio))
+ return (ENOTTY);
+
+ s = splhigh ();
+
+ DELAY (30);
+ outb (MIDI_DATA, data);
+ DELAY (70); /* Ze best pause.. find a better one if you
+ * can :) */
+ splx (s);
+ }
+
+ return (ESUCCESS);
+
+}
+
+
+int
+pro_midi_read (int dev, struct uio *uio)
+{
+
+ int s;
+ unsigned char data;
+
+ s = splhigh ();
+
+ /* For each uio_iov[] entry .... */
+
+ while (uio->uio_resid)
+ {
+
+ if (((inb (MIDI_STATUS) & M_S_INPUT_AVAIL) == 0) &&
+ ((inb (MIDI_FIFO_STATUS) & MIDI_INPUT_AVAILABLE) == 0))
+
+ data = 0xfe;
+ else
+ data = inb (MIDI_DATA);
+
+ if (uiomove (&data, 1, uio))
+ {
+
+ printf ("midi: Bad copyout()!\n");
+ return (ENOTTY);
+
+ }
+
+ }
+ splx (s);
+ return (ESUCCESS);
+
+}
+
+#endif
+
+#endif
diff --git a/sys/i386/isa/sound/sb.h b/sys/i386/isa/sound/sb.h
new file mode 100644
index 0000000..bb8ae12
--- /dev/null
+++ b/sys/i386/isa/sound/sb.h
@@ -0,0 +1,28 @@
+#define DSP_RESET (sbc_base + 0x6)
+#define DSP_READ (sbc_base + 0xA)
+#define DSP_WRITE (sbc_base + 0xC)
+#define DSP_COMMAND (sbc_base + 0xC)
+#define DSP_STATUS (sbc_base + 0xC)
+#define DSP_DATA_AVAIL (sbc_base + 0xE)
+#define DSP_DATA_AVL16 (sbc_base + 0xF)
+#define MIXER_ADDR (sbc_base + 0x4)
+#define MIXER_DATA (sbc_base + 0x5)
+#define OPL3_LEFT (sbc_base + 0x0)
+#define OPL3_RIGHT (sbc_base + 0x2)
+#define OPL3_BOTH (sbc_base + 0x8)
+/* DSP Commands */
+
+#define DSP_CMD_SPKON 0xD1
+#define DSP_CMD_SPKOFF 0xD3
+#define DSP_CMD_DMAON 0xD0
+#define DSP_CMD_DMAOFF 0xD4
+
+#define IMODE_NONE 0
+#define IMODE_OUTPUT 1
+#define IMODE_INPUT 2
+#define IMODE_INIT 3
+#define IMODE_MIDI 4
+
+#define NORMAL_MIDI 0
+#define UART_MIDI 1
+
diff --git a/sys/i386/isa/sound/sb16_dsp.c b/sys/i386/isa/sound/sb16_dsp.c
new file mode 100644
index 0000000..b545f8c
--- /dev/null
+++ b/sys/i386/isa/sound/sb16_dsp.c
@@ -0,0 +1,627 @@
+/*
+ * sound/sb16_dsp.c
+ *
+ * The low level driver for the SoundBlaster DSP chip.
+ *
+ * (C) 1993 J. Schubert (jsb@sth.ruhr-uni-bochum.de)
+ *
+ * based on SB-driver by (C) Hannu Savolainen
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#define DEB(x)
+#define DEB1(x)
+/*
+ #define DEB_DMARES
+ */
+#include "sound_config.h"
+#include "sb.h"
+#include "sb_mixer.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_AUDIO) && !defined(EXCLUDE_SBPRO)
+
+extern int sbc_base, sbc_minor, sbc_major;
+
+static int sb16_dsp_ok = 0;/* Set to 1 after successful initialization */
+static int dsp_16bit = 0;
+static int dsp_stereo = 0;
+static int dsp_current_speed = 8000; /*DSP_DEFAULT_SPEED; */
+static int dsp_busy = 0;
+static int dma16, dma8;
+static unsigned long dsp_count = 0;
+
+static int irq_mode = IMODE_NONE; /* IMODE_INPUT, IMODE_OUTPUT or
+
+ IMODE_NONE */
+static int my_dev = 0;
+
+static volatile int intr_active = 0;
+
+static int sb16_dsp_open (int dev, int mode);
+static void sb16_dsp_close (int dev);
+static void sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
+static void sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart);
+static int sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local);
+static int sb16_dsp_prepare_for_input (int dev, int bsize, int bcount);
+static int sb16_dsp_prepare_for_output (int dev, int bsize, int bcount);
+static void sb16_dsp_reset (int dev);
+static void sb16_dsp_halt (int dev);
+static int dsp_set_speed (int);
+static int dsp_set_stereo (int);
+static void dsp_cleanup (void);
+int sb_reset_dsp (void);
+
+static struct audio_operations sb16_dsp_operations =
+{
+ "SoundBlaster 16",
+ NOTHING_SPECIAL,
+ sb16_dsp_open,
+ sb16_dsp_close,
+ sb16_dsp_output_block,
+ sb16_dsp_start_input,
+ sb16_dsp_ioctl,
+ sb16_dsp_prepare_for_input,
+ sb16_dsp_prepare_for_output,
+ sb16_dsp_reset,
+ sb16_dsp_halt,
+ NULL,
+ NULL
+};
+
+static int
+sb_dsp_command01 (unsigned char val)
+{
+ int i = 1 << 16;
+
+ while (--i & (!INB (DSP_STATUS) & 0x80));
+ if (!i)
+ printk ("SB16 sb_dsp_command01 Timeout\n");
+ return sb_dsp_command (val);
+}
+
+static int
+wait_data_avail (unsigned long t)
+{
+ int loopc = 5000000;
+
+ t += GET_TIME ();
+ do
+ {
+ if (INB (DSP_DATA_AVAIL) & 0x80)
+ return 1;
+ }
+ while (--loopc && GET_TIME () < t);
+ printk ("!data_avail l=%d\n", loopc);
+ return 0;
+}
+
+static int
+read_dsp (int t)
+{
+ if (!wait_data_avail ((unsigned long) t))
+ return -1;
+ else
+ return INB (DSP_READ);
+}
+
+static int
+dsp_ini2 (void)
+{
+#if 0
+ /* sb_setmixer(0x83, sb_getmixer(0x83) | 0x03); */
+ sb_dsp_command (0xe2);
+ sb_dsp_command (0x76); /* E0 ??? */
+ sb_dsp_command (0xe2);
+ sb_dsp_command (0x30); /* A0 ??? */
+ sb_dsp_command (0xe4);
+ sb_dsp_command (0xaa);
+ sb_dsp_command (0xe8);
+ if (read_dsp (100) != 0xaa)
+ printk ("Error dsp_ini2\n");
+#endif
+ return 0;
+}
+
+/*
+ static char *dsp_getmessage(unsigned char command,int maxn)
+ {
+ static char buff[100];
+ int n=0;
+
+ sb_dsp_command(command);
+ while(n<maxn && wait_data_avail(2L)) {
+ buff[++n]=INB(DSP_READ);
+ if(!buff[n])
+ break;
+ }
+ buff[0]=n;
+ return buff;
+ }
+
+ static void dsp_showmessage(unsigned char command,int len)
+ {
+ int n;
+ unsigned char *c;
+ c=dsp_getmessage(command,len);
+ printk("DSP C=%x l=%d,lr=%d b=",command,len,c[0]);
+ for(n=1;n<=c[0];n++)
+ if(c[n]>=' ' & c[n]<='z')
+ printk("%c",c[n]);
+ else
+ printk("|%x|",c[n]);
+ printk("\n");
+ }
+ */
+static int
+dsp_set_speed (int mode)
+{
+ DEB (printk ("dsp_set_speed(%d)\n", mode));
+ if (mode)
+ {
+ if (mode < 5000)
+ mode = 5000;
+ if (mode > 44100)
+ mode = 44100;
+ dsp_current_speed = mode;
+ }
+ return mode;
+}
+
+static int
+dsp_set_stereo (int mode)
+{
+ DEB (printk ("dsp_set_stereo(%d)\n", mode));
+
+ dsp_stereo = mode;
+
+ return mode;
+}
+
+static int
+dsp_set_bits (int arg)
+{
+ DEB (printk ("dsp_set_bits(%d)\n", arg));
+
+ if (arg)
+ switch (arg)
+ {
+ case 8:
+ dsp_16bit = 0;
+ break;
+ case 16:
+ dsp_16bit = 1;
+ break;
+ default:
+ return RET_ERROR (EINVAL);
+ }
+ return dsp_16bit ? 16 : 8;
+}
+
+static int
+sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+{
+ switch (cmd)
+ {
+ case SOUND_PCM_WRITE_RATE:
+ if (local)
+ return dsp_set_speed (arg);
+ return IOCTL_OUT (arg, dsp_set_speed (IOCTL_IN (arg)));
+
+ case SOUND_PCM_READ_RATE:
+ if (local)
+ return dsp_current_speed;
+ return IOCTL_OUT (arg, dsp_current_speed);
+
+ case SNDCTL_DSP_STEREO:
+ if (local)
+ return dsp_set_stereo (arg);
+ return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg)));
+
+ case SOUND_PCM_WRITE_CHANNELS:
+ if (local)
+ return dsp_set_stereo (arg - 1) + 1;
+ return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg) - 1) + 1);
+
+ case SOUND_PCM_READ_CHANNELS:
+ if (local)
+ return dsp_stereo + 1;
+ return IOCTL_OUT (arg, dsp_stereo + 1);
+
+ case SNDCTL_DSP_SAMPLESIZE:
+ if (local)
+ return dsp_set_bits (arg);
+ return IOCTL_OUT (arg, dsp_set_bits (IOCTL_IN (arg)));
+
+ case SOUND_PCM_READ_BITS:
+ if (local)
+ return dsp_16bit ? 16 : 8;
+ return IOCTL_OUT (arg, dsp_16bit ? 16 : 8);
+
+ case SOUND_PCM_WRITE_FILTER: /* NOT YET IMPLEMENTED */
+ if (IOCTL_IN (arg) > 1)
+ return IOCTL_OUT (arg, RET_ERROR (EINVAL));
+ default:
+ return RET_ERROR (EINVAL);
+ }
+
+ return RET_ERROR (EINVAL);
+}
+
+static int
+sb16_dsp_open (int dev, int mode)
+{
+ int retval;
+
+ DEB (printk ("sb16_dsp_open()\n"));
+ if (!sb16_dsp_ok)
+ {
+ printk ("SB16 Error: SoundBlaster board not installed\n");
+ return RET_ERROR (ENXIO);
+ }
+
+ if (intr_active)
+ return RET_ERROR (EBUSY);
+
+ retval = sb_get_irq ();
+ if (retval < 0)
+ return retval;
+
+ if (ALLOC_DMA_CHN (dma8))
+ {
+ printk ("SB16: Unable to grab DMA%d\n", dma8);
+ sb_free_irq ();
+ return RET_ERROR (EBUSY);
+ }
+
+ if (dma16 != dma8)
+ if (ALLOC_DMA_CHN (dma16))
+ {
+ printk ("SB16: Unable to grab DMA%d\n", dma16);
+ sb_free_irq ();
+ RELEASE_DMA_CHN (dma8);
+ return RET_ERROR (EBUSY);
+ }
+
+ dsp_ini2 ();
+
+ irq_mode = IMODE_NONE;
+ dsp_busy = 1;
+
+ return 0;
+}
+
+static void
+sb16_dsp_close (int dev)
+{
+ unsigned long flags;
+
+ DEB (printk ("sb16_dsp_close()\n"));
+ sb_dsp_command01 (0xd9);
+ sb_dsp_command01 (0xd5);
+
+ DISABLE_INTR (flags);
+ RELEASE_DMA_CHN (dma8);
+
+ if (dma16 != dma8)
+ RELEASE_DMA_CHN (dma16);
+ sb_free_irq ();
+ dsp_cleanup ();
+ dsp_busy = 0;
+ RESTORE_INTR (flags);
+}
+
+static void
+sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
+{
+ unsigned long flags, cnt;
+
+ cnt = count;
+ if (dsp_16bit)
+ cnt >>= 1;
+ cnt--;
+
+#ifdef DEB_DMARES
+ printk ("output_block: %x %d %d\n", buf, count, intrflag);
+ if (intrflag)
+ {
+ int pos, chan = sound_dsp_dmachan[dev];
+
+ DISABLE_INTR (flags);
+ clear_dma_ff (chan);
+ disable_dma (chan);
+ pos = get_dma_residue (chan);
+ enable_dma (chan);
+ RESTORE_INTR (flags);
+ printk ("dmapos=%d %x\n", pos, pos);
+ }
+#endif
+ if (sound_dma_automode[dev] &&
+ intrflag &&
+ cnt == dsp_count)
+ {
+ irq_mode = IMODE_OUTPUT;
+ intr_active = 1;
+ return; /* Auto mode on. No need to react */
+ }
+ DISABLE_INTR (flags);
+
+ if (dma_restart)
+ {
+ sb16_dsp_halt (dev);
+ DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
+ }
+ sb_dsp_command (0x41);
+ sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff));
+ sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff));
+ sb_dsp_command ((unsigned char) (dsp_16bit ? 0xb6 : 0xc6));
+ sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) +
+ (dsp_16bit ? 0x10 : 0)));
+ sb_dsp_command01 ((unsigned char) (cnt & 0xff));
+ sb_dsp_command ((unsigned char) (cnt >> 8));
+ /* sb_dsp_command (0);
+ sb_dsp_command (0); */
+
+ RESTORE_INTR (flags);
+ dsp_count = cnt;
+ irq_mode = IMODE_OUTPUT;
+ intr_active = 1;
+}
+
+static void
+sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
+{
+ unsigned long flags, cnt;
+
+ cnt = count;
+ if (dsp_16bit)
+ cnt >>= 1;
+ cnt--;
+
+#ifdef DEB_DMARES
+ printk ("start_input: %x %d %d\n", buf, count, intrflag);
+ if (intrflag)
+ {
+ int pos, chan = sound_dsp_dmachan[dev];
+
+ DISABLE_INTR (flags);
+ clear_dma_ff (chan);
+ disable_dma (chan);
+ pos = get_dma_residue (chan);
+ enable_dma (chan);
+ RESTORE_INTR (flags);
+ printk ("dmapos=%d %x\n", pos, pos);
+ }
+#endif
+ if (sound_dma_automode[dev] &&
+ intrflag &&
+ cnt == dsp_count)
+ {
+ irq_mode = IMODE_INPUT;
+ intr_active = 1;
+ return; /* Auto mode on. No need to react */
+ }
+ DISABLE_INTR (flags);
+
+ if (dma_restart)
+ {
+ sb16_dsp_halt (dev);
+ DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
+ }
+
+ sb_dsp_command (0x42);
+ sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff));
+ sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff));
+ sb_dsp_command ((unsigned char) (dsp_16bit ? 0xbe : 0xce));
+ sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) +
+ (dsp_16bit ? 0x10 : 0)));
+ sb_dsp_command01 ((unsigned char) (cnt & 0xff));
+ sb_dsp_command ((unsigned char) (cnt >> 8));
+
+ /* sb_dsp_command (0);
+ sb_dsp_command (0); */
+ RESTORE_INTR (flags);
+ dsp_count = cnt;
+ irq_mode = IMODE_INPUT;
+ intr_active = 1;
+}
+
+static int
+sb16_dsp_prepare_for_input (int dev, int bsize, int bcount)
+{
+ sound_dsp_dmachan[my_dev] = dsp_16bit ? dma16 : dma8;
+ dsp_count = 0;
+ dsp_cleanup ();
+ return 0;
+}
+
+static int
+sb16_dsp_prepare_for_output (int dev, int bsize, int bcount)
+{
+ sound_dsp_dmachan[my_dev] = dsp_16bit ? dma16 : dma8;
+ dsp_count = 0;
+ dsp_cleanup ();
+ return 0;
+}
+
+static void
+dsp_cleanup (void)
+{
+ irq_mode = IMODE_NONE;
+ intr_active = 0;
+}
+
+static void
+sb16_dsp_reset (int dev)
+{
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+
+ sb_reset_dsp ();
+ dsp_cleanup ();
+
+ RESTORE_INTR (flags);
+}
+
+static void
+sb16_dsp_halt (int dev)
+{
+ if (dsp_16bit)
+ {
+ sb_dsp_command01 (0xd9);
+ sb_dsp_command01 (0xd5);
+ }
+ else
+ {
+ sb_dsp_command01 (0xda);
+ sb_dsp_command01 (0xd0);
+ }
+}
+
+static void
+set_irq_hw (int level)
+{
+ int ival;
+
+ switch (level)
+ {
+ case 5:
+ ival = 2;
+ break;
+ case 7:
+ ival = 4;
+ break;
+ case 10:
+ ival = 8;
+ break;
+ default:
+ printk ("SB16_IRQ_LEVEL %d does not exist\n", level);
+ return;
+ }
+ sb_setmixer (IRQ_NR, ival);
+}
+
+long
+sb16_dsp_init (long mem_start, struct address_info *hw_config)
+{
+ if (sbc_major < 4)
+ return mem_start;
+
+#ifndef SCO
+ sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor);
+#endif
+
+#ifdef __FreeBSD__
+ printk ("snd6: <%s>", sb16_dsp_operations.name);
+#else
+ printk (" <%s>", sb16_dsp_operations.name);
+#endif
+
+ if (num_dspdevs < MAX_DSP_DEV)
+ {
+ dsp_devs[my_dev = num_dspdevs++] = &sb16_dsp_operations;
+ sound_dsp_dmachan[my_dev] = hw_config->dma;
+#ifndef NO_AUTODMA
+ sound_buffcounts[my_dev] = 1;
+ sound_dma_automode[my_dev] = 1;
+#else
+ sound_buffcounts[my_dev] = DSP_BUFFCOUNT;
+ sound_dma_automode[my_dev] = 0;
+#endif
+ sound_buffsizes[my_dev] = DSP_BUFFSIZE;
+ }
+ else
+ printk ("SB: Too many DSP devices available\n");
+ sb16_dsp_ok = 1;
+ return mem_start;
+}
+
+int
+sb16_dsp_detect (struct address_info *hw_config)
+{
+ struct address_info *sb_config;
+
+ if (sb16_dsp_ok)
+ return 1; /* Already initialized */
+
+ if (!(sb_config = sound_getconf (SNDCARD_SB)))
+ {
+ printk ("SB16 Error: Plain SB not configured\n");
+ return 0;
+ }
+
+ /* sb_setmixer(OPSW,0xf);
+ if(sb_getmixer(OPSW)!=0xf)
+ return 0; */
+
+ if (!sb_reset_dsp ())
+ return 0;
+
+ if (hw_config->dma < 4)
+ if (hw_config->dma != sb_config->dma)
+ {
+ printk ("SB16 Error: Invalid DMA channel %d/%d\n",
+ sb_config->dma, hw_config->dma);
+ return 0;
+ }
+
+ dma16 = hw_config->dma;
+ dma8 = sb_config->dma;
+ set_irq_hw (sb_config->irq);
+ sb_setmixer (DMA_NR, (1 << hw_config->dma) | (1 << sb_config->dma));
+
+ DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, hw_config->dma));
+
+ /*
+ dsp_showmessage(0xe3,99);
+ */
+ sb16_dsp_ok = 1;
+ return 1;
+}
+
+void
+sb16_dsp_interrupt (int unused)
+{
+ int data;
+
+ data = INB (DSP_DATA_AVL16); /* Interrupt acknowledge */
+
+ if (intr_active)
+ switch (irq_mode)
+ {
+ case IMODE_OUTPUT:
+ intr_active = 0;
+ DMAbuf_outputintr (my_dev, 1);
+ break;
+
+ case IMODE_INPUT:
+ intr_active = 0;
+ DMAbuf_inputintr (my_dev);
+ break;
+
+ default:
+ printk ("SoundBlaster: Unexpected interrupt\n");
+ }
+}
+
+#endif
diff --git a/sys/i386/isa/sound/sb16_midi.c b/sys/i386/isa/sound/sb16_midi.c
new file mode 100644
index 0000000..39808c8
--- /dev/null
+++ b/sys/i386/isa/sound/sb16_midi.c
@@ -0,0 +1,287 @@
+/*
+ * sound/sb16_midi.c
+ *
+ * The low level driver for the MPU-401 UART emulation of the SB16.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_MIDI)
+
+#define DATAPORT (sb16midi_base) /* MPU-401 Data I/O Port on IBM */
+#define COMDPORT (sb16midi_base+1) /* MPU-401 Command Port on IBM */
+#define STATPORT (sb16midi_base+1) /* MPU-401 Status Port on IBM */
+
+#define sb16midi_status() INB(STATPORT)
+#define input_avail() (!(sb16midi_status()&INPUT_AVAIL))
+#define output_ready() (!(sb16midi_status()&OUTPUT_READY))
+#define sb16midi_cmd(cmd) OUTB(cmd, COMDPORT)
+#define sb16midi_read() INB(DATAPORT)
+#define sb16midi_write(byte) OUTB(byte, DATAPORT)
+
+#define OUTPUT_READY 0x40 /* Mask for Data Read Redy Bit */
+#define INPUT_AVAIL 0x80 /* Mask for Data Send Ready Bit */
+#define MPU_ACK 0xFE /* MPU-401 Acknowledge Response */
+#define MPU_RESET 0xFF /* MPU-401 Total Reset Command */
+#define UART_MODE_ON 0x3F /* MPU-401 "Dumb UART Mode" */
+
+static int sb16midi_opened = 0;
+static int sb16midi_base = 0x330;
+static int sb16midi_detected = 0;
+static int my_dev;
+
+static int reset_sb16midi (void);
+static void (*midi_input_intr) (int dev, unsigned char data);
+
+extern int sbc_major;
+
+static void
+sb16midi_input_loop (void)
+{
+
+ while (input_avail ())
+ {
+ unsigned char c = sb16midi_read ();
+
+ if (sb16midi_opened & OPEN_READ)
+ midi_input_intr (my_dev, c);
+ }
+}
+
+void
+sb16midiintr (int unit)
+{
+ if (input_avail ())
+ sb16midi_input_loop ();
+}
+
+static int
+sb16midi_open (int dev, int mode,
+ void (*input) (int dev, unsigned char data),
+ void (*output) (int dev)
+)
+{
+ if (sb16midi_opened)
+ {
+ return RET_ERROR (EBUSY);
+ }
+
+ sb16midi_input_loop ();
+
+ midi_input_intr = input;
+ sb16midi_opened = mode;
+
+ return 0;
+}
+
+static void
+sb16midi_close (int dev)
+{
+ sb16midi_opened = 0;
+}
+
+static int
+sb16midi_out (int dev, unsigned char midi_byte)
+{
+ int timeout;
+ unsigned long flags;
+
+ /*
+ * Test for input since pending input seems to block the output.
+ */
+
+ DISABLE_INTR (flags);
+
+ if (input_avail ())
+ sb16midi_input_loop ();
+
+ RESTORE_INTR (flags);
+
+ /*
+ * Sometimes it takes about 13000 loops before the output becomes ready
+ * (After reset). Normally it takes just about 10 loops.
+ */
+
+ for (timeout = 30000; timeout > 0 && !output_ready (); timeout--); /* Wait */
+
+ if (!output_ready ())
+ {
+ printk ("MPU-401: Timeout\n");
+ return 0;
+ }
+
+ sb16midi_write (midi_byte);
+ return 1;
+}
+
+static int
+sb16midi_command (int dev, unsigned char midi_byte)
+{
+ return 1;
+}
+
+static int
+sb16midi_start_read (int dev)
+{
+ return 0;
+}
+
+static int
+sb16midi_end_read (int dev)
+{
+ return 0;
+}
+
+static int
+sb16midi_ioctl (int dev, unsigned cmd, unsigned arg)
+{
+ return RET_ERROR (EINVAL);
+}
+
+static void
+sb16midi_kick (int dev)
+{
+}
+
+static int
+sb16midi_buffer_status (int dev)
+{
+ return 0; /* No data in buffers */
+}
+
+static struct midi_operations sb16midi_operations =
+{
+ {"SoundBlaster MPU-401", 0, 0, SNDCARD_SB16MIDI},
+ sb16midi_open,
+ sb16midi_close,
+ sb16midi_ioctl,
+ sb16midi_out,
+ sb16midi_start_read,
+ sb16midi_end_read,
+ sb16midi_kick,
+ sb16midi_command,
+ sb16midi_buffer_status
+};
+
+
+long
+attach_sb16midi (long mem_start, struct address_info *hw_config)
+{
+ int ok, timeout;
+ unsigned long flags;
+
+ sb16midi_base = hw_config->io_base;
+
+ if (!sb16midi_detected)
+ return RET_ERROR (EIO);
+
+ DISABLE_INTR (flags);
+ for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* Wait */
+ sb16midi_cmd (UART_MODE_ON);
+
+ ok = 0;
+ for (timeout = 50000; timeout > 0 && !ok; timeout--)
+ if (input_avail ())
+ if (sb16midi_read () == MPU_ACK)
+ ok = 1;
+
+ RESTORE_INTR (flags);
+
+#ifdef __FreeBSD__
+ printk ("snd7: <SoundBlaster MPU-401>");
+#else
+ printk (" <SoundBlaster MPU-401>");
+#endif
+
+ my_dev = num_midis;
+ midi_devs[num_midis++] = &sb16midi_operations;
+ return mem_start;
+}
+
+static int
+reset_sb16midi (void)
+{
+ unsigned long flags;
+ int ok, timeout, n;
+
+ /*
+ * Send the RESET command. Try again if no success at the first time.
+ */
+
+ ok = 0;
+
+ DISABLE_INTR (flags);
+
+ for (n = 0; n < 2 && !ok; n++)
+ {
+ for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* Wait */
+ sb16midi_cmd (MPU_RESET); /* Send MPU-401 RESET Command */
+
+ /*
+ * Wait at least 25 msec. This method is not accurate so let's make the
+ * loop bit longer. Cannot sleep since this is called during boot.
+ */
+
+ for (timeout = 50000; timeout > 0 && !ok; timeout--)
+ if (input_avail ())
+ if (sb16midi_read () == MPU_ACK)
+ ok = 1;
+
+ }
+
+ sb16midi_opened = 0;
+ if (ok)
+ sb16midi_input_loop (); /* Flush input before enabling interrupts */
+
+ RESTORE_INTR (flags);
+
+ return ok;
+}
+
+
+int
+probe_sb16midi (struct address_info *hw_config)
+{
+ int ok = 0;
+
+ sb16midi_base = hw_config->io_base;
+ if (sbc_major < 4)
+ return 0; /* SB16 not detected */
+
+ if (sb_get_irq () < 0)
+ return 0;
+
+ ok = reset_sb16midi ();
+
+ sb16midi_detected = ok;
+ return ok;
+}
+
+#endif
+
+#endif
diff --git a/sys/i386/isa/sound/sb_card.c b/sys/i386/isa/sound/sb_card.c
new file mode 100644
index 0000000..f7588e1
--- /dev/null
+++ b/sys/i386/isa/sound/sb_card.c
@@ -0,0 +1,52 @@
+/*
+ * sound/sb_card.c
+ *
+ * Detection routine for the SoundBlaster cards.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB)
+
+long
+attach_sb_card (long mem_start, struct address_info *hw_config)
+{
+#if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_MIDI)
+ if (!sb_dsp_detect (hw_config))
+ return mem_start;
+ mem_start = sb_dsp_init (mem_start, hw_config);
+#endif
+
+ return mem_start;
+}
+
+int
+probe_sb (struct address_info *hw_config)
+{
+ return sb_dsp_detect (hw_config);
+}
+
+#endif
diff --git a/sys/i386/isa/sound/sb_dsp.c b/sys/i386/isa/sound/sb_dsp.c
new file mode 100644
index 0000000..17fb4b7
--- /dev/null
+++ b/sys/i386/isa/sound/sb_dsp.c
@@ -0,0 +1,785 @@
+/*
+ * sound/sb_dsp.c
+ *
+ * The low level driver for the SoundBlaster DSP chip.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Modified:
+ * Hunyue Yau Jan 6 1994
+ * Added code to support Sound Galaxy NX Pro
+ *
+ */
+
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB)
+
+#include "sb.h"
+#include "sb_mixer.h"
+#undef SB_TEST_IRQ
+
+int sbc_base = 0;
+static int sbc_irq = 0;
+static int open_mode=0;
+
+/*
+ * The DSP channel can be used either for input or output. Variable
+ * 'sb_irq_mode' will be set when the program calls read or write first time
+ * after open. Current version doesn't support mode changes without closing
+ * and reopening the device. Support for this feature may be implemented in a
+ * future version of this driver.
+ */
+
+int sb_dsp_ok = 0; /* Set to 1 after successful initialization */
+static int midi_disabled = 0;
+int sb_dsp_highspeed = 0;
+int sbc_major = 1;
+int sbc_minor = 0; /* DSP version */
+static int dsp_stereo = 0;
+static int dsp_current_speed = DSP_DEFAULT_SPEED;
+static int sb16 = 0;
+static int irq_verified = 0;
+
+int sb_midi_mode = NORMAL_MIDI;
+int sb_midi_busy = 0; /* 1 if the process has output to MIDI */
+int sb_dsp_busy = 0;
+
+volatile int sb_irq_mode = IMODE_NONE; /* IMODE_INPUT, IMODE_OUTPUT
+
+ * or IMODE_NONE */
+static volatile int irq_ok = 0;
+
+int sb_duplex_midi = 0;
+static int my_dev = 0;
+
+volatile int sb_intr_active = 0;
+
+static int dsp_speed (int);
+static int dsp_set_stereo (int mode);
+int sb_dsp_command (unsigned char val);
+
+#if !defined(EXCLUDE_MIDI) || !defined(EXCLUDE_AUDIO)
+
+/* Common code for the midi and pcm functions */
+
+int
+sb_dsp_command (unsigned char val)
+{
+ int i;
+ unsigned long limit;
+
+ limit = GET_TIME () + HZ / 10;/* The timeout is 0.1 secods */
+
+ /*
+ * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes
+ * called while interrupts are disabled. This means that the timer is
+ * disabled also. However the timeout situation is a abnormal condition.
+ * Normally the DSP should be ready to accept commands after just couple of
+ * loops.
+ */
+
+ for (i = 0; i < 500000 && GET_TIME () < limit; i++)
+ {
+ if ((INB (DSP_STATUS) & 0x80) == 0)
+ {
+ OUTB (val, DSP_COMMAND);
+ return 1;
+ }
+ }
+
+ printk ("SoundBlaster: DSP Command(%x) Timeout.\n", val);
+ printk ("IRQ conflict???\n");
+ return 0;
+}
+
+void
+sbintr (int unit)
+{
+ int status;
+
+#ifndef EXCLUDE_SBPRO
+ if (sb16)
+ {
+ unsigned char src = sb_getmixer (IRQ_STAT); /* Interrupt source register */
+
+#ifndef EXCLUDE_SB16
+ if (src & 3)
+ sb16_dsp_interrupt (unit);
+
+#ifndef EXCLUDE_MIDI
+ if (src & 4)
+ sb16midiintr (unit); /* MPU401 interrupt */
+#endif
+
+#endif
+
+ if (!(src & 1))
+ return; /* Not a DSP interupt */
+ }
+#endif
+
+ status = INB (DSP_DATA_AVAIL);/* Clear interrupt */
+
+ if (sb_intr_active)
+ switch (sb_irq_mode)
+ {
+ case IMODE_OUTPUT:
+ sb_intr_active = 0;
+ DMAbuf_outputintr (my_dev, 1);
+ break;
+
+ case IMODE_INPUT:
+ sb_intr_active = 0;
+ DMAbuf_inputintr (my_dev);
+ /* A complete buffer has been input. Let's start new one */
+ break;
+
+ case IMODE_INIT:
+ sb_intr_active = 0;
+ irq_ok = 1;
+ break;
+
+ case IMODE_MIDI:
+ sb_midi_interrupt (unit);
+ break;
+
+ default:
+ printk ("SoundBlaster: Unexpected interrupt\n");
+ }
+}
+
+static int sb_irq_usecount = 0;
+
+int
+sb_get_irq (void)
+{
+ int ok;
+
+ if (!sb_irq_usecount)
+ if ((ok = snd_set_irq_handler (sbc_irq, sbintr)) < 0)
+ return ok;
+
+ sb_irq_usecount++;
+
+ return 0;
+}
+
+void
+sb_free_irq (void)
+{
+ if (!sb_irq_usecount)
+ return;
+
+ sb_irq_usecount--;
+
+ if (!sb_irq_usecount)
+ snd_release_irq (sbc_irq);
+}
+
+int
+sb_reset_dsp (void)
+{
+ int loopc;
+
+ OUTB (1, DSP_RESET);
+ tenmicrosec ();
+ OUTB (0, DSP_RESET);
+ tenmicrosec ();
+ tenmicrosec ();
+ tenmicrosec ();
+
+ for (loopc = 0; loopc < 1000 && !(INB (DSP_DATA_AVAIL) & 0x80); loopc++); /* Wait for data
+ * available status */
+
+ if (INB (DSP_READ) != 0xAA)
+ return 0; /* Sorry */
+
+ return 1;
+}
+
+#endif
+
+#ifndef EXCLUDE_AUDIO
+
+static void
+dsp_speaker (char state)
+{
+ if (state)
+ sb_dsp_command (DSP_CMD_SPKON);
+ else
+ sb_dsp_command (DSP_CMD_SPKOFF);
+}
+
+static int
+dsp_speed (int speed)
+{
+ unsigned char tconst;
+ unsigned long flags;
+ int max_speed = 44100;
+
+ if (speed < 4000)
+ speed = 4000;
+
+ /*
+ * Older SB models don't support higher speeds than 22050.
+ */
+
+ if (sbc_major < 2 ||
+ (sbc_major == 2 && sbc_minor == 0))
+ max_speed = 22050;
+
+ /*
+ * SB models earlier than SB Pro have low limit for the input speed.
+ */
+ if (open_mode != OPEN_WRITE) /* Recording is possible */
+ if (sbc_major < 3) /* Limited input speed with these cards */
+ if (sbc_major == 2 && sbc_minor > 0)
+ max_speed = 15000;
+ else
+ max_speed = 13000;
+
+ if (speed > max_speed)
+ speed = max_speed; /* Invalid speed */
+
+ if (dsp_stereo && speed > 22050)
+ speed = 22050;
+ /* Max. stereo speed is 22050 */
+
+ if ((speed > 22050) && sb_midi_busy)
+ {
+ printk ("SB Warning: High speed DSP not possible simultaneously with MIDI output\n");
+ speed = 22050;
+ }
+
+ if (dsp_stereo)
+ speed *= 2;
+
+ /* Now the speed should be valid */
+
+ if (speed > 22050)
+ { /* High speed mode */
+ int tmp;
+
+ tconst = (unsigned char) ((65536 -
+ ((256000000 + speed / 2) / speed)) >> 8);
+ sb_dsp_highspeed = 1;
+
+ DISABLE_INTR (flags);
+ if (sb_dsp_command (0x40))
+ sb_dsp_command (tconst);
+ RESTORE_INTR (flags);
+
+ tmp = 65536 - (tconst << 8);
+ speed = (256000000 + tmp / 2) / tmp;
+ }
+ else
+ {
+ int tmp;
+
+ sb_dsp_highspeed = 0;
+ tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
+
+ DISABLE_INTR (flags);
+ if (sb_dsp_command (0x40))/* Set time constant */
+ sb_dsp_command (tconst);
+ RESTORE_INTR (flags);
+
+ tmp = 256 - tconst;
+ speed = (1000000 + tmp / 2) / tmp;
+ }
+
+ if (dsp_stereo)
+ speed /= 2;
+
+ dsp_current_speed = speed;
+ return speed;
+}
+
+static int
+dsp_set_stereo (int mode)
+{
+ dsp_stereo = 0;
+
+#ifdef EXCLUDE_SBPRO
+ return 0;
+#else
+ if (sbc_major < 3 || sb16)
+ return 0; /* Sorry no stereo */
+
+ if (mode && sb_midi_busy)
+ {
+ printk ("SB Warning: Stereo DSP not possible simultaneously with MIDI output\n");
+ return 0;
+ }
+
+ dsp_stereo = !!mode;
+ return dsp_stereo;
+#endif
+}
+
+static void
+sb_dsp_output_block (int dev, unsigned long buf, int count,
+ int intrflag, int restart_dma)
+{
+ unsigned long flags;
+
+ if (!sb_irq_mode)
+ dsp_speaker (ON);
+
+ sb_irq_mode = IMODE_OUTPUT;
+ DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
+
+ if (sound_dsp_dmachan[dev] > 3)
+ count >>= 1;
+ count--;
+
+ if (sb_dsp_highspeed)
+ {
+ DISABLE_INTR (flags);
+ if (sb_dsp_command (0x48))/* High speed size */
+ {
+ sb_dsp_command ((unsigned char) (count & 0xff));
+ sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
+ sb_dsp_command (0x91);/* High speed 8 bit DAC */
+ }
+ else
+ printk ("SB Error: Unable to start (high speed) DAC\n");
+ RESTORE_INTR (flags);
+ }
+ else
+ {
+ DISABLE_INTR (flags);
+ if (sb_dsp_command (0x14))/* 8-bit DAC (DMA) */
+ {
+ sb_dsp_command ((unsigned char) (count & 0xff));
+ sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
+ }
+ else
+ printk ("SB Error: Unable to start DAC\n");
+ RESTORE_INTR (flags);
+ }
+ sb_intr_active = 1;
+}
+
+static void
+sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag,
+ int restart_dma)
+{
+ /* Start a DMA input to the buffer pointed by dmaqtail */
+
+ unsigned long flags;
+
+ if (!sb_irq_mode)
+ dsp_speaker (OFF);
+
+ sb_irq_mode = IMODE_INPUT;
+ DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
+
+ if (sound_dsp_dmachan[dev] > 3)
+ count >>= 1;
+ count--;
+
+ if (sb_dsp_highspeed)
+ {
+ DISABLE_INTR (flags);
+ if (sb_dsp_command (0x48))/* High speed size */
+ {
+ sb_dsp_command ((unsigned char) (count & 0xff));
+ sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
+ sb_dsp_command (0x99);/* High speed 8 bit ADC */
+ }
+ else
+ printk ("SB Error: Unable to start (high speed) ADC\n");
+ RESTORE_INTR (flags);
+ }
+ else
+ {
+ DISABLE_INTR (flags);
+ if (sb_dsp_command (0x24))/* 8-bit ADC (DMA) */
+ {
+ sb_dsp_command ((unsigned char) (count & 0xff));
+ sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
+ }
+ else
+ printk ("SB Error: Unable to start ADC\n");
+ RESTORE_INTR (flags);
+ }
+
+ sb_intr_active = 1;
+}
+
+static void
+dsp_cleanup (void)
+{
+ sb_intr_active = 0;
+}
+
+static int
+sb_dsp_prepare_for_input (int dev, int bsize, int bcount)
+{
+ dsp_cleanup ();
+ dsp_speaker (OFF);
+
+ if (sbc_major == 3) /* SB Pro */
+ {
+ if (dsp_stereo)
+ sb_dsp_command (0xa8);
+ else
+ sb_dsp_command (0xa0);
+
+ dsp_speed (dsp_current_speed); /* Speed must be recalculated if #channels
+ * changes */
+ }
+ return 0;
+}
+
+static int
+sb_dsp_prepare_for_output (int dev, int bsize, int bcount)
+{
+ dsp_cleanup ();
+ dsp_speaker (ON);
+
+#ifndef EXCLUDE_SBPRO
+ if (sbc_major == 3) /* SB Pro */
+ {
+ sb_mixer_set_stereo (dsp_stereo);
+ dsp_speed (dsp_current_speed); /* Speed must be recalculated if #channels
+ * changes */
+ }
+#endif
+ return 0;
+}
+
+static void
+sb_dsp_halt_xfer (int dev)
+{
+}
+
+static int
+verify_irq (void)
+{
+#if 0
+ DEFINE_WAIT_QUEUE (testq, testf);
+
+ irq_ok = 0;
+
+ if (sb_get_irq () == -1)
+ {
+ printk ("*** SB Error: Irq %d already in use\n", sbc_irq);
+ return 0;
+ }
+
+
+ sb_irq_mode = IMODE_INIT;
+
+ sb_dsp_command (0xf2); /* This should cause immediate interrupt */
+
+ DO_SLEEP (testq, testf, HZ / 5);
+
+ sb_free_irq ();
+
+ if (!irq_ok)
+ {
+ printk ("SB Warning: IRQ%d test not passed!", sbc_irq);
+ irq_ok = 1;
+ }
+#else
+ irq_ok = 1;
+#endif
+ return irq_ok;
+}
+
+static int
+sb_dsp_open (int dev, int mode)
+{
+ int retval;
+
+ if (!sb_dsp_ok)
+ {
+ printk ("SB Error: SoundBlaster board not installed\n");
+ return RET_ERROR (ENXIO);
+ }
+
+ if (sb_intr_active || (sb_midi_busy && sb_midi_mode == UART_MIDI))
+ {
+ printk ("SB: PCM not possible during MIDI input\n");
+ return RET_ERROR (EBUSY);
+ }
+
+ if (!irq_verified)
+ {
+ verify_irq ();
+ irq_verified = 1;
+ }
+ else if (!irq_ok)
+ printk ("SB Warning: Incorrect IRQ setting %d\n",
+ sbc_irq);
+
+ retval = sb_get_irq ();
+ if (retval)
+ return retval;
+
+ if (!DMAbuf_open_dma (dev))
+ {
+ sb_free_irq ();
+ printk ("SB: DMA Busy\n");
+ return RET_ERROR (EBUSY);
+ }
+
+ sb_irq_mode = IMODE_NONE;
+
+ sb_dsp_busy = 1;
+ open_mode = mode;
+
+ return 0;
+}
+
+static void
+sb_dsp_close (int dev)
+{
+ DMAbuf_close_dma (dev);
+ sb_free_irq ();
+ dsp_cleanup ();
+ dsp_speaker (OFF);
+ sb_dsp_busy = 0;
+ sb_dsp_highspeed = 0;
+ open_mode = 0;
+}
+
+static int
+sb_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+{
+ switch (cmd)
+ {
+ case SOUND_PCM_WRITE_RATE:
+ if (local)
+ return dsp_speed (arg);
+ return IOCTL_OUT (arg, dsp_speed (IOCTL_IN (arg)));
+ break;
+
+ case SOUND_PCM_READ_RATE:
+ if (local)
+ return dsp_current_speed;
+ return IOCTL_OUT (arg, dsp_current_speed);
+ break;
+
+ case SOUND_PCM_WRITE_CHANNELS:
+ if (local)
+ return dsp_set_stereo (arg - 1) + 1;
+ return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg) - 1) + 1);
+ break;
+
+ case SOUND_PCM_READ_CHANNELS:
+ if (local)
+ return dsp_stereo + 1;
+ return IOCTL_OUT (arg, dsp_stereo + 1);
+ break;
+
+ case SNDCTL_DSP_STEREO:
+ if (local)
+ return dsp_set_stereo (arg);
+ return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg)));
+ break;
+
+ case SOUND_PCM_WRITE_BITS:
+ case SOUND_PCM_READ_BITS:
+ if (local)
+ return 8;
+ return IOCTL_OUT (arg, 8);/* Only 8 bits/sample supported */
+ break;
+
+ case SOUND_PCM_WRITE_FILTER:
+ case SOUND_PCM_READ_FILTER:
+ return RET_ERROR (EINVAL);
+ break;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+
+ return RET_ERROR (EINVAL);
+}
+
+static void
+sb_dsp_reset (int dev)
+{
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+
+ sb_reset_dsp ();
+ dsp_speed (dsp_current_speed);
+ dsp_cleanup ();
+
+ RESTORE_INTR (flags);
+}
+
+#endif
+
+int
+sb_dsp_detect (struct address_info *hw_config)
+{
+ sbc_base = hw_config->io_base;
+ sbc_irq = hw_config->irq;
+
+ if (sb_dsp_ok)
+ return 0; /* Already initialized */
+
+ if (!sb_reset_dsp ())
+ return 0;
+
+ return 1; /* Detected */
+}
+
+static char card_name[32] = "SoundBlaster";
+
+#ifndef EXCLUDE_AUDIO
+static struct audio_operations sb_dsp_operations =
+{
+ "SoundBlaster",
+ NOTHING_SPECIAL,
+ sb_dsp_open,
+ sb_dsp_close,
+ sb_dsp_output_block,
+ sb_dsp_start_input,
+ sb_dsp_ioctl,
+ sb_dsp_prepare_for_input,
+ sb_dsp_prepare_for_output,
+ sb_dsp_reset,
+ sb_dsp_halt_xfer,
+ NULL, /* has_output_drained */
+ NULL /* copy_from_user */
+};
+
+#endif
+
+long
+sb_dsp_init (long mem_start, struct address_info *hw_config)
+{
+ int i;
+ int prostat = 0;
+
+ sbc_major = sbc_minor = 0;
+ sb_dsp_command (0xe1); /* Get version */
+
+ for (i = 1000; i; i--)
+ {
+ if (INB (DSP_DATA_AVAIL) & 0x80)
+ { /* wait for Data Ready */
+ if (sbc_major == 0)
+ sbc_major = INB (DSP_READ);
+ else
+ {
+ sbc_minor = INB (DSP_READ);
+ break;
+ }
+ }
+ }
+
+ if (sbc_major == 2 || sbc_major == 3) /* SB 2.0 or SB Pro */
+ sb_duplex_midi = 1;
+
+ if (sbc_major == 4)
+ sb16 = 1;
+
+#ifndef EXCLUDE_SBPRO
+ if (sbc_major >= 3 ||
+ (sbc_major == 2 && sbc_minor == 1)) /* Sound Galaxy ??? */
+ prostat = sb_mixer_init (sbc_major);
+#endif
+
+#ifndef EXCLUDE_YM3812
+ if (sbc_major > 3 ||
+ (sbc_major == 3 && INB (0x388) == 0x00)) /* Non OPL-3 should return 0x06 */
+ enable_opl3_mode (OPL3_LEFT, OPL3_RIGHT, OPL3_BOTH);
+#endif
+
+ if (sbc_major >= 3)
+ {
+#ifndef SCO
+ if (prostat)
+ {
+#ifndef EXCLUDE_AUDIO
+ sprintf (sb_dsp_operations.name, "Sound Galaxy NX Pro %d.%d", sbc_major, sbc_minor);
+#endif
+ sprintf (card_name, "Sound Galaxy NX Pro %d.%d", sbc_major, sbc_minor);
+ }
+ else
+ {
+#ifndef EXCLUDE_AUDIO
+ sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor);
+#endif
+ sprintf (card_name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor);
+ }
+#endif
+ }
+ else
+ {
+#ifndef SCO
+#ifndef EXCLUDE_AUDIO
+ sprintf (sb_dsp_operations.name, "SoundBlaster %d.%d", sbc_major, sbc_minor);
+#endif
+ sprintf (card_name, "SoundBlaster %d.%d", sbc_major, sbc_minor);
+#endif
+ }
+
+#ifdef __FreeBSD__
+ printk ("snd2: <%s>", card_name);
+#else
+ printk (" <%s>", card_name);
+#endif
+
+#ifndef EXCLUDE_AUDIO
+#if !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO)
+ if (!sb16) /* There is a better driver for SB16 */
+#endif
+ if (num_dspdevs < MAX_DSP_DEV)
+ {
+ dsp_devs[my_dev = num_dspdevs++] = &sb_dsp_operations;
+ sound_buffcounts[my_dev] = DSP_BUFFCOUNT;
+ sound_buffsizes[my_dev] = DSP_BUFFSIZE;
+ sound_dsp_dmachan[my_dev] = hw_config->dma;
+ sound_dma_automode[my_dev] = 0;
+ }
+ else
+ printk ("SB: Too many DSP devices available\n");
+#endif
+
+#ifndef EXCLUDE_MIDI
+ if (!midi_disabled && !sb16) /* Midi don't work in the SB emulation mode
+ * of PAS, SB16 has better midi interface */
+ sb_midi_init (sbc_major);
+#endif
+
+ sb_dsp_ok = 1;
+ return mem_start;
+}
+
+void
+sb_dsp_disable_midi (void)
+{
+ midi_disabled = 1;
+}
+
+#endif
diff --git a/sys/i386/isa/sound/sb_midi.c b/sys/i386/isa/sound/sb_midi.c
new file mode 100644
index 0000000..fed19ab
--- /dev/null
+++ b/sys/i386/isa/sound/sb_midi.c
@@ -0,0 +1,224 @@
+/*
+ * sound/sb_dsp.c
+ *
+ * The low level driver for the SoundBlaster DS chips.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_MIDI)
+
+#include "sb.h"
+#undef SB_TEST_IRQ
+
+/*
+ * The DSP channel can be used either for input or output. Variable
+ * 'sb_irq_mode' will be set when the program calls read or write first time
+ * after open. Current version doesn't support mode changes without closing
+ * and reopening the device. Support for this feature may be implemented in a
+ * future version of this driver.
+ */
+
+extern int sb_dsp_ok; /* Set to 1 after successful initialization */
+
+extern int sb_midi_mode;
+extern int sb_midi_busy; /* 1 if the process has output to MIDI */
+extern int sb_dsp_busy;
+extern int sb_dsp_highspeed;
+
+extern volatile int sb_irq_mode;/* IMODE_INPUT, IMODE_OUTPUT
+
+ * or IMODE_NONE */
+extern int sb_duplex_midi;
+extern int sb_intr_active;
+extern int sbc_base;
+
+static int input_opened = 0;
+static void (*midi_input_intr) (int dev, unsigned char data);
+static int my_dev = 0;
+
+static int
+sb_midi_open (int dev, int mode,
+ void (*input) (int dev, unsigned char data),
+ void (*output) (int dev)
+)
+{
+ int ret;
+
+ if (!sb_dsp_ok)
+ {
+ printk ("SB Error: MIDI hardware not installed\n");
+ return RET_ERROR (ENXIO);
+ }
+
+ if (mode != OPEN_WRITE && !sb_duplex_midi)
+ {
+ if (num_midis == 1)
+ printk ("SoundBlaster: MIDI input not supported with plain SB\n");
+ return RET_ERROR (EPERM);
+ }
+
+ sb_midi_mode = NORMAL_MIDI;
+ if (mode != OPEN_WRITE)
+ {
+ if (sb_dsp_busy || sb_intr_active)
+ return RET_ERROR (EBUSY);
+ sb_midi_mode = UART_MIDI;
+ }
+
+ if (sb_dsp_highspeed)
+ {
+ printk ("SB Error: Midi output not possible during stereo or high speed audio\n");
+ return RET_ERROR (EBUSY);
+ }
+
+ if (sb_midi_mode == UART_MIDI)
+ {
+ sb_irq_mode = IMODE_MIDI;
+
+ sb_reset_dsp ();
+
+ if (!sb_dsp_command (0xf2)) /* This is undodumented, isn't it */
+ return RET_ERROR (EIO); /* be nice to DSP */
+
+ if (!sb_dsp_command (0x35))
+ return RET_ERROR (EIO); /* Enter the UART mode */
+ sb_intr_active = 1;
+
+ if ((ret = sb_get_irq ()) < 0)
+ {
+ sb_reset_dsp ();
+ return 0; /* IRQ not free */
+ }
+ input_opened = 1;
+ my_dev = dev;
+ midi_input_intr = input;
+ }
+
+ sb_midi_busy = 1;
+
+ return 0;
+}
+
+static void
+sb_midi_close (int dev)
+{
+ if (sb_midi_mode == UART_MIDI)
+ {
+ sb_reset_dsp (); /* The only way to kill the UART mode */
+ sb_free_irq ();
+ }
+ sb_intr_active = 0;
+ sb_midi_busy = 0;
+ input_opened = 0;
+}
+
+static int
+sb_midi_out (int dev, unsigned char midi_byte)
+{
+ unsigned long flags;
+
+ sb_midi_busy = 1; /* Kill all notes after close */
+
+ if (sb_midi_mode == NORMAL_MIDI)
+ {
+ DISABLE_INTR (flags);
+ if (sb_dsp_command (0x38))
+ sb_dsp_command (midi_byte);
+ else
+ printk ("SB Error: Unable to send a MIDI byte\n");
+ RESTORE_INTR (flags);
+ }
+ else
+ sb_dsp_command (midi_byte); /* UART write */
+
+ return 1;
+}
+
+static int
+sb_midi_start_read (int dev)
+{
+ if (sb_midi_mode != UART_MIDI)
+ {
+ printk ("SoundBlaster: MIDI input not implemented.\n");
+ return RET_ERROR (EPERM);
+ }
+ return 0;
+}
+
+static int
+sb_midi_end_read (int dev)
+{
+ if (sb_midi_mode == UART_MIDI)
+ {
+ sb_reset_dsp ();
+ sb_intr_active = 0;
+ }
+ return 0;
+}
+
+static int
+sb_midi_ioctl (int dev, unsigned cmd, unsigned arg)
+{
+ return RET_ERROR (EPERM);
+}
+
+void
+sb_midi_interrupt (int dummy)
+{
+ unsigned long flags;
+ unsigned char data;
+
+ DISABLE_INTR (flags);
+
+ data = INB (DSP_READ);
+ if (input_opened)
+ midi_input_intr (my_dev, data);
+
+ RESTORE_INTR (flags);
+}
+
+static struct midi_operations sb_midi_operations =
+{
+ {"SoundBlaster", 0, 0, SNDCARD_SB},
+ sb_midi_open,
+ sb_midi_close,
+ sb_midi_ioctl,
+ sb_midi_out,
+ sb_midi_start_read,
+ sb_midi_end_read,
+ NULL, /* Kick */
+ NULL, /* command */
+ NULL /* buffer_status */
+};
+
+void
+sb_midi_init (int model)
+{
+ midi_devs[num_midis++] = &sb_midi_operations;
+}
+
+#endif
diff --git a/sys/i386/isa/sound/sb_mixer.c b/sys/i386/isa/sound/sb_mixer.c
new file mode 100644
index 0000000..39b97ca
--- /dev/null
+++ b/sys/i386/isa/sound/sb_mixer.c
@@ -0,0 +1,422 @@
+
+/*
+ * sound/sb_mixer.c
+ *
+ * The low level mixer driver for the SoundBlaster Pro and SB16 cards.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Modified:
+ * Hunyue Yau Jan 6 1994
+ * Added code to support the Sound Galaxy NX Pro mixer.
+ *
+ */
+
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_SBPRO)
+#define __SB_MIXER_C__
+
+#include "sb.h"
+#include "sb_mixer.h"
+#undef SB_TEST_IRQ
+
+extern int sbc_base;
+
+static int mixer_initialized = 0;
+
+static int supported_rec_devices;
+static int supported_devices;
+static int recmask = 0;
+static int mixer_model;
+static int mixer_caps;
+static mixer_tab *iomap;
+
+void
+sb_setmixer (unsigned int port, unsigned int value)
+{
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+ OUTB ((unsigned char) (port & 0xff), MIXER_ADDR); /* Select register */
+ tenmicrosec ();
+ OUTB ((unsigned char) (value & 0xff), MIXER_DATA);
+ tenmicrosec ();
+ RESTORE_INTR (flags);
+}
+
+int
+sb_getmixer (unsigned int port)
+{
+ int val;
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+ OUTB ((unsigned char) (port & 0xff), MIXER_ADDR); /* Select register */
+ tenmicrosec ();
+ val = INB (MIXER_DATA);
+ tenmicrosec ();
+ RESTORE_INTR (flags);
+
+ return val;
+}
+
+void
+sb_mixer_set_stereo (int mode)
+{
+ if (!mixer_initialized)
+ return;
+
+ sb_setmixer (OUT_FILTER, ((sb_getmixer (OUT_FILTER) & ~STEREO_DAC)
+ | (mode ? STEREO_DAC : MONO_DAC)));
+}
+
+/*
+ * Returns:
+ * 0 No mixer detected.
+ * 1 Only a plain Sound Blaster Pro style mixer detected.
+ * 2 The Sound Galaxy NX Pro mixer detected.
+ */
+static int
+detect_mixer (void)
+{
+#ifdef __SGNXPRO__
+ int oldbass, oldtreble;
+
+#endif
+ int retcode = 1;
+
+ /*
+ * Detect the mixer by changing parameters of two volume channels. If the
+ * values read back match with the values written, the mixer is there (is
+ * it?)
+ */
+ sb_setmixer (FM_VOL, 0xff);
+ sb_setmixer (VOC_VOL, 0x33);
+
+ if (sb_getmixer (FM_VOL) != 0xff)
+ return 0; /* No match */
+ if (sb_getmixer (VOC_VOL) != 0x33)
+ return 0;
+
+#ifdef __SGNXPRO__
+ /* Attempt to detect the SG NX Pro by check for valid bass/treble
+ * registers.
+ */
+ oldbass = sb_getmixer (BASS_LVL);
+ oldtreble = sb_getmixer (TREBLE_LVL);
+
+ sb_setmixer (BASS_LVL, 0xaa);
+ sb_setmixer (TREBLE_LVL, 0x55);
+
+ if ((sb_getmixer (BASS_LVL) != 0xaa) ||
+ (sb_getmixer (TREBLE_LVL) != 0x55))
+ {
+ retcode = 1; /* 1 == Only SB Pro detected */
+ }
+ else
+ retcode = 2; /* 2 == SG NX Pro detected */
+ /* Restore register in either case since SG NX Pro has EEPROM with
+ * 'preferred' values stored.
+ */
+ sb_setmixer (BASS_LVL, oldbass);
+ sb_setmixer (TREBLE_LVL, oldtreble);
+#endif
+ return retcode;
+}
+
+static void
+change_bits (unsigned char *regval, int dev, int chn, int newval)
+{
+ unsigned char mask;
+ int shift;
+
+ mask = (1 << (*iomap)[dev][chn].nbits) - 1;
+ newval = ((newval * mask) + 50) / 100; /* Scale it */
+
+ shift = (*iomap)[dev][chn].bitoffs - (*iomap)[dev][LEFT_CHN].nbits + 1;
+
+ *regval &= ~(mask << shift); /* Filter out the previous value */
+ *regval |= (newval & mask) << shift; /* Set the new value */
+}
+
+static int
+sb_mixer_get (int dev)
+{
+ if (!((1 << dev) & supported_devices))
+ return RET_ERROR (EINVAL);
+
+ return levels[dev];
+}
+
+static int
+sb_mixer_set (int dev, int value)
+{
+ int left = value & 0x000000ff;
+ int right = (value & 0x0000ff00) >> 8;
+
+ int regoffs;
+ unsigned char val;
+
+ if (left > 100)
+ left = 100;
+ if (right > 100)
+ right = 100;
+
+ if (dev > 31)
+ return RET_ERROR (EINVAL);
+
+ if (!(supported_devices & (1 << dev))) /* Not supported */
+ return RET_ERROR (EINVAL);
+
+ regoffs = (*iomap)[dev][LEFT_CHN].regno;
+
+ if (regoffs == 0)
+ return RET_ERROR (EINVAL);
+
+ val = sb_getmixer (regoffs);
+ change_bits (&val, dev, LEFT_CHN, left);
+
+ levels[dev] = left | (left << 8);
+
+ if ((*iomap)[dev][RIGHT_CHN].regno != regoffs) /* Change register */
+ {
+ sb_setmixer (regoffs, val); /* Save the old one */
+ regoffs = (*iomap)[dev][RIGHT_CHN].regno;
+
+ if (regoffs == 0)
+ return left | (left << 8); /* Just left channel present */
+
+ val = sb_getmixer (regoffs); /* Read the new one */
+ }
+
+ change_bits (&val, dev, RIGHT_CHN, right);
+ sb_setmixer (regoffs, val);
+
+ levels[dev] = left | (right << 8);
+ return left | (right << 8);
+}
+
+static void
+set_recsrc (int src)
+{
+ sb_setmixer (RECORD_SRC, (sb_getmixer (RECORD_SRC) & ~7) | (src & 0x7));
+}
+
+static int
+set_recmask (int mask)
+{
+ int devmask, i;
+ unsigned char regimageL, regimageR;
+
+ devmask = mask & supported_rec_devices;
+
+ switch (mixer_model)
+ {
+ case 3:
+
+ if (devmask != SOUND_MASK_MIC &&
+ devmask != SOUND_MASK_LINE &&
+ devmask != SOUND_MASK_CD)
+ { /* More than one devices selected. Drop the
+ * previous selection */
+ devmask &= ~recmask;
+ }
+
+ if (devmask != SOUND_MASK_MIC &&
+ devmask != SOUND_MASK_LINE &&
+ devmask != SOUND_MASK_CD)
+ { /* More than one devices selected. Default to
+ * mic */
+ devmask = SOUND_MASK_MIC;
+ }
+
+
+ if (devmask ^ recmask) /* Input source changed */
+ {
+ switch (devmask)
+ {
+
+ case SOUND_MASK_MIC:
+ set_recsrc (SRC_MIC);
+ break;
+
+ case SOUND_MASK_LINE:
+ set_recsrc (SRC_LINE);
+ break;
+
+ case SOUND_MASK_CD:
+ set_recsrc (SRC_CD);
+ break;
+
+ default:
+ set_recsrc (SRC_MIC);
+ }
+ }
+
+ break;
+
+ case 4:
+ if (!devmask)
+ devmask = SOUND_MASK_MIC;
+
+ regimageL = regimageR = 0;
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+ if ((1 << i) & devmask)
+ {
+ regimageL |= sb16_recmasks_L[i];
+ regimageR |= sb16_recmasks_R[i];
+ }
+ sb_setmixer (SB16_IMASK_L, regimageL);
+ sb_setmixer (SB16_IMASK_R, regimageR);
+ break;
+ }
+
+ recmask = devmask;
+ return recmask;
+}
+
+static int
+sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
+{
+ if (((cmd >> 8) & 0xff) == 'M')
+ {
+ if (cmd & IOC_IN)
+ switch (cmd & 0xff)
+ {
+ case SOUND_MIXER_RECSRC:
+ return IOCTL_OUT (arg, set_recmask (IOCTL_IN (arg)));
+ break;
+
+ default:
+ return IOCTL_OUT (arg, sb_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
+ }
+ else
+ switch (cmd & 0xff) /* Return parameters */
+ {
+
+ case SOUND_MIXER_RECSRC:
+ return IOCTL_OUT (arg, recmask);
+ break;
+
+ case SOUND_MIXER_DEVMASK:
+ return IOCTL_OUT (arg, supported_devices);
+ break;
+
+ case SOUND_MIXER_STEREODEVS:
+ return IOCTL_OUT (arg, supported_devices &
+ ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
+ break;
+
+ case SOUND_MIXER_RECMASK:
+ return IOCTL_OUT (arg, supported_rec_devices);
+ break;
+
+ case SOUND_MIXER_CAPS:
+ return IOCTL_OUT (arg, mixer_caps);
+ break;
+
+ default:
+ return IOCTL_OUT (arg, sb_mixer_get (cmd & 0xff));
+ }
+ }
+ else
+ return RET_ERROR (EINVAL);
+}
+
+static struct mixer_operations sb_mixer_operations =
+{
+ sb_mixer_ioctl
+};
+
+static void
+sb_mixer_reset (void)
+{
+ int i;
+
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+ sb_mixer_set (i, levels[i]);
+ set_recmask (SOUND_MASK_MIC);
+}
+
+/*
+ * Returns a code depending on whether a SG NX Pro was detected.
+ * 0 == Plain SB 16 or SB Pro
+ * 1 == SG NX Pro detected.
+ *
+ * Used to update message.
+ */
+int
+sb_mixer_init (int major_model)
+{
+ int mixerstat;
+
+ sb_setmixer (0x00, 0); /* Reset mixer */
+
+ mixerstat = detect_mixer ();
+
+ if (!mixerstat)
+ return 0; /* No mixer. Why? */
+
+ mixer_initialized = 1;
+ mixer_model = major_model;
+
+ switch (major_model)
+ {
+ case 3:
+ mixer_caps = SOUND_CAP_EXCL_INPUT;
+#ifdef __SGNXPRO__
+ if (mixerstat == 2)
+ { /* A SGNXPRO was detected */
+ supported_devices = SGNXPRO_MIXER_DEVICES;
+ supported_rec_devices = SGNXPRO_RECORDING_DEVICES;
+ iomap = &sgnxpro_mix;
+ }
+ else
+#endif
+ { /* Otherwise plain SB Pro */
+ supported_devices = SBPRO_MIXER_DEVICES;
+ supported_rec_devices = SBPRO_RECORDING_DEVICES;
+ iomap = &sbpro_mix;
+ }
+
+ break;
+
+ case 4:
+ mixer_caps = 0;
+ supported_devices = SB16_MIXER_DEVICES;
+ supported_rec_devices = SB16_RECORDING_DEVICES;
+ iomap = &sb16_mix;
+ break;
+
+ default:
+ printk ("SB Warning: Unsupported mixer type\n");
+ return 0;
+ }
+
+ mixer_devs[num_mixers++] = &sb_mixer_operations;
+ sb_mixer_reset ();
+ return (mixerstat == 2);
+}
+
+#endif
diff --git a/sys/i386/isa/sound/sb_mixer.h b/sys/i386/isa/sound/sb_mixer.h
new file mode 100644
index 0000000..4caf773
--- /dev/null
+++ b/sys/i386/isa/sound/sb_mixer.h
@@ -0,0 +1,212 @@
+/*
+ * sound/sb_mixer.h
+ *
+ * Definitions for the SB Pro and SB16 mixers
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Modified:
+ * Hunyue Yau Jan 6 1994
+ * Added defines for the Sound Galaxy NX Pro mixer.
+ *
+ */
+
+#define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD)
+
+/* Same as SB Pro, unless I find otherwise */
+#define SGNXPRO_RECORDING_DEVICES SBPRO_RECORDING_DEVICES
+
+#define SBPRO_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \
+ SOUND_MASK_CD | SOUND_MASK_VOLUME)
+
+/* SG NX Pro has treble and bass settings on the mixer. The 'speaker'
+ * channel is the COVOX/DisneySoundSource emulation volume control
+ * on the mixer. It does NOT control speaker volume. Should have own
+ * mask eventually?
+ */
+#define SGNXPRO_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_BASS| \
+ SOUND_MASK_TREBLE|SOUND_MASK_SPEAKER )
+
+#define SB16_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \
+ SOUND_MASK_CD)
+
+#define SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
+ SOUND_MASK_CD | SOUND_MASK_RECLEV | \
+ SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE)
+
+/*
+ * Mixer registers
+ *
+ * NOTE! RECORD_SRC == IN_FILTER
+ */
+
+/*
+ * Mixer registers of SB Pro
+ */
+#define VOC_VOL 0x04
+#define MIC_VOL 0x0A
+#define MIC_MIX 0x0A
+#define RECORD_SRC 0x0C
+#define IN_FILTER 0x0C
+#define OUT_FILTER 0x0E
+#define MASTER_VOL 0x22
+#define FM_VOL 0x26
+#define CD_VOL 0x28
+#define LINE_VOL 0x2E
+#define IRQ_NR 0x80
+#define DMA_NR 0x81
+#define IRQ_STAT 0x82
+#define OPSW 0x3c
+
+/*
+ * Additional registers on the SG NX Pro
+ */
+#define COVOX_VOL 0x42
+#define TREBLE_LVL 0x44
+#define BASS_LVL 0x46
+
+#define FREQ_HI (1 << 3)/* Use High-frequency ANFI filters */
+#define FREQ_LOW 0 /* Use Low-frequency ANFI filters */
+#define FILT_ON 0 /* Yes, 0 to turn it on, 1 for off */
+#define FILT_OFF (1 << 5)
+
+#define MONO_DAC 0x00
+#define STEREO_DAC 0x02
+
+/*
+ * Mixer registers of SB16
+ */
+#define SB16_IMASK_L 0x3d
+#define SB16_IMASK_R 0x3e
+
+#define LEFT_CHN 0
+#define RIGHT_CHN 1
+
+struct mixer_def {
+ unsigned int regno: 8;
+ unsigned int bitoffs:4;
+ unsigned int nbits:4;
+};
+
+
+typedef struct mixer_def mixer_tab[32][2];
+typedef struct mixer_def mixer_ent;
+
+#define MIX_ENT(name, reg_l, bit_l, len_l, reg_r, bit_r, len_r) \
+ {{reg_l, bit_l, len_l}, {reg_r, bit_r, len_r}}
+
+#ifdef __SB_MIXER_C__
+mixer_tab sbpro_mix = {
+MIX_ENT(SOUND_MIXER_VOLUME, 0x22, 7, 4, 0x22, 3, 4),
+MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_SYNTH, 0x26, 7, 4, 0x26, 3, 4),
+MIX_ENT(SOUND_MIXER_PCM, 0x04, 7, 4, 0x04, 3, 4),
+MIX_ENT(SOUND_MIXER_SPEAKER, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE, 0x2e, 7, 4, 0x2e, 3, 4),
+MIX_ENT(SOUND_MIXER_MIC, 0x0a, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_CD, 0x28, 7, 4, 0x28, 3, 4),
+MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0)
+};
+
+#ifdef __SGNXPRO__
+mixer_tab sgnxpro_mix = {
+MIX_ENT(SOUND_MIXER_VOLUME, 0x22, 7, 4, 0x22, 3, 4),
+MIX_ENT(SOUND_MIXER_BASS, 0x46, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_TREBLE, 0x44, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_SYNTH, 0x26, 7, 4, 0x26, 3, 4),
+MIX_ENT(SOUND_MIXER_PCM, 0x04, 7, 4, 0x04, 3, 4),
+MIX_ENT(SOUND_MIXER_SPEAKER, 0x42, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE, 0x2e, 7, 4, 0x2e, 3, 4),
+MIX_ENT(SOUND_MIXER_MIC, 0x0a, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_CD, 0x28, 7, 4, 0x28, 3, 4),
+MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0)
+};
+#endif
+
+mixer_tab sb16_mix = {
+MIX_ENT(SOUND_MIXER_VOLUME, 0x30, 7, 5, 0x31, 7, 5),
+MIX_ENT(SOUND_MIXER_BASS, 0x46, 7, 4, 0x47, 7, 4),
+MIX_ENT(SOUND_MIXER_TREBLE, 0x44, 7, 4, 0x45, 7, 4),
+MIX_ENT(SOUND_MIXER_SYNTH, 0x34, 7, 5, 0x35, 7, 5),
+MIX_ENT(SOUND_MIXER_PCM, 0x32, 7, 5, 0x33, 7, 5),
+MIX_ENT(SOUND_MIXER_SPEAKER, 0x3b, 7, 2, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE, 0x38, 7, 5, 0x39, 7, 5),
+MIX_ENT(SOUND_MIXER_MIC, 0x3a, 7, 5, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_CD, 0x36, 7, 5, 0x37, 7, 5),
+MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_RECLEV, 0x3f, 7, 2, 0x40, 7, 2)
+};
+
+static unsigned short levels[SOUND_MIXER_NRDEVICES] =
+{
+ 0x5a5a, /* Master Volume */
+ 0x3232, /* Bass */
+ 0x3232, /* Treble */
+ 0x4b4b, /* FM */
+ 0x4b4b, /* PCM */
+ 0x4b4b, /* PC Speaker */
+ 0x4b4b, /* Ext Line */
+ 0x0000, /* Mic */
+ 0x4b4b, /* CD */
+ 0x4b4b, /* Recording monitor */
+ 0x4b4b, /* SB PCM */
+ 0x4b4b}; /* Recording level */
+
+static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] =
+{
+ 0x00, /* SOUND_MIXER_VOLUME */
+ 0x00, /* SOUND_MIXER_BASS */
+ 0x00, /* SOUND_MIXER_TREBLE */
+ 0x40, /* SOUND_MIXER_SYNTH */
+ 0x00, /* SOUND_MIXER_PCM */
+ 0x00, /* SOUND_MIXER_SPEAKER */
+ 0x10, /* SOUND_MIXER_LINE */
+ 0x01, /* SOUND_MIXER_MIC */
+ 0x04, /* SOUND_MIXER_CD */
+ 0x00, /* SOUND_MIXER_IMIX */
+ 0x00, /* SOUND_MIXER_ALTPCM */
+ 0x00 /* SOUND_MIXER_RECLEV */
+};
+
+static unsigned char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] =
+{
+ 0x00, /* SOUND_MIXER_VOLUME */
+ 0x00, /* SOUND_MIXER_BASS */
+ 0x00, /* SOUND_MIXER_TREBLE */
+ 0x20, /* SOUND_MIXER_SYNTH */
+ 0x00, /* SOUND_MIXER_PCM */
+ 0x00, /* SOUND_MIXER_SPEAKER */
+ 0x08, /* SOUND_MIXER_LINE */
+ 0x01, /* SOUND_MIXER_MIC */
+ 0x02, /* SOUND_MIXER_CD */
+ 0x00, /* SOUND_MIXER_IMIX */
+ 0x00, /* SOUND_MIXER_ALTPCM */
+ 0x00 /* SOUND_MIXER_RECLEV */
+};
+#endif
diff --git a/sys/i386/isa/sound/sequencer.c b/sys/i386/isa/sound/sequencer.c
new file mode 100644
index 0000000..9885473
--- /dev/null
+++ b/sys/i386/isa/sound/sequencer.c
@@ -0,0 +1,1167 @@
+/*
+ * sound/sequencer.c
+ *
+ * The sequencer personality manager.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#define SEQUENCER_C
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+#ifndef EXCLUDE_SEQUENCER
+
+static int sequencer_ok = 0;
+
+DEFINE_WAIT_QUEUE (seq_sleeper, seq_sleep_flag);
+/* DEFINE_WAIT_QUEUE (midi_sleeper, midi_sleep_flag); */
+#define midi_sleeper seq_sleeper
+#define midi_sleep_flag seq_sleep_flag
+
+static int midi_opened[MAX_MIDI_DEV] =
+{0}; /* 1 if the process has opened MIDI */
+static int midi_written[MAX_MIDI_DEV] =
+{0};
+
+unsigned long seq_time = 0; /* Reference point for the timer */
+
+#include "tuning.h"
+
+#define EV_SZ 8
+#define IEV_SZ 4
+static unsigned char *queue = NULL; /* SEQ_MAX_QUEUE * EV_SZ bytes */
+static unsigned char *iqueue = NULL; /* SEQ_MAX_QUEUE * IEV_SZ bytes */
+
+static volatile int qhead = 0, qtail = 0, qlen = 0;
+static volatile int iqhead = 0, iqtail = 0, iqlen = 0;
+static volatile int seq_playing = 0;
+static int sequencer_busy = 0;
+static int output_treshold;
+static unsigned synth_open_mask;
+
+static int seq_queue (unsigned char *note);
+static void seq_startplay (void);
+static int seq_sync (void);
+static void seq_reset (void);
+static int pmgr_present[MAX_SYNTH_DEV] =
+{0};
+
+#if MAX_SYNTH_DEV > 15
+#error Too many synthesizer devices
+#endif
+
+int
+sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ int c = count, p = 0;
+
+ dev = dev >> 4;
+
+ if (dev) /* Patch manager device */
+ return pmgr_read (dev - 1, file, buf, count);
+
+ while (c > 3)
+ {
+ if (!iqlen)
+ {
+ if (c != count) /* Some data has been received */
+ return count - c; /* Return what we have */
+
+ DO_SLEEP (midi_sleeper, midi_sleep_flag, 0);
+
+ if (!iqlen)
+ return count - c;
+ }
+
+ COPY_TO_USER (buf, p, &iqueue[iqhead * IEV_SZ], IEV_SZ);
+ p += 4;
+ c -= 4;
+
+ iqhead = (iqhead + 1) % SEQ_MAX_QUEUE;
+ iqlen--;
+ }
+
+ return count - c;
+}
+
+static void
+sequencer_midi_output (int dev)
+{
+ /* Currently NOP */
+}
+
+static void
+copy_to_input (unsigned char *event)
+{
+ unsigned long flags;
+
+ if (iqlen >= (SEQ_MAX_QUEUE - 1))
+ return; /* Overflow */
+
+ memcpy (&iqueue[iqtail * IEV_SZ], event, IEV_SZ);
+ iqlen++;
+ iqtail = (iqtail + 1) % SEQ_MAX_QUEUE;
+
+ DISABLE_INTR (flags);
+ if (SOMEONE_WAITING (midi_sleeper, midi_sleep_flag))
+ {
+ WAKE_UP (midi_sleeper, midi_sleep_flag);
+ }
+ RESTORE_INTR (flags);
+}
+
+static void
+sequencer_midi_input (int dev, unsigned char data)
+{
+ int tstamp;
+ unsigned char event[4];
+
+ if (data == 0xfe) /* Active sensing */
+ return; /* Ignore */
+
+ tstamp = GET_TIME () - seq_time; /* Time since open() */
+ tstamp = (tstamp << 8) | SEQ_WAIT;
+
+ copy_to_input ((unsigned char *) &tstamp);
+
+ event[0] = SEQ_MIDIPUTC;
+ event[1] = data;
+ event[2] = dev;
+ event[3] = 0;
+
+ copy_to_input (event);
+}
+
+int
+sequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ unsigned char event[EV_SZ], ev_code;
+ int p = 0, c, ev_size;
+ int err;
+ int mode = file->mode & O_ACCMODE;
+
+ dev = dev >> 4;
+
+ DEB (printk ("sequencer_write(dev=%d, count=%d)\n", dev, count));
+
+ if (mode == OPEN_READ)
+ return RET_ERROR (EIO);
+
+ if (dev) /* Patch manager device */
+ return pmgr_write (dev - 1, file, buf, count);
+
+ c = count;
+
+ while (c >= 4)
+ {
+ COPY_FROM_USER (event, buf, p, 4);
+ ev_code = event[0];
+
+ if (ev_code == SEQ_FULLSIZE)
+ {
+ int err;
+
+ dev = *(unsigned short *) &event[2];
+ if (dev < 0 || dev >= num_synths)
+ return RET_ERROR (ENXIO);
+
+ if (!(synth_open_mask & (1 << dev)))
+ return RET_ERROR (ENXIO);
+
+ err = synth_devs[dev]->load_patch (dev, *(short *) &event[0], buf, p + 4, c, 0);
+ if (err < 0)
+ return err;
+
+ return err;
+ }
+
+ if (ev_code == SEQ_EXTENDED || ev_code == SEQ_PRIVATE)
+ {
+
+ ev_size = 8;
+
+ if (c < ev_size)
+ {
+ if (!seq_playing)
+ seq_startplay ();
+ return count - c;
+ }
+
+ COPY_FROM_USER (&event[4], buf, p + 4, 4);
+
+ }
+ else
+ ev_size = 4;
+
+ if (event[0] == SEQ_MIDIPUTC)
+ {
+
+ if (!midi_opened[event[2]])
+ {
+ int mode;
+ int dev = event[2];
+
+ if (dev >= num_midis)
+ {
+ printk ("Sequencer Error: Nonexistent MIDI device %d\n", dev);
+ return RET_ERROR (ENXIO);
+ }
+
+ mode = file->mode & O_ACCMODE;
+
+ if ((err = midi_devs[dev]->open (dev, mode,
+ sequencer_midi_input, sequencer_midi_output)) < 0)
+ {
+ seq_reset ();
+ printk ("Sequencer Error: Unable to open Midi #%d\n", dev);
+ return err;
+ }
+
+ midi_opened[dev] = 1;
+ }
+
+ }
+
+ if (!seq_queue (event))
+ {
+
+ if (!seq_playing)
+ seq_startplay ();
+ return count - c;
+ }
+
+ p += ev_size;
+ c -= ev_size;
+ }
+
+ if (!seq_playing)
+ seq_startplay ();
+
+ return count;
+}
+
+static int
+seq_queue (unsigned char *note)
+{
+
+ /* Test if there is space in the queue */
+
+ if (qlen >= SEQ_MAX_QUEUE)
+ if (!seq_playing)
+ seq_startplay (); /* Give chance to drain the queue */
+
+ if (qlen >= SEQ_MAX_QUEUE && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
+ {
+ /* Sleep until there is enough space on the queue */
+ DO_SLEEP (seq_sleeper, seq_sleep_flag, 0);
+ }
+
+ if (qlen >= SEQ_MAX_QUEUE)
+ return 0; /* To be sure */
+
+ memcpy (&queue[qtail * EV_SZ], note, EV_SZ);
+
+ qtail = (qtail + 1) % SEQ_MAX_QUEUE;
+ qlen++;
+
+ return 1;
+}
+
+static int
+extended_event (unsigned char *q)
+{
+ int dev = q[2];
+
+ if (dev < 0 || dev >= num_synths)
+ return RET_ERROR (ENXIO);
+
+ if (!(synth_open_mask & (1 << dev)))
+ return RET_ERROR (ENXIO);
+
+ switch (q[1])
+ {
+ case SEQ_NOTEOFF:
+ synth_devs[dev]->kill_note (dev, q[3], q[5]);
+ break;
+
+ case SEQ_NOTEON:
+ if (q[4] > 127 && q[4] != 255)
+ return 0;
+
+ synth_devs[dev]->start_note (dev, q[3], q[4], q[5]);
+ break;
+
+ case SEQ_PGMCHANGE:
+ synth_devs[dev]->set_instr (dev, q[3], q[4]);
+ break;
+
+ case SEQ_AFTERTOUCH:
+ synth_devs[dev]->aftertouch (dev, q[3], q[4]);
+ break;
+
+ case SEQ_BALANCE:
+ synth_devs[dev]->panning (dev, q[3], (char) q[4]);
+ break;
+
+ case SEQ_CONTROLLER:
+ synth_devs[dev]->controller (dev, q[3], q[4], *(short *) &q[5]);
+ break;
+
+ case SEQ_VOLMODE:
+ synth_devs[dev]->volume_method (dev, q[3]);
+ break;
+
+ default:
+ return RET_ERROR (EINVAL);
+ }
+
+ return 0;
+}
+
+static void
+seq_startplay (void)
+{
+ int this_one;
+ unsigned long *delay;
+ unsigned char *q;
+
+ while (qlen > 0)
+ {
+ qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE;
+ qlen--;
+
+ q = &queue[this_one * EV_SZ];
+
+ switch (q[0])
+ {
+ case SEQ_NOTEOFF:
+ if (synth_open_mask & (1 << 0))
+ if (synth_devs[0])
+ synth_devs[0]->kill_note (0, q[1], q[3]);
+ break;
+
+ case SEQ_NOTEON:
+ if (q[4] < 128 || q[4] == 255)
+ if (synth_open_mask & (1 << 0))
+ if (synth_devs[0])
+ synth_devs[0]->start_note (0, q[1], q[2], q[3]);
+ break;
+
+ case SEQ_WAIT:
+ delay = (unsigned long *) q; /* Bytes 1 to 3 are containing the
+ * delay in GET_TIME() */
+ *delay = (*delay >> 8) & 0xffffff;
+
+ if (*delay > 0)
+ {
+ long time;
+
+ seq_playing = 1;
+ time = *delay;
+
+ request_sound_timer (time);
+
+ if ((SEQ_MAX_QUEUE - qlen) >= output_treshold)
+ {
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+ if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
+ {
+ WAKE_UP (seq_sleeper, seq_sleep_flag);
+ }
+ RESTORE_INTR (flags);
+ }
+ return; /* Stop here. Timer routine will continue
+ * playing after the delay */
+ }
+ break;
+
+ case SEQ_PGMCHANGE:
+ if (synth_open_mask & (1 << 0))
+ if (synth_devs[0])
+ synth_devs[0]->set_instr (0, q[1], q[2]);
+ break;
+
+ case SEQ_SYNCTIMER: /* Reset timer */
+ seq_time = GET_TIME ();
+ break;
+
+ case SEQ_MIDIPUTC: /* Put a midi character */
+ if (midi_opened[q[2]])
+ {
+ int dev;
+
+ dev = q[2];
+
+ if (!midi_devs[dev]->putc (dev, q[1]))
+ {
+ /*
+ * Output FIFO is full. Wait one timer cycle and try again.
+ */
+
+ qlen++;
+ qhead = this_one; /* Restore queue */
+ seq_playing = 1;
+ request_sound_timer (-1);
+ return;
+ }
+ else
+ midi_written[dev] = 1;
+ }
+ break;
+
+ case SEQ_ECHO:
+ copy_to_input (q); /* Echo back to the process */
+ break;
+
+ case SEQ_PRIVATE:
+ if (q[1] < num_synths)
+ synth_devs[q[1]]->hw_control (q[1], q);
+ break;
+
+ case SEQ_EXTENDED:
+ extended_event (q);
+ break;
+
+ default:;
+ }
+
+ }
+
+ seq_playing = 0;
+
+ if ((SEQ_MAX_QUEUE - qlen) >= output_treshold)
+ {
+ unsigned long flags;
+
+ DISABLE_INTR (flags);
+ if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
+ {
+ WAKE_UP (seq_sleeper, seq_sleep_flag);
+ }
+ RESTORE_INTR (flags);
+ }
+
+}
+
+int
+sequencer_open (int dev, struct fileinfo *file)
+{
+ int retval, mode, i;
+
+ dev = dev >> 4;
+ mode = file->mode & O_ACCMODE;
+
+ DEB (printk ("sequencer_open(dev=%d)\n", dev));
+
+ if (!sequencer_ok)
+ {
+ printk ("Soundcard: Sequencer not initialized\n");
+ return RET_ERROR (ENXIO);
+ }
+
+ if (dev) /* Patch manager device */
+ {
+ int err;
+
+ dev--;
+ if (pmgr_present[dev])
+ return RET_ERROR (EBUSY);
+ if ((err = pmgr_open (dev)) < 0)
+ return err; /* Failed */
+
+ pmgr_present[dev] = 1;
+ return err;
+ }
+
+ if (sequencer_busy)
+ {
+ printk ("Sequencer busy\n");
+ return RET_ERROR (EBUSY);
+ }
+
+ if (!(num_synths + num_midis))
+ return RET_ERROR (ENXIO);
+
+ synth_open_mask = 0;
+
+ if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
+ for (i = 0; i < num_synths; i++) /* Open synth devices */
+ if (synth_devs[i]->open (i, mode) < 0)
+ printk ("Sequencer: Warning! Cannot open synth device #%d\n", i);
+ else
+ synth_open_mask |= (1 << i);
+
+ seq_time = GET_TIME ();
+
+ for (i = 0; i < num_midis; i++)
+ {
+ midi_opened[i] = 0;
+ midi_written[i] = 0;
+ }
+
+ if (mode == OPEN_READ || mode == OPEN_READWRITE)
+ { /* Initialize midi input devices */
+ if (!num_midis)
+ {
+ printk ("Sequencer: No Midi devices. Input not possible\n");
+ return RET_ERROR (ENXIO);
+ }
+
+ for (i = 0; i < num_midis; i++)
+ {
+ if ((retval = midi_devs[i]->open (i, mode,
+ sequencer_midi_input, sequencer_midi_output)) >= 0)
+ midi_opened[i] = 1;
+ }
+ }
+
+ sequencer_busy = 1;
+ RESET_WAIT_QUEUE (seq_sleeper, seq_sleep_flag);
+ RESET_WAIT_QUEUE (midi_sleeper, midi_sleep_flag);
+ output_treshold = SEQ_MAX_QUEUE / 2;
+
+ for (i = 0; i < num_synths; i++)
+ if (pmgr_present[i])
+ pmgr_inform (i, PM_E_OPENED, 0, 0, 0, 0);
+
+ return 0;
+}
+
+void
+seq_drain_midi_queues (void)
+{
+ int i, n;
+
+ /*
+ * Give the Midi drivers time to drain their output queues
+ */
+
+ n = 1;
+
+ while (!PROCESS_ABORTING (midi_sleeper, midi_sleep_flag) && n)
+ {
+ n = 0;
+
+ for (i = 0; i < num_midis; i++)
+ if (midi_opened[i] && midi_written[i])
+ if (midi_devs[i]->buffer_status != NULL)
+ if (midi_devs[i]->buffer_status (i))
+ n++;
+
+ /*
+ * Let's have a delay
+ */
+ if (n)
+ {
+ DO_SLEEP (seq_sleeper, seq_sleep_flag, HZ / 10);
+ }
+ }
+}
+
+void
+sequencer_release (int dev, struct fileinfo *file)
+{
+ int i;
+ int mode = file->mode & O_ACCMODE;
+
+ dev = dev >> 4;
+
+ DEB (printk ("sequencer_release(dev=%d)\n", dev));
+
+ if (dev) /* Patch manager device */
+ {
+ dev--;
+ pmgr_release (dev);
+ pmgr_present[dev] = 0;
+ return;
+ }
+
+ /*
+ * Wait until the queue is empty
+ */
+
+ while (!PROCESS_ABORTING (seq_sleeper, seq_sleep_flag) && qlen)
+ {
+ seq_sync ();
+ }
+
+ if (mode != OPEN_READ)
+ seq_drain_midi_queues (); /* Ensure the output queues are empty */
+ seq_reset ();
+ if (mode != OPEN_READ)
+ seq_drain_midi_queues (); /* Flush the all notes off messages */
+
+ for (i = 0; i < num_midis; i++)
+ if (midi_opened[i])
+ midi_devs[i]->close (i);
+
+ if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
+ for (i = 0; i < num_synths; i++)
+ if (synth_open_mask & (1 << i)) /* Actually opened */
+ if (synth_devs[i])
+ synth_devs[i]->close (i);
+
+ for (i = 0; i < num_synths; i++)
+ if (pmgr_present[i])
+ pmgr_inform (i, PM_E_CLOSED, 0, 0, 0, 0);
+
+ sequencer_busy = 0;
+}
+
+static int
+seq_sync (void)
+{
+ if (qlen && !seq_playing && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag))
+ seq_startplay ();
+
+ if (qlen && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) /* Queue not empty */
+ {
+ DO_SLEEP (seq_sleeper, seq_sleep_flag, 0);
+ }
+
+ return qlen;
+}
+
+static void
+midi_outc (int dev, unsigned char data)
+{
+ /*
+ * NOTE! Calls sleep(). Don't call this from interrupt.
+ */
+
+ int n;
+
+ /* This routine sends one byte to the Midi channel. */
+ /* If the output Fifo is full, it waits until there */
+ /* is space in the queue */
+
+ n = 300; /* Timeout in jiffies */
+
+ while (n && !midi_devs[dev]->putc (dev, data))
+ {
+ DO_SLEEP (seq_sleeper, seq_sleep_flag, 4);
+ n--;
+ }
+}
+
+static void
+seq_reset (void)
+{
+ /*
+ * NOTE! Calls sleep(). Don't call this from interrupt.
+ */
+
+ int i, chn;
+
+ sound_stop_timer ();
+
+ qlen = qhead = qtail = 0;
+ iqlen = iqhead = iqtail = 0;
+
+ for (i = 0; i < num_synths; i++)
+ if (synth_open_mask & (1 << i))
+ if (synth_devs[i])
+ synth_devs[i]->reset (i);
+
+ for (i = 0; i < num_midis; i++)
+ if (midi_written[i]) /* Midi used. Some notes may still be playing */
+ {
+ for (chn = 0; chn < 16; chn++)
+ {
+ midi_outc (i,
+ (unsigned char) (0xb0 + (chn & 0xff))); /* Channel msg */
+ midi_outc (i, 0x7b);/* All notes off */
+ midi_outc (i, 0); /* Dummy parameter */
+ }
+
+ midi_devs[i]->close (i);
+
+ midi_written[i] = 0;
+ midi_opened[i] = 0;
+ }
+
+ seq_playing = 0;
+
+ if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
+ printk ("Sequencer Warning: Unexpected sleeping process\n");
+
+}
+
+int
+sequencer_ioctl (int dev, struct fileinfo *file,
+ unsigned int cmd, unsigned int arg)
+{
+ int midi_dev, orig_dev;
+ int mode = file->mode & O_ACCMODE;
+
+ orig_dev = dev = dev >> 4;
+
+ switch (cmd)
+ {
+
+ case SNDCTL_SEQ_SYNC:
+ if (dev) /* Patch manager */
+ return RET_ERROR (EIO);
+
+ if (mode == OPEN_READ)
+ return 0;
+ while (qlen && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag))
+ seq_sync ();
+ return 0;
+ break;
+
+ case SNDCTL_SEQ_RESET:
+ if (dev) /* Patch manager */
+ return RET_ERROR (EIO);
+
+ seq_reset ();
+ return 0;
+ break;
+
+ case SNDCTL_SEQ_TESTMIDI:
+ if (dev) /* Patch manager */
+ return RET_ERROR (EIO);
+
+ midi_dev = IOCTL_IN (arg);
+ if (midi_dev >= num_midis)
+ return RET_ERROR (ENXIO);
+
+ if (!midi_opened[midi_dev])
+ {
+ int err, mode;
+
+ mode = file->mode & O_ACCMODE;
+ if ((err = midi_devs[midi_dev]->open (midi_dev, mode,
+ sequencer_midi_input,
+ sequencer_midi_output)) < 0)
+ return err;
+ }
+
+ midi_opened[midi_dev] = 1;
+
+ return 0;
+ break;
+
+ case SNDCTL_SEQ_GETINCOUNT:
+ if (dev) /* Patch manager */
+ return RET_ERROR (EIO);
+
+ if (mode == OPEN_WRITE)
+ return 0;
+ return IOCTL_OUT (arg, iqlen);
+ break;
+
+ case SNDCTL_SEQ_GETOUTCOUNT:
+
+ if (mode == OPEN_READ)
+ return 0;
+ return IOCTL_OUT (arg, SEQ_MAX_QUEUE - qlen);
+ break;
+
+ case SNDCTL_SEQ_CTRLRATE:
+ if (dev) /* Patch manager */
+ return RET_ERROR (EIO);
+
+ /* If *arg == 0, just return the current rate */
+ return IOCTL_OUT (arg, HZ);
+ break;
+
+ case SNDCTL_SEQ_RESETSAMPLES:
+ dev = IOCTL_IN (arg);
+ if (dev < 0 || dev >= num_synths)
+ return RET_ERROR (ENXIO);
+
+ if (!(synth_open_mask & (1 << dev)) && !orig_dev)
+ return RET_ERROR (EBUSY);
+
+ if (!orig_dev && pmgr_present[dev])
+ pmgr_inform (dev, PM_E_PATCH_RESET, 0, 0, 0, 0);
+
+ return synth_devs[dev]->ioctl (dev, cmd, arg);
+ break;
+
+ case SNDCTL_SEQ_NRSYNTHS:
+ return IOCTL_OUT (arg, num_synths);
+ break;
+
+ case SNDCTL_SEQ_NRMIDIS:
+ return IOCTL_OUT (arg, num_midis);
+ break;
+
+ case SNDCTL_SYNTH_MEMAVL:
+ {
+ int dev = IOCTL_IN (arg);
+
+ if (dev < 0 || dev >= num_synths)
+ return RET_ERROR (ENXIO);
+
+ if (!(synth_open_mask & (1 << dev)) && !orig_dev)
+ return RET_ERROR (EBUSY);
+
+ return IOCTL_OUT (arg, synth_devs[dev]->ioctl (dev, cmd, arg));
+ }
+ break;
+
+ case SNDCTL_FM_4OP_ENABLE:
+ {
+ int dev = IOCTL_IN (arg);
+
+ if (dev < 0 || dev >= num_synths)
+ return RET_ERROR (ENXIO);
+
+ if (!(synth_open_mask & (1 << dev)))
+ return RET_ERROR (ENXIO);
+
+ synth_devs[dev]->ioctl (dev, cmd, arg);
+ return 0;
+ }
+ break;
+
+ case SNDCTL_SYNTH_INFO:
+ {
+ struct synth_info inf;
+ int dev;
+
+ IOCTL_FROM_USER ((char *) &inf, (char *) arg, 0, sizeof (inf));
+ dev = inf.device;
+
+ if (dev < 0 || dev >= num_synths)
+ return RET_ERROR (ENXIO);
+
+ if (!(synth_open_mask & (1 << dev)) && !orig_dev)
+ return RET_ERROR (EBUSY);
+
+ return synth_devs[dev]->ioctl (dev, cmd, arg);
+ }
+ break;
+
+ case SNDCTL_MIDI_INFO:
+ {
+ struct midi_info inf;
+ int dev;
+
+ IOCTL_FROM_USER ((char *) &inf, (char *) arg, 0, sizeof (inf));
+ dev = inf.device;
+
+ if (dev < 0 || dev >= num_midis)
+ return RET_ERROR (ENXIO);
+
+ IOCTL_TO_USER ((char *) arg, 0, (char *) &(midi_devs[dev]->info), sizeof (inf));
+ return 0;
+ }
+ break;
+
+ case SNDCTL_PMGR_IFACE:
+ {
+ struct patmgr_info *inf;
+ int dev, err;
+
+ inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf));
+
+ IOCTL_FROM_USER ((char *) inf, (char *) arg, 0, sizeof (*inf));
+ dev = inf->device;
+
+ if (dev < 0 || dev >= num_synths)
+ {
+ KERNEL_FREE (inf);
+ return RET_ERROR (ENXIO);
+ }
+
+ if (!synth_devs[dev]->pmgr_interface)
+ {
+ KERNEL_FREE (inf);
+ return RET_ERROR (ENXIO);
+ }
+
+ if ((err = synth_devs[dev]->pmgr_interface (dev, inf)) == -1)
+ {
+ KERNEL_FREE (inf);
+ return err;
+ }
+
+ IOCTL_TO_USER ((char *) arg, 0, (char *) inf, sizeof (*inf));
+ KERNEL_FREE (inf);
+ return 0;
+ }
+ break;
+
+ case SNDCTL_PMGR_ACCESS:
+ {
+ struct patmgr_info *inf;
+ int dev, err;
+
+ inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf));
+
+ IOCTL_FROM_USER ((char *) inf, (char *) arg, 0, sizeof (*inf));
+ dev = inf->device;
+
+ if (dev < 0 || dev >= num_synths)
+ {
+ KERNEL_FREE (inf);
+ return RET_ERROR (ENXIO);
+ }
+
+ if (!pmgr_present[dev])
+ {
+ KERNEL_FREE (inf);
+ return RET_ERROR (ESRCH);
+ }
+
+ if ((err = pmgr_access (dev, inf)) < 0)
+ {
+ KERNEL_FREE (inf);
+ return err;
+ }
+
+ IOCTL_TO_USER ((char *) arg, 0, (char *) inf, sizeof (*inf));
+ KERNEL_FREE (inf);
+ return 0;
+ }
+ break;
+
+ case SNDCTL_SEQ_TRESHOLD:
+ {
+ int tmp = IOCTL_IN (arg);
+
+ if (dev) /* Patch manager */
+ return RET_ERROR (EIO);
+
+ if (tmp < 1)
+ tmp = 1;
+ if (tmp >= SEQ_MAX_QUEUE)
+ tmp = SEQ_MAX_QUEUE - 1;
+ output_treshold = tmp;
+ return 0;
+ }
+ break;
+
+ default:
+ if (dev) /* Patch manager */
+ return RET_ERROR (EIO);
+
+ if (mode == OPEN_READ)
+ return RET_ERROR (EIO);
+
+ if (!synth_devs[0])
+ return RET_ERROR (ENXIO);
+ if (!(synth_open_mask & (1 << 0)))
+ return RET_ERROR (ENXIO);
+ return synth_devs[0]->ioctl (0, cmd, arg);
+ break;
+ }
+
+ return RET_ERROR (EINVAL);
+}
+
+#ifdef ALLOW_SELECT
+int
+sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
+{
+ dev = dev >> 4;
+
+ switch (sel_type)
+ {
+ case SEL_IN:
+ if (!iqlen)
+ {
+ select_wait (&midi_sleeper, wait);
+ return 0;
+ }
+ return 1;
+
+ break;
+
+ case SEL_OUT:
+ if (qlen >= SEQ_MAX_QUEUE)
+ {
+ select_wait (&seq_sleeper, wait);
+ return 0;
+ }
+ return 1;
+ break;
+
+ case SEL_EX:
+ return 0;
+ }
+
+ return 0;
+}
+
+#endif
+
+void
+sequencer_timer (void)
+{
+ seq_startplay ();
+}
+
+int
+note_to_freq (int note_num)
+{
+
+ /*
+ * This routine converts a midi note to a frequency (multiplied by 1000)
+ */
+
+ int note, octave, note_freq;
+ int notes[] =
+ {
+ 261632, 277189, 293671, 311132, 329632, 349232,
+ 369998, 391998, 415306, 440000, 466162, 493880
+ }; /* Note freq*1000 for octave 5 */
+
+#define BASE_OCTAVE 5
+
+ octave = note_num / 12;
+ note = note_num % 12;
+
+ note_freq = notes[note];
+
+ if (octave < BASE_OCTAVE)
+ note_freq >>= (BASE_OCTAVE - octave);
+ else if (octave > BASE_OCTAVE)
+ note_freq <<= (octave - BASE_OCTAVE);
+
+ /* note_freq >>= 1; */
+
+ return note_freq;
+}
+
+unsigned long
+compute_finetune (unsigned long base_freq, int bend, int range)
+{
+ unsigned long amount;
+ int negative, semitones, cents, multiplier = 1;
+
+ if (!bend)
+ return base_freq;
+ if (!range)
+ return base_freq;
+
+ if (!base_freq)
+ return base_freq;
+
+ if (range >= 8192)
+ range = 8191;
+
+ bend = bend * range / 8192;
+ if (!bend)
+ return base_freq;
+
+ negative = bend < 0 ? 1 : 0;
+
+ if (bend < 0)
+ bend *= -1;
+ if (bend > range)
+ bend = range;
+
+ /*
+ if (bend > 2399)
+ bend = 2399;
+ */
+ while (bend > 2399)
+ {
+ multiplier *= 4;
+ bend -= 2400;
+ }
+
+ semitones = bend / 100;
+ cents = bend % 100;
+
+ amount = semitone_tuning[semitones] * multiplier * cent_tuning[cents] / 10000;
+
+ if (negative)
+ return (base_freq * 10000) / amount; /* Bend down */
+ else
+ return (base_freq * amount) / 10000; /* Bend up */
+}
+
+
+long
+sequencer_init (long mem_start)
+{
+
+ sequencer_ok = 1;
+ PERMANENT_MALLOC (unsigned char *, queue, SEQ_MAX_QUEUE * EV_SZ, mem_start);
+ PERMANENT_MALLOC (unsigned char *, iqueue, SEQ_MAX_QUEUE * IEV_SZ, mem_start);
+
+ return mem_start;
+}
+
+#else
+/* Stub version */
+int
+sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ return RET_ERROR (EIO);
+}
+
+int
+sequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ return RET_ERROR (EIO);
+}
+
+int
+sequencer_open (int dev, struct fileinfo *file)
+{
+ return RET_ERROR (ENXIO);
+}
+
+void
+sequencer_release (int dev, struct fileinfo *file)
+{
+}
+int
+sequencer_ioctl (int dev, struct fileinfo *file,
+ unsigned int cmd, unsigned int arg)
+{
+ return RET_ERROR (EIO);
+}
+
+int
+sequencer_lseek (int dev, struct fileinfo *file, off_t offset, int orig)
+{
+ return RET_ERROR (EIO);
+}
+
+long
+sequencer_init (long mem_start)
+{
+ return mem_start;
+}
+
+int
+sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
+{
+ return RET_ERROR (EIO);
+}
+
+#endif
+
+#endif
diff --git a/sys/i386/isa/sound/sound_calls.h b/sys/i386/isa/sound/sound_calls.h
new file mode 100644
index 0000000..abc8200
--- /dev/null
+++ b/sys/i386/isa/sound/sound_calls.h
@@ -0,0 +1,208 @@
+/*
+ * DMA buffer calls
+ */
+
+int DMAbuf_open(int dev, int mode);
+int DMAbuf_release(int dev, int mode);
+int DMAbuf_read (int dev, snd_rw_buf *user_buf, int count);
+int DMAbuf_getwrbuffer(int dev, char **buf, int *size);
+int DMAbuf_getrdbuffer(int dev, char **buf, int *len);
+int DMAbuf_rmchars(int dev, int buff_no, int c);
+int DMAbuf_start_output(int dev, int buff_no, int l);
+int DMAbuf_ioctl(int dev, unsigned int cmd, unsigned int arg, int local);
+long DMAbuf_init(long mem_start);
+int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode);
+int DMAbuf_open_dma (int chan);
+void DMAbuf_close_dma (int chan);
+void DMAbuf_reset_dma (int chan);
+void DMAbuf_inputintr(int dev);
+void DMAbuf_outputintr(int dev, int underflow_flag);
+
+/*
+ * System calls for /dev/dsp and /dev/audio
+ */
+
+int audio_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
+int audio_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
+int audio_open (int dev, struct fileinfo *file);
+void audio_release (int dev, struct fileinfo *file);
+int audio_ioctl (int dev, struct fileinfo *file,
+ unsigned int cmd, unsigned int arg);
+int audio_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
+long audio_init (long mem_start);
+
+/*
+ * System calls for the /dev/sequencer
+ */
+
+int sequencer_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
+int sequencer_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
+int sequencer_open (int dev, struct fileinfo *file);
+void sequencer_release (int dev, struct fileinfo *file);
+int sequencer_ioctl (int dev, struct fileinfo *file,
+ unsigned int cmd, unsigned int arg);
+int sequencer_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
+long sequencer_init (long mem_start);
+void sequencer_timer(void);
+int note_to_freq(int note_num);
+unsigned long compute_finetune(unsigned long base_freq, int bend, int range);
+
+#ifdef ALLOW_SELECT
+int sequencer_select(int dev, struct fileinfo *file, int sel_type, select_table * wait);
+#endif
+
+/*
+ * System calls for the /dev/midi
+ */
+
+int MIDIbuf_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
+int MIDIbuf_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
+int MIDIbuf_open (int dev, struct fileinfo *file);
+void MIDIbuf_release (int dev, struct fileinfo *file);
+int MIDIbuf_ioctl (int dev, struct fileinfo *file,
+ unsigned int cmd, unsigned int arg);
+int MIDIbuf_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
+void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count);
+long MIDIbuf_init(long mem_start);
+
+/*
+ * System calls for the generic midi interface.
+ *
+ */
+
+long CMIDI_init (long mem_start);
+int CMIDI_open (int dev, struct fileinfo *file);
+int CMIDI_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
+int CMIDI_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
+int CMIDI_close (int dev, struct fileinfo *file);
+
+/*
+ *
+ * Misc calls from various sources
+ */
+
+/* From pro_midi.c */
+
+long pro_midi_attach(long mem_start);
+int pro_midi_open(int dev, int mode);
+void pro_midi_close(int dev);
+int pro_midi_write(int dev, snd_rw_buf *uio);
+int pro_midi_read(int dev, snd_rw_buf *uio);
+
+/* From soundcard.c */
+long soundcard_init(long mem_start);
+void tenmicrosec(void);
+void request_sound_timer (int count);
+void sound_stop_timer(void);
+int snd_ioctl_return(int *addr, int value);
+int snd_set_irq_handler (int interrupt_level, void(*hndlr)(int));
+void snd_release_irq(int vect);
+void sound_dma_malloc(int dev);
+void sound_dma_free(int dev);
+
+/* From sound_switch.c */
+int sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
+int sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
+int sound_open_sw (int dev, struct fileinfo *file);
+void sound_release_sw (int dev, struct fileinfo *file);
+int sound_ioctl_sw (int dev, struct fileinfo *file,
+ unsigned int cmd, unsigned long arg);
+
+/* From sb_dsp.c */
+int sb_dsp_detect (struct address_info *hw_config);
+long sb_dsp_init (long mem_start, struct address_info *hw_config);
+void sb_dsp_disable_midi(void);
+int sb_get_irq(void);
+void sb_free_irq(void);
+int sb_dsp_command (unsigned char val);
+int sb_reset_dsp (void);
+
+/* From sb16_dsp.c */
+void sb16_dsp_interrupt (int unused);
+long sb16_dsp_init(long mem_start, struct address_info *hw_config);
+int sb16_dsp_detect(struct address_info *hw_config);
+
+/* From sb16_midi.c */
+void sb16midiintr (int unit);
+long attach_sb16midi(long mem_start, struct address_info * hw_config);
+int probe_sb16midi(struct address_info *hw_config);
+
+/* From sb_midi.c */
+void sb_midi_init(int model);
+void sb_midi_interrupt(int dummy);
+
+/* From sb_mixer.c */
+void sb_setmixer (unsigned int port, unsigned int value);
+int sb_getmixer (unsigned int port);
+void sb_mixer_set_stereo(int mode);
+int sb_mixer_init(int major_model);
+
+/* From opl3.c */
+int opl3_detect (int ioaddr);
+long opl3_init(long mem_start);
+
+/* From sb_card.c */
+long attach_sb_card(long mem_start, struct address_info *hw_config);
+int probe_sb(struct address_info *hw_config);
+
+/* From adlib_card.c */
+long attach_adlib_card(long mem_start, struct address_info *hw_config);
+int probe_adlib(struct address_info *hw_config);
+
+/* From pas_card.c */
+long attach_pas_card(long mem_start, struct address_info *hw_config);
+int probe_pas(struct address_info *hw_config);
+int pas_set_intr(int mask);
+int pas_remove_intr(int mask);
+unsigned char pas_read(int ioaddr);
+void pas_write(unsigned char data, int ioaddr);
+
+/* From pas_audio.c */
+void pas_pcm_interrupt(unsigned char status, int cause);
+long pas_pcm_init(long mem_start, struct address_info *hw_config);
+
+/* From pas_mixer.c */
+int pas_init_mixer(void);
+
+/* From pas_midi.c */
+long pas_midi_init(long mem_start);
+void pas_midi_interrupt(void);
+
+/* From gus_card.c */
+long attach_gus_card(long mem_start, struct address_info * hw_config);
+int probe_gus(struct address_info *hw_config);
+int gus_set_midi_irq(int num);
+void gusintr(int);
+
+/* From gus_wave.c */
+int gus_wave_detect(int baseaddr);
+long gus_wave_init(long mem_start, int irq, int dma);
+void gus_voice_irq(void);
+unsigned char gus_read8 (int reg);
+void gus_write8(int reg, unsigned int data);
+void guswave_dma_irq(void);
+void gus_delay(void);
+int gus_default_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg);
+
+/* From gus_midi.c */
+long gus_midi_init(long mem_start);
+void gus_midi_interrupt(int dummy);
+
+/* From mpu401.c */
+long attach_mpu401(long mem_start, struct address_info * hw_config);
+int probe_mpu401(struct address_info *hw_config);
+
+/* From opl3.c */
+void enable_opl3_mode(int left, int right, int both);
+
+/* From patmgr.c */
+int pmgr_open(int dev);
+void pmgr_release(int dev);
+int pmgr_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count);
+int pmgr_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count);
+int pmgr_access(int dev, struct patmgr_info *rec);
+int pmgr_inform(int dev, int event, unsigned long parm1, unsigned long parm2,
+ unsigned long parm3, unsigned long parm4);
+
+/* From ics2101.c */
+long ics2101_mixer_init(long mem_start);
diff --git a/sys/i386/isa/sound/sound_config.h b/sys/i386/isa/sound/sound_config.h
new file mode 100644
index 0000000..0d30c12
--- /dev/null
+++ b/sys/i386/isa/sound/sound_config.h
@@ -0,0 +1,241 @@
+/* sound_config.h
+ *
+ * A driver for Soundcards, misc configuration parameters.
+ *
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "local.h"
+
+
+#undef CONFIGURE_SOUNDCARD
+#undef DYNAMIC_BUFFER
+
+#ifdef KERNEL_SOUNDCARD
+#define CONFIGURE_SOUNDCARD
+#define DYNAMIC_BUFFER
+#undef LOADABLE_SOUNDCARD
+#endif
+
+#ifdef EXCLUDE_SEQUENCER
+#ifndef EXCLUDE_MIDI
+#define EXCLUDE_MIDI
+#endif
+#ifndef EXCLUDE_YM3812
+#define EXCLUDE_YM3812
+#endif
+#ifndef EXCLUDE_OPL3
+#define EXCLUDE_OPL3
+#endif
+#endif
+
+#ifndef SND_DEFAULT_ENABLE
+#define SND_DEFAULT_ENABLE 1
+#endif
+
+/** UWM - new MIDI stuff **/
+
+#ifdef EXCLUDE_CHIP_MIDI
+#ifndef EXCLUDE_PRO_MIDI
+#define EXCLUDE_PRO_MIDI
+#endif
+#endif
+
+/** UWM - stuff **/
+
+#if defined(EXCLUDE_SEQUENCER) && defined(EXCLUDE_AUDIO)
+#undef CONFIGURE_SOUNDCARD
+#endif
+
+#ifdef CONFIGURE_SOUNDCARD
+
+/* ****** IO-address, DMA and IRQ settings ****
+
+If your card has nonstandard I/O address or IRQ number, change defines
+ for the following settings in your kernel Makefile */
+
+#ifndef SBC_BASE
+#define SBC_BASE 0x220 /* 0x220 is the factory default. */
+#endif
+
+#ifndef SBC_IRQ
+#define SBC_IRQ 7 /* IQR7 is the factory default. */
+#endif
+
+#ifndef SBC_DMA
+#define SBC_DMA 1
+#endif
+
+#ifndef SB16_DMA
+#define SB16_DMA 6
+#endif
+
+#ifndef SB16MIDI_BASE
+#define SB16MIDI_BASE 0x300
+#endif
+
+#ifndef PAS_BASE
+#define PAS_BASE 0x388
+#endif
+
+#ifndef PAS_IRQ
+#define PAS_IRQ 5
+#endif
+
+#ifndef PAS_DMA
+#define PAS_DMA 3
+#endif
+
+#ifndef GUS_BASE
+#define GUS_BASE 0x220
+#endif
+
+#ifndef GUS_IRQ
+#define GUS_IRQ 15
+#endif
+
+#ifndef GUS_MIDI_IRQ
+#define GUS_MIDI_IRQ GUS_IRQ
+#endif
+
+#ifndef GUS_DMA
+#define GUS_DMA 6
+#endif
+
+#ifndef MPU_BASE
+#define MPU_BASE 0x330
+#endif
+
+#ifndef MPU_IRQ
+#define MPU_IRQ 6
+#endif
+
+#ifndef MAX_REALTIME_FACTOR
+#define MAX_REALTIME_FACTOR 4
+#endif
+
+/************* PCM DMA buffer sizes *******************/
+
+/* If you are using high playback or recording speeds, the default buffersize
+ is too small. DSP_BUFFSIZE must be 64k or less.
+
+ A rule of thumb is 64k for PAS16, 32k for PAS+, 16k for SB Pro and
+ 4k for SB.
+
+ If you change the DSP_BUFFSIZE, don't modify this file.
+ Use the make config command instead. */
+
+#ifndef DSP_BUFFSIZE
+#define DSP_BUFFSIZE (4096)
+#endif
+
+#ifndef DSP_BUFFCOUNT
+#define DSP_BUFFCOUNT 2 /* 2 is recommended. */
+#endif
+
+#define DMA_AUTOINIT 0x10
+
+#define FM_MONO 0x388 /* This is the I/O address used by AdLib */
+
+/* SEQ_MAX_QUEUE is the maximum number of sequencer events buffered by the
+ driver. (There is no need to alter this) */
+#define SEQ_MAX_QUEUE 1024
+
+#define SBFM_MAXINSTR (256) /* Size of the FM Instrument
+ bank */
+/* 128 instruments for general MIDI setup and 16 unassigned */
+
+#define SND_NDEVS 50 /* Number of supported devices */
+#define SND_DEV_CTL 0 /* Control port /dev/mixer */
+#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM
+ synthesizer and MIDI output) */
+#define SND_DEV_MIDIN 2 /* MIDI input /dev/midin (not implemented
+ yet) */
+#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */
+#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */
+#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */
+#define SND_DEV_STATUS 6 /* /dev/sndstatus */
+
+/* UWM ... note add new MIDI devices here..
+ * Also do not forget to add table midi_supported[]
+ * Minor numbers for on-chip midi devices start from 15.. and
+ * should be contiguous.. viz. 15,16,17....
+ * ERROR!!!!!!!!! NO NO. Minor numbers above 15 are reserved!!!!!! Hannu
+ * Also note the max # of midi devices as MAX_MIDI_DEV
+ */
+
+#define CMIDI_DEV_PRO 15 /* Chip midi device == /dev/pro_midi */
+
+/*
+ * Add other midis here...
+ .
+ .
+ .
+ .
+ */
+
+#define DSP_DEFAULT_SPEED 8000
+
+#define ON 1
+#define OFF 0
+
+#define MAX_DSP_DEV 4
+#define MAX_MIXER_DEV 2
+#define MAX_SYNTH_DEV 3
+#define MAX_MIDI_DEV 4
+
+struct fileinfo {
+ int mode; /* Open mode */
+ };
+
+struct address_info {
+ int io_base;
+ int irq;
+ int dma;
+};
+
+/*
+ * Process wakeup reasons
+ */
+#define WK_NONE 0x00
+#define WK_WAKEUP 0x01
+#define WK_TIMEOUT 0x02
+#define WK_SIGNAL 0x04
+#define WK_SLEEP 0x08
+
+#define OPEN_READ 1
+#define OPEN_WRITE 2
+#define OPEN_READWRITE 3
+
+#include "os.h"
+#include "sound_calls.h"
+#include "dev_table.h"
+
+#ifndef DEB
+#define DEB(x)
+#endif
+
+#endif
diff --git a/sys/i386/isa/sound/sound_switch.c b/sys/i386/isa/sound/sound_switch.c
new file mode 100644
index 0000000..68c7575
--- /dev/null
+++ b/sys/i386/isa/sound/sound_switch.c
@@ -0,0 +1,445 @@
+/*
+ * sound/sound_switch.c
+ *
+ * The system call switch
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+struct sbc_device
+ {
+ int usecount;
+ };
+
+static struct sbc_device sbc_devices[SND_NDEVS] =
+{
+ {0}};
+
+static int in_use = 0; /* Total # of open device files (excluding
+
+ * minor 0) */
+
+/*
+ * /dev/sndstatus -device
+ */
+static char *status_buf = NULL;
+static int status_len, status_ptr;
+static int status_busy = 0;
+
+static int
+put_status (char *s)
+{
+ int l;
+
+ for (l = 0; l < 256, s[l]; l++); /* l=strlen(s); */
+
+ if (status_len + l >= 4000)
+ return 0;
+
+ memcpy (&status_buf[status_len], s, l);
+ status_len += l;
+
+ return 1;
+}
+
+static int
+put_status_int (unsigned int val, int radix)
+{
+ int l, v;
+
+ static char hx[] = "0123456789abcdef";
+ char buf[11];
+
+ if (!val)
+ return put_status ("0");
+
+ l = 0;
+ buf[10] = 0;
+
+ while (val)
+ {
+ v = val % radix;
+ val = val / radix;
+
+ buf[9 - l] = hx[v];
+ l++;
+ }
+
+ if (status_len + l >= 4000)
+ return 0;
+
+ memcpy (&status_buf[status_len], &buf[10 - l], l);
+ status_len += l;
+
+ return 1;
+}
+
+static void
+init_status (void)
+{
+ /*
+ * Write the status information to the status_buf and update status_len.
+ * There is a limit of 4000 bytes for the data.
+ */
+
+ int i;
+
+ status_ptr = 0;
+
+ put_status ("Sound Driver:" SOUND_VERSION_STRING
+ " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY "@"
+ SOUND_CONFIG_HOST "." SOUND_CONFIG_DOMAIN ")"
+ "\n");
+
+ if (!put_status ("Config options: "))
+ return;
+ if (!put_status_int (SELECTED_SOUND_OPTIONS, 16))
+ return;
+
+ if (!put_status ("\n\nHW config: \n"))
+ return;
+
+ for (i = 0; i < (num_sound_drivers - 1); i++)
+ {
+ if (!supported_drivers[i].enabled)
+ if (!put_status ("("))
+ return;
+
+ if (!put_status ("Type "))
+ return;
+ if (!put_status_int (supported_drivers[i].card_type, 10))
+ return;
+ if (!put_status (": "))
+ return;
+ if (!put_status (supported_drivers[i].name))
+ return;
+ if (!put_status (" at 0x"))
+ return;
+ if (!put_status_int (supported_drivers[i].config.io_base, 16))
+ return;
+ if (!put_status (" irq "))
+ return;
+ if (!put_status_int (supported_drivers[i].config.irq, 10))
+ return;
+ if (!put_status (" drq "))
+ return;
+ if (!put_status_int (supported_drivers[i].config.dma, 10))
+ return;
+
+ if (!supported_drivers[i].enabled)
+ if (!put_status (")"))
+ return;
+
+ if (!put_status ("\n"))
+ return;
+ }
+
+ if (!put_status ("\nPCM devices:\n"))
+ return;
+
+ for (i = 0; i < num_dspdevs; i++)
+ {
+ if (!put_status_int (i, 10))
+ return;
+ if (!put_status (": "))
+ return;
+ if (!put_status (dsp_devs[i]->name))
+ return;
+ if (!put_status ("\n"))
+ return;
+ }
+
+ if (!put_status ("\nSynth devices:\n"))
+ return;
+
+ for (i = 0; i < num_synths; i++)
+ {
+ if (!put_status_int (i, 10))
+ return;
+ if (!put_status (": "))
+ return;
+ if (!put_status (synth_devs[i]->info->name))
+ return;
+ if (!put_status ("\n"))
+ return;
+ }
+
+ if (!put_status ("\nMidi devices:\n"))
+ return;
+
+ for (i = 0; i < num_midis; i++)
+ {
+ if (!put_status_int (i, 10))
+ return;
+ if (!put_status (": "))
+ return;
+ if (!put_status (midi_devs[i]->info.name))
+ return;
+ if (!put_status ("\n"))
+ return;
+ }
+
+ if (num_mixers)
+ {
+ if (!put_status ("\nMixer(s) installed\n"))
+ return;
+ }
+ else
+ {
+ if (!put_status ("\nNo mixers installed\n"))
+ return;
+ }
+}
+
+static int
+read_status (snd_rw_buf * buf, int count)
+{
+ /*
+ * Return at most 'count' bytes from the status_buf.
+ */
+ int l, c;
+
+ l = count;
+ c = status_len - status_ptr;
+
+ if (l > c)
+ l = c;
+ if (l <= 0)
+ return 0;
+
+ COPY_TO_USER (buf, 0, &status_buf[status_ptr], l);
+ status_ptr += l;
+
+ return l;
+}
+
+int
+sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+ DEB (printk ("sound_read_sw(dev=%d, count=%d)\n", dev, count));
+
+ switch (dev & 0x0f)
+ {
+ case SND_DEV_STATUS:
+ return read_status (buf, count);
+ break;
+
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ return audio_read (dev, file, buf, count);
+ break;
+
+ case SND_DEV_SEQ:
+ return sequencer_read (dev, file, buf, count);
+ break;
+
+#ifndef EXCLUDE_MPU401
+ case SND_DEV_MIDIN:
+ return MIDIbuf_read (dev, file, buf, count);
+#endif
+
+ default:
+ printk ("Sound: Undefined minor device %d\n", dev);
+ }
+
+ return RET_ERROR (EPERM);
+}
+
+int
+sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+{
+
+ DEB (printk ("sound_write_sw(dev=%d, count=%d)\n", dev, count));
+
+ switch (dev & 0x0f)
+ {
+
+ case SND_DEV_SEQ:
+ return sequencer_write (dev, file, buf, count);
+ break;
+
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ return audio_write (dev, file, buf, count);
+ break;
+
+ default:
+ return RET_ERROR (EPERM);
+ }
+
+ return count;
+}
+
+int
+sound_open_sw (int dev, struct fileinfo *file)
+{
+ int retval;
+
+ DEB (printk ("sound_open_sw(dev=%d) : usecount=%d\n", dev, sbc_devices[dev].usecount));
+
+ if ((dev >= SND_NDEVS) || (dev < 0))
+ {
+ printk ("Invalid minor device %d\n", dev);
+ return RET_ERROR (ENXIO);
+ }
+
+ switch (dev & 0x0f)
+ {
+ case SND_DEV_STATUS:
+ if (status_busy)
+ return RET_ERROR (EBUSY);
+ status_busy = 1;
+ if ((status_buf = (char *) KERNEL_MALLOC (4000)) == NULL)
+ return RET_ERROR (EIO);
+ status_len = status_ptr = 0;
+ init_status ();
+ break;
+
+ case SND_DEV_CTL:
+ return 0;
+ break;
+
+ case SND_DEV_SEQ:
+ if ((retval = sequencer_open (dev, file)) < 0)
+ return retval;
+ break;
+
+#ifndef EXCLUDE_MPU401
+ case SND_DEV_MIDIN:
+ if ((retval = MIDIbuf_open (dev, file)) < 0)
+ return retval;
+ break;
+#endif
+
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ if ((retval = audio_open (dev, file)) < 0)
+ return retval;
+ break;
+
+ default:
+ printk ("Invalid minor device %d\n", dev);
+ return RET_ERROR (ENXIO);
+ }
+
+ sbc_devices[dev].usecount++;
+ in_use++;
+
+ return 0;
+}
+
+void
+sound_release_sw (int dev, struct fileinfo *file)
+{
+
+ DEB (printk ("sound_release_sw(dev=%d)\n", dev));
+
+ switch (dev & 0x0f)
+ {
+ case SND_DEV_STATUS:
+ if (status_buf)
+ KERNEL_FREE (status_buf);
+ status_buf = NULL;
+ status_busy = 0;
+ break;
+
+ case SND_DEV_CTL:
+ break;
+
+ case SND_DEV_SEQ:
+ sequencer_release (dev, file);
+ break;
+
+#ifndef EXCLUDE_MPU401
+ case SND_DEV_MIDIN:
+ MIDIbuf_release (dev, file);
+ break;
+#endif
+
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ audio_release (dev, file);
+ break;
+
+ default:
+ printk ("Sound error: Releasing unknown device 0x%02x\n", dev);
+ }
+
+ sbc_devices[dev].usecount--;
+ in_use--;
+}
+
+int
+sound_ioctl_sw (int dev, struct fileinfo *file,
+ unsigned int cmd, unsigned long arg)
+{
+ DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
+
+ switch (dev & 0x0f)
+ {
+
+ case SND_DEV_CTL:
+
+ if (!num_mixers)
+ return RET_ERROR (ENXIO);
+
+ if ((dev >> 4) >= num_mixers)
+ return RET_ERROR (ENXIO);
+
+ return mixer_devs[dev >> 4]->ioctl (dev >> 4, cmd, arg);
+ break;
+
+ case SND_DEV_SEQ:
+ return sequencer_ioctl (dev, file, cmd, arg);
+ break;
+
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ return audio_ioctl (dev, file, cmd, arg);
+ break;
+
+#ifndef EXCLUDE_MPU401
+ case SND_DEV_MIDIN:
+ return MIDIbuf_ioctl (dev, file, cmd, arg);
+ break;
+#endif
+
+ default:
+ return RET_ERROR (EPERM);
+ break;
+ }
+
+ return RET_ERROR (EPERM);
+}
+
+#endif
diff --git a/sys/i386/isa/sound/soundcard.c b/sys/i386/isa/sound/soundcard.c
new file mode 100644
index 0000000..9691e4f
--- /dev/null
+++ b/sys/i386/isa/sound/soundcard.c
@@ -0,0 +1,394 @@
+/*
+ * sound/386bsd/soundcard.c
+ *
+ * Soundcard driver for FreeBSD.
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "sound_config.h"
+
+#ifdef CONFIGURE_SOUNDCARD
+
+#include "dev_table.h"
+
+u_int snd1_imask;
+u_int snd2_imask;
+u_int snd3_imask;
+u_int snd4_imask;
+u_int snd5_imask;
+u_int snd6_imask;
+u_int snd7_imask;
+u_int snd8_imask;
+u_int snd9_imask;
+
+#define FIX_RETURN(ret) {if ((ret)<0) return -(ret); else return 0;}
+
+static int timer_running = 0;
+
+static int soundcards_installed = 0; /* Number of installed
+ * soundcards */
+static int soundcard_configured = 0;
+extern char *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT];
+extern unsigned long snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT];
+extern int snd_raw_count[MAX_DSP_DEV];
+
+static struct fileinfo files[SND_NDEVS];
+
+int sndprobe (struct isa_device *dev);
+int sndattach (struct isa_device *dev);
+int sndopen (dev_t dev, int flags);
+int sndclose (dev_t dev, int flags);
+int sndioctl (dev_t dev, int cmd, caddr_t arg, int mode);
+int sndread (int dev, struct uio *uio);
+int sndwrite (int dev, struct uio *uio);
+int sndselect (int dev, int rw);
+static void sound_mem_init(void);
+
+unsigned
+long
+get_time(void)
+{
+extern struct timeval time;
+struct timeval timecopy;
+int x;
+
+ x = splclock();
+ timecopy = time;
+ splx(x);
+ return timecopy.tv_usec/(1000000/HZ) +
+ (unsigned long)timecopy.tv_sec*HZ;
+}
+
+
+int
+sndread (int dev, struct uio *buf)
+{
+ int count = buf->uio_resid;
+
+ dev = minor (dev);
+
+ FIX_RETURN (sound_read_sw (dev, &files[dev], buf, count));
+}
+
+int
+sndwrite (int dev, struct uio *buf)
+{
+ int count = buf->uio_resid;
+
+ dev = minor (dev);
+
+ FIX_RETURN (sound_write_sw (dev, &files[dev], buf, count));
+}
+
+int
+sndopen (dev_t dev, int flags)
+{
+ int retval;
+
+ dev = minor (dev);
+
+ if (!soundcard_configured && dev)
+ {
+ printk ("SoundCard Error: The soundcard system has not been configured\n");
+ FIX_RETURN (-ENODEV);
+ }
+
+ files[dev].mode = 0;
+
+ if (flags & FREAD && flags & FWRITE)
+ files[dev].mode = OPEN_READWRITE;
+ else if (flags & FREAD)
+ files[dev].mode = OPEN_READ;
+ else if (flags & FWRITE)
+ files[dev].mode = OPEN_WRITE;
+
+ FIX_RETURN(sound_open_sw (dev, &files[dev]));
+}
+
+int
+sndclose (dev_t dev, int flags)
+{
+
+ dev = minor (dev);
+
+ sound_release_sw(dev, &files[dev]);
+ FIX_RETURN (0);
+}
+
+int
+sndioctl (dev_t dev, int cmd, caddr_t arg, int mode)
+{
+ dev = minor (dev);
+
+ FIX_RETURN (sound_ioctl_sw (dev, &files[dev], cmd, (unsigned int) arg));
+}
+
+int
+sndselect (int dev, int rw)
+{
+ dev = minor (dev);
+
+ DEB (printk ("sound_ioctl(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
+
+ FIX_RETURN (0);
+}
+
+static unsigned short
+ipri_to_irq (unsigned short ipri)
+{
+ /*
+ * Converts the ipri (bitmask) to the corresponding irq number
+ */
+ int irq;
+
+ for (irq = 0; irq < 16; irq++)
+ if (ipri == (1 << irq))
+ return irq;
+
+ return -1; /* Invalid argument */
+}
+
+int
+sndprobe (struct isa_device *dev)
+{
+ struct address_info hw_config;
+
+ hw_config.io_base = dev->id_iobase;
+ hw_config.irq = ipri_to_irq (dev->id_irq);
+ hw_config.dma = dev->id_drq;
+
+ return sndtable_probe (dev->id_unit, &hw_config);
+}
+
+int
+sndattach (struct isa_device *dev)
+{
+ int i;
+ static int dsp_initialized = 0;
+ static int midi_initialized = 0;
+ static int seq_initialized = 0;
+ static int generic_midi_initialized = 0;
+ unsigned long mem_start = 0xefffffffUL;
+ struct address_info hw_config;
+
+ hw_config.io_base = dev->id_iobase;
+ hw_config.irq = ipri_to_irq (dev->id_irq);
+ hw_config.dma = dev->id_drq;
+
+ if (dev->id_unit) /* Card init */
+ if (!sndtable_init_card (dev->id_unit, &hw_config))
+ {
+ printf (" <Driver not configured>");
+ return FALSE;
+ }
+
+ /*
+ * Init the high level sound driver
+ */
+
+ if (!(soundcards_installed = sndtable_get_cardcount ()))
+ {
+ printf (" <No such hardware>");
+ return FALSE; /* No cards detected */
+ }
+
+ printf("\n");
+
+#ifndef EXCLUDE_AUDIO
+ soundcard_configured = 1;
+ if (num_dspdevs)
+ sound_mem_init ();
+#endif
+
+ if (num_dspdevs && !dsp_initialized) /* Audio devices present */
+ {
+ dsp_initialized = 1;
+ mem_start = DMAbuf_init (mem_start);
+ mem_start = audio_init (mem_start);
+ }
+
+/** UWM stuff **/
+
+#ifndef EXCLUDE_CHIP_MIDI
+
+ if (!generic_midi_initialized)
+ {
+ generic_midi_initialized = 1;
+ mem_start = CMIDI_init (mem_start);
+ }
+
+#endif
+
+#ifndef EXCLUDE_MPU401
+ if (num_midis && !midi_initialized)
+ {
+ midi_initialized = 1;
+ mem_start = MIDIbuf_init (mem_start);
+ }
+#endif
+
+ if ((num_midis + num_synths) && !seq_initialized)
+ {
+ seq_initialized = 1;
+ mem_start = sequencer_init (mem_start);
+ }
+
+ return TRUE;
+}
+
+void
+tenmicrosec (void)
+{
+ int i;
+
+ for (i = 0; i < 16; i++)
+ inb (0x80);
+}
+
+#ifdef EXCLUDE_GUS
+void
+gusintr (int unit)
+{
+ return;
+}
+#endif
+
+void
+request_sound_timer (int count)
+{
+ static int current = 0;
+ int tmp = count;
+
+ if (count < 0)
+ timeout ((timeout_func_t)sequencer_timer, 0, -count);
+ else
+ {
+
+ if (count < current)
+ current = 0; /* Timer restarted */
+
+ count = count - current;
+
+ current = tmp;
+
+ if (!count)
+ count = 1;
+
+ timeout ((timeout_func_t)sequencer_timer, 0, count);
+ }
+ timer_running = 1;
+}
+
+void
+sound_stop_timer (void)
+{
+ if (timer_running)
+ untimeout ((timeout_func_t)sequencer_timer, 0);
+ timer_running = 0;
+}
+
+#ifndef EXCLUDE_AUDIO
+static void
+sound_mem_init (void)
+{
+ int i, dev;
+ unsigned long dma_pagesize;
+ static unsigned long dsp_init_mask = 0;
+
+ for (dev = 0; dev < num_dspdevs; dev++) /* Enumerate devices */
+ if (!(dsp_init_mask & (1 << dev))) /* Not already done */
+ if (sound_buffcounts[dev] > 0 && sound_dsp_dmachan[dev] > 0)
+ {
+ dsp_init_mask |= (1 << dev);
+
+ if (sound_dma_automode[dev])
+ sound_buffcounts[dev] = 1;
+
+ if (sound_dsp_dmachan[dev] > 3 && sound_buffsizes[dev] > 65536)
+ dma_pagesize = 131072; /* 128k */
+ else
+ dma_pagesize = 65536;
+
+ /* More sanity checks */
+
+ if (sound_buffsizes[dev] > dma_pagesize)
+ sound_buffsizes[dev] = dma_pagesize;
+ sound_buffsizes[dev] &= ~0xfff; /* Truncate to n*4k */
+ if (sound_buffsizes[dev] < 4096)
+ sound_buffsizes[dev] = 4096;
+
+ /* Now allocate the buffers */
+
+ for (snd_raw_count[dev] = 0; snd_raw_count[dev] < sound_buffcounts[dev]; snd_raw_count[dev]++)
+ {
+ char *tmpbuf = contigmalloc (sound_buffsizes[dev], M_DEVBUF, M_NOWAIT,
+ 0xFFFFFFul, 0ul, dma_pagesize - 1);
+
+ if (tmpbuf == NULL)
+ {
+ printk ("snd: Unable to allocate %d bytes of buffer\n",
+ sound_buffsizes[dev]);
+ return;
+ }
+
+ snd_raw_buf[dev][snd_raw_count[dev]] = tmpbuf;
+ /*
+ * Use virtual address as the physical address, since
+ * isa_dmastart performs the phys address computation.
+ */
+ snd_raw_buf_phys[dev][snd_raw_count[dev]] =
+ (unsigned long) snd_raw_buf[dev][snd_raw_count[dev]];
+ }
+ } /* for dev */
+
+}
+
+#endif
+
+struct isa_driver snddriver =
+{sndprobe, sndattach, "snd"};
+
+int
+snd_ioctl_return (int *addr, int value)
+{
+ if (value < 0)
+ return value; /* Error */
+ suword (addr, value);
+ return 0;
+}
+
+int
+snd_set_irq_handler (int interrupt_level, void(*hndlr)(int))
+{
+ return 1;
+}
+
+void
+snd_release_irq(int vect)
+{
+}
+
+#endif
diff --git a/sys/i386/isa/sound/tuning.h b/sys/i386/isa/sound/tuning.h
new file mode 100644
index 0000000..858e1fe
--- /dev/null
+++ b/sys/i386/isa/sound/tuning.h
@@ -0,0 +1,29 @@
+#ifdef SEQUENCER_C
+
+unsigned short semitone_tuning[24] =
+{
+/* 0 */ 10000, 10595, 11225, 11892, 12599, 13348, 14142, 14983,
+/* 8 */ 15874, 16818, 17818, 18877, 20000, 21189, 22449, 23784,
+/* 16 */ 25198, 26697, 28284, 29966, 31748, 33636, 35636, 37755
+};
+
+unsigned short cent_tuning[100] =
+{
+/* 0 */ 10000, 10006, 10012, 10017, 10023, 10029, 10035, 10041,
+/* 8 */ 10046, 10052, 10058, 10064, 10070, 10075, 10081, 10087,
+/* 16 */ 10093, 10099, 10105, 10110, 10116, 10122, 10128, 10134,
+/* 24 */ 10140, 10145, 10151, 10157, 10163, 10169, 10175, 10181,
+/* 32 */ 10187, 10192, 10198, 10204, 10210, 10216, 10222, 10228,
+/* 40 */ 10234, 10240, 10246, 10251, 10257, 10263, 10269, 10275,
+/* 48 */ 10281, 10287, 10293, 10299, 10305, 10311, 10317, 10323,
+/* 56 */ 10329, 10335, 10341, 10347, 10353, 10359, 10365, 10371,
+/* 64 */ 10377, 10383, 10389, 10395, 10401, 10407, 10413, 10419,
+/* 72 */ 10425, 10431, 10437, 10443, 10449, 10455, 10461, 10467,
+/* 80 */ 10473, 10479, 10485, 10491, 10497, 10503, 10509, 10515,
+/* 88 */ 10521, 10528, 10534, 10540, 10546, 10552, 10558, 10564,
+/* 96 */ 10570, 10576, 10582, 10589
+};
+#else
+extern unsigned short semitone_tuning[24];
+extern unsigned short cent_tuning[100];
+#endif
diff --git a/sys/i386/isa/sound/ulaw.h b/sys/i386/isa/sound/ulaw.h
new file mode 100644
index 0000000..be9f92d
--- /dev/null
+++ b/sys/i386/isa/sound/ulaw.h
@@ -0,0 +1,69 @@
+static unsigned char ulaw_dsp[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 2,
+ 5, 9, 13, 17, 21, 25, 29, 33,
+ 37, 41, 45, 49, 53, 57, 61, 65,
+ 68, 70, 72, 74, 76, 78, 80, 82,
+ 84, 86, 88, 90, 92, 94, 96, 98,
+ 100, 101, 102, 103, 104, 105, 106, 107,
+ 108, 109, 110, 111, 112, 113, 114, 115,
+ 115, 116, 116, 117, 117, 118, 118, 119,
+ 119, 120, 120, 121, 121, 122, 122, 123,
+ 123, 123, 124, 124, 124, 124, 125, 125,
+ 125, 125, 126, 126, 126, 126, 127, 127,
+ 127, 127, 127, 127, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 252, 248, 244, 240, 236, 232, 228, 224,
+ 220, 216, 212, 208, 204, 200, 196, 192,
+ 189, 187, 185, 183, 181, 179, 177, 175,
+ 173, 171, 169, 167, 165, 163, 161, 159,
+ 157, 156, 155, 154, 153, 152, 151, 150,
+ 149, 148, 147, 146, 145, 144, 143, 142,
+ 142, 141, 141, 140, 140, 139, 139, 138,
+ 138, 137, 137, 136, 136, 135, 135, 134,
+ 134, 134, 133, 133, 133, 133, 132, 132,
+ 132, 132, 131, 131, 131, 131, 130, 130,
+ 130, 130, 130, 130, 129, 129, 129, 129,
+ 129, 129, 129, 129, 128, 128, 128, 128,
+};
+
+static unsigned char dsp_ulaw[] = {
+ 31, 31, 31, 32, 32, 32, 32, 33,
+ 33, 33, 33, 34, 34, 34, 34, 35,
+ 35, 35, 35, 36, 36, 36, 36, 37,
+ 37, 37, 37, 38, 38, 38, 38, 39,
+ 39, 39, 39, 40, 40, 40, 40, 41,
+ 41, 41, 41, 42, 42, 42, 42, 43,
+ 43, 43, 43, 44, 44, 44, 44, 45,
+ 45, 45, 45, 46, 46, 46, 46, 47,
+ 47, 47, 47, 48, 48, 49, 49, 50,
+ 50, 51, 51, 52, 52, 53, 53, 54,
+ 54, 55, 55, 56, 56, 57, 57, 58,
+ 58, 59, 59, 60, 60, 61, 61, 62,
+ 62, 63, 63, 64, 65, 66, 67, 68,
+ 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 78, 79, 81, 83, 85, 87, 89,
+ 91, 93, 95, 99, 103, 107, 111, 119,
+ 255, 247, 239, 235, 231, 227, 223, 221,
+ 219, 217, 215, 213, 211, 209, 207, 206,
+ 205, 204, 203, 202, 201, 200, 199, 198,
+ 197, 196, 195, 194, 193, 192, 191, 191,
+ 190, 190, 189, 189, 188, 188, 187, 187,
+ 186, 186, 185, 185, 184, 184, 183, 183,
+ 182, 182, 181, 181, 180, 180, 179, 179,
+ 178, 178, 177, 177, 176, 176, 175, 175,
+ 175, 175, 174, 174, 174, 174, 173, 173,
+ 173, 173, 172, 172, 172, 172, 171, 171,
+ 171, 171, 170, 170, 170, 170, 169, 169,
+ 169, 169, 168, 168, 168, 168, 167, 167,
+ 167, 167, 166, 166, 166, 166, 165, 165,
+ 165, 165, 164, 164, 164, 164, 163, 163,
+ 163, 163, 162, 162, 162, 162, 161, 161,
+ 161, 161, 160, 160, 160, 160, 159, 159,
+};
diff --git a/sys/i386/isa/spkr.c b/sys/i386/isa/spkr.c
new file mode 100644
index 0000000..d273f31
--- /dev/null
+++ b/sys/i386/isa/spkr.c
@@ -0,0 +1,541 @@
+/*
+ * spkr.c -- device driver for console speaker
+ *
+ * v1.4 by Eric S. Raymond (esr@snark.thyrsus.com) Aug 1993
+ * modified for FreeBSD by Andrew A. Chernov <ache@astral.msk.su>
+ *
+ * $Id: spkr.c,v 1.7 1994/01/25 23:04:27 ache Exp $
+ */
+
+#include "speaker.h"
+
+#if NSPEAKER > 0
+
+#include "param.h"
+#include "systm.h"
+#include "kernel.h"
+#include "errno.h"
+#include "buf.h"
+#include "uio.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/timerreg.h"
+#include "machine/speaker.h"
+
+/**************** MACHINE DEPENDENT PART STARTS HERE *************************
+ *
+ * This section defines a function tone() which causes a tone of given
+ * frequency and duration from the 80x86's console speaker.
+ * Another function endtone() is defined to force sound off, and there is
+ * also a rest() entry point to do pauses.
+ *
+ * Audible sound is generated using the Programmable Interval Timer (PIT) and
+ * Programmable Peripheral Interface (PPI) attached to the 80x86's speaker. The
+ * PPI controls whether sound is passed through at all; the PIT's channel 2 is
+ * used to generate clicks (a square wave) of whatever frequency is desired.
+ */
+
+/*
+ * PIT and PPI port addresses and control values
+ *
+ * Most of the magic is hidden in the TIMER_PREP value, which selects PIT
+ * channel 2, frequency LSB first, square-wave mode and binary encoding.
+ * The encoding is as follows:
+ *
+ * +----------+----------+---------------+-----+
+ * | 1 0 | 1 1 | 0 1 1 | 0 |
+ * | SC1 SC0 | RW1 RW0 | M2 M1 M0 | BCD |
+ * +----------+----------+---------------+-----+
+ * Counter Write Mode 3 Binary
+ * Channel 2 LSB first, (Square Wave) Encoding
+ * MSB second
+ */
+#define PPI_SPKR 0x03 /* turn these PPI bits on to pass sound */
+#define PIT_MODE 0xB6 /* set timer mode for sound generation */
+
+/*
+ * Magic numbers for timer control.
+ */
+#define TIMER_CLK 1193180L /* corresponds to 18.2 MHz tick rate */
+
+#define SPKRPRI PSOCK
+static char endtone, endrest;
+
+static void tone(thz, ticks)
+/* emit tone of frequency thz for given number of ticks */
+unsigned int thz, ticks;
+{
+ unsigned int divisor = TIMER_CLK / thz;
+ int sps;
+
+#ifdef DEBUG
+ (void) printf("tone: thz=%d ticks=%d\n", thz, ticks);
+#endif /* DEBUG */
+
+ /* set timer to generate clicks at given frequency in Hertz */
+ sps = spltty();
+
+ if (acquire_timer2(PIT_MODE)) {
+ /* enter list of waiting procs ??? */
+ return;
+ }
+ outb(TIMER_CNTR2, (divisor & 0xff)); /* send lo byte */
+ outb(TIMER_CNTR2, (divisor >> 8)); /* send hi byte */
+ splx(sps);
+
+ /* turn the speaker on */
+ outb(IO_PPI, inb(IO_PPI) | PPI_SPKR);
+
+ /*
+ * Set timeout to endtone function, then give up the timeslice.
+ * This is so other processes can execute while the tone is being
+ * emitted.
+ */
+ (void) tsleep((caddr_t)&endtone, SPKRPRI | PCATCH, "spkrtn", ticks);
+ outb(IO_PPI, inb(IO_PPI) & ~PPI_SPKR);
+ release_timer2();
+}
+
+static void rest(ticks)
+/* rest for given number of ticks */
+int ticks;
+{
+ /*
+ * Set timeout to endrest function, then give up the timeslice.
+ * This is so other processes can execute while the rest is being
+ * waited out.
+ */
+#ifdef DEBUG
+ (void) printf("rest: %d\n", ticks);
+#endif /* DEBUG */
+ (void) tsleep((caddr_t)&endrest, SPKRPRI | PCATCH, "spkrrs", ticks);
+}
+
+/**************** PLAY STRING INTERPRETER BEGINS HERE **********************
+ *
+ * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement;
+ * M[LNS] are missing; the ~ synonym and the _ slur mark and the octave-
+ * tracking facility are added.
+ * Requires tone(), rest(), and endtone(). String play is not interruptible
+ * except possibly at physical block boundaries.
+ */
+
+typedef int bool;
+#define TRUE 1
+#define FALSE 0
+
+#define toupper(c) ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z')))
+#define isdigit(c) (((c) >= '0') && ((c) <= '9'))
+#define dtoi(c) ((c) - '0')
+
+static int octave; /* currently selected octave */
+static int whole; /* whole-note time at current tempo, in ticks */
+static int value; /* whole divisor for note time, quarter note = 1 */
+static int fill; /* controls spacing of notes */
+static bool octtrack; /* octave-tracking on? */
+static bool octprefix; /* override current octave-tracking state? */
+
+/*
+ * Magic number avoidance...
+ */
+#define SECS_PER_MIN 60 /* seconds per minute */
+#define WHOLE_NOTE 4 /* quarter notes per whole note */
+#define MIN_VALUE 64 /* the most we can divide a note by */
+#define DFLT_VALUE 4 /* default value (quarter-note) */
+#define FILLTIME 8 /* for articulation, break note in parts */
+#define STACCATO 6 /* 6/8 = 3/4 of note is filled */
+#define NORMAL 7 /* 7/8ths of note interval is filled */
+#define LEGATO 8 /* all of note interval is filled */
+#define DFLT_OCTAVE 4 /* default octave */
+#define MIN_TEMPO 32 /* minimum tempo */
+#define DFLT_TEMPO 120 /* default tempo */
+#define MAX_TEMPO 255 /* max tempo */
+#define NUM_MULT 3 /* numerator of dot multiplier */
+#define DENOM_MULT 2 /* denominator of dot multiplier */
+
+/* letter to half-tone: A B C D E F G */
+static int notetab[8] = {9, 11, 0, 2, 4, 5, 7};
+
+/*
+ * This is the American Standard A440 Equal-Tempered scale with frequencies
+ * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook...
+ * our octave 0 is standard octave 2.
+ */
+#define OCTAVE_NOTES 12 /* semitones per octave */
+static int pitchtab[] =
+{
+/* C C# D D# E F F# G G# A A# B*/
+/* 0 */ 65, 69, 73, 78, 82, 87, 93, 98, 103, 110, 117, 123,
+/* 1 */ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247,
+/* 2 */ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494,
+/* 3 */ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988,
+/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975,
+/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951,
+/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902,
+};
+
+static void playinit()
+{
+ octave = DFLT_OCTAVE;
+ whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO;
+ fill = NORMAL;
+ value = DFLT_VALUE;
+ octtrack = FALSE;
+ octprefix = TRUE; /* act as though there was an initial O(n) */
+}
+
+static void playtone(pitch, value, sustain)
+/* play tone of proper duration for current rhythm signature */
+int pitch, value, sustain;
+{
+ register int sound, silence, snum = 1, sdenom = 1;
+
+ /* this weirdness avoids floating-point arithmetic */
+ for (; sustain; sustain--)
+ {
+ /* See the BUGS section in the man page for discussion */
+ snum *= NUM_MULT;
+ sdenom *= DENOM_MULT;
+ }
+
+ if (pitch == -1)
+ rest(whole * snum / (value * sdenom));
+ else
+ {
+ sound = (whole * snum) / (value * sdenom)
+ - (whole * (FILLTIME - fill)) / (value * FILLTIME);
+ silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom);
+
+#ifdef DEBUG
+ (void) printf("playtone: pitch %d for %d ticks, rest for %d ticks\n",
+ pitch, sound, silence);
+#endif /* DEBUG */
+
+ tone(pitchtab[pitch], sound);
+ if (fill != LEGATO)
+ rest(silence);
+ }
+}
+
+static int abs(n)
+int n;
+{
+ if (n < 0)
+ return(-n);
+ else
+ return(n);
+}
+
+static void playstring(cp, slen)
+/* interpret and play an item from a notation string */
+char *cp;
+size_t slen;
+{
+ int pitch, oldfill, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE;
+
+#define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \
+ {v = v * 10 + (*++cp - '0'); slen--;}
+ for (; slen--; cp++)
+ {
+ int sustain, timeval, tempo;
+ register char c = toupper(*cp);
+
+#ifdef DEBUG
+ (void) printf("playstring: %c (%x)\n", c, c);
+#endif /* DEBUG */
+
+ switch (c)
+ {
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+
+ /* compute pitch */
+ pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES;
+
+ /* this may be followed by an accidental sign */
+ if (cp[1] == '#' || cp[1] == '+')
+ {
+ ++pitch;
+ ++cp;
+ slen--;
+ }
+ else if (cp[1] == '-')
+ {
+ --pitch;
+ ++cp;
+ slen--;
+ }
+
+ /*
+ * If octave-tracking mode is on, and there has been no octave-
+ * setting prefix, find the version of the current letter note
+ * closest to the last regardless of octave.
+ */
+ if (octtrack && !octprefix)
+ {
+ if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch))
+ {
+ ++octave;
+ pitch += OCTAVE_NOTES;
+ }
+
+ if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch))
+ {
+ --octave;
+ pitch -= OCTAVE_NOTES;
+ }
+ }
+ octprefix = FALSE;
+ lastpitch = pitch;
+
+ /* ...which may in turn be followed by an override time value */
+ GETNUM(cp, timeval);
+ if (timeval <= 0 || timeval > MIN_VALUE)
+ timeval = value;
+
+ /* ...and/or sustain dots */
+ for (sustain = 0; cp[1] == '.'; cp++)
+ {
+ slen--;
+ sustain++;
+ }
+
+ /* ...and/or a slur mark */
+ oldfill = fill;
+ if (cp[1] == '_')
+ {
+ fill = LEGATO;
+ ++cp;
+ slen--;
+ }
+
+ /* time to emit the actual tone */
+ playtone(pitch, timeval, sustain);
+
+ fill = oldfill;
+ break;
+
+ case 'O':
+ if (cp[1] == 'N' || cp[1] == 'n')
+ {
+ octprefix = octtrack = FALSE;
+ ++cp;
+ slen--;
+ }
+ else if (cp[1] == 'L' || cp[1] == 'l')
+ {
+ octtrack = TRUE;
+ ++cp;
+ slen--;
+ }
+ else
+ {
+ GETNUM(cp, octave);
+ if (octave >= sizeof(pitchtab) / OCTAVE_NOTES)
+ octave = DFLT_OCTAVE;
+ octprefix = TRUE;
+ }
+ break;
+
+ case '>':
+ if (octave < sizeof(pitchtab) / OCTAVE_NOTES - 1)
+ octave++;
+ octprefix = TRUE;
+ break;
+
+ case '<':
+ if (octave > 0)
+ octave--;
+ octprefix = TRUE;
+ break;
+
+ case 'N':
+ GETNUM(cp, pitch);
+ for (sustain = 0; cp[1] == '.'; cp++)
+ {
+ slen--;
+ sustain++;
+ }
+ oldfill = fill;
+ if (cp[1] == '_')
+ {
+ fill = LEGATO;
+ ++cp;
+ slen--;
+ }
+ playtone(pitch - 1, value, sustain);
+ fill = oldfill;
+ break;
+
+ case 'L':
+ GETNUM(cp, value);
+ if (value <= 0 || value > MIN_VALUE)
+ value = DFLT_VALUE;
+ break;
+
+ case 'P':
+ case '~':
+ /* this may be followed by an override time value */
+ GETNUM(cp, timeval);
+ if (timeval <= 0 || timeval > MIN_VALUE)
+ timeval = value;
+ for (sustain = 0; cp[1] == '.'; cp++)
+ {
+ slen--;
+ sustain++;
+ }
+ playtone(-1, timeval, sustain);
+ break;
+
+ case 'T':
+ GETNUM(cp, tempo);
+ if (tempo < MIN_TEMPO || tempo > MAX_TEMPO)
+ tempo = DFLT_TEMPO;
+ whole = (hz * SECS_PER_MIN * WHOLE_NOTE) / tempo;
+ break;
+
+ case 'M':
+ if (cp[1] == 'N' || cp[1] == 'n')
+ {
+ fill = NORMAL;
+ ++cp;
+ slen--;
+ }
+ else if (cp[1] == 'L' || cp[1] == 'l')
+ {
+ fill = LEGATO;
+ ++cp;
+ slen--;
+ }
+ else if (cp[1] == 'S' || cp[1] == 's')
+ {
+ fill = STACCATO;
+ ++cp;
+ slen--;
+ }
+ break;
+ }
+ }
+}
+
+/******************* UNIX DRIVER HOOKS BEGIN HERE **************************
+ *
+ * This section implements driver hooks to run playstring() and the tone(),
+ * endtone(), and rest() functions defined above.
+ */
+
+static int spkr_active = FALSE; /* exclusion flag */
+static struct buf *spkr_inbuf; /* incoming buf */
+
+int spkropen(dev)
+dev_t dev;
+{
+#ifdef DEBUG
+ (void) printf("spkropen: entering with dev = %x\n", dev);
+#endif /* DEBUG */
+
+ if (minor(dev) != 0)
+ return(ENXIO);
+ else if (spkr_active)
+ return(EBUSY);
+ else
+ {
+#ifdef DEBUG
+ (void) printf("spkropen: about to perform play initialization\n");
+#endif /* DEBUG */
+ playinit();
+ spkr_inbuf = geteblk(DEV_BSIZE);
+ spkr_active = TRUE;
+ return(0);
+ }
+}
+
+int spkrwrite(dev, uio)
+dev_t dev;
+struct uio *uio;
+{
+#ifdef DEBUG
+ printf("spkrwrite: entering with dev = %x, count = %d\n",
+ dev, uio->uio_resid);
+#endif /* DEBUG */
+
+ if (minor(dev) != 0)
+ return(ENXIO);
+ else if (uio->uio_resid > DEV_BSIZE) /* prevent system crashes */
+ return(E2BIG);
+ else
+ {
+ unsigned n;
+ char *cp;
+ int error;
+
+ n = uio->uio_resid;
+ cp = spkr_inbuf->b_un.b_addr;
+ if (!(error = uiomove(cp, n, uio)))
+ playstring(cp, n);
+ return(error);
+ }
+}
+
+int spkrclose(dev)
+dev_t dev;
+{
+#ifdef DEBUG
+ (void) printf("spkrclose: entering with dev = %x\n", dev);
+#endif /* DEBUG */
+
+ if (minor(dev) != 0)
+ return(ENXIO);
+ else
+ {
+ wakeup((caddr_t)&endtone);
+ wakeup((caddr_t)&endrest);
+ brelse(spkr_inbuf);
+ spkr_active = FALSE;
+ return(0);
+ }
+}
+
+int spkrioctl(dev, cmd, cmdarg)
+dev_t dev;
+int cmd;
+caddr_t cmdarg;
+{
+#ifdef DEBUG
+ (void) printf("spkrioctl: entering with dev = %x, cmd = %x\n");
+#endif /* DEBUG */
+
+ if (minor(dev) != 0)
+ return(ENXIO);
+ else if (cmd == SPKRTONE)
+ {
+ tone_t *tp = (tone_t *)cmdarg;
+
+ if (tp->frequency == 0)
+ rest(tp->duration);
+ else
+ tone(tp->frequency, tp->duration);
+ return 0;
+ }
+ else if (cmd == SPKRTUNE)
+ {
+ tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg);
+ tone_t ttp;
+ int error;
+
+ for (; ; tp++) {
+ error = copyin(tp, &ttp, sizeof(tone_t));
+ if (error)
+ return(error);
+ if (ttp.duration == 0)
+ break;
+ if (ttp.frequency == 0)
+ rest(ttp.duration);
+ else
+ tone(ttp.frequency, ttp.duration);
+ }
+ return(0);
+ }
+ return(EINVAL);
+}
+
+#endif /* NSPEAKER > 0 */
+/* spkr.c ends here */
diff --git a/sys/i386/isa/syscons.c b/sys/i386/isa/syscons.c
new file mode 100644
index 0000000..8757295
--- /dev/null
+++ b/sys/i386/isa/syscons.c
@@ -0,0 +1,2659 @@
+/*-
+ * Copyright (c) 1992-1994 Søren Schmidt
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz and Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from:@(#)syscons.c 1.3 940129
+ * $Id: syscons.c,v 1.44 1994/04/21 14:22:26 sos Exp $
+ *
+ */
+
+#if !defined(__FreeBSD__)
+#define FAT_CURSOR
+#endif
+
+#include "param.h"
+#include "conf.h"
+#include "ioctl.h"
+#include "proc.h"
+#include "user.h"
+#include "tty.h"
+#include "uio.h"
+#include "callout.h"
+#include "systm.h"
+#include "kernel.h"
+#include "syslog.h"
+#include "errno.h"
+#include "malloc.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/timerreg.h"
+#include "i386/i386/cons.h"
+#include "machine/console.h"
+#include "machine/psl.h"
+#include "machine/frame.h"
+#include "machine/pc/display.h"
+#include "iso8859.font"
+#include "kbdtables.h"
+#include "sc.h"
+
+#if NSC > 0
+
+#if !defined(NCONS)
+#define NCONS 12
+#endif
+
+/* status flags */
+#define LOCK_KEY_MASK 0x0000F
+#define LED_MASK 0x00007
+#define UNKNOWN_MODE 0x00010
+#define KBD_RAW_MODE 0x00020
+#define SWITCH_WAIT_REL 0x00040
+#define SWITCH_WAIT_ACQ 0x00080
+
+/* video hardware memory addresses */
+#define VIDEOMEM 0x000A0000
+
+/* misc defines */
+#define MAX_ESC_PAR 3
+#define TEXT80x25 1
+#define TEXT80x50 2
+#define COL 80
+#define ROW 25
+#define BELL_DURATION 5
+#define BELL_PITCH 800
+#define TIMER_FREQ 1193182 /* should be in isa.h */
+#define PCBURST 128
+
+/* defines related to hardware addresses */
+#define MONO_BASE 0x3B4 /* crt controller base mono */
+#define COLOR_BASE 0x3D4 /* crt controller base color */
+#define ATC IO_VGA+0x00 /* attribute controller */
+#define TSIDX IO_VGA+0x04 /* timing sequencer idx */
+#define TSREG IO_VGA+0x05 /* timing sequencer data */
+#define PIXMASK IO_VGA+0x06 /* pixel write mask */
+#define PALRADR IO_VGA+0x07 /* palette read address */
+#define PALWADR IO_VGA+0x08 /* palette write address */
+#define PALDATA IO_VGA+0x09 /* palette data register */
+#define GDCIDX IO_VGA+0x0E /* graph data controller idx */
+#define GDCREG IO_VGA+0x0F /* graph data controller data */
+
+/* special characters */
+#define cntlc 0x03
+#define cntld 0x04
+#define bs 0x08
+#define lf 0x0a
+#define cr 0x0d
+#define del 0x7f
+
+typedef struct term_stat {
+ int esc; /* processing escape sequence */
+ int num_param; /* # of parameters to ESC */
+ int last_param; /* last parameter # */
+ int param[MAX_ESC_PAR]; /* contains ESC parameters */
+ int cur_attr; /* current attributes */
+ int std_attr; /* normal attributes */
+ int rev_attr; /* reverse attributes */
+} term_stat;
+
+typedef struct scr_stat {
+ u_short *crt_base; /* address of screen memory */
+ u_short *scr_buf; /* buffer when off screen */
+ u_short *crtat; /* cursor address */
+ int xpos; /* current X position */
+ int ypos; /* current Y position */
+ int xsize; /* X size */
+ int ysize; /* Y size */
+ term_stat term; /* terminal emulation stuff */
+ char cursor_start; /* cursor start line # */
+ char cursor_end; /* cursor end line # */
+ u_char border; /* border color */
+ u_short bell_duration;
+ u_short bell_pitch;
+ u_short status; /* status (bitfield) */
+ u_short mode; /* mode */
+ pid_t pid; /* pid of controlling proc */
+ struct proc *proc; /* proc* of controlling proc */
+ struct vt_mode smode; /* switch mode */
+} scr_stat;
+
+typedef struct default_attr {
+ int std_attr; /* normal attributes */
+ int rev_attr; /* reverse attributes */
+} default_attr;
+
+static default_attr user_default = {
+ (FG_LIGHTGREY | BG_BLACK) << 8,
+ (FG_BLACK | BG_LIGHTGREY) << 8
+};
+
+static default_attr kernel_default = {
+ (FG_WHITE | BG_BLACK) << 8,
+ (FG_BLACK | BG_LIGHTGREY) << 8
+};
+
+#define CONSOLE_BUFFER_SIZE 1024
+int console_buffer_count;
+char console_buffer[CONSOLE_BUFFER_SIZE];
+
+static scr_stat console[NCONS];
+static scr_stat *cur_console = &console[0];
+static scr_stat *new_scp, *old_scp;
+static term_stat kernel_console;
+static default_attr *current_default;
+static int switch_in_progress = 0;
+static u_short *crtat = 0;
+static u_int crtc_addr = MONO_BASE;
+static char crtc_vga = 0;
+static u_char shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0;
+static u_char nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0;
+static char palette[3*256];
+static const u_int n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab);
+static int cur_cursor_pos = -1;
+static char in_putc = 0;
+static char polling = 0;
+static int delayed_next_scr;
+static char saved_console = -1; /* saved console number */
+static long scrn_blank_time = 0; /* screen saver timout value */
+static int scrn_blanked = 0; /* screen saver active flag */
+static int scrn_saver = 0; /* screen saver routine */
+static long scrn_time_stamp;
+static u_char scr_map[256];
+extern int hz;
+extern struct timeval time;
+
+/* function prototypes */
+int pcprobe(struct isa_device *dev);
+int pcattach(struct isa_device *dev);
+int pcopen(dev_t dev, int flag, int mode, struct proc *p);
+int pcclose(dev_t dev, int flag, int mode, struct proc *p);
+int pcread(dev_t dev, struct uio *uio, int flag);
+int pcwrite(dev_t dev, struct uio *uio, int flag);
+int pcparam(struct tty *tp, struct termios *t);
+int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p);
+void pcxint(dev_t dev);
+void pcstart(struct tty *tp);
+void pccnprobe(struct consdev *cp);
+void pccninit(struct consdev *cp);
+void pccnputc(dev_t dev, char c);
+int pccngetc(dev_t dev);
+void scintr(int unit);
+int pcmmap(dev_t dev, int offset, int nprot);
+u_int sgetc(int noblock);
+int getchar(void);
+static void scinit(void);
+static void scput(u_char c);
+static u_int scgetc(int noblock);
+static struct tty *get_tty_ptr(dev_t dev);
+static scr_stat *get_scr_stat(dev_t dev);
+static int get_scr_num();
+static void cursor_shape(int start, int end);
+static void get_cursor_shape(int *start, int *end);
+static void cursor_pos(int force);
+static void clear_screen(scr_stat *scp);
+static int switch_scr(u_int next_scr);
+static void exchange_scr(void);
+static void move_crsr(scr_stat *scp, int x, int y);
+static void move_up(u_short *s, u_short *d, u_int len);
+static void move_down(u_short *s, u_short *d, u_int len);
+static void scan_esc(scr_stat *scp, u_char c);
+static void ansi_put(scr_stat *scp, u_char c);
+static u_char *get_fstr(u_int c, u_int *len);
+static void update_leds(int which);
+static void kbd_wait(void);
+static void kbd_cmd(u_char command);
+static void kbd_cmd2(u_char command, u_char arg);
+static int kbd_reply(void);
+static void set_mode(scr_stat *scp);
+static void set_border(int color);
+static void load_font(int segment, int size, char* font);
+static void save_palette(void);
+static void load_palette(void);
+static void change_winsize(struct tty *tp, int x, int y);
+
+
+/* available screen savers */
+
+static void none_saver(int test);
+static void blank_saver(int test);
+static void fade_saver(int test);
+static void star_saver(int test);
+static void snake_saver(int test);
+
+static const struct {
+ char *name;
+ void (*routine)();
+} screen_savers[] = {
+ { "none", none_saver }, /* 0 */
+ { "blank", blank_saver }, /* 1 */
+ { "fade", fade_saver }, /* 2 */
+ { "star", star_saver }, /* 3 */
+ { "snake", snake_saver }, /* 4 */
+};
+#define SCRN_SAVER(arg) (*screen_savers[scrn_saver].routine)(arg)
+#define NUM_SCRN_SAVERS (sizeof(screen_savers) / sizeof(screen_savers[0]))
+
+/* OS specific stuff */
+
+#if defined(NetBSD)
+#define VIRTUAL_TTY(x) pc_tty[x] ? (pc_tty[x]) : (pc_tty[x] = ttymalloc())
+#define CONSOLE_TTY pc_tty[NCONS] ? (pc_tty[NCONS]) : (pc_tty[NCONS] = ttymalloc())
+#define frametype struct trapframe
+#define eflags tf_eflags
+extern u_short *Crtat;
+struct tty *pc_tty[NCONS+1];
+int ttrstrt();
+#endif
+
+#if defined(__FreeBSD__)
+#define VIRTUAL_TTY(x) (pccons[x] = ttymalloc(pccons[x]))
+#define CONSOLE_TTY (pccons[NCONS] = ttymalloc(pccons[NCONS]))
+#define frametype struct trapframe
+#define eflags tf_eflags
+#define timeout_t timeout_func_t
+#define MONO_BUF (KERNBASE+0xB0000)
+#define CGA_BUF (KERNBASE+0xB8000)
+struct tty *pccons[NCONS+1];
+#endif
+
+#if defined(__386BSD__) && !defined(__FreeBSD__)
+#define VIRTUAL_TTY(x) &pccons[x]
+#define CONSOLE_TTY &pccons[NCONS]
+#define frametype struct syscframe
+#define eflags sf_eflags
+#define timeout_t caddr_t
+#define MONO_BUF (0xFE0B0000)
+#define CGA_BUF (0xFE0B8000)
+struct tty pccons[NCONS+1];
+#endif
+
+#if defined(__386BSD__) || defined(__FreeBSD__)
+u_short *Crtat = (u_short *)MONO_BUF;
+void consinit(void) {scinit();}
+#include "ddb.h"
+#if NDDB > 0
+#define DDB 1
+#endif
+#endif
+
+struct isa_driver scdriver = {
+ pcprobe, pcattach, "sc",
+};
+
+
+int pcprobe(struct isa_device *dev)
+{
+ /* Enable interrupts and keyboard controller */
+ kbd_wait();
+ outb(KB_STAT, KB_WRITE);
+ kbd_cmd(0x4D);
+
+ /* Start keyboard stuff RESET */
+ for (;;) {
+ kbd_cmd(KB_RESET);
+ if (kbd_reply() == KB_ACK && /* command accepted */
+ kbd_reply() == 0xaa) /* self test passed */
+ break;
+ printf("Keyboard reset failed\n");
+ }
+ return (IO_KBDSIZE);
+}
+
+
+int pcattach(struct isa_device *dev)
+{
+ scr_stat *scp;
+ int start = -1, end = -1, i;
+
+ printf("sc%d: ", dev->id_unit);
+ if (crtc_vga)
+ if (crtc_addr == MONO_BASE)
+ printf("VGA mono");
+ else
+ printf("VGA color");
+ else
+ if (crtc_addr == MONO_BASE)
+ printf("MDA/hercules");
+ else
+ printf("CGA/EGA");
+
+ if (NCONS > 1)
+ printf(" <%d virtual consoles>\n", NCONS);
+ else
+ printf("\n");
+#if defined(FAT_CURSOR)
+ start = 0;
+ end = 18;
+ if (crtc_vga) {
+#else
+ if (crtc_vga) {
+ get_cursor_shape(&start, &end);
+#endif
+ save_palette();
+ load_font(0, 16, font_8x16);
+ load_font(1, 8, font_8x8);
+ load_font(2, 14, font_8x14);
+ }
+ current_default = &user_default;
+ for (i = 0; i < NCONS; i++) {
+ scp = &console[i];
+ scp->scr_buf = (u_short *)malloc(COL * ROW * 2, M_DEVBUF, M_NOWAIT);
+ scp->mode = TEXT80x25;
+ scp->term.esc = 0;
+ scp->term.std_attr = current_default->std_attr;
+ scp->term.rev_attr = current_default->rev_attr;
+ scp->term.cur_attr = scp->term.std_attr;
+ scp->border = BG_BLACK;
+ scp->cursor_start = start;
+ scp->cursor_end = end;
+ scp->xsize = COL;
+ scp->ysize = ROW;
+ scp->bell_pitch = BELL_PITCH;
+ scp->bell_duration = BELL_DURATION;
+ scp->status = 0;
+ scp->pid = 0;
+ scp->proc = NULL;
+ scp->smode.mode = VT_AUTO;
+ if (i > 0) {
+ scp->crt_base = scp->crtat = scp->scr_buf;
+ fillw(scp->term.cur_attr|scr_map[0x20], scp->scr_buf, COL*ROW);
+ }
+ }
+ /* get cursor going */
+#if defined(FAT_CURSOR)
+ cursor_shape(console[0].cursor_start,
+ console[0].cursor_end);
+#endif
+ cursor_pos(1);
+ return 0;
+}
+
+
+static struct tty *get_tty_ptr(dev_t dev)
+{
+ int unit = minor(dev);
+
+ if (unit > NCONS)
+ return(NULL);
+ if (unit == NCONS)
+ return(CONSOLE_TTY);
+ return(VIRTUAL_TTY(unit));
+}
+
+
+static scr_stat *get_scr_stat(dev_t dev)
+{
+ int unit = minor(dev);
+
+ if (unit > NCONS)
+ return(NULL);
+ if (unit == NCONS)
+ return(&console[0]);
+ return(&console[unit]);
+}
+
+
+static int get_scr_num()
+{
+ int i = 0;
+
+ while ((i < NCONS) && (cur_console != &console[i])) i++;
+ return i < NCONS ? i : 0;
+}
+
+int pcopen(dev_t dev, int flag, int mode, struct proc *p)
+{
+ struct tty *tp = get_tty_ptr(dev);
+
+ if (!tp)
+ return(ENXIO);
+
+ tp->t_oproc = pcstart;
+ tp->t_param = pcparam;
+ tp->t_dev = dev;
+ if (!(tp->t_state & TS_ISOPEN)) {
+ tp->t_state |= TS_WOPEN;
+ ttychars(tp);
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
+ pcparam(tp, &tp->t_termios);
+ ttsetwater(tp);
+ } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
+ return(EBUSY);
+ tp->t_state |= TS_CARR_ON;
+ tp->t_cflag |= CLOCAL;
+#if defined(__FreeBSD__)
+ return((*linesw[tp->t_line].l_open)(dev, tp, 0));
+#else
+ return((*linesw[tp->t_line].l_open)(dev, tp));
+#endif
+}
+
+
+int pcclose(dev_t dev, int flag, int mode, struct proc *p)
+{
+ struct tty *tp = get_tty_ptr(dev);
+ struct scr_stat *scp;
+
+ if (!tp)
+ return(ENXIO);
+ if (minor(dev) < NCONS) {
+ scp = get_scr_stat(tp->t_dev);
+ if (scp->status & SWITCH_WAIT_ACQ)
+ wakeup((caddr_t)&scp->smode);
+ scp->pid = 0;
+ scp->proc = NULL;
+ scp->smode.mode = VT_AUTO;
+ }
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ ttyclose(tp);
+ return(0);
+}
+
+
+int pcread(dev_t dev, struct uio *uio, int flag)
+{
+ struct tty *tp = get_tty_ptr(dev);
+
+ if (!tp)
+ return(ENXIO);
+ return((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+
+int pcwrite(dev_t dev, struct uio *uio, int flag)
+{
+ struct tty *tp = get_tty_ptr(dev);
+
+ if (!tp)
+ return(ENXIO);
+ return((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+
+/*
+ * Got a console interrupt, keyboard action !
+ * Catch the character, and see who it goes to.
+ */
+void scintr(int unit)
+{
+ static struct tty *cur_tty;
+ int c, len;
+ u_char *cp;
+
+ /* make screensaver happy */
+ scrn_time_stamp = time.tv_sec;
+ if (scrn_blanked)
+ SCRN_SAVER(0);
+
+ c = scgetc(1);
+
+ cur_tty = VIRTUAL_TTY(get_scr_num());
+ if (!(cur_tty->t_state & TS_ISOPEN))
+ cur_tty = CONSOLE_TTY;
+
+ if (!(cur_tty->t_state & TS_ISOPEN) || polling)
+ return;
+
+ switch (c & 0xff00) {
+ case 0x0000: /* normal key */
+ (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
+ break;
+ case NOKEY: /* nothing there */
+ break;
+ case FKEY: /* function key, return string */
+ if (cp = get_fstr((u_int)c, (u_int *)&len)) {
+ while (len-- > 0)
+ (*linesw[cur_tty->t_line].l_rint)
+ (*cp++ & 0xFF, cur_tty);
+ }
+ break;
+ case MKEY: /* meta is active, prepend ESC */
+ (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
+ (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
+ break;
+ }
+}
+
+
+/*
+ * Set line parameters
+ */
+int pcparam(struct tty *tp, struct termios *t)
+{
+ int cflag = t->c_cflag;
+
+ /* and copy to tty */
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
+ tp->t_cflag = cflag;
+ return 0;
+}
+
+
+int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
+{
+ int i, error;
+ struct tty *tp;
+ frametype *fp;
+ scr_stat *scp;
+
+ tp = get_tty_ptr(dev);
+ if (!tp)
+ return ENXIO;
+ scp = get_scr_stat(tp->t_dev);
+
+ switch (cmd) { /* process console hardware related ioctl's */
+
+ case CONS_BLANKTIME: /* set screen saver timeout (0 = no saver) */
+ scrn_blank_time = *(int*)data;
+ return 0;
+ case CONS_SSAVER: /* set screen saver */
+ {
+ register ssaver_t *sav = (ssaver_t *)data;
+ if (sav->num < 0 || sav->num >= NUM_SCRN_SAVERS)
+ return EIO;
+ SCRN_SAVER(0);
+ scrn_saver = sav->num;
+ scrn_blank_time = sav->time;
+ return 0;
+ }
+ case CONS_GSAVER: /* get screen saver info */
+ {
+ register ssaver_t *sav = (ssaver_t *)data;
+ if (sav->num < 0)
+ sav->num = scrn_saver;
+ else if (sav->num >= NUM_SCRN_SAVERS)
+ return EIO;
+ sav->time = scrn_blank_time;
+ strcpy(sav->name, screen_savers[sav->num].name);
+ return 0;
+ }
+ case CONS_80x25TEXT: /* set 80x25 text mode */
+ if (!crtc_vga)
+ return ENXIO;
+ scp->mode = TEXT80x25;
+ scp->ysize = 25;
+ free(scp->scr_buf, M_DEVBUF);
+ scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*2,
+ M_DEVBUF, M_NOWAIT);
+ if (scp != cur_console)
+ scp->crt_base = scp->scr_buf;
+ set_mode(scp);
+ clear_screen(scp);
+ change_winsize(tp, scp->xsize, scp->ysize);
+ return 0;
+
+ case CONS_80x50TEXT: /* set 80x50 text mode */
+ if (!crtc_vga)
+ return ENXIO;
+ scp->mode = TEXT80x50;
+ scp->ysize = 50;
+ free(scp->scr_buf, M_DEVBUF);
+ scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*2,
+ M_DEVBUF, M_NOWAIT);
+ if (scp != cur_console)
+ scp->crt_base = scp->scr_buf;
+ set_mode(scp);
+ clear_screen(scp);
+ change_winsize(tp, scp->xsize, scp->ysize);
+ return 0;
+
+ case CONS_GETVERS: /* get version number */
+ *(int*)data = 0x103; /* version 1.3 */
+ return 0;
+
+ case CONS_GETINFO: /* get current (virtual) console info */
+ {
+ vid_info_t *ptr = (vid_info_t*)data;
+ if (ptr->size == sizeof(struct vid_info)) {
+ ptr->m_num = get_scr_num();
+ ptr->mv_col = scp->xpos;
+ ptr->mv_row = scp->ypos;
+ ptr->mv_csz = scp->xsize;
+ ptr->mv_rsz = scp->ysize;
+ ptr->mv_norm.fore = (scp->term.std_attr & 0x0f00)>>8;
+ ptr->mv_norm.back = (scp->term.std_attr & 0xf000)>>12;
+ ptr->mv_rev.fore = (scp->term.rev_attr & 0x0f00)>>8;
+ ptr->mv_rev.back = (scp->term.rev_attr & 0xf000)>>12;
+ ptr->mv_grfc.fore = 0; /* not supported */
+ ptr->mv_grfc.back = 0; /* not supported */
+ ptr->mv_ovscan = scp->border;
+ ptr->mk_keylock = scp->status & LOCK_KEY_MASK;
+ return 0;
+ }
+ return EINVAL;
+ }
+
+ case VT_SETMODE: /* set screen switcher mode */
+ bcopy(data, &scp->smode, sizeof(struct vt_mode));
+ if (scp->smode.mode == VT_PROCESS) {
+ scp->proc = p;
+ scp->pid = scp->proc->p_pid;
+ }
+ return 0;
+
+ case VT_GETMODE: /* get screen switcher mode */
+ bcopy(&scp->smode, data, sizeof(struct vt_mode));
+ return 0;
+
+ case VT_RELDISP: /* screen switcher ioctl */
+ switch(*data) {
+ case VT_FALSE: /* user refuses to release screen, abort */
+ if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
+ old_scp->status &= ~SWITCH_WAIT_REL;
+ switch_in_progress = 0;
+ return 0;
+ }
+ return EINVAL;
+
+ case VT_TRUE: /* user has released screen, go on */
+ if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
+ scp->status &= ~SWITCH_WAIT_REL;
+ exchange_scr();
+ if (new_scp->smode.mode == VT_PROCESS) {
+ new_scp->status |= SWITCH_WAIT_ACQ;
+ psignal(new_scp->proc,
+ new_scp->smode.acqsig);
+ }
+ else
+ switch_in_progress = 0;
+ return 0;
+ }
+ return EINVAL;
+
+ case VT_ACKACQ: /* acquire acknowledged, switch completed */
+ if (scp == new_scp && (scp->status & SWITCH_WAIT_ACQ)) {
+ scp->status &= ~SWITCH_WAIT_ACQ;
+ switch_in_progress = 0;
+ return 0;
+ }
+ return EINVAL;
+
+ default:
+ return EINVAL;
+ }
+ /* NOT REACHED */
+
+ case VT_OPENQRY: /* return free virtual console */
+ for (i = 0; i < NCONS; i++) {
+ tp = VIRTUAL_TTY(i);
+ if (!(tp->t_state & TS_ISOPEN)) {
+ *data = i + 1;
+ return 0;
+ }
+ }
+ return EINVAL;
+
+ case VT_ACTIVATE: /* switch to screen *data */
+ return switch_scr((*data) - 1);
+
+ case VT_WAITACTIVE: /* wait for switch to occur */
+ if (*data > NCONS)
+ return EINVAL;
+ if (minor(dev) == (*data) - 1)
+ return 0;
+ if (*data == 0) {
+ if (scp == cur_console)
+ return 0;
+ while ((error=tsleep((caddr_t)&scp->smode,
+ PZERO|PCATCH, "waitvt", 0)) == ERESTART) ;
+ }
+ else
+ while ((error=tsleep(
+ (caddr_t)&console[*(data-1)].smode,
+ PZERO|PCATCH, "waitvt", 0)) == ERESTART) ;
+ return error;
+
+ case VT_GETACTIVE:
+ *data = get_scr_num()+1;
+ return 0;
+
+ case KDENABIO: /* allow io operations */
+ fp = (frametype *)p->p_regs;
+ fp->eflags |= PSL_IOPL;
+ return 0;
+
+ case KDDISABIO: /* disallow io operations (default) */
+ fp = (frametype *)p->p_regs;
+ fp->eflags &= ~PSL_IOPL;
+ return 0;
+
+ case KDSETMODE: /* set current mode of this (virtual) console */
+ switch (*data) {
+ case KD_TEXT: /* switch to TEXT (known) mode */
+ /* restore fonts & palette ! */
+ if (crtc_vga) {
+ load_font(0, 16, font_8x16);
+ load_font(1, 8, font_8x8);
+ load_font(2, 14, font_8x14);
+ load_palette();
+ }
+ /* FALL THROUGH */
+
+ case KD_TEXT1: /* switch to TEXT (known) mode */
+ /* no restore fonts & palette */
+ scp->status &= ~UNKNOWN_MODE;
+ set_mode(scp);
+ clear_screen(scp);
+ return 0;
+
+ case KD_GRAPHICS:/* switch to GRAPHICS (unknown) mode */
+ scp->status |= UNKNOWN_MODE;
+ return 0;
+ default:
+ return EINVAL;
+ }
+ /* NOT REACHED */
+
+ case KDGETMODE: /* get current mode of this (virtual) console */
+ *data = (scp->status & UNKNOWN_MODE) ? KD_GRAPHICS : KD_TEXT;
+ return 0;
+
+ case KDSBORDER: /* set border color of this (virtual) console */
+ if (!crtc_vga)
+ return ENXIO;
+ scp->border = *data;
+ if (scp == cur_console)
+ set_border(scp->border);
+ return 0;
+
+ case KDSKBSTATE: /* set keyboard state (locks) */
+ if (*data >= 0 && *data <= LOCK_KEY_MASK) {
+ scp->status &= ~LOCK_KEY_MASK;
+ scp->status |= *data;
+ if (scp == cur_console)
+ update_leds(scp->status);
+ return 0;
+ }
+ return EINVAL;
+
+ case KDGKBSTATE: /* get keyboard state (locks) */
+ *data = scp->status & LOCK_KEY_MASK;
+ return 0;
+
+ case KDSETRAD: /* set keyboard repeat & delay rates */
+ if (*data & 0x80)
+ return EINVAL;
+ kbd_cmd2(KB_SETRAD, *data);
+ return 0;
+
+ case KDSKBMODE: /* set keyboard mode */
+ switch (*data) {
+ case K_RAW: /* switch to RAW scancode mode */
+ scp->status |= KBD_RAW_MODE;
+ return 0;
+
+ case K_XLATE: /* switch to XLT ascii mode */
+ if (scp == cur_console && scp->status == KBD_RAW_MODE)
+ shfts = ctls = alts = agrs = metas = 0;
+ scp->status &= ~KBD_RAW_MODE;
+ return 0;
+ default:
+ return EINVAL;
+ }
+ /* NOT REACHED */
+
+ case KDGKBMODE: /* get keyboard mode */
+ *data = (scp->status & KBD_RAW_MODE) ? K_RAW : K_XLATE;
+ return 0;
+
+ case KDMKTONE: /* sound the bell */
+ if (scp == cur_console)
+ sysbeep(scp->bell_pitch, scp->bell_duration);
+ return 0;
+
+ case KIOCSOUND: /* make tone (*data) hz */
+ if (scp == cur_console) {
+ if (*(int*)data) {
+ int pitch = TIMER_FREQ/(*(int*)data);
+ /* set command for counter 2, 2 byte write */
+ if (acquire_timer2(TIMER_16BIT|TIMER_SQWAVE)) {
+ return EBUSY;
+ }
+ /* set pitch */
+ outb(TIMER_CNTR2, pitch);
+ outb(TIMER_CNTR2, (pitch>>8));
+ /* enable counter 2 output to speaker */
+ outb(IO_PPI, inb(IO_PPI) | 3);
+ }
+ else {
+ /* disable counter 2 output to speaker */
+ outb(IO_PPI, inb(IO_PPI) & 0xFC);
+ release_timer2();
+ }
+ }
+ return 0;
+
+ case KDGKBTYPE: /* get keyboard type */
+ *data = 0; /* type not known (yet) */
+ return 0;
+
+ case KDSETLED: /* set keyboard LED status */
+ if (*data >= 0 && *data <= LED_MASK) {
+ scp->status &= ~LED_MASK;
+ scp->status |= *data;
+ if (scp == cur_console)
+ update_leds(scp->status);
+ return 0;
+ }
+ return EINVAL;
+
+ case KDGETLED: /* get keyboard LED status */
+ *data = scp->status & LED_MASK;
+ return 0;
+
+ case GETFKEY: /* get functionkey string */
+ if (*(u_short*)data < n_fkey_tab) {
+ fkeyarg_t *ptr = (fkeyarg_t*)data;
+ bcopy(&fkey_tab[ptr->keynum].str,
+ ptr->keydef,
+ fkey_tab[ptr->keynum].len);
+ ptr->flen = fkey_tab[ptr->keynum].len;
+ return 0;
+ }
+ else
+ return EINVAL;
+
+ case SETFKEY: /* set functionkey string */
+ if (*(u_short*)data < n_fkey_tab) {
+ fkeyarg_t *ptr = (fkeyarg_t*)data;
+ bcopy(ptr->keydef,
+ &fkey_tab[ptr->keynum].str,
+ min(ptr->flen, MAXFK));
+ fkey_tab[ptr->keynum].len = min(ptr->flen, MAXFK);
+ return 0;
+ }
+ else
+ return EINVAL;
+
+ case GIO_SCRNMAP: /* get output translation table */
+ bcopy(&scr_map, data, sizeof(scr_map));
+ return 0;
+
+ case PIO_SCRNMAP: /* set output translation table */
+ bcopy(data, &scr_map, sizeof(scr_map));
+ return 0;
+
+ case GIO_KEYMAP: /* get keyboard translation table */
+ bcopy(&key_map, data, sizeof(key_map));
+ return 0;
+
+ case PIO_KEYMAP: /* set keyboard translation table */
+ bcopy(data, &key_map, sizeof(key_map));
+ return 0;
+
+ case PIO_FONT8x8: /* set 8x8 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(data, &font_8x8, sizeof(font_8x8));
+ load_font(1, 8, font_8x8);
+ return 0;
+
+ case GIO_FONT8x8: /* get 8x8 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(&font_8x8, data, sizeof(font_8x8));
+ return 0;
+
+ case PIO_FONT8x14: /* set 8x14 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(data, &font_8x14, sizeof(font_8x14));
+ load_font(2, 14, font_8x14);
+ return 0;
+
+ case GIO_FONT8x14: /* get 8x14 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(&font_8x14, data, sizeof(font_8x14));
+ return 0;
+
+ case PIO_FONT8x16: /* set 8x16 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(data, &font_8x16, sizeof(font_8x16));
+ load_font(0, 16, font_8x16);
+ return 0;
+
+ case GIO_FONT8x16: /* get 8x16 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(&font_8x16, data, sizeof(font_8x16));
+ return 0;
+
+ case CONSOLE_X_MODE_ON: /* just to be compatible */
+ if (saved_console < 0) {
+ saved_console = get_scr_num();
+ switch_scr(minor(dev));
+ fp = (frametype *)p->p_regs;
+ fp->eflags |= PSL_IOPL;
+ scp->status |= UNKNOWN_MODE;
+ scp->status |= KBD_RAW_MODE;
+ return 0;
+ }
+ return EAGAIN;
+
+ case CONSOLE_X_MODE_OFF:/* just to be compatible */
+ fp = (frametype *)p->p_regs;
+ fp->eflags &= ~PSL_IOPL;
+ if (crtc_vga) {
+ load_font(0, 16, font_8x16);
+ load_font(1, 8, font_8x8);
+ load_font(2, 14, font_8x14);
+ load_palette();
+ }
+ scp->status &= ~UNKNOWN_MODE;
+ set_mode(scp);
+ clear_screen(scp);
+ scp->status &= ~KBD_RAW_MODE;
+ switch_scr(saved_console);
+ saved_console = -1;
+ return 0;
+
+ case CONSOLE_X_BELL: /* more compatibility */
+ /*
+ * if set, data is a pointer to a length 2 array of
+ * integers. data[0] is the pitch in Hz and data[1]
+ * is the duration in msec.
+ */
+ if (data)
+ sysbeep(TIMER_FREQ/((int*)data)[0],
+ ((int*)data)[1]*hz/3000);
+ else
+ sysbeep(scp->bell_pitch, scp->bell_duration);
+ return 0;
+
+ default:
+ break;
+ }
+
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
+ if (error >= 0)
+ return(error);
+ error = ttioctl(tp, cmd, data, flag);
+ if (error >= 0)
+ return(error);
+ return(ENOTTY);
+}
+
+
+void pcxint(dev_t dev)
+{
+ struct tty *tp = get_tty_ptr(dev);
+
+ if (!tp)
+ return;
+ tp->t_state &= ~TS_BUSY;
+ if (tp->t_line)
+ (*linesw[tp->t_line].l_start)(tp);
+ else
+ pcstart(tp);
+}
+
+
+void pcstart(struct tty *tp)
+{
+#if defined(NetBSD)
+ struct clist *rbp;
+ int i, s, len;
+ u_char buf[PCBURST];
+ scr_stat *scp = get_scr_stat(tp->t_dev);
+
+ if (scp->status & SLKED)
+ return;
+ s = spltty();
+ if (!(tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))) {
+ tp->t_state |= TS_BUSY;
+ splx(s);
+ rbp = &tp->t_outq;
+ len = q_to_b(rbp, buf, PCBURST);
+ for (i=0; i<len; i++)
+ if (buf[i]) ansi_put(scp, buf[i]);
+ s = spltty();
+ tp->t_state &= ~TS_BUSY;
+ if (rbp->c_cc) {
+ tp->t_state |= TS_TIMEOUT;
+ timeout((timeout_t)ttrstrt, (caddr_t)tp, 1);
+ }
+ if (rbp->c_cc <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)rbp);
+ }
+ selwakeup(&tp->t_wsel);
+ }
+ }
+ splx(s);
+
+#else /* __FreeBSD__ & __386BSD__ */
+
+ int c, s, len, i;
+ scr_stat *scp = get_scr_stat(tp->t_dev);
+ u_char buf[PCBURST];
+
+ if (scp->status & SLKED)
+ return;
+ s = spltty();
+ if (!(tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))) {
+ for (;;) {
+ if (RB_LEN(tp->t_out) <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)tp->t_out);
+ }
+ if (tp->t_wsel) {
+ selwakeup(tp->t_wsel,
+ tp->t_state & TS_WCOLL);
+ tp->t_wsel = 0;
+ tp->t_state &= ~TS_WCOLL;
+ }
+ }
+ if (RB_LEN(tp->t_out) == 0)
+ break;
+ if (scp->status & SLKED)
+ break;
+ len = 0;
+ while( len < PCBURST) {
+ buf[len++] = getc(tp->t_out);
+ if( RB_LEN(tp->t_out) == 0)
+ break;
+ }
+ tp->t_state |= TS_BUSY;
+ splx(s);
+ for(i=0;i<len;i++)
+ ansi_put(scp, buf[i]);
+ s = spltty();
+ tp->t_state &= ~TS_BUSY;
+ }
+ tp->t_state |= TS_BUSY;
+ if( in_putc == 0) {
+ int i;
+ for(i=0;i<console_buffer_count;i++) {
+ scput(console_buffer[i]);
+ }
+ console_buffer_count = 0;
+ }
+ tp->t_state &= ~TS_BUSY;
+ }
+ splx(s);
+#endif
+}
+
+
+void pccnprobe(struct consdev *cp)
+{
+ int maj;
+
+ /* locate the major number */
+ for (maj = 0; maj < nchrdev; maj++)
+ if ((void*)cdevsw[maj].d_open == (void*)pcopen)
+ break;
+
+ /* initialize required fields */
+ cp->cn_dev = makedev(maj, NCONS);
+ cp->cn_pri = CN_INTERNAL;
+#if defined(__386BSD__) && !defined(__FreeBSD__)
+ cp->cn_tp = CONSOLE_TTY;
+#endif
+}
+
+
+void pccninit(struct consdev *cp)
+{
+ scinit();
+}
+
+
+void pccnputc(dev_t dev, char c)
+{
+ if (c == '\n')
+ scput('\r');
+ scput(c);
+ if (cur_console == &console[0]) {
+ int pos = cur_console->crtat - cur_console->crt_base;
+ if (pos != cur_cursor_pos) {
+ cur_cursor_pos = pos;
+ outb(crtc_addr,14);
+ outb(crtc_addr+1,pos >> 8);
+ outb(crtc_addr,15);
+ outb(crtc_addr+1,pos&0xff);
+ }
+ }
+}
+
+
+int pccngetc(dev_t dev)
+{
+ int s = spltty(); /* block scintr while we poll */
+ int c = scgetc(0);
+ splx(s);
+ if (c == '\r') c = '\n';
+ return(c);
+}
+
+static void none_saver(int test)
+{
+}
+
+static void fade_saver(int test)
+{
+ static int count = 0;
+ int i;
+
+ if (test) {
+ scrn_blanked = 1;
+ if (count < 64) {
+ outb(PIXMASK, 0xFF); /* no pixelmask */
+ outb(PALWADR, 0x00);
+ outb(PALDATA, 0);
+ outb(PALDATA, 0);
+ outb(PALDATA, 0);
+ for (i = 3; i < 768; i++) {
+ if (palette[i] - count > 15)
+ outb(PALDATA, palette[i]-count);
+ else
+ outb(PALDATA, 15);
+ }
+ inb(crtc_addr+6); /* reset flip/flop */
+ outb(ATC, 0x20); /* enable palette */
+ count++;
+ }
+ }
+ else {
+ count = scrn_blanked = 0;
+ load_palette();
+ }
+}
+
+static void blank_saver(int test)
+{
+ u_char val;
+ if (test) {
+ scrn_blanked = 1;
+ outb(TSIDX, 0x01); val = inb(TSREG);
+ outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
+ }
+ else {
+ scrn_blanked = 0;
+ outb(TSIDX, 0x01); val = inb(TSREG);
+ outb(TSIDX, 0x01); outb(TSREG, val & 0xDF);
+ }
+}
+
+static u_long rand_next = 1;
+
+static int rand()
+{
+ return ((rand_next = rand_next * 1103515245 + 12345) & 0x7FFFFFFF);
+}
+
+/*
+ * Alternate saver that got its inspiration from a well known utility
+ * package for an unfamous OS.
+ */
+
+#define NUM_STARS 50
+
+static void star_saver(int test)
+{
+ scr_stat *scp = cur_console;
+ int cell, i;
+ char pattern[] = {"...........++++*** "};
+ char colors[] = {FG_DARKGREY, FG_LIGHTGREY,
+ FG_WHITE, FG_LIGHTCYAN};
+ static u_short stars[NUM_STARS][2];
+
+ if (test) {
+ if (!scrn_blanked) {
+ bcopy(Crtat, scp->scr_buf,
+ scp->xsize * scp->ysize * 2);
+ fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20], Crtat,
+ scp->xsize * scp->ysize);
+ set_border(0);
+ i = scp->ysize * scp->xsize + 5;
+ outb(crtc_addr, 14);
+ outb(crtc_addr+1, i >> 8);
+ outb(crtc_addr, 15);
+ outb(crtc_addr+1, i & 0xff);
+ scrn_blanked = 1;
+ for(i=0; i<NUM_STARS; i++) {
+ stars[i][0] =
+ rand() % (scp->xsize*scp->ysize);
+ stars[i][1] = 0;
+ }
+ }
+ cell = rand() % NUM_STARS;
+ *((u_short*)(Crtat + stars[cell][0])) =
+ scr_map[pattern[stars[cell][1]]] |
+ colors[rand()%sizeof(colors)] << 8;
+ if ((stars[cell][1]+=(rand()%4)) >= sizeof(pattern)-1) {
+ stars[cell][0] = rand() % (scp->xsize*scp->ysize);
+ stars[cell][1] = 0;
+ }
+ }
+ else {
+ if (scrn_blanked) {
+ bcopy(scp->scr_buf, Crtat, scp->xsize*scp->ysize*2);
+ cur_cursor_pos = -1;
+ set_border(scp->border);
+ scrn_blanked = 0;
+ }
+ }
+}
+
+
+static void snake_saver(int test)
+{
+ const char saves[] = {"FreeBSD"};
+ static u_char *savs[sizeof(saves)-1];
+ static int dirx, diry;
+ int f;
+ scr_stat *scp = cur_console;
+
+ if (test) {
+ if (!scrn_blanked) {
+ bcopy(Crtat, scp->scr_buf,
+ scp->xsize * scp->ysize * 2);
+ fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20],
+ Crtat, scp->xsize * scp->ysize);
+ set_border(0);
+ dirx = (scp->xpos ? 1 : -1);
+ diry = (scp->ypos ?
+ scp->xsize : -scp->xsize);
+ for (f=0; f< sizeof(saves)-1; f++)
+ savs[f] = (u_char *)Crtat + 2 *
+ (scp->xpos+scp->ypos*scp->xsize);
+ *(savs[0]) = scr_map[*saves];
+ f = scp->ysize * scp->xsize + 5;
+ outb(crtc_addr, 14);
+ outb(crtc_addr+1, f >> 8);
+ outb(crtc_addr, 15);
+ outb(crtc_addr+1, f & 0xff);
+ scrn_blanked = 1;
+ }
+ if (scrn_blanked++ < 4)
+ return;
+ scrn_blanked = 1;
+ *(savs[sizeof(saves)-2]) = scr_map[0x20];
+ for (f=sizeof(saves)-2; f > 0; f--)
+ savs[f] = savs[f-1];
+ f = (savs[0] - (u_char *)Crtat) / 2;
+ if ((f % scp->xsize) == 0 ||
+ (f % scp->xsize) == scp->xsize - 1 ||
+ (rand() % 50) == 0)
+ dirx = -dirx;
+ if ((f / scp->xsize) == 0 ||
+ (f / scp->xsize) == scp->ysize - 1 ||
+ (rand() % 20) == 0)
+ diry = -diry;
+ savs[0] += 2*dirx + 2*diry;
+ for (f=sizeof(saves)-2; f>=0; f--)
+ *(savs[f]) = scr_map[saves[f]];
+ }
+ else {
+ if (scrn_blanked) {
+ bcopy(scp->scr_buf, Crtat,
+ scp->xsize * scp->ysize * 2);
+ cur_cursor_pos = -1;
+ set_border(scp->border);
+ scrn_blanked = 0;
+ }
+ }
+}
+
+static void cursor_shape(int start, int end)
+{
+ outb(crtc_addr, 10);
+ outb(crtc_addr+1, start & 0xFF);
+ outb(crtc_addr, 11);
+ outb(crtc_addr+1, end & 0xFF);
+}
+
+
+#if !defined(FAT_CURSOR)
+static void get_cursor_shape(int *start, int *end)
+{
+ outb(crtc_addr, 10);
+ *start = inb(crtc_addr+1) & 0x1F;
+ outb(crtc_addr, 11);
+ *end = inb(crtc_addr+1) & 0x1F;
+}
+#endif
+
+
+static void cursor_pos(int force)
+{
+ int pos;
+
+ if (cur_console->status & UNKNOWN_MODE)
+ return;
+ if (scrn_blank_time && (time.tv_sec > scrn_time_stamp+scrn_blank_time))
+ SCRN_SAVER(1);
+ pos = cur_console->crtat - cur_console->crt_base;
+ if (force || (!scrn_blanked && pos != cur_cursor_pos)) {
+ cur_cursor_pos = pos;
+ outb(crtc_addr, 14);
+ outb(crtc_addr+1, pos>>8);
+ outb(crtc_addr, 15);
+ outb(crtc_addr+1, pos&0xff);
+ }
+ timeout((timeout_t)cursor_pos, 0, hz/20);
+}
+
+
+static void clear_screen(scr_stat *scp)
+{
+ move_crsr(scp, 0, 0);
+ fillw(scp->term.cur_attr | scr_map[0x20], scp->crt_base,
+ scp->xsize * scp->ysize);
+}
+
+
+static int switch_scr(u_int next_scr)
+{
+ if (in_putc) { /* delay switch if in putc */
+ delayed_next_scr = next_scr+1;
+ return 0;
+ }
+ if (switch_in_progress &&
+ (cur_console->proc != pfind(cur_console->pid)))
+ switch_in_progress = 0;
+
+ if (next_scr >= NCONS || switch_in_progress) {
+ sysbeep(BELL_PITCH, BELL_DURATION);
+ return EINVAL;
+ }
+
+ /* is the wanted virtual console open ? */
+ if (next_scr) {
+ struct tty *tp = VIRTUAL_TTY(next_scr);
+ if (!(tp->t_state & TS_ISOPEN)) {
+ sysbeep(BELL_PITCH, BELL_DURATION);
+ return EINVAL;
+ }
+ }
+
+ switch_in_progress = 1;
+ old_scp = cur_console;
+ new_scp = &console[next_scr];
+ wakeup((caddr_t)&new_scp->smode);
+ if (new_scp == old_scp) {
+ switch_in_progress = 0;
+ return 0;
+ }
+
+ /* has controlling process died? */
+ if (old_scp->proc && (old_scp->proc != pfind(old_scp->pid)))
+ old_scp->smode.mode = VT_AUTO;
+ if (new_scp->proc && (new_scp->proc != pfind(new_scp->pid)))
+ new_scp->smode.mode = VT_AUTO;
+
+ /* check the modes and switch approbiatly */
+ if (old_scp->smode.mode == VT_PROCESS) {
+ old_scp->status |= SWITCH_WAIT_REL;
+ psignal(old_scp->proc, old_scp->smode.relsig);
+ }
+ else {
+ exchange_scr();
+ if (new_scp->smode.mode == VT_PROCESS) {
+ new_scp->status |= SWITCH_WAIT_ACQ;
+ psignal(new_scp->proc, new_scp->smode.acqsig);
+ }
+ else
+ switch_in_progress = 0;
+ }
+ return 0;
+}
+
+
+static void exchange_scr(void)
+{
+ struct tty *tp;
+
+ bcopy(Crtat, old_scp->scr_buf, old_scp->xsize * old_scp->ysize * 2);
+ old_scp->crt_base = old_scp->scr_buf;
+ move_crsr(old_scp, old_scp->xpos, old_scp->ypos);
+ cur_console = new_scp;
+ set_mode(new_scp);
+ new_scp->crt_base = Crtat;
+ move_crsr(new_scp, new_scp->xpos, new_scp->ypos);
+ bcopy(new_scp->scr_buf, Crtat, new_scp->xsize * new_scp->ysize * 2);
+ update_leds(new_scp->status);
+ if ((old_scp->status & UNKNOWN_MODE) && crtc_vga) {
+ load_font(0, 16, font_8x16);
+ load_font(1, 8, font_8x8);
+ load_font(2, 14, font_8x14);
+ load_palette();
+ }
+ if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE)
+ shfts = ctls = alts = agrs = metas = 0;
+ delayed_next_scr = 0;
+}
+
+
+static void move_crsr(scr_stat *scp, int x, int y)
+{
+ if (x < 0 || y < 0 || x >= scp->xsize || y >= scp->ysize)
+ return;
+ scp->xpos = x;
+ scp->ypos = y;
+ scp->crtat = scp->crt_base + scp->ypos * scp->xsize + scp->xpos;
+}
+
+static void move_up(u_short *s, u_short *d, u_int len)
+{
+ s += len;
+ d += len;
+ while (len-- > 0)
+ *--d = *--s;
+}
+
+static void move_down(u_short *s, u_short *d, u_int len)
+{
+ while (len-- > 0)
+ *d++ = *s++;
+}
+
+static void scan_esc(scr_stat *scp, u_char c)
+{
+ static u_char ansi_col[16] =
+ {0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15};
+ int i, n;
+ u_short *src, *dst, count;
+
+ if (scp->term.esc == 1) {
+ switch (c) {
+
+ case '[': /* Start ESC [ sequence */
+ scp->term.esc = 2;
+ scp->term.last_param = -1;
+ for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
+ scp->term.param[i] = 1;
+ scp->term.num_param = 0;
+ return;
+
+ case 'M': /* Move cursor up 1 line, scroll if at top */
+ if (scp->ypos > 0)
+ move_crsr(scp, scp->xpos, scp->ypos - 1);
+ else {
+ move_up(scp->crt_base,
+ scp->crt_base + scp->xsize,
+ (scp->ysize - 1) * scp->xsize);
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base, scp->xsize);
+ }
+ break;
+#if notyet
+ case 'Q':
+ scp->term.esc = 4;
+ break;
+#endif
+ case 'c': /* Clear screen & home */
+ clear_screen(scp);
+ break;
+ }
+ }
+ else if (scp->term.esc == 2) {
+ if (c >= '0' && c <= '9') {
+ if (scp->term.num_param < MAX_ESC_PAR) {
+ if (scp->term.last_param != scp->term.num_param) {
+ scp->term.last_param = scp->term.num_param;
+ scp->term.param[scp->term.num_param] = 0;
+ }
+ else
+ scp->term.param[scp->term.num_param] *= 10;
+ scp->term.param[scp->term.num_param] += c - '0';
+ return;
+ }
+ }
+ scp->term.num_param = scp->term.last_param + 1;
+ switch (c) {
+
+ case ';':
+ if (scp->term.num_param < MAX_ESC_PAR)
+ return;
+ break;
+
+ case '=':
+ scp->term.esc = 3;
+ scp->term.last_param = -1;
+ for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
+ scp->term.param[i] = 1;
+ scp->term.num_param = 0;
+ return;
+
+ case 'A': /* up n rows */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos, scp->ypos - n);
+ break;
+
+ case 'B': /* down n rows */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos, scp->ypos + n);
+ break;
+
+ case 'C': /* right n columns */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos + n, scp->ypos);
+ break;
+
+ case 'D': /* left n columns */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos - n, scp->ypos);
+ break;
+
+ case 'E': /* cursor to start of line n lines down */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, 0, scp->ypos + n);
+ break;
+
+ case 'F': /* cursor to start of line n lines up */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, 0, scp->ypos - n);
+ break;
+
+ case 'f': /* System V consoles .. */
+ case 'H': /* Cursor move */
+ if (scp->term.num_param == 0)
+ move_crsr(scp, 0, 0);
+ else if (scp->term.num_param == 2)
+ move_crsr(scp, scp->term.param[1] - 1,
+ scp->term.param[0] - 1);
+ break;
+
+ case 'J': /* Clear all or part of display */
+ if (scp->term.num_param == 0)
+ n = 0;
+ else
+ n = scp->term.param[0];
+ switch (n) {
+ case 0: /* clear form cursor to end of display */
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crtat, scp->crt_base +
+ scp->xsize * scp->ysize -
+ scp->crtat);
+ break;
+ case 1: /* clear from beginning of display to cursor */
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base,
+ scp->crtat - scp->crt_base);
+ break;
+ case 2: /* clear entire display */
+ clear_screen(scp);
+ break;
+ }
+ break;
+
+ case 'K': /* Clear all or part of line */
+ if (scp->term.num_param == 0)
+ n = 0;
+ else
+ n = scp->term.param[0];
+ switch (n) {
+ case 0: /* clear form cursor to end of line */
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crtat, scp->xsize - scp->xpos);
+ break;
+ case 1: /* clear from beginning of line to cursor */
+ fillw(scp->term.cur_attr|scr_map[0x20],
+ scp->crtat - (scp->xsize - scp->xpos),
+ (scp->xsize - scp->xpos) + 1);
+ break;
+ case 2: /* clear entire line */
+ fillw(scp->term.cur_attr|scr_map[0x20],
+ scp->crtat - (scp->xsize - scp->xpos),
+ scp->xsize);
+ break;
+ }
+ break;
+
+ case 'L': /* Insert n lines */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->ysize - scp->ypos)
+ n = scp->ysize - scp->ypos;
+ src = scp->crt_base + scp->ypos * scp->xsize;
+ dst = src + n * scp->xsize;
+ count = scp->ysize - (scp->ypos + n);
+ move_up(src, dst, count * scp->xsize);
+ fillw(scp->term.cur_attr | scr_map[0x20], src,
+ n * scp->xsize);
+ break;
+
+ case 'M': /* Delete n lines */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->ysize - scp->ypos)
+ n = scp->ysize - scp->ypos;
+ dst = scp->crt_base + scp->ypos * scp->xsize;
+ src = dst + n * scp->xsize;
+ count = scp->ysize - (scp->ypos + n);
+ move_down(src, dst, count * scp->xsize);
+ src = dst + count * scp->xsize;
+ fillw(scp->term.cur_attr | scr_map[0x20], src,
+ n * scp->xsize);
+ break;
+
+ case 'P': /* Delete n chars */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->xsize - scp->xpos)
+ n = scp->xsize - scp->xpos;
+ dst = scp->crtat;
+ src = dst + n;
+ count = scp->xsize - (scp->xpos + n);
+ move_down(src, dst, count);
+ src = dst + count;
+ fillw(scp->term.cur_attr | scr_map[0x20], src, n);
+ break;
+
+ case '@': /* Insert n chars */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->xsize - scp->xpos)
+ n = scp->xsize - scp->xpos;
+ src = scp->crtat;
+ dst = src + n;
+ count = scp->xsize - (scp->xpos + n);
+ move_up(src, dst, count);
+ fillw(scp->term.cur_attr | scr_map[0x20], src, n);
+ break;
+
+ case 'S': /* scroll up n lines */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->ypos)
+ n = scp->ypos;
+ bcopy(scp->crt_base + (scp->xsize * n),
+ scp->crt_base,
+ scp->xsize * (scp->ysize - n) *
+ sizeof(u_short));
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base + scp->xsize *
+ (scp->ysize - 1),
+ scp->xsize);
+ break;
+
+ case 'T': /* scroll down n lines */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->ysize - scp->ypos)
+ n = scp->ysize - scp->ypos;
+ bcopy(scp->crt_base,
+ scp->crt_base + (scp->xsize * n),
+ scp->xsize * (scp->ysize - n) *
+ sizeof(u_short));
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base, scp->xsize);
+ break;
+
+ case 'X': /* delete n characters in line */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->xsize - scp->xpos)
+ n = scp->xsize - scp->xpos;
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base + scp->xpos +
+ ((scp->xsize*scp->ypos) * sizeof(u_short)), n);
+ break;
+
+ case 'Z': /* move n tabs backwards */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if ((i = scp->xpos & 0xf8) == scp->xpos)
+ i -= 8*n;
+ else
+ i -= 8*(n-1);
+ if (i < 0)
+ i = 0;
+ move_crsr(scp, i, scp->ypos);
+ break;
+
+ case '`': /* move cursor to column n */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, n, scp->ypos);
+ break;
+
+ case 'a': /* move cursor n columns to the right */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos + n, scp->ypos);
+ break;
+
+ case 'd': /* move cursor to row n */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos, n);
+ break;
+
+ case 'e': /* move cursor n rows down */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos, scp->ypos + n);
+ break;
+
+ case 'm': /* change attribute */
+ if (scp->term.num_param == 0)
+ n = 0;
+ else
+ n = scp->term.param[0];
+ switch (n) {
+ case 0: /* back to normal */
+ scp->term.cur_attr = scp->term.std_attr;
+ break;
+ case 1: /* highlight (bold) */
+ scp->term.cur_attr &= 0xFF00;
+ scp->term.cur_attr |= 0x0800;
+ break;
+ case 4: /* highlight (underline) */
+ scp->term.cur_attr &= 0x0F00;
+ scp->term.cur_attr |= 0x0800;
+ break;
+ case 5: /* blink */
+ scp->term.cur_attr &= 0xFF00;
+ scp->term.cur_attr |= 0x8000;
+ break;
+ case 7: /* reverse video */
+ scp->term.cur_attr = scp->term.rev_attr;
+ break;
+ case 30: case 31: case 32: case 33: /* set fg color */
+ case 34: case 35: case 36: case 37:
+ scp->term.cur_attr = (scp->term.cur_attr & 0xF0FF)
+ | (ansi_col[(n - 30) & 7] << 8);
+ break;
+ case 40: case 41: case 42: case 43: /* set bg color */
+ case 44: case 45: case 46: case 47:
+ scp->term.cur_attr = (scp->term.cur_attr & 0x0FFF)
+ | (ansi_col[(n - 40) & 7] << 12);
+ break;
+ }
+ break;
+
+ case 'x':
+ if (scp->term.num_param == 0)
+ n = 0;
+ else
+ n = scp->term.param[0];
+ switch (n) {
+ case 0: /* reset attributes */
+ scp->term.cur_attr = scp->term.std_attr =
+ current_default->std_attr;
+ scp->term.rev_attr = current_default->rev_attr;
+ break;
+ case 1: /* set ansi background */
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.std_attr & 0x0F00) |
+ (ansi_col[(scp->term.param[1])&0x0F]<<12);
+ break;
+ case 2: /* set ansi foreground */
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.std_attr & 0xF000) |
+ (ansi_col[(scp->term.param[1])&0x0F]<<8);
+ break;
+ case 3: /* set ansi attribute directly */
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.param[1]&0xFF)<<8;
+ break;
+ case 5: /* set ansi reverse video background */
+ scp->term.rev_attr =
+ (scp->term.rev_attr & 0x0F00) |
+ (ansi_col[(scp->term.param[1])&0x0F]<<12);
+ break;
+ case 6: /* set ansi reverse video foreground */
+ scp->term.rev_attr =
+ (scp->term.rev_attr & 0xF000) |
+ (ansi_col[(scp->term.param[1])&0x0F]<<8);
+ break;
+ case 7: /* set ansi reverse video directly */
+ scp->term.rev_attr = (scp->term.param[1]&0xFF)<<8;
+ break;
+ }
+ break;
+
+ case 'z': /* switch to (virtual) console n */
+ if (scp->term.num_param == 1)
+ switch_scr(scp->term.param[0]);
+ break;
+ }
+ }
+ else if (scp->term.esc == 3) {
+ if (c >= '0' && c <= '9') {
+ if (scp->term.num_param < MAX_ESC_PAR) {
+ if (scp->term.last_param != scp->term.num_param) {
+ scp->term.last_param = scp->term.num_param;
+ scp->term.param[scp->term.num_param] = 0;
+ }
+ else
+ scp->term.param[scp->term.num_param] *= 10;
+ scp->term.param[scp->term.num_param] += c - '0';
+ return;
+ }
+ }
+ scp->term.num_param = scp->term.last_param + 1;
+ switch (c) {
+
+ case ';':
+ if (scp->term.num_param < MAX_ESC_PAR)
+ return;
+ break;
+
+ case 'A': /* set display border color */
+ if (scp->term.num_param == 1)
+ scp->border=scp->term.param[0] & 0xff;
+ if (scp == cur_console)
+ set_border(scp->border);
+ break;
+
+ case 'B': /* set bell pitch and duration */
+ if (scp->term.num_param == 2) {
+ scp->bell_pitch = scp->term.param[0];
+ scp->bell_duration = scp->term.param[1]*10;
+ }
+ break;
+
+ case 'C': /* set cursor shape (start & end line) */
+ if (scp->term.num_param == 2) {
+ scp->cursor_start = scp->term.param[0] & 0x1F;
+ scp->cursor_end = scp->term.param[1] & 0x1F;
+ if (scp == cur_console)
+ cursor_shape(scp->cursor_start,
+ scp->cursor_end);
+ }
+ break;
+
+ case 'F': /* set ansi foreground */
+ if (scp->term.num_param == 1)
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.std_attr & 0xF000)
+ | ((scp->term.param[0] & 0x0F) << 8);
+ break;
+
+ case 'G': /* set ansi background */
+ if (scp->term.num_param == 1)
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.std_attr & 0x0F00)
+ | ((scp->term.param[0] & 0x0F) << 12);
+ break;
+
+ case 'H': /* set ansi reverse video foreground */
+ if (scp->term.num_param == 1)
+ scp->term.rev_attr =
+ (scp->term.rev_attr & 0xF000)
+ | ((scp->term.param[0] & 0x0F) << 8);
+ break;
+
+ case 'I': /* set ansi reverse video background */
+ if (scp->term.num_param == 1)
+ scp->term.rev_attr =
+ (scp->term.rev_attr & 0x0F00)
+ | ((scp->term.param[0] & 0x0F) << 12);
+ break;
+ }
+ }
+ scp->term.esc = 0;
+}
+
+
+static void ansi_put(scr_stat *scp, u_char c)
+{
+ if (scp->status & UNKNOWN_MODE)
+ return;
+
+ /* make screensaver happy */
+ if (scp == cur_console) {
+ scrn_time_stamp = time.tv_sec;
+ if (scrn_blanked)
+ SCRN_SAVER(0);
+ }
+ in_putc++;
+ if (scp->term.esc)
+ scan_esc(scp, c);
+ else switch(c) {
+ case 0x1B: /* start escape sequence */
+ scp->term.esc = 1;
+ scp->term.num_param = 0;
+ break;
+ case 0x07:
+ if (scp == cur_console)
+ sysbeep(scp->bell_pitch, scp->bell_duration);
+ break;
+ case '\t': /* non-destructive tab */
+ scp->crtat += (8 - scp->xpos % 8);
+ scp->xpos += (8 - scp->xpos % 8);
+ break;
+ case '\b': /* non-destructive backspace */
+ if (scp->crtat > scp->crt_base) {
+ scp->crtat--;
+ if (scp->xpos > 0)
+ scp->xpos--;
+ else {
+ scp->xpos += scp->xsize - 1;
+ scp->ypos--;
+ }
+ }
+ break;
+ case '\r': /* return to pos 0 */
+ move_crsr(scp, 0, scp->ypos);
+ break;
+ case '\n': /* newline, same pos */
+ scp->crtat += scp->xsize;
+ scp->ypos++;
+ break;
+ case '\f': /* form feed, clears screen */
+ clear_screen(scp);
+ break;
+ default:
+ /* Print only printables */
+ *scp->crtat = (scp->term.cur_attr | scr_map[c]);
+ scp->crtat++;
+ if (++scp->xpos >= scp->xsize) {
+ scp->xpos = 0;
+ scp->ypos++;
+ }
+ break;
+ }
+ if (scp->crtat >= scp->crt_base + scp->ysize * scp->xsize) {
+ bcopy(scp->crt_base + scp->xsize, scp->crt_base,
+ scp->xsize * (scp->ysize - 1) * sizeof(u_short));
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base + scp->xsize * (scp->ysize - 1),
+ scp->xsize);
+ scp->crtat -= scp->xsize;
+ scp->ypos--;
+ }
+ in_putc--;
+ if (delayed_next_scr)
+ switch_scr(delayed_next_scr - 1);
+}
+
+static void scinit(void)
+{
+ u_short volatile *cp = Crtat + (CGA_BUF-MONO_BUF)/sizeof(u_short), was;
+ unsigned cursorat;
+ int i;
+
+ /*
+ * catch that once in a blue moon occurence when scinit is called
+ * TWICE, adding the CGA_BUF offset again -> poooff
+ */
+ if (crtat != 0)
+ return;
+ /*
+ * Crtat initialized to point to MONO buffer, if not present change
+ * to CGA_BUF offset. ONLY ADD the difference since locore.s adds
+ * in the remapped offset at the "right" time
+ */
+ was = *cp;
+ *cp = (u_short) 0xA55A;
+ if (*cp != 0xA55A) {
+ crtc_addr = MONO_BASE;
+ } else {
+ *cp = was;
+ crtc_addr = COLOR_BASE;
+ Crtat = Crtat + (CGA_BUF-MONO_BUF)/sizeof(u_short);
+ }
+
+ /* Extract cursor location */
+ outb(crtc_addr,14);
+ cursorat = inb(crtc_addr+1)<<8 ;
+ outb(crtc_addr,15);
+ cursorat |= inb(crtc_addr+1);
+ crtat = Crtat + cursorat;
+
+ /* is this a VGA or higher ? */
+ outb(crtc_addr, 7);
+ if (inb(crtc_addr) == 7)
+ crtc_vga = 1;
+
+ current_default = &user_default;
+ console[0].crtat = crtat;
+ console[0].crt_base = Crtat;
+ console[0].term.esc = 0;
+ console[0].term.std_attr = current_default->std_attr;
+ console[0].term.rev_attr = current_default->rev_attr;
+ console[0].term.cur_attr = current_default->std_attr;
+ console[0].xpos = cursorat % COL;
+ console[0].ypos = cursorat / COL;
+ console[0].border = BG_BLACK;;
+ console[0].xsize = COL;
+ console[0].ysize = ROW;
+ console[0].status = 0;
+ console[0].pid = 0;
+ console[0].proc = NULL;
+ console[0].smode.mode = VT_AUTO;
+ console[0].bell_pitch = BELL_PITCH;
+ console[0].bell_duration = BELL_DURATION;
+ kernel_console.esc = 0;
+ kernel_console.std_attr = kernel_default.std_attr;
+ kernel_console.rev_attr = kernel_default.rev_attr;
+ kernel_console.cur_attr = kernel_default.std_attr;
+ /* initialize mapscrn array to a one to one map */
+ for (i=0; i<sizeof(scr_map); i++)
+ scr_map[i] = i;
+ clear_screen(&console[0]);
+}
+
+
+static void scput(u_char c)
+{
+ scr_stat *scp = &console[0];
+ term_stat save;
+
+ if (crtat == 0)
+ scinit();
+ if( in_putc == 0) {
+ ++in_putc;
+ save = scp->term;
+ scp->term = kernel_console;
+ current_default = &kernel_default;
+ ansi_put(scp, c);
+ kernel_console = scp->term;
+ current_default = &user_default;
+ scp->term = save;
+ --in_putc;
+ } else {
+ if( console_buffer_count < CONSOLE_BUFFER_SIZE)
+ console_buffer[console_buffer_count++] = c;
+ }
+}
+
+
+static u_char *get_fstr(u_int c, u_int *len)
+{
+ u_int i;
+
+ if (!(c & FKEY))
+ return(NULL);
+ i = (c & 0xFF) - F_FN;
+ if (i > n_fkey_tab)
+ return(NULL);
+ *len = fkey_tab[i].len;
+ return(fkey_tab[i].str);
+}
+
+
+static void update_leds(int which)
+{
+ static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+
+ /* replace CAPS led with ALTGR led for ALTGR keyboards */
+ if (key_map.n_keys > ALTGR_OFFSET) {
+ if (which & ALKED)
+ which |= CLKED;
+ else
+ which &= ~CLKED;
+ }
+ kbd_cmd2(KB_SETLEDS, xlate_leds[which & LED_MASK]);
+}
+
+
+/*
+ * scgetc(noblock) : get a character from the keyboard.
+ * If noblock = 0 wait until a key is gotten. Otherwise return NOKEY.
+ */
+u_int scgetc(int noblock)
+{
+ u_char val, code, release;
+ u_int state, action;
+ struct key_t *key;
+ static u_char esc_flag = 0, compose = 0;
+ static u_int chr = 0;
+
+next_code:
+ kbd_wait();
+ /* First see if there is something in the keyboard port */
+ if (inb(KB_STAT) & KB_BUF_FULL)
+ val = inb(KB_DATA);
+ else if (noblock)
+ return(NOKEY);
+ else
+ goto next_code;
+
+ if (cur_console->status & KBD_RAW_MODE)
+ return val;
+
+ code = val & 0x7F;
+ release = val & 0x80;
+
+ switch (esc_flag) {
+ case 0x00: /* normal scancode */
+ switch(code) {
+ case 0x38: /* left alt (compose key) */
+ if (release && compose) {
+ compose = 0;
+ if (chr > 255) {
+ sysbeep(BELL_PITCH, BELL_DURATION);
+ chr = 0;
+ }
+ }
+ else {
+ if (!compose) {
+ compose = 1;
+ chr = 0;
+ }
+ }
+ break;
+ case 0x60:
+ case 0x61:
+ esc_flag = code;
+ goto next_code;
+ }
+ break;
+ case 0x60: /* 0xE0 prefix */
+ esc_flag = 0;
+ switch (code) {
+ case 0x1c: /* right enter key */
+ code = 0x59;
+ break;
+ case 0x1d: /* right ctrl key */
+ code = 0x5a;
+ break;
+ case 0x35: /* keypad divide key */
+ code = 0x5b;
+ break;
+ case 0x37: /* print scrn key */
+ code = 0x5c;
+ break;
+ case 0x38: /* right alt key (alt gr) */
+ code = 0x5d;
+ break;
+ case 0x47: /* grey home key */
+ code = 0x5e;
+ break;
+ case 0x48: /* grey up arrow key */
+ code = 0x5f;
+ break;
+ case 0x49: /* grey page up key */
+ code = 0x60;
+ break;
+ case 0x4b: /* grey left arrow key */
+ code = 0x61;
+ break;
+ case 0x4d: /* grey right arrow key */
+ code = 0x62;
+ break;
+ case 0x4f: /* grey end key */
+ code = 0x63;
+ break;
+ case 0x50: /* grey down arrow key */
+ code = 0x64;
+ break;
+ case 0x51: /* grey page down key */
+ code = 0x65;
+ break;
+ case 0x52: /* grey insert key */
+ code = 0x66;
+ break;
+ case 0x53: /* grey delete key */
+ code = 0x67;
+ break;
+ default: /* ignore everything else */
+ goto next_code;
+ }
+ break;
+ case 0x61: /* 0xE1 prefix */
+ esc_flag = 0;
+ if (code == 0x1D)
+ esc_flag = 0x1D;
+ goto next_code;
+ /* NOT REACHED */
+ case 0x1D: /* pause / break */
+ esc_flag = 0;
+ if (code != 0x45)
+ goto next_code;
+ code = 0x68;
+ break;
+ }
+
+ if (compose) {
+ switch (code) {
+ case 0x47:
+ case 0x48: /* keypad 7,8,9 */
+ case 0x49:
+ if (!release)
+ chr = (code - 0x40) + chr*10;
+ goto next_code;
+ case 0x4b:
+ case 0x4c: /* keypad 4,5,6 */
+ case 0x4d:
+ if (!release)
+ chr = (code - 0x47) + chr*10;
+ goto next_code;
+ case 0x4f:
+ case 0x50: /* keypad 1,2,3 */
+ case 0x51:
+ if (!release)
+ chr = (code - 0x4e) + chr*10;
+ goto next_code;
+ case 0x52: /* keypad 0 */
+ if (!release)
+ chr *= 10;
+ goto next_code;
+ case 0x38: /* left alt key */
+ break;
+ default:
+ if (chr) {
+ compose = chr = 0;
+ sysbeep(BELL_PITCH, BELL_DURATION);
+ goto next_code;
+ }
+ break;
+ }
+ }
+
+ state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0));
+ if ((!agrs && (cur_console->status & ALKED))
+ || (agrs && !(cur_console->status & ALKED)))
+ code += ALTGR_OFFSET;
+ key = &key_map.key[code];
+ if ( ((key->flgs & FLAG_LOCK_C) && (cur_console->status & CLKED))
+ || ((key->flgs & FLAG_LOCK_N) && (cur_console->status & NLKED)) )
+ state ^= 1;
+
+ /* Check for make/break */
+ action = key->map[state];
+ if (release) { /* key released */
+ if (key->spcl & 0x80) {
+ switch (action) {
+ case LSH:
+ shfts &= ~1;
+ break;
+ case RSH:
+ shfts &= ~2;
+ break;
+ case LCTR:
+ ctls &= ~1;
+ break;
+ case RCTR:
+ ctls &= ~2;
+ break;
+ case LALT:
+ alts &= ~1;
+ break;
+ case RALT:
+ alts &= ~2;
+ break;
+ case NLK:
+ nlkcnt = 0;
+ break;
+ case CLK:
+ clkcnt = 0;
+ break;
+ case SLK:
+ slkcnt = 0;
+ break;
+ case ASH:
+ agrs = 0;
+ break;
+ case ALK:
+ alkcnt = 0;
+ break;
+ case META:
+ metas = 0;
+ break;
+ }
+ }
+ if (chr && !compose) {
+ action = chr;
+ chr = 0;
+ return(action);
+ }
+ } else {
+ /* key pressed */
+ if (key->spcl & (0x80>>state)) {
+ switch (action) {
+ /* LOCKING KEYS */
+ case NLK:
+ if (!nlkcnt) {
+ nlkcnt++;
+ if (cur_console->status & NLKED)
+ cur_console->status &= ~NLKED;
+ else
+ cur_console->status |= NLKED;
+ update_leds(cur_console->status);
+ }
+ break;
+ case CLK:
+ if (!clkcnt) {
+ clkcnt++;
+ if (cur_console->status & CLKED)
+ cur_console->status &= ~CLKED;
+ else
+ cur_console->status |= CLKED;
+ update_leds(cur_console->status);
+ }
+ break;
+ case SLK:
+ if (!slkcnt) {
+ slkcnt++;
+ if (cur_console->status & SLKED) {
+ cur_console->status &= ~SLKED;
+ pcstart(VIRTUAL_TTY(get_scr_num()));
+ }
+ else
+ cur_console->status |= SLKED;
+ update_leds(cur_console->status);
+ }
+ break;
+ case ALK:
+ if (!alkcnt) {
+ alkcnt++;
+ if (cur_console->status & ALKED)
+ cur_console->status &= ~ALKED;
+ else
+ cur_console->status |= ALKED;
+ update_leds(cur_console->status);
+ }
+ break;
+
+ /* NON-LOCKING KEYS */
+ case NOP:
+ break;
+ case RBT:
+#if defined(__FreeBSD__)
+ shutdown_nice();
+#else
+ cpu_reset();
+#endif
+ break;
+ case DBG:
+#if DDB > 0 /* try to switch to console 0 */
+ if (cur_console->smode.mode == VT_AUTO &&
+ console[0].smode.mode == VT_AUTO)
+ switch_scr(0);
+ Debugger("manual escape to debugger");
+ return(NOKEY);
+#else
+ printf("No debugger in kernel\n");
+#endif
+ break;
+ case LSH:
+ shfts |= 1;
+ break;
+ case RSH:
+ shfts |= 2;
+ break;
+ case LCTR:
+ ctls |= 1;
+ break;
+ case RCTR:
+ ctls |= 2;
+ break;
+ case LALT:
+ alts |= 1;
+ break;
+ case RALT:
+ alts |= 2;
+ break;
+ case ASH:
+ agrs = 1;
+ break;
+ case META:
+ metas = 1;
+ break;
+ case NEXT:
+ switch_scr((get_scr_num()+1)%NCONS);
+ break;
+ default:
+ if (action >= F_SCR && action <= L_SCR) {
+ switch_scr(action - F_SCR);
+ break;
+ }
+ if (action >= F_FN && action <= L_FN)
+ action |= FKEY;
+ return(action);
+ }
+ }
+ else {
+ if (metas)
+ action |= MKEY;
+ return(action);
+ }
+ }
+ goto next_code;
+}
+
+
+int getchar(void)
+{
+ u_char thechar;
+ int s;
+
+ polling = 1;
+ s = splhigh();
+ scput('>');
+ thechar = (u_char) scgetc(0);
+ polling = 0;
+ splx(s);
+ switch (thechar) {
+ default:
+ if (thechar >= scr_map[0x20])
+ scput(thechar);
+ return(thechar);
+ case cr:
+ case lf:
+ scput(cr); scput(lf);
+ return(lf);
+ case bs:
+ case del:
+ scput(bs); scput(scr_map[0x20]); scput(bs);
+ return(thechar);
+ case cntld:
+ scput('^'); scput('D'); scput('\r'); scput('\n');
+ return(0);
+ }
+}
+
+
+u_int sgetc(int noblock)
+{
+ return (scgetc(noblock) & 0xff);
+}
+
+int pcmmap(dev_t dev, int offset, int nprot)
+{
+ if (offset > 0x20000)
+ return EINVAL;
+ return i386_btop((VIDEOMEM + offset));
+}
+
+
+static void kbd_wait(void)
+{
+ int i;
+
+ for (i=0; i<1000; i++) { /* up to 10 msec */
+ if ((inb(KB_STAT) & KB_READY) == 0)
+ break;
+ DELAY (10);
+ }
+}
+
+
+static void kbd_cmd(u_char command)
+{
+ kbd_wait();
+ outb(KB_DATA, command);
+}
+
+
+static void kbd_cmd2(u_char command, u_char arg)
+{
+ int r, s = spltty();
+ do {
+ kbd_cmd(command);
+ r = kbd_reply();
+ if (r == KB_ACK) {
+ kbd_cmd(arg & 0x7f);
+ r = kbd_reply();
+ }
+ } while (r != KB_ACK);
+ splx(s);
+}
+
+
+static int kbd_reply()
+{
+ int i;
+
+ kbd_wait();
+ for (i=0; i<60000; i++) { /* at least 300 msec, 600 msec enough */
+ if (inb(KB_STAT) & KB_BUF_FULL)
+ return ((u_char) inb(KB_DATA));
+ DELAY (10);
+ }
+ return(-1);
+}
+
+
+static void set_mode(scr_stat *scp)
+{
+ u_char byte;
+ int s;
+
+ if (scp != cur_console)
+ return;
+
+ /* (re)activate cursor */
+ untimeout((timeout_t)cursor_pos, 0);
+ cursor_pos(1);
+
+ /* change cursor type if set */
+ if (scp->cursor_start != -1 && scp->cursor_end != -1)
+ cursor_shape(scp->cursor_start, scp->cursor_end);
+
+ /* mode change only on VGA's */
+ if (!crtc_vga)
+ return;
+
+ /* setup video hardware for the given mode */
+ s = splhigh();
+ switch(scp->mode) {
+ case TEXT80x25:
+ outb(crtc_addr, 9); byte = inb(crtc_addr+1);
+ outb(crtc_addr, 9); outb(crtc_addr+1, byte | 0x0F);
+ outb(TSIDX, 0x03); outb(TSREG, 0x00); /* select font 0 */
+ break;
+ case TEXT80x50:
+ outb(crtc_addr, 9); byte = inb(crtc_addr+1);
+ outb(crtc_addr, 9); outb(crtc_addr+1, (byte & 0xF0) | 0x07);
+ outb(TSIDX, 0x03); outb(TSREG, 0x05); /* select font 1 */
+ break;
+ default:
+ break;
+ }
+ splx(s);
+
+ /* set border color for this (virtual) console */
+ set_border(scp->border);
+ return;
+}
+
+
+static void set_border(int color)
+{
+ inb(crtc_addr+6); /* reset flip-flop */
+ outb(ATC, 0x11); outb(ATC, color);
+ inb(crtc_addr+6); /* reset flip-flop */
+ outb(ATC, 0x20); /* enable Palette */
+}
+
+static void load_font(int segment, int size, char* font)
+{
+ int ch, line, s;
+ u_char val;
+
+ outb(TSIDX, 0x01); val = inb(TSREG); /* blank screen */
+ outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
+
+ /* setup vga for loading fonts (graphics plane mode) */
+ s = splhigh();
+ inb(crtc_addr+6); /* reset flip/flop */
+ outb(ATC, 0x30); outb(ATC, 0x01);
+ outb(TSIDX, 0x02); outb(TSREG, 0x04);
+ outb(TSIDX, 0x04); outb(TSREG, 0x06);
+ outb(GDCIDX, 0x04); outb(GDCREG, 0x02);
+ outb(GDCIDX, 0x05); outb(GDCREG, 0x00);
+ outb(GDCIDX, 0x06); outb(GDCREG, 0x05); /* addr = a0000, 64kb */
+ splx(s);
+ for (ch=0; ch < 256; ch++)
+ for (line=0; line < size; line++)
+ *((char *)atdevbase+(segment*0x4000)+(ch*32)+line) =
+ font[(ch*size)+line];
+ /* setup vga for text mode again */
+ s = splhigh();
+ inb(crtc_addr+6); /* reset flip/flop */
+ outb(ATC, 0x30); outb(ATC, 0x0C);
+ outb(TSIDX, 0x02); outb(TSREG, 0x03);
+ outb(TSIDX, 0x04); outb(TSREG, 0x02);
+ outb(GDCIDX, 0x04); outb(GDCREG, 0x00);
+ outb(GDCIDX, 0x05); outb(GDCREG, 0x10);
+ if (crtc_addr == MONO_BASE) {
+ outb(GDCIDX, 0x06); outb(GDCREG, 0x0A); /* addr = b0000, 32kb */
+ }
+ else {
+ outb(GDCIDX, 0x06); outb(GDCREG, 0x0E); /* addr = b8000, 32kb */
+ }
+ splx(s);
+ outb(TSIDX, 0x01); val = inb(TSREG); /* unblank screen */
+ outb(TSIDX, 0x01); outb(TSREG, val & 0xDF);
+}
+
+
+static void load_palette(void)
+{
+ int i;
+
+ outb(PIXMASK, 0xFF); /* no pixelmask */
+ outb(PALWADR, 0x00);
+ for (i=0x00; i<0x300; i++)
+ outb(PALDATA, palette[i]);
+ inb(crtc_addr+6); /* reset flip/flop */
+ outb(ATC, 0x20); /* enable palette */
+}
+
+static void save_palette(void)
+{
+ int i;
+
+ outb(PALRADR, 0x00);
+ for (i=0x00; i<0x300; i++)
+ palette[i] = inb(PALDATA);
+ inb(crtc_addr+6); /* reset flip/flop */
+}
+
+
+static void change_winsize(struct tty *tp, int x, int y)
+{
+ if (tp->t_winsize.ws_col != x || tp->t_winsize.ws_row != y) {
+ tp->t_winsize.ws_col = x;
+ tp->t_winsize.ws_row = y;
+ pgsignal(tp->t_pgrp, SIGWINCH, 1);
+ }
+}
+
+#endif /* NSC */
diff --git a/sys/i386/isa/timerreg.h b/sys/i386/isa/timerreg.h
new file mode 100644
index 0000000..5742f66
--- /dev/null
+++ b/sys/i386/isa/timerreg.h
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Header: timerreg.h,v 1.2 93/02/28 15:08:58 mccanne Exp
+ * $Id$
+ */
+
+/*
+ *
+ * Register definitions for the Intel 8253 Programmable Interval Timer.
+ *
+ * This chip has three independent 16-bit down counters that can be
+ * read on the fly. There are three mode registers and three countdown
+ * registers. The countdown registers are addressed directly, via the
+ * first three I/O ports. The three mode registers are accessed via
+ * the fourth I/O port, with two bits in the mode byte indicating the
+ * register. (Why are hardware interfaces always so braindead?).
+ *
+ * To write a value into the countdown register, the mode register
+ * is first programmed with a command indicating the which byte of
+ * the two byte register is to be modified. The three possibilities
+ * are load msb (TMR_MR_MSB), load lsb (TMR_MR_LSB), or load lsb then
+ * msb (TMR_MR_BOTH).
+ *
+ * To read the current value ("on the fly") from the countdown register,
+ * you write a "latch" command into the mode register, then read the stable
+ * value from the corresponding I/O port. For example, you write
+ * TMR_MR_LATCH into the corresponding mode register. Presumably,
+ * after doing this, a write operation to the I/O port would result
+ * in undefined behavior (but hopefully not fry the chip).
+ * Reading in this manner has no side effects.
+ *
+ * The outputs of the three timers are connected as follows:
+ *
+ * timer 0 -> irq 0
+ * timer 1 -> dma chan 0 (for dram refresh)
+ * timer 2 -> speaker (via keyboard controller)
+ *
+ * Timer 0 is used to call hardclock.
+ * Timer 2 is used to generate console beeps.
+ */
+
+/*
+ * Macros for specifying values to be written into a mode register.
+ */
+#define TIMER_CNTR0 (IO_TIMER1 + 0) /* timer 0 counter port */
+#define TIMER_CNTR1 (IO_TIMER1 + 1) /* timer 1 counter port */
+#define TIMER_CNTR2 (IO_TIMER1 + 2) /* timer 2 counter port */
+#define TIMER_MODE (IO_TIMER1 + 3) /* timer mode port */
+#define TIMER_SEL0 0x00 /* select counter 0 */
+#define TIMER_SEL1 0x40 /* select counter 1 */
+#define TIMER_SEL2 0x80 /* select counter 2 */
+#define TIMER_INTTC 0x00 /* mode 0, intr on terminal cnt */
+#define TIMER_ONESHOT 0x02 /* mode 1, one shot */
+#define TIMER_RATEGEN 0x04 /* mode 2, rate generator */
+#define TIMER_SQWAVE 0x06 /* mode 3, square wave */
+#define TIMER_SWSTROBE 0x08 /* mode 4, s/w triggered strobe */
+#define TIMER_HWSTROBE 0x0a /* mode 5, h/w triggered strobe */
+#define TIMER_LATCH 0x00 /* latch counter for reading */
+#define TIMER_LSB 0x10 /* r/w counter LSB */
+#define TIMER_MSB 0x20 /* r/w counter MSB */
+#define TIMER_16BIT 0x30 /* r/w counter 16 bits, LSB first */
+#define TIMER_BCD 0x01 /* count in BCD */
+
diff --git a/sys/i386/isa/ultra14f.c b/sys/i386/isa/ultra14f.c
new file mode 100644
index 0000000..c184904
--- /dev/null
+++ b/sys/i386/isa/ultra14f.c
@@ -0,0 +1,1151 @@
+/*
+ * Ported for use with the UltraStor 14f by Gary Close (gclose@wvnvms.wvnet.edu)
+ * Slight fixes to timeouts to run with the 34F
+ * Thanks to Julian Elischer for advice and help with this port.
+ *
+ * Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems for use under the MACH(2.5) operating system.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ * commenced: Sun Sep 27 18:14:01 PDT 1992
+ * slight mod to make work with 34F as well: Wed Jun 2 18:05:48 WST 1993
+ *
+ * $Id: ultra14f.c,v 1.16 1994/03/20 00:30:04 wollman Exp $
+ */
+
+#include <sys/types.h>
+
+#ifdef KERNEL /* don't laugh.. this compiles to a program too.. look */
+#include <uha.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+
+#include <i386/include/pio.h>
+#include <i386/isa/isa_device.h>
+#endif /*KERNEL */
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+/* */
+
+#ifdef KERNEL
+#include "ddb.h"
+#else /*KERNEL */
+#define NUHA 1
+#endif /*KERNEL */
+
+typedef struct {
+ unsigned char addr[4];
+} physaddr;
+typedef struct {
+ unsigned char len[4];
+} physlen;
+
+#define KVTOPHYS(x) vtophys(x)
+
+#define UHA_MSCP_MAX 32 /* store up to 32MSCPs at any one time
+ * MAX = ?
+ */
+#define MSCP_HASH_SIZE 32 /* when we have a physical addr. for
+ * a mscp and need to find the mscp in
+ * space, look it up in the hash table
+ */
+#define MSCP_HASH_SHIFT 9 /* only hash on multiples of 512 */
+#define MSCP_HASH(x) ((((long int)(x))>>MSCP_HASH_SHIFT) % MSCP_HASH_SIZE)
+
+extern int hz;
+#define UHA_NSEG 33 /* number of dma segments supported */
+
+/************************** board definitions *******************************/
+/*
+ * I/O Port Interface
+ */
+#define UHA_LMASK (0x000) /* local doorbell mask reg */
+#define UHA_LINT (0x001) /* local doorbell int/stat reg */
+#define UHA_SMASK (0x002) /* system doorbell mask reg */
+#define UHA_SINT (0x003) /* system doorbell int/stat reg */
+#define UHA_ID0 (0x004) /* product id reg 0 */
+#define UHA_ID1 (0x005) /* product id reg 1 */
+#define UHA_CONF1 (0x006) /* config reg 1 */
+#define UHA_CONF2 (0x007) /* config reg 2 */
+#define UHA_OGM0 (0x008) /* outgoing mail ptr 0 least sig */
+#define UHA_OGM1 (0x009) /* outgoing mail ptr 1 least mid */
+#define UHA_OGM2 (0x00a) /* outgoing mail ptr 2 most mid */
+#define UHA_OGM3 (0x00b) /* outgoing mail ptr 3 most sig */
+#define UHA_ICM0 (0x00c) /* incoming mail ptr 0 */
+#define UHA_ICM1 (0x00d) /* incoming mail ptr 1 */
+#define UHA_ICM2 (0x00e) /* incoming mail ptr 2 */
+#define UHA_ICM3 (0x00f) /* incoming mail ptr 3 */
+
+/*
+ * UHA_LMASK bits (read only)
+ */
+
+#define UHA_LDIE 0x80 /* local doorbell int enabled */
+#define UHA_SRSTE 0x40 /* soft reset enabled */
+#define UHA_ABORTEN 0x10 /* abort MSCP enabled */
+#define UHA_OGMINTEN 0x01 /* outgoing mail interrupt enabled */
+
+/*
+ * UHA_LINT bits (read)
+ */
+
+#define UHA_LDIP 0x80 /* local doorbell int pending */
+
+/*
+ * UHA_LINT bits (write)
+ */
+
+#define UHA_ADRST 0x40 /* adapter soft reset */
+#define UHA_SBRST 0x20 /* scsi bus reset */
+#define UHA_ASRST 0x60 /* adapter and scsi reset */
+#define UHA_ABORT 0x10 /* abort MSCP */
+#define UHA_OGMINT 0x01 /* tell adapter to get mail */
+
+/*
+ * UHA_SMASK bits (read)
+ */
+
+#define UHA_SINTEN 0x80 /* system doorbell interupt Enabled */
+#define UHA_ABORT_COMPLETE_EN 0x10 /* abort MSCP command complete int Enabled */
+#define UHA_ICM_ENABLED 0x01 /* ICM interrupt enabled */
+
+/*
+ * UHA_SMASK bits (write)
+ */
+
+#define UHA_ENSINT 0x80 /* enable system doorbell interrupt */
+#define UHA_EN_ABORT_COMPLETE 0x10 /* enable abort MSCP complete int */
+#define UHA_ENICM 0x01 /* enable ICM interrupt */
+
+/*
+ * UHA_SINT bits (read)
+ */
+
+#define UHA_SINTP 0x80 /* system doorbell int pending */
+#define UHA_ABORT_SUCC 0x10 /* abort MSCP successful */
+#define UHA_ABORT_FAIL 0x18 /* abort MSCP failed */
+
+/*
+ * UHA_SINT bits (write)
+ */
+
+#define UHA_ABORT_ACK 0x18 /* acknowledge status and clear */
+#define UHA_ICM_ACK 0x01 /* acknowledge ICM and clear */
+
+/*
+ * UHA_CONF1 bits (read only)
+ */
+
+#define UHA_DMA_CH5 0x00 /* DMA channel 5 */
+#define UHA_DMA_CH6 0x40 /* 6 */
+#define UHA_DMA_CH7 0x80 /* 7 */
+#define UHA_IRQ15 0x00 /* IRQ 15 */
+#define UHA_IRQ14 0x10 /* 14 */
+#define UHA_IRQ11 0x20 /* 11 */
+#define UHA_IRQ10 0x30 /* 10 */
+
+/*
+ * ha_status error codes
+ */
+
+#define UHA_NO_ERR 0x00 /* No error supposedly */
+#define UHA_SBUS_ABORT_ERR 0x84 /* scsi bus abort error */
+#define UHA_SBUS_TIMEOUT 0x91 /* scsi bus selection timeout */
+#define UHA_SBUS_OVER_UNDER 0x92 /* scsi bus over/underrun */
+#define UHA_BAD_SCSI_CMD 0x96 /* illegal scsi command */
+#define UHA_AUTO_SENSE_ERR 0x9b /* auto request sense err */
+#define UHA_SBUS_RES_ERR 0xa3 /* scsi bus reset error */
+#define UHA_BAD_SG_LIST 0xff /* invalid scatter gath list */
+
+struct uha_dma_seg {
+ physaddr addr;
+ physlen len;
+};
+
+struct mscp {
+ unsigned char opcode:3;
+#define U14_HAC 0x01 /* host adapter command */
+#define U14_TSP 0x02 /* target scsi pass through command */
+#define U14_SDR 0x04 /* scsi device reset */
+ unsigned char xdir:2; /* xfer direction */
+#define U14_SDET 0x00 /* determined by scsi command */
+#define U14_SDIN 0x01 /* scsi data in */
+#define U14_SDOUT 0x02 /* scsi data out */
+#define U14_NODATA 0x03 /* no data xfer */
+ unsigned char dcn:1; /* disable disconnect for this command */
+ unsigned char ca:1; /* cache control */
+ unsigned char sgth:1; /* scatter gather flag */
+ unsigned char target:3;
+ unsigned char chan:2; /* scsi channel (always 0 for 14f) */
+ unsigned char lun:3;
+ physaddr data;
+ physlen datalen;
+ physaddr link;
+ unsigned char link_id;
+ unsigned char sg_num; /*number of scat gath segs */
+ /*in s-g list if sg flag is */
+ /*set. starts at 1, 8bytes per */
+ unsigned char senselen;
+ unsigned char cdblen;
+ unsigned char cdb[12];
+ unsigned char ha_status;
+ unsigned char targ_status;
+ physaddr sense; /* if 0 no auto sense */
+ /*-----------------end of hardware supported fields----------------*/
+ struct mscp *next; /* in free list */
+ struct scsi_xfer *xs; /* the scsi_xfer for this cmd */
+ int flags;
+#define MSCP_FREE 0
+#define MSCP_ACTIVE 1
+#define MSCP_ABORTED 2
+ struct uha_dma_seg uha_dma[UHA_NSEG];
+ struct scsi_sense_data mscp_sense;
+ struct mscp *nexthash;
+ long int hashkey;
+};
+
+struct uha_data {
+ int flags;
+#define UHA_INIT 0x01;
+ int baseport;
+ struct mscp *mscphash[MSCP_HASH_SIZE];
+ struct mscp *free_mscp;
+ int our_id; /* our scsi id */
+ int vect;
+ int dma;
+ int nummscps;
+ struct scsi_link sc_link;
+} *uhadata[NUHA];
+
+int uhaprobe();
+int uha_attach();
+int uhaintr();
+int32 uha_scsi_cmd();
+void uha_timeout(caddr_t, int);
+void uha_free_mscp();
+int uha_abort();
+void uhaminphys();
+void uha_done();
+u_int32 uha_adapter_info();
+struct mscp *uha_mscp_phys_kv();
+
+struct mscp *cheat;
+unsigned long int scratch;
+static uha_unit = 0;
+#define UHA_SHOWMSCPS 0x01
+#define UHA_SHOWINTS 0x02
+#define UHA_SHOWCMDS 0x04
+#define UHA_SHOWMISC 0x08
+#define FAIL 1
+#define SUCCESS 0
+#define PAGESIZ 4096
+
+#ifdef KERNEL
+struct isa_driver uhadriver =
+{
+ uhaprobe,
+ uha_attach,
+ "uha"
+};
+
+struct scsi_adapter uha_switch =
+{
+ uha_scsi_cmd,
+ uhaminphys,
+ 0,
+ 0,
+ uha_adapter_info,
+ "uha",
+ 0, 0
+};
+
+/* the below structure is so we have a default dev struct for out link struct */
+struct scsi_device uha_dev =
+{
+ NULL, /* Use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+ "uha",
+ 0,
+ 0, 0
+};
+
+#endif /*KERNEL */
+
+#ifndef KERNEL
+main()
+{
+ printf("uha_data is %d bytes\n", sizeof(struct uha_data));
+ printf("mscp is %d bytes\n", sizeof(struct mscp));
+}
+
+#else /*KERNEL*/
+/*
+ * Function to send a command out through a mailbox
+ */
+void
+uha_send_mbox(int unit, struct mscp *mscp)
+{
+ struct uha_data *uha = uhadata[unit];
+ int port = uha->baseport;
+ int spincount = 100000; /* 1s should be enough */
+ int s = splbio();
+
+ while (--spincount) {
+ if ((inb(port + UHA_LINT) & UHA_LDIP) == 0)
+ break;
+ DELAY(100);
+ }
+ if (spincount == 0) {
+ printf("uha%d: uha_send_mbox, board not responding\n", unit);
+ Debugger("ultra14f");
+ }
+ outl(port + UHA_OGM0, KVTOPHYS(mscp));
+ outb(port + UHA_LINT, (UHA_OGMINT));
+ splx(s);
+}
+
+/*
+ * Function to send abort to 14f
+ */
+int
+uha_abort(int unit, struct mscp *mscp)
+{
+ struct uha_data *uha = uhadata[unit];
+ int port = uha->baseport;
+ int spincount = 100; /* 1 mSec */
+ int abortcount = 200000; /*2 secs */
+ int s = splbio();
+
+ while (--spincount) {
+ if ((inb(port + UHA_LINT) & UHA_LDIP) == 0)
+ break;
+ DELAY(10);
+ }
+ if (spincount == 0) {
+ printf("uha%d: uha_abort, board not responding\n", unit);
+ Debugger("ultra14f");
+ }
+ outl(port + UHA_OGM0, KVTOPHYS(mscp));
+ outb(port + UHA_LINT, UHA_ABORT);
+
+ while (--abortcount) {
+ if (inb(port + UHA_SINT) & UHA_ABORT_FAIL)
+ break;
+ DELAY(10);
+ }
+ if (abortcount == 0) {
+ printf("uha%d: uha_abort, board not responding\n", unit);
+ Debugger("ultra14f");
+ }
+ if ((inb(port + UHA_SINT) & 0x10) != 0) {
+ outb(port + UHA_SINT, UHA_ABORT_ACK);
+ splx(s);
+ return (1);
+ } else {
+ outb(port + UHA_SINT, UHA_ABORT_ACK);
+ splx(s);
+ return (0);
+ }
+}
+
+/*
+ * Function to poll for command completion when in poll mode.
+ *
+ * wait = timeout in msec
+ */
+int
+uha_poll(int unit, int wait)
+{
+ struct uha_data *uha = uhadata[unit];
+ int port = uha->baseport;
+ int stport = port + UHA_SINT;
+
+ retry:
+ while (--wait) {
+ if (inb(stport) & UHA_SINTP)
+ break;
+ DELAY(1000); /* 1 mSec per loop */
+ }
+ if (wait == 0) {
+ printf("uha%d: uha_poll, board not responding\n", unit);
+ return (EIO);
+ }
+ uhaintr(unit);
+ return (0);
+}
+
+/*
+ * Check if the device can be found at the port given and if so, set it up
+ * ready for further work as an argument, takes the isa_device structure
+ * from autoconf.c
+ */
+int
+uhaprobe(dev)
+ struct isa_device *dev;
+{
+ int unit = uha_unit;
+ struct uha_data *uha;
+
+ dev->id_unit = unit;
+
+ /*
+ * find unit and check we have that many defined
+ */
+ if (unit >= NUHA) {
+ printf("uha: unit number (%d) too high\n", unit);
+ return (0);
+ }
+ dev->id_unit = unit;
+
+ /*
+ * Allocate a storage area for us
+ */
+ if (uhadata[unit]) {
+ printf("uha%d: memory already allocated\n", unit);
+ return 0;
+ }
+ uha = malloc(sizeof(struct uha_data), M_TEMP, M_NOWAIT);
+ if (!uha) {
+ printf("uha%d: cannot malloc!\n", unit);
+ return 0;
+ }
+ bzero(uha, sizeof(struct uha_data));
+ uhadata[unit] = uha;
+ uha->baseport = dev->id_iobase;
+ /*
+ * Try initialise a unit at this location
+ * sets up dma and bus speed, loads uha->vect
+ */
+ if (uha_init(unit) != 0) {
+ uhadata[unit] = NULL;
+ free(uha, M_TEMP);
+ return (0);
+ }
+ /* if it's there put in its interrupt and DRQ vectors */
+ dev->id_irq = (1 << uha->vect);
+ dev->id_drq = uha->dma;
+
+ uha_unit++;
+ return (16);
+}
+
+/*
+ * Attach all the sub-devices we can find
+ */
+int
+uha_attach(dev)
+ struct isa_device *dev;
+{
+ int unit = dev->id_unit;
+ struct uha_data *uha = uhadata[unit];
+
+ /*
+ * fill in the prototype scsi_link.
+ */
+ uha->sc_link.adapter_unit = unit;
+ uha->sc_link.adapter_targ = uha->our_id;
+ uha->sc_link.adapter = &uha_switch;
+ uha->sc_link.device = &uha_dev;
+ uha->sc_link.flags = SDEV_BOUNCE;
+
+ /*
+ * ask the adapter what subunits are present
+ */
+ scsi_attachdevs(&(uha->sc_link));
+
+ return 1;
+}
+
+/*
+ * Return some information to the caller about
+ * the adapter and it's capabilities
+ */
+u_int32
+uha_adapter_info(unit)
+ int unit;
+{
+ return (2); /* 2 outstanding requests at a time per device */
+}
+
+/*
+ * Catch an interrupt from the adaptor
+ */
+int
+uhaintr(unit)
+ int unit;
+{
+ struct uha_data *uha = uhadata[unit];
+ struct mscp *mscp;
+ u_char uhastat;
+ unsigned long int mboxval;
+
+ int port = uha->baseport;
+
+#ifdef UHADEBUG
+ printf("uhaintr ");
+#endif /*UHADEBUG */
+
+ while (inb(port + UHA_SINT) & UHA_SINTP) {
+ /*
+ * First get all the information and then
+ * acknowledge the interrupt
+ */
+ uhastat = inb(port + UHA_SINT);
+ mboxval = inl(port + UHA_ICM0);
+ outb(port + UHA_SINT, UHA_ICM_ACK);
+
+#ifdef UHADEBUG
+ printf("status = 0x%x ", uhastat);
+#endif /*UHADEBUG*/
+ /*
+ * Process the completed operation
+ */
+
+ mscp = uha_mscp_phys_kv(uha, mboxval);
+ if (!mscp) {
+ printf("uha: BAD MSCP RETURNED\n");
+ return (0); /* whatever it was, it'll timeout */
+ }
+ untimeout(uha_timeout, (caddr_t)mscp);
+
+ uha_done(unit, mscp);
+ }
+ return (1);
+}
+
+/*
+ * We have a mscp which has been processed by the adaptor, now we look to see
+ * how the operation went.
+ */
+void
+uha_done(unit, mscp)
+ int unit;
+ struct mscp *mscp;
+{
+ struct uha_data *uha = uhadata[unit];
+ struct scsi_sense_data *s1, *s2;
+ struct scsi_xfer *xs = mscp->xs;
+
+ SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_done\n"));
+ /*
+ * Otherwise, put the results of the operation
+ * into the xfer and call whoever started it
+ */
+ if ((mscp->ha_status == UHA_NO_ERR) || (xs->flags & SCSI_ERR_OK)) { /* All went correctly OR errors expected */
+ xs->resid = 0;
+ xs->error = 0;
+ } else {
+
+ s1 = &(mscp->mscp_sense);
+ s2 = &(xs->sense);
+
+ if (mscp->ha_status != UHA_NO_ERR) {
+ switch (mscp->ha_status) {
+ case UHA_SBUS_TIMEOUT: /* No response */
+ SC_DEBUG(xs->sc_link, SDEV_DB3,
+ ("timeout reported back\n"));
+ xs->error = XS_TIMEOUT;
+ break;
+ case UHA_SBUS_OVER_UNDER:
+ SC_DEBUG(xs->sc_link, SDEV_DB3,
+ ("scsi bus xfer over/underrun\n"));
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ case UHA_BAD_SG_LIST:
+ SC_DEBUG(xs->sc_link, SDEV_DB3,
+ ("bad sg list reported back\n"));
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ default: /* Other scsi protocol messes */
+ xs->error = XS_DRIVER_STUFFUP;
+ SC_DEBUG(xs->sc_link, SDEV_DB3,
+ ("unexpected ha_status: %x\n",
+ mscp->ha_status));
+ }
+ } else {
+
+ if (mscp->targ_status != 0)
+/*
+ * I have no information for any possible value of target status field
+ * other than 0 means no error!! So I guess any error is unexpected in that
+ * event!!
+ */
+
+ {
+ SC_DEBUG(xs->sc_link, SDEV_DB3,
+ ("unexpected targ_status: %x\n",
+ mscp->targ_status));
+ xs->error = XS_DRIVER_STUFFUP;
+ }
+ }
+ }
+ done:
+ xs->flags |= ITSDONE;
+ uha_free_mscp(unit, mscp, xs->flags);
+ scsi_done(xs);
+}
+
+/*
+ * A mscp (and hence a mbx-out) is put onto the free list.
+ */
+void
+uha_free_mscp(unit, mscp, flags)
+ int unit;
+ struct mscp *mscp;
+ int flags;
+{
+ struct uha_data *uha = uhadata[unit];
+ unsigned int opri = 0;
+
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+
+ mscp->next = uha->free_mscp;
+ uha->free_mscp = mscp;
+ mscp->flags = MSCP_FREE;
+ /*
+ * If there were none, wake abybody waiting for
+ * one to come free, starting with queued entries
+ */
+ if (!mscp->next) {
+ wakeup((caddr_t)&uha->free_mscp);
+ }
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+}
+
+/*
+ * Get a free mscp
+ *
+ * If there are none, see if we can allocate a new one. If so, put it in the
+ * hash table too otherwise either return an error or sleep.
+ */
+struct mscp *
+uha_get_mscp(unit, flags)
+ int unit, flags;
+{
+ struct uha_data *uha = uhadata[unit];
+ unsigned opri = 0;
+ struct mscp *mscpp;
+ int hashnum;
+
+ if (!(flags & SCSI_NOMASK))
+ opri = splbio();
+ /*
+ * If we can and have to, sleep waiting for one to come free
+ * but only if we can't allocate a new one
+ */
+ while (!(mscpp = uha->free_mscp)) {
+ if (uha->nummscps < UHA_MSCP_MAX) {
+ if (mscpp = (struct mscp *)malloc(sizeof(struct mscp),
+ M_TEMP,
+ M_NOWAIT)) {
+ bzero(mscpp, sizeof(struct mscp));
+ uha->nummscps++;
+ mscpp->flags = MSCP_ACTIVE;
+ /*
+ * put in the phystokv hash table
+ * Never gets taken out.
+ */
+ mscpp->hashkey = KVTOPHYS(mscpp);
+ hashnum = MSCP_HASH(mscpp->hashkey);
+ mscpp->nexthash = uha->mscphash[hashnum];
+ uha->mscphash[hashnum] = mscpp;
+ } else {
+ printf("uha%d: Can't malloc MSCP\n", unit);
+ }
+ goto gottit;
+ } else {
+ if (!(flags & SCSI_NOSLEEP)) {
+ tsleep((caddr_t)&uha->free_mscp, PRIBIO,
+ "uhamscp", 0);
+ }
+ }
+ }
+ if (mscpp) {
+ /* Get MSCP from from free list */
+ uha->free_mscp = mscpp->next;
+ mscpp->flags = MSCP_ACTIVE;
+ }
+ gottit:
+ if (!(flags & SCSI_NOMASK))
+ splx(opri);
+
+ return (mscpp);
+}
+
+/*
+ * given a physical address, find the mscp that it corresponds to.
+ */
+struct mscp *
+uha_mscp_phys_kv(uha, mscp_phys)
+ struct uha_data *uha;
+ long int mscp_phys;
+{
+ int hashnum = MSCP_HASH(mscp_phys);
+ struct mscp *mscpp = uha->mscphash[hashnum];
+
+ while (mscpp) {
+ if (mscpp->hashkey == mscp_phys)
+ break;
+ mscpp = mscpp->nexthash;
+ }
+ return mscpp;
+}
+
+/*
+ * Start the board, ready for normal operation
+ */
+int
+uha_init(unit)
+ int unit;
+{
+ struct uha_data *uha = uhadata[unit];
+ unsigned char ad[4];
+ volatile unsigned char model;
+ volatile unsigned char submodel;
+ unsigned char config_reg1;
+ unsigned char config_reg2;
+ unsigned char dma_ch;
+ unsigned char irq_ch;
+ unsigned char uha_id;
+ int port = uha->baseport;
+ int i;
+ int resetcount = 4000; /* 4 secs? */
+
+ model = inb(port + UHA_ID0);
+ submodel = inb(port + UHA_ID1);
+ if ((model != 0x56) & (submodel != 0x40)) {
+ printf("uha%d: uha_init, board not responding\n", unit);
+ return (ENXIO);
+ }
+ printf("uha%d: reading board settings, ", unit);
+
+ config_reg1 = inb(port + UHA_CONF1);
+ config_reg2 = inb(port + UHA_CONF2);
+ dma_ch = (config_reg1 & 0xc0);
+ irq_ch = (config_reg1 & 0x30);
+ uha_id = (config_reg2 & 0x07);
+
+ switch (dma_ch) {
+ case UHA_DMA_CH5:
+ uha->dma = 5;
+ printf("dma=5 ");
+ break;
+ case UHA_DMA_CH6:
+ uha->dma = 6;
+ printf("dma=6 ");
+ break;
+ case UHA_DMA_CH7:
+ uha->dma = 7;
+ printf("dma=7 ");
+ break;
+ default:
+ printf("illegal dma jumper setting\n");
+ return (EIO);
+ }
+ switch (irq_ch) {
+ case UHA_IRQ10:
+ uha->vect = 10;
+ printf("int=10 ");
+ break;
+ case UHA_IRQ11:
+ uha->vect = 11;
+ printf("int=11 ");
+ break;
+ case UHA_IRQ14:
+ uha->vect = 14;
+ printf("int=14 ");
+ break;
+ case UHA_IRQ15:
+ uha->vect = 15;
+ printf("int=15 ");
+ break;
+ default:
+ printf("illegal int jumper setting\n");
+ return (EIO);
+ }
+
+ /* who are we on the scsi bus */
+ printf("id=%x\n", uha_id);
+ uha->our_id = uha_id;
+
+ /*
+ * Note that we are going and return (to probe)
+ */
+ outb(port + UHA_LINT, UHA_ASRST);
+ while (--resetcount) {
+ if (inb(port + UHA_LINT))
+ break;
+ DELAY(1000); /* 1 mSec per loop */
+ }
+ if (resetcount == 0) {
+ printf("uha%d: board timed out during reset\n", unit);
+ return (ENXIO);
+ }
+ outb(port + UHA_SMASK, 0x81); /* make sure interrupts are enabled */
+ uha->flags |= UHA_INIT;
+ return (0);
+}
+
+#ifndef min
+#define min(x,y) (x < y ? x : y)
+#endif /* min */
+
+void
+uhaminphys(bp)
+ struct buf *bp;
+{
+ if (bp->b_bcount > ((UHA_NSEG - 1) * PAGESIZ)) {
+ bp->b_bcount = ((UHA_NSEG - 1) * PAGESIZ);
+ }
+}
+
+/*
+ * start a scsi operation given the command and the data address. Also
+ * needs the unit, target and lu.
+ */
+int32
+uha_scsi_cmd(xs)
+ struct scsi_xfer *xs;
+{
+ struct scsi_sense_data *s1, *s2;
+ struct mscp *mscp;
+ struct uha_dma_seg *sg;
+ int seg; /* scatter gather seg being worked on */
+ int i = 0;
+ int rc = 0;
+ int thiskv;
+ unsigned long int thisphys, nextphys;
+ int unit = xs->sc_link->adapter_unit;
+ int bytes_this_seg, bytes_this_page, datalen, flags;
+ struct iovec *iovp;
+ struct uha_data *uha = uhadata[unit];
+ int s;
+ unsigned int stat;
+ int port = uha->baseport;
+ unsigned long int templen;
+
+ SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_scsi_cmd\n"));
+ /*
+ * get a mscp (mbox-out) to use. If the transfer
+ * is from a buf (possibly from interrupt time)
+ * then we can't allow it to sleep
+ */
+ flags = xs->flags;
+ if (xs->bp)
+ flags |= (SCSI_NOSLEEP); /* just to be sure */
+ if (flags & ITSDONE) {
+ printf("uha%d: Already done?", unit);
+ xs->flags &= ~ITSDONE;
+ }
+ if (!(flags & INUSE)) {
+ printf("uha%d: Not in use?", unit);
+ xs->flags |= INUSE;
+ }
+ if (!(mscp = uha_get_mscp(unit, flags))) {
+ xs->error = XS_DRIVER_STUFFUP;
+ return (TRY_AGAIN_LATER);
+ }
+ cheat = mscp;
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("start mscp(%x)\n", mscp));
+ mscp->xs = xs;
+
+ /*
+ * Put all the arguments for the xfer in the mscp
+ */
+ if (flags & SCSI_RESET) {
+ mscp->opcode = 0x04;
+ mscp->ca = 0x01;
+ } else {
+ mscp->opcode = 0x02;
+ mscp->ca = 0x01;
+ }
+ if (flags & SCSI_DATA_IN) {
+ mscp->xdir = 0x01;
+ }
+ if (flags & SCSI_DATA_OUT) {
+ mscp->xdir = 0x02;
+ }
+#ifdef GOTTABEJOKING
+ if (xs->sc_link->lun != 0) {
+ xs->error = XS_DRIVER_STUFFUP;
+ uha_free_mscp(unit, mscp, flags);
+ return (HAD_ERROR);
+ }
+#endif
+ mscp->dcn = 0x00;
+ mscp->chan = 0x00;
+ mscp->target = xs->sc_link->target;
+ mscp->lun = xs->sc_link->lun;
+ mscp->link.addr[0] = 0x00;
+ mscp->link.addr[1] = 0x00;
+ mscp->link.addr[2] = 0x00;
+ mscp->link.addr[3] = 0x00;
+ mscp->link_id = 0x00;
+ mscp->cdblen = xs->cmdlen;
+ scratch = KVTOPHYS(&(mscp->mscp_sense));
+ mscp->sense.addr[0] = (scratch & 0xff);
+ mscp->sense.addr[1] = ((scratch >> 8) & 0xff);
+ mscp->sense.addr[2] = ((scratch >> 16) & 0xff);
+ mscp->sense.addr[3] = ((scratch >> 24) & 0xff);
+ mscp->senselen = sizeof(mscp->mscp_sense);
+ mscp->ha_status = 0x00;
+ mscp->targ_status = 0x00;
+
+ if (xs->datalen) { /* should use S/G only if not zero length */
+ scratch = KVTOPHYS(mscp->uha_dma);
+ mscp->data.addr[0] = (scratch & 0xff);
+ mscp->data.addr[1] = ((scratch >> 8) & 0xff);
+ mscp->data.addr[2] = ((scratch >> 16) & 0xff);
+ mscp->data.addr[3] = ((scratch >> 24) & 0xff);
+ sg = mscp->uha_dma;
+ seg = 0;
+ mscp->sgth = 0x01;
+
+#ifdef TFS
+ if (flags & SCSI_DATA_UIO) {
+ iovp = ((struct uio *) xs->data)->uio_iov;
+ datalen = ((struct uio *) xs->data)->uio_iovcnt;
+ xs->datalen = 0;
+ while ((datalen) && (seg < UHA_NSEG)) {
+ scratch = (unsigned long) iovp->iov_base;
+ sg->addr.addr[0] = (scratch & 0xff);
+ sg->addr.addr[1] = ((scratch >> 8) & 0xff);
+ sg->addr.addr[2] = ((scratch >> 16) & 0xff);
+ sg->addr.addr[3] = ((scratch >> 24) & 0xff);
+ xs->datalen += *(unsigned long *) sg->len.len = iovp->iov_len;
+ SC_DEBUGN(xs->sc_link, SDEV_DB4, ("(0x%x@0x%x)",
+ iovp->iov_len,
+ iovp->iov_base));
+ sg++;
+ iovp++;
+ seg++;
+ datalen--;
+ }
+ } else
+#endif /*TFS */
+ {
+ /*
+ * Set up the scatter gather block
+ */
+
+ SC_DEBUG(xs->sc_link, SDEV_DB4,
+ ("%d @0x%x:- ", xs->datalen, xs->data));
+ datalen = xs->datalen;
+ thiskv = (int) xs->data;
+ thisphys = KVTOPHYS(thiskv);
+ templen = 0;
+
+ while ((datalen) && (seg < UHA_NSEG)) {
+ bytes_this_seg = 0;
+
+ /* put in the base address */
+ sg->addr.addr[0] = (thisphys & 0xff);
+ sg->addr.addr[1] = ((thisphys >> 8) & 0xff);
+ sg->addr.addr[2] = ((thisphys >> 16) & 0xff);
+ sg->addr.addr[3] = ((thisphys >> 24) & 0xff);
+
+ SC_DEBUGN(xs->sc_link, SDEV_DB4, ("0x%x", thisphys));
+
+ /* do it at least once */
+ nextphys = thisphys;
+ while ((datalen) && (thisphys == nextphys))
+ /*
+ * This page is contiguous (physically) with
+ * the the last, just extend the length
+ */
+ {
+ /* how far to the end of the page */
+ nextphys = (thisphys & (~(PAGESIZ - 1)))
+ + PAGESIZ;
+ bytes_this_page = nextphys - thisphys;
+ /**** or the data ****/
+ bytes_this_page = min(bytes_this_page
+ ,datalen);
+ bytes_this_seg += bytes_this_page;
+ datalen -= bytes_this_page;
+
+ /* get more ready for the next page */
+ thiskv = (thiskv & (~(PAGESIZ - 1)))
+ + PAGESIZ;
+ if (datalen)
+ thisphys = KVTOPHYS(thiskv);
+ }
+ /*
+ * next page isn't contiguous, finish the seg
+ */
+ SC_DEBUGN(xs->sc_link, SDEV_DB4,
+ ("(0x%x)", bytes_this_seg));
+ sg->len.len[0] = (bytes_this_seg & 0xff);
+ sg->len.len[1] = ((bytes_this_seg >> 8) & 0xff);
+ sg->len.len[2] = ((bytes_this_seg >> 16) & 0xff);
+ sg->len.len[3] = ((bytes_this_seg >> 24) & 0xff);
+ templen += bytes_this_seg;
+ sg++;
+ seg++;
+ }
+ }
+
+ /* end of iov/kv decision */
+ mscp->datalen.len[0] = (templen & 0xff);
+ mscp->datalen.len[1] = ((templen >> 8) & 0xff);
+ mscp->datalen.len[2] = ((templen >> 16) & 0xff);
+ mscp->datalen.len[3] = ((templen >> 24) & 0xff);
+ mscp->sg_num = seg;
+
+ SC_DEBUGN(xs->sc_link, SDEV_DB4, ("\n"));
+ if (datalen) { /* there's still data, must have run out of segs! */
+ printf("uha%d: uha_scsi_cmd, more than %d DMA segs\n",
+ unit, UHA_NSEG);
+ xs->error = XS_DRIVER_STUFFUP;
+ uha_free_mscp(unit, mscp, flags);
+ return (HAD_ERROR);
+ }
+ } else { /* No data xfer, use non S/G values */
+ mscp->data.addr[0] = 0x00;
+ mscp->data.addr[1] = 0x00;
+ mscp->data.addr[2] = 0x00;
+ mscp->data.addr[3] = 0x00;
+ mscp->datalen.len[0] = 0x00;
+ mscp->datalen.len[1] = 0x00;
+ mscp->datalen.len[2] = 0x00;
+ mscp->datalen.len[3] = 0x00;
+ mscp->xdir = 0x03;
+ mscp->sgth = 0x00;
+ mscp->sg_num = 0x00;
+ }
+
+ /*
+ * Put the scsi command in the mscp and start it
+ */
+ bcopy(xs->cmd, mscp->cdb, xs->cmdlen);
+
+ /*
+ * Usually return SUCCESSFULLY QUEUED
+ */
+ if (!(flags & SCSI_NOMASK)) {
+ s = splbio();
+ uha_send_mbox(unit, mscp);
+ timeout(uha_timeout, (caddr_t)mscp, (xs->timeout * hz) / 1000);
+ splx(s);
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_sent\n"));
+ return (SUCCESSFULLY_QUEUED);
+ }
+
+ /*
+ * If we can't use interrupts, poll on completion
+ */
+ uha_send_mbox(unit, mscp);
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_wait\n"));
+ do {
+ if (uha_poll(unit, xs->timeout)) {
+ if (!(xs->flags & SCSI_SILENT))
+ printf("uha%d: cmd fail\n", unit);
+ if (!(uha_abort(unit, mscp))) {
+ printf("uha%d: abort failed in wait\n", unit);
+ uha_free_mscp(unit, mscp, flags);
+ }
+ xs->error = XS_DRIVER_STUFFUP;
+ return (HAD_ERROR);
+ }
+ }
+ while (!(xs->flags & ITSDONE)); /* something (?) else finished */
+ if (xs->error) {
+ return (HAD_ERROR);
+ }
+ return (COMPLETE);
+}
+
+void
+uha_timeout(caddr_t arg1, int arg2)
+{
+ struct mscp *mscp = (struct mscp *)arg1;
+ int unit;
+ struct uha_data *uha;
+ int s = splbio();
+ /*int port = uha->baseport; */
+
+ unit = mscp->xs->sc_link->adapter_unit;
+ uha = uhadata[unit];
+ printf("uha%d:%d:%d (%s%d) timed out ", unit
+ ,mscp->xs->sc_link->target
+ ,mscp->xs->sc_link->lun
+ ,mscp->xs->sc_link->device->name
+ ,mscp->xs->sc_link->dev_unit);
+
+#ifdef UHADEBUG
+ uha_print_active_mscp(unit);
+#endif /*UHADEBUG */
+
+ if ((uha_abort(unit, mscp) != 1) || (mscp->flags = MSCP_ABORTED)) {
+ printf("AGAIN");
+ mscp->xs->retries = 0; /* I MEAN IT ! */
+ uha_done(unit, mscp, FAIL);
+ } else { /* abort the operation that has timed out */
+ printf("\n");
+ timeout(uha_timeout, (caddr_t)mscp, 2 * hz);
+ mscp->flags = MSCP_ABORTED;
+ }
+ splx(s);
+}
+
+#ifdef UHADEBUG
+void
+uha_print_mscp(mscp)
+ struct mscp *mscp;
+{
+ printf("mscp:%x op:%x cmdlen:%d senlen:%d\n"
+ ,mscp
+ ,mscp->opcode
+ ,mscp->cdblen
+ ,mscp->senselen);
+ printf(" sg:%d sgnum:%x datlen:%d hstat:%x tstat:%x flags:%x\n"
+ ,mscp->sgth
+ ,mscp->sg_num
+ ,mscp->datalen
+ ,mscp->ha_status
+ ,mscp->targ_status
+ ,mscp->flags);
+ show_scsi_cmd(mscp->xs);
+}
+
+void
+uha_print_active_mscp(int unit)
+{
+ struct uha_data *uha = uhadata[unit];
+ struct mscp *mscp;
+ int i = 0;
+
+ while (i < MSCP_HASH_SIZE) {
+ mscp = uha->mscphash[i];
+ while (mscp) {
+ if (mscp->flags != MSCP_FREE) {
+ uha_print_mscp(mscp);
+ }
+ mscp = mscp->nexthash;
+ }
+ i++;
+ }
+}
+#endif /*UHADEBUG */
+#endif /*KERNEL */
diff --git a/sys/i386/isa/vector.s b/sys/i386/isa/vector.s
new file mode 100644
index 0000000..7135ae7
--- /dev/null
+++ b/sys/i386/isa/vector.s
@@ -0,0 +1,360 @@
+/*
+ * from: vector.s, 386BSD 0.1 unknown origin
+ * $Id: vector.s,v 1.6 1994/01/10 23:15:09 ache Exp $
+ */
+
+#include "i386/isa/icu.h"
+#include "i386/isa/isa.h"
+#include "vector.h"
+
+#define ICU_EOI 0x20 /* XXX - define elsewhere */
+
+#define IRQ_BIT(irq_num) (1 << ((irq_num) % 8))
+#define IRQ_BYTE(irq_num) ((irq_num) / 8)
+
+#ifdef AUTO_EOI_1
+#define ENABLE_ICU1 /* use auto-EOI to reduce i/o */
+#else
+#define ENABLE_ICU1 \
+ movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \
+ FASTER_NOP ; /* ... ASAP ... */ \
+ outb %al,$IO_ICU1 /* ... to clear in service bit */
+#endif
+
+#ifdef AUTO_EOI_2
+/*
+ * The data sheet says no auto-EOI on slave, but it sometimes works.
+ */
+#define ENABLE_ICU1_AND_2 ENABLE_ICU1
+#else
+#define ENABLE_ICU1_AND_2 \
+ movb $ICU_EOI,%al ; /* as above */ \
+ FASTER_NOP ; \
+ outb %al,$IO_ICU2 ; /* but do second icu first */ \
+ FASTER_NOP ; \
+ outb %al,$IO_ICU1 /* then first icu */
+#endif
+
+#ifdef FAST_INTR_HANDLER_USES_ES
+#define ACTUALLY_PUSHED 1
+#define MAYBE_MOVW_AX_ES movl %ax,%es
+#define MAYBE_POPL_ES popl %es
+#define MAYBE_PUSHL_ES pushl %es
+#else
+/*
+ * We can usually skip loading %es for fastintr handlers. %es should
+ * only be used for string instructions, and fastintr handlers shouldn't
+ * do anything slow enough to justify using a string instruction.
+ */
+#define ACTUALLY_PUSHED 0
+#define MAYBE_MOVW_AX_ES
+#define MAYBE_POPL_ES
+#define MAYBE_PUSHL_ES
+#endif
+
+/*
+ * Macros for interrupt interrupt entry, call to handler, and exit.
+ *
+ * XXX - the interrupt frame is set up to look like a trap frame. This is
+ * usually a waste of time. The only interrupt handlers that want a frame
+ * are the clock handler (it wants a clock frame), the npx handler (it's
+ * easier to do right all in assembler). The interrupt return routine
+ * needs a trap frame for rare AST's (it could easily convert the frame).
+ * The direct costs of setting up a trap frame are two pushl's (error
+ * code and trap number), an addl to get rid of these, and pushing and
+ * popping the call-saved regs %esi, %edi and %ebp twice, The indirect
+ * costs are making the driver interface nonuniform so unpending of
+ * interrupts is more complicated and slower (call_driver(unit) would
+ * be easier than ensuring an interrupt frame for all handlers. Finally,
+ * there are some struct copies in the npx handler and maybe in the clock
+ * handler that could be avoided by working more with pointers to frames
+ * instead of frames.
+ *
+ * XXX - should we do a cld on every system entry to avoid the requirement
+ * for scattered cld's?
+ *
+ * Coding notes for *.s:
+ *
+ * If possible, avoid operations that involve an operand size override.
+ * Word-sized operations might be smaller, but the operand size override
+ * makes them slower on on 486's and no faster on 386's unless perhaps
+ * the instruction pipeline is depleted. E.g.,
+ *
+ * Use movl to seg regs instead of the equivalent but more descriptive
+ * movw - gas generates an irelevant (slower) operand size override.
+ *
+ * Use movl to ordinary regs in preference to movw and especially
+ * in preference to movz[bw]l. Use unsigned (long) variables with the
+ * top bits clear instead of unsigned short variables to provide more
+ * opportunities for movl.
+ *
+ * If possible, use byte-sized operations. They are smaller and no slower.
+ *
+ * Use (%reg) instead of 0(%reg) - gas generates larger code for the latter.
+ *
+ * If the interrupt frame is made more flexible, INTR can push %eax first
+ * and decide the ipending case with less overhead, e.g., by avoiding
+ * loading segregs.
+ */
+
+#define FAST_INTR(unit, irq_num, id_num, handler, enable_icus) \
+ pushl %eax ; /* save only call-used registers */ \
+ pushl %ecx ; \
+ pushl %edx ; \
+ pushl %ds ; \
+ MAYBE_PUSHL_ES ; \
+ movl $KDSEL,%eax ; \
+ movl %ax,%ds ; \
+ MAYBE_MOVW_AX_ES ; \
+ FAKE_MCOUNT((4+ACTUALLY_PUSHED)*4(%esp)) ; \
+ pushl $unit ; \
+ call handler ; /* do the work ASAP */ \
+ enable_icus ; /* (re)enable ASAP (helps edge trigger?) */ \
+ addl $4,%esp ; \
+ incl _cnt+V_INTR ; /* book-keeping can wait */ \
+ incl _intrcnt_actv + (id_num) * 4 ; \
+ movl _cpl,%eax ; /* are we unmasking pending HWIs or SWIs? */ \
+ notl %eax ; \
+ andl _ipending,%eax ; \
+ jne 1f ; /* yes, handle them */ \
+ MEXITCOUNT ; \
+ MAYBE_POPL_ES ; \
+ popl %ds ; \
+ popl %edx ; \
+ popl %ecx ; \
+ popl %eax ; \
+ iret ; \
+; \
+ ALIGN_TEXT ; \
+1: ; \
+ movl _cpl,%eax ; \
+ movl $HWI_MASK|SWI_MASK,_cpl ; /* limit nesting ... */ \
+ sti ; /* ... to do this as early as possible */ \
+ MAYBE_POPL_ES ; /* discard most of thin frame ... */ \
+ popl %ecx ; /* ... original %ds ... */ \
+ popl %edx ; \
+ xchgl %eax,(1+ACTUALLY_PUSHED)*4(%esp) ; /* orig %eax; save cpl */ \
+ pushal ; /* build fat frame (grrr) ... */ \
+ pushl %ecx ; /* ... actually %ds ... */ \
+ pushl %es ; \
+ movl $KDSEL,%eax ; \
+ movl %ax,%es ; \
+ movl (2+8+0)*4(%esp),%ecx ; /* ... %ecx from thin frame ... */ \
+ movl %ecx,(2+6)*4(%esp) ; /* ... to fat frame ... */ \
+ movl (2+8+1)*4(%esp),%eax ; /* ... cpl from thin frame */ \
+ pushl %eax ; \
+ subl $4,%esp ; /* junk for unit number */ \
+ MEXITCOUNT ; \
+ jmp _doreti
+
+#define INTR(unit, irq_num, id_num, mask, handler, icu, enable_icus, reg, stray) \
+ pushl $0 ; /* dumby error code */ \
+ pushl $0 ; /* dumby trap type */ \
+ pushal ; \
+ pushl %ds ; /* save our data and extra segments ... */ \
+ pushl %es ; \
+ movl $KDSEL,%eax ; /* ... and reload with kernel's own ... */ \
+ movl %ax,%ds ; /* ... early for obsolete reasons */ \
+ movl %ax,%es ; \
+ movb _imen + IRQ_BYTE(irq_num),%al ; \
+ orb $IRQ_BIT(irq_num),%al ; \
+ movb %al,_imen + IRQ_BYTE(irq_num) ; \
+ FASTER_NOP ; \
+ outb %al,$icu+1 ; \
+ enable_icus ; \
+ incl _cnt+V_INTR ; /* tally interrupts */ \
+ movl _cpl,%eax ; \
+ testb $IRQ_BIT(irq_num),%reg ; \
+ jne 2f ; \
+1: ; \
+ FAKE_MCOUNT(12*4(%esp)) ; /* XXX late to avoid double count */ \
+ incl _intrcnt_actv + (id_num) * 4 ; \
+ movl _cpl,%eax ; \
+ pushl %eax ; \
+ pushl $unit ; \
+ orl mask,%eax ; \
+ movl %eax,_cpl ; \
+ sti ; \
+ call handler ; \
+ movb _imen + IRQ_BYTE(irq_num),%al ; \
+ andb $~IRQ_BIT(irq_num),%al ; \
+ movb %al,_imen + IRQ_BYTE(irq_num) ; \
+ FASTER_NOP ; \
+ outb %al,$icu+1 ; \
+ MEXITCOUNT ; \
+ /* We could usually avoid the following jmp by inlining some of */ \
+ /* _doreti, but it's probably better to use less cache. */ \
+ jmp _doreti ; \
+; \
+ ALIGN_TEXT ; \
+2: ; \
+ /* XXX skip mcounting here to avoid double count */ \
+ movl $1b,%eax ; /* register resume address */ \
+ /* XXX - someday do it at attach time */ \
+ movl %eax,ihandlers + (irq_num) * 4 ; \
+ orb $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) ; \
+ popl %es ; \
+ popl %ds ; \
+ popal ; \
+ addl $4+4,%esp ; \
+ iret
+
+/*
+ * vector.h has defined a macro 'BUILD_VECTORS' containing a big list of info
+ * about vectors, including a submacro 'BUILD_VECTOR' that operates on the
+ * info about each vector. We redefine 'BUILD_VECTOR' to expand the info
+ * in different ways. Here we expand it to a list of interrupt handlers.
+ * This order is of course unimportant. Elsewhere we expand it to inline
+ * linear search code for which the order is a little more important and
+ * concatenating the code with no holes is very important.
+ *
+ * XXX - now there is BUILD_FAST_VECTOR as well as BUILD_VECTOR.
+ *
+ * The info consists of the following items for each vector:
+ *
+ * name (identifier): name of the vector; used to build labels
+ * unit (expression): unit number to call the device driver with
+ * irq_num (number): number of the IRQ to handled (0-15)
+ * id_num (number): uniq numeric id for handler (assigned by config)
+ * mask (blank-ident): priority mask used
+ * handler (blank-ident): interrupt handler to call
+ * icu_num (number): (1 + irq_num / 8) converted for label building
+ * icu_enables (number): 1 for icu_num == 1, 1_AND_2 for icu_num == 2
+ * reg (blank-ident): al for icu_num == 1, ah for icu_num == 2
+ *
+ * 'irq_num' is converted in several ways at config time to get around
+ * limitations in cpp. The macros have blanks after commas iff they would
+ * not mess up identifiers and numbers.
+ */
+
+#undef BUILD_FAST_VECTOR
+#define BUILD_FAST_VECTOR(name, unit, irq_num, id_num, mask, handler, \
+ icu_num, icu_enables, reg) \
+ .globl handler ; \
+ .text ; \
+ .globl _V/**/name ; \
+ SUPERALIGN_TEXT ; \
+_V/**/name: ; \
+ FAST_INTR(unit, irq_num,id_num, handler, ENABLE_ICU/**/icu_enables)
+
+#undef BUILD_VECTOR
+#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \
+ icu_num, icu_enables, reg) \
+ .globl handler ; \
+ .text ; \
+ .globl _V/**/name ; \
+ SUPERALIGN_TEXT ; \
+_V/**/name: ; \
+ INTR(unit,irq_num, id_num, mask, handler, IO_ICU/**/icu_num, \
+ ENABLE_ICU/**/icu_enables, reg,)
+
+MCOUNT_LABEL(bintr)
+ BUILD_VECTORS
+
+ /* hardware interrupt catcher (IDT 32 - 47) */
+ .globl _isa_strayintr
+
+#define STRAYINTR(irq_num, icu_num, icu_enables, reg) \
+IDTVEC(intr/**/irq_num) ; \
+ INTR(irq_num,irq_num,irq_num, _high_imask, _isa_strayintr, \
+ IO_ICU/**/icu_num, ENABLE_ICU/**/icu_enables, reg,stray)
+
+/*
+ * XXX - the mask (1 << 2) == IRQ_SLAVE will be generated for IRQ 2, instead
+ * of the mask IRQ2 (defined as IRQ9 == (1 << 9)). But IRQ 2 "can't happen".
+ * In fact, all stray interrupts "can't happen" except for bugs. The
+ * "stray" IRQ 7 is documented behaviour of the 8259. It happens when there
+ * is a glitch on any of its interrupt inputs. Does it really interrupt when
+ * IRQ 7 is masked?
+ *
+ * XXX - unpend doesn't work for these, it sends them to the real handler.
+ *
+ * XXX - the race bug during initialization may be because I changed the
+ * order of switching from the stray to the real interrupt handler to before
+ * enabling interrupts. The old order looked unsafe but maybe it is OK with
+ * the stray interrupt handler installed. But these handlers only reduce
+ * the window of vulnerability - it is still open at the end of
+ * isa_configure().
+ *
+ * XXX - many comments are stale.
+ */
+
+ STRAYINTR(0,1,1, al)
+ STRAYINTR(1,1,1, al)
+ STRAYINTR(2,1,1, al)
+ STRAYINTR(3,1,1, al)
+ STRAYINTR(4,1,1, al)
+ STRAYINTR(5,1,1, al)
+ STRAYINTR(6,1,1, al)
+ STRAYINTR(7,1,1, al)
+ STRAYINTR(8,2,1_AND_2, ah)
+ STRAYINTR(9,2,1_AND_2, ah)
+ STRAYINTR(10,2,1_AND_2, ah)
+ STRAYINTR(11,2,1_AND_2, ah)
+ STRAYINTR(12,2,1_AND_2, ah)
+ STRAYINTR(13,2,1_AND_2, ah)
+ STRAYINTR(14,2,1_AND_2, ah)
+ STRAYINTR(15,2,1_AND_2, ah)
+#if 0
+ INTRSTRAY(255, _highmask, 255) ; call _isa_strayintr ; INTREXIT2
+#endif
+MCOUNT_LABEL(eintr)
+
+/*
+ * These are the interrupt counters, I moved them here from icu.s so that
+ * they are with the name table. rgrimes
+ *
+ * There are now lots of counters, this has been redone to work with
+ * Bruce Evans intr-0.1 code, which I modified some more to make it all
+ * work with vmstat.
+ */
+ .data
+ihandlers: /* addresses of interrupt handlers */
+ .space NHWI*4 /* actually resumption addresses for HWI's */
+ .long swi_tty, swi_net, 0, 0, 0, 0, 0, 0
+ .long 0, 0, 0, 0, 0, 0, swi_clock, swi_ast
+imasks: /* masks for interrupt handlers */
+ .space NHWI*4 /* padding; HWI masks are elsewhere */
+ .long SWI_TTY_MASK, SWI_NET_MASK, 0, 0, 0, 0, 0, 0
+ .long 0, 0, 0, 0, 0, 0, SWI_CLOCK_MASK, SWI_AST_MASK
+
+ .globl _intrcnt
+_intrcnt: /* used by vmstat to calc size of table */
+ .globl _intrcnt_bad7
+_intrcnt_bad7: .space 4 /* glitches on irq 7 */
+ .globl _intrcnt_bad15
+_intrcnt_bad15: .space 4 /* glitches on irq 15 */
+ .globl _intrcnt_stray
+_intrcnt_stray: .space 4 /* total count of stray interrupts */
+ .globl _intrcnt_actv
+_intrcnt_actv: .space NR_REAL_INT_HANDLERS * 4 /* active interrupts */
+ .globl _eintrcnt
+_eintrcnt: /* used by vmstat to calc size of table */
+
+/*
+ * Build the interrupt name table for vmstat
+ */
+
+#undef BUILD_FAST_VECTOR
+#define BUILD_FAST_VECTOR BUILD_VECTOR
+
+#undef BUILD_VECTOR
+#define BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \
+ icu_num, icu_enables, reg) \
+ .ascii "name irq" ; \
+ .asciz "irq_num"
+/*
+ * XXX - use the __STRING and __CONCAT macros from <sys/cdefs.h> to stringize
+ * and concatenate names above and elsewhere. Note that __CONCAT doesn't
+ * work when nested.
+ */
+
+ .text
+ .globl _intrnames, _eintrnames
+_intrnames:
+ BUILD_VECTOR(bad,,7,,,,,,)
+ BUILD_VECTOR(bad,,15,,,,,,)
+ BUILD_VECTOR(stray,,,,,,,,)
+ BUILD_VECTORS
+
+_eintrnames:
diff --git a/sys/i386/isa/wd.c b/sys/i386/isa/wd.c
new file mode 100644
index 0000000..b8cf448
--- /dev/null
+++ b/sys/i386/isa/wd.c
@@ -0,0 +1,1823 @@
+#define WD_COUNT_RETRIES
+static int wdtest = 0;
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)wd.c 7.2 (Berkeley) 5/9/91
+ * $Id: wd.c,v 1.37 1994/04/10 11:17:13 csgr Exp $
+ */
+
+/* TODO:
+ * o Bump error count after timeout.
+ * o Satisfy ATA timing in all cases.
+ * o Finish merging berry/sos timeout code (bump error count...).
+ * o Merge/fix TIH/NetBSD bad144 code.
+ * o Merge/fix Dyson/NetBSD clustering code.
+ * o Don't use polling except for initialization. Need to
+ * reorganize the state machine. Then "extra" interrupts
+ * shouldn't happen (except maybe one for initialization).
+ * o Fix disklabel, boot and driver inconsistencies with
+ * bad144 in standard versions.
+ * o Support extended DOS partitions.
+ * o Support swapping to DOS partitions.
+ * o Look at latest linux clustering methods. Our disksort()
+ * gets in the way of clustering.
+ * o Handle bad sectors, clustering, disklabelling, DOS
+ * partitions and swapping driver-independently. Use
+ * i386/dkbad.c for bad sectors. Swapping will need new
+ * driver entries for polled reinit and polled write).
+ */
+
+#include "wd.h"
+#if NWDC > 0
+
+#include "param.h"
+#include "dkbad.h"
+#include "systm.h"
+#include "kernel.h"
+#include "conf.h"
+#include "file.h"
+#include "stat.h"
+#include "ioctl.h"
+#include "disklabel.h"
+#include "buf.h"
+#include "uio.h"
+#include "malloc.h"
+#include "machine/cpu.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/wdreg.h"
+#include "syslog.h"
+#include "vm/vm.h"
+
+#define TIMEOUT 10000
+#define RETRIES 5 /* number of retries before giving up */
+#define RECOVERYTIME 500000 /* usec for controller to recover after err */
+#define MAXTRANSFER 256 /* max size of transfer in sectors */
+#define BAD144_NO_CYL 0xffff /* XXX should be in dkbad.h; bad144.c uses -1 */
+
+#ifdef notyet
+#define wdnoreloc(dev) (minor(dev) & 0x80) /* ignore partition table */
+#endif
+#define wddospart(dev) (minor(dev) & 0x40) /* use dos partitions */
+#define wdunit(dev) ((minor(dev) & 0x38) >> 3)
+#define wdpart(dev) (minor(dev) & 0x7)
+#define makewddev(maj, unit, part) (makedev(maj,((unit<<3)+part)))
+#define WDRAW 3 /* 'd' partition isn't a partition! */
+
+/* Cylinder number for doing IO to. Shares an entry in the buf struct. */
+#define b_cylin b_resid
+
+/*
+ * This biotab field doubles as a field for the physical unit number on
+ * the controller.
+ */
+#define id_physid id_scsiid
+
+/*
+ * Drive states. Used to initialize drive.
+ */
+
+#define CLOSED 0 /* disk is closed. */
+#define WANTOPEN 1 /* open requested, not started */
+#define RECAL 2 /* doing restore */
+#define OPEN 3 /* done with open */
+
+/*
+ * The structure of a disk drive.
+ */
+struct disk {
+ long dk_bc; /* byte count left */
+ short dk_skip; /* blocks already transferred */
+ char dk_ctrlr; /* physical controller number */
+ char dk_unit; /* physical unit number */
+ char dk_lunit; /* logical unit number */
+ char dk_state; /* control state */
+ u_char dk_status; /* copy of status reg. */
+ u_char dk_error; /* copy of error reg. */
+ u_char dk_timeout; /* countdown to next timeout */
+ short dk_port; /* i/o port base */
+
+ u_long dk_copenpart; /* character units open on this drive */
+ u_long dk_bopenpart; /* block units open on this drive */
+ u_long dk_openpart; /* all units open on this drive */
+ short dk_wlabel; /* label writable? */
+ short dk_flags; /* drive characteistics found */
+#define DKFL_DOSPART 0x00001 /* has DOS partition table */
+#define DKFL_SINGLE 0x00004 /* sector at a time mode */
+#define DKFL_ERROR 0x00008 /* processing a disk error */
+#define DKFL_BSDLABEL 0x00010 /* has a BSD disk label */
+#define DKFL_BADSECT 0x00020 /* has a bad144 badsector table */
+#define DKFL_WRITEPROT 0x00040 /* manual unit write protect */
+#define DKFL_LABELLING 0x00080 /* readdisklabel() in progress */
+ struct wdparams dk_params; /* ESDI/IDE drive/controller parameters */
+ struct disklabel dk_dd; /* device configuration data */
+ struct disklabel dk_dd2; /* DOS view converted to label */
+ struct dos_partition
+ dk_dospartitions[NDOSPART]; /* DOS view of disk */
+ struct dkbad dk_bad; /* bad sector table */
+ long dk_badsect[127]; /* 126 plus trailing -1 marker */
+};
+
+static struct disk *wddrives[NWD]; /* table of units */
+static struct buf wdtab[NWDC];
+static struct buf wdutab[NWD]; /* head of queue per drive */
+#ifdef notyet
+static struct buf rwdbuf[NWD]; /* buffers for raw IO */
+#endif
+static long wdxfer[NWD]; /* count of transfers */
+
+
+static void bad144intern(struct disk *);
+static int wdprobe(struct isa_device *dvp);
+static int wdattach(struct isa_device *dvp);
+static void wdustart(struct disk *du);
+static void wdstart(int ctrlr);
+static int wdcontrol(struct buf *bp);
+static int wdcommand(struct disk *du, u_int cylinder, u_int head,
+ u_int sector, u_int count, u_int command);
+static int wdsetctlr(struct disk *du);
+static int wdwsetctlr(struct disk *du);
+static int wdgetctlr(struct disk *du);
+static void wderror(struct buf *bp, struct disk *du, char *mesg);
+static void wdflushirq(struct disk *du, int old_ipl);
+static int wdreset(struct disk *du);
+static void wdsleep(int ctrlr, char *wmesg);
+static void wdtimeout(caddr_t cdu, int ticks);
+static int wdunwedge(struct disk *du);
+static int wdwait(struct disk *du, u_char bits_wanted, int timeout);
+
+struct isa_driver wdcdriver = {
+ wdprobe, wdattach, "wdc",
+};
+
+/*
+ * Probe for controller.
+ */
+static int
+wdprobe(struct isa_device *dvp)
+{
+ int unit = dvp->id_unit;
+ struct disk *du;
+
+ if (unit >= NWDC)
+ return (0);
+ du = malloc(sizeof *du, M_TEMP, M_NOWAIT);
+ if (du == NULL)
+ return (0);
+ bzero(du, sizeof *du);
+ du->dk_ctrlr = dvp->id_unit;
+ du->dk_port = dvp->id_iobase;
+
+ /* check if we have registers that work */
+ outb(du->dk_port + wd_cyl_lo, 0xa5); /* wd_cyl_lo is read/write */
+ if (inb(du->dk_port + wd_cyl_lo) != 0xa5)
+ goto nodevice;
+
+ if (wdreset(du) != 0 && (DELAY(RECOVERYTIME), wdreset(du)) != 0)
+ goto nodevice;
+
+ /* execute a controller only command */
+ if (wdcommand(du, 0, 0, 0, 0, WDCC_DIAGNOSE) != 0
+ || wdwait(du, 0, TIMEOUT) < 0)
+ goto nodevice;
+
+ /*
+ * drive(s) did not time out during diagnostic :
+ * Get error status and check that both drives are OK.
+ * Table 9-2 of ATA specs suggests that we must check for
+ * a value of 0x01
+ *
+ * Strangely, some controllers will return a status of
+ * 0x81 (drive 0 OK, drive 1 failure), and then when
+ * the DRV bit is set, return status of 0x01 (OK) for
+ * drive 2. (This seems to contradict the ATA spec.)
+ */
+ du->dk_error = inb(du->dk_port + wd_error);
+ /* printf("Error : %x\n", du->dk_error); */
+ if(du->dk_error != 0x01) {
+ if(du->dk_error & 0x80) { /* drive 1 failure */
+
+ /* first set the DRV bit */
+ u_int sdh;
+ sdh = inb(du->dk_port+ wd_sdh);
+ sdh = sdh | 0x10;
+ outb(du->dk_port+ wd_sdh, sdh);
+
+ /* Wait, to make sure drv 1 has completed diags */
+ if ( wdwait(du, 0, TIMEOUT) < 0)
+ goto nodevice;
+
+ /* Get status for drive 1 */
+ du->dk_error = inb(du->dk_port + wd_error);
+ /* printf("Error (drv 1) : %x\n", du->dk_error); */
+
+ if(du->dk_error != 0x01)
+ goto nodevice;
+ } else /* drive 0 fail */
+ goto nodevice;
+ }
+
+
+ free(du, M_TEMP);
+ return (IO_WDCSIZE);
+
+nodevice:
+ free(du, M_TEMP);
+ return (0);
+}
+
+/*
+ * Attach each drive if possible.
+ */
+static int
+wdattach(struct isa_device *dvp)
+{
+ int unit, lunit;
+ struct isa_device *wdup;
+ struct disk *du;
+
+ if (dvp->id_unit >= NWDC)
+ return (0);
+
+ for (wdup = isa_biotab_wdc; wdup->id_driver != 0; wdup++) {
+ if (wdup->id_iobase != dvp->id_iobase)
+ continue;
+ lunit = wdup->id_unit;
+ if (lunit >= NWD)
+ continue;
+ unit = wdup->id_physid;
+
+ du = malloc(sizeof *du, M_TEMP, M_NOWAIT);
+ if (du == NULL)
+ continue;
+ if (wddrives[lunit] != NULL)
+ panic("drive attached twice");
+ wddrives[lunit] = du;
+ bzero(du, sizeof *du);
+ du->dk_ctrlr = dvp->id_unit;
+ du->dk_unit = unit;
+ du->dk_lunit = lunit;
+ du->dk_port = dvp->id_iobase;
+
+ /*
+ * Print out description of drive.
+ * wdp_model can be [0..40] bytes, thus \0 can be missing so
+ * so copy it and add a null before printing.
+ */
+ if (wdgetctlr(du) == 0) {
+ char buf[sizeof(du->dk_params.wdp_model) + 1];
+ bcopy(du->dk_params.wdp_model, buf, sizeof(buf)-1);
+ buf[sizeof(buf)-1] = '\0';
+ printf("wdc%d: unit %d (wd%d): <%s>\n",
+ dvp->id_unit, unit, lunit, buf);
+ if (du->dk_params.wdp_heads == 0)
+ printf("wd%d: size unknown\n", lunit);
+ else
+ printf("wd%d: %luMB (%lu total sec), ",
+ lunit,
+ du->dk_dd.d_secperunit
+ * du->dk_dd.d_secsize / (1024 * 1024),
+ du->dk_dd.d_secperunit);
+ printf("%lu cyl, %lu head, %lu sec, bytes/sec %lu\n",
+ du->dk_dd.d_ncylinders,
+ du->dk_dd.d_ntracks,
+ du->dk_dd.d_nsectors,
+ du->dk_dd.d_secsize);
+ /*
+ * Start timeout routine for this drive.
+ * XXX timeout should be per controller.
+ */
+ wdtimeout((caddr_t)du, 0);
+ } else {
+ free(du, M_TEMP);
+ wddrives[lunit] = NULL;
+ }
+ }
+
+ /*
+ * Discard any interrupts generated by wdgetctlr(). wdflushirq()
+ * doesn't work now because the ambient ipl is too high.
+ */
+ wdtab[dvp->id_unit].b_active = 2;
+
+ return (1);
+}
+
+/* Read/write routine for a buffer. Finds the proper unit, range checks
+ * arguments, and schedules the transfer. Does not wait for the transfer
+ * to complete. Multi-page transfers are supported. All I/O requests must
+ * be a multiple of a sector in length.
+ */
+void
+wdstrategy(register struct buf *bp)
+{
+ register struct buf *dp;
+ struct disk *du;
+ int lunit = wdunit(bp->b_dev);
+ int s;
+
+ /* valid unit, controller, and request? */
+ if (lunit >= NWD || bp->b_blkno < 0 || (du = wddrives[lunit]) == NULL) {
+
+ bp->b_error = EINVAL;
+ bp->b_flags |= B_ERROR;
+ goto done;
+ }
+
+ /* "soft" write protect check */
+ if ((du->dk_flags & DKFL_WRITEPROT) && (bp->b_flags & B_READ) == 0) {
+ bp->b_error = EROFS;
+ bp->b_flags |= B_ERROR;
+ goto done;
+ }
+
+ /*
+ * Do bounds checking, adjust transfer, and set b_cylin.
+ */
+ if (bounds_check_with_label(bp, wddospart(bp->b_dev)
+ ? &du->dk_dd2 : &du->dk_dd,
+ du->dk_wlabel) <= 0)
+ goto done;
+
+ /*
+ * Check for *any* block on this transfer being on the bad block list
+ * if it is, then flag the block as a transfer that requires
+ * bad block handling. Also, used as a hint for low level disksort
+ * clustering code to keep from coalescing a bad transfer into
+ * a normal transfer. Single block transfers for a large number of
+ * blocks associated with a cluster I/O are undersirable.
+ */
+ if( du->dk_flags & DKFL_BADSECT) {
+ int i;
+ int nsecs = howmany(bp->b_bcount, DEV_BSIZE);
+ int blkend = bp->b_pblkno + nsecs;
+ for(i=0;du->dk_badsect[i] != -1 && du->dk_badsect[i] < blkend;i++) {
+ if( du->dk_badsect[i] >= bp->b_pblkno) {
+ bp->b_flags |= B_BAD;
+ break;
+ }
+ }
+ }
+
+ /* queue transfer on drive, activate drive and controller if idle */
+ dp = &wdutab[lunit];
+ s = splbio();
+
+ cldisksort(dp, bp, 254*DEV_BSIZE);
+
+ if (dp->b_active == 0)
+ wdustart(du); /* start drive */
+
+ /* Pick up changes made by readdisklabel(). */
+ if (du->dk_flags & DKFL_LABELLING && du->dk_state > RECAL) {
+ wdsleep(du->dk_ctrlr, "wdlab");
+ du->dk_state = WANTOPEN;
+ }
+
+ if (wdtab[du->dk_ctrlr].b_active == 0)
+ wdstart(du->dk_ctrlr); /* start controller */
+ splx(s);
+ return;
+
+done:
+ s = splbio();
+ /* toss transfer, we're done early */
+ biodone(bp);
+ splx(s);
+}
+
+/*
+ * Routine to queue a command to the controller. The unit's
+ * request is linked into the active list for the controller.
+ * If the controller is idle, the transfer is started.
+ */
+static void
+wdustart(register struct disk *du)
+{
+ register struct buf *bp, *dp = &wdutab[du->dk_lunit];
+ int ctrlr = du->dk_ctrlr;
+
+ /* unit already active? */
+ if (dp->b_active)
+ return;
+
+ /* anything to start? */
+ bp = dp->b_actf;
+ if (bp == NULL)
+ return;
+
+ /* link onto controller queue */
+ dp->b_forw = NULL;
+ if (wdtab[ctrlr].b_actf == NULL)
+ wdtab[ctrlr].b_actf = dp;
+ else
+ wdtab[ctrlr].b_actl->b_forw = dp;
+ wdtab[ctrlr].b_actl = dp;
+
+ /* mark the drive unit as busy */
+ dp->b_active = 1;
+}
+
+/*
+ * Controller startup routine. This does the calculation, and starts
+ * a single-sector read or write operation. Called to start a transfer,
+ * or from the interrupt routine to continue a multi-sector transfer.
+ * RESTRICTIONS:
+ * 1. The transfer length must be an exact multiple of the sector size.
+ */
+
+static void
+wdstart(int ctrlr)
+{
+ register struct disk *du;
+ register struct buf *bp;
+ struct disklabel *lp;
+ struct buf *dp;
+ register struct bt_bad *bt_ptr;
+ long blknum, cylin, head, sector;
+ long secpertrk, secpercyl;
+ int lunit;
+
+loop:
+ /* is there a drive for the controller to do a transfer with? */
+ dp = wdtab[ctrlr].b_actf;
+ if (dp == NULL)
+ return;
+
+ /*
+ * Is there a transfer to this drive? If so, link it on the
+ * controller's queue.
+ */
+ bp = dp->b_actf;
+ if (bp == NULL) {
+ wdtab[ctrlr].b_actf = dp->b_forw;
+ goto loop;
+ }
+
+ /* obtain controller and drive information */
+ lunit = wdunit(bp->b_dev);
+ du = wddrives[lunit];
+
+ /* if not really a transfer, do control operations specially */
+ if (du->dk_state < OPEN) {
+ if (du->dk_state != WANTOPEN)
+ printf("wd%d: wdstart: weird dk_state %d\n",
+ du->dk_lunit, du->dk_state);
+ if (wdcontrol(bp) != 0)
+ printf("wd%d: wdstart: wdcontrol returned nonzero, state = %d\n",
+ du->dk_lunit, du->dk_state);
+ return;
+ }
+
+ /* calculate transfer details */
+ blknum = bp->b_pblkno + du->dk_skip;
+#ifdef WDDEBUG
+ if (du->dk_skip == 0)
+ printf("wd%d: wdstart: %s %d@%d; map ", lunit,
+ (bp->b_flags & B_READ) ? "read" : "write",
+ bp->b_bcount, blknum);
+ else
+ printf(" %d)%x", du->dk_skip, inb(du->dk_port + wd_altsts));
+#endif
+
+ lp = &du->dk_dd;
+ secpertrk = lp->d_nsectors;
+ secpercyl = lp->d_secpercyl;
+
+ if (du->dk_skip == 0) {
+ du->dk_bc = bp->b_bcount;
+ if (bp->b_flags & B_BAD) {
+ du->dk_flags |= DKFL_SINGLE;
+ }
+ }
+
+ if ((du->dk_flags & (DKFL_SINGLE|DKFL_BADSECT)) /* 19 Aug 92*/
+ == (DKFL_SINGLE|DKFL_BADSECT)) {
+ int i;
+
+ for(i=0;
+ du->dk_badsect[i] != -1 && du->dk_badsect[i] <= blknum;
+ i++) {
+
+ if( du->dk_badsect[i] == blknum) {
+ /*
+ * XXX the offset of the bad sector table ought
+ * to be stored in the in-core copy of the table.
+ */
+#define BAD144_PART 2 /* XXX scattered magic numbers */
+#define BSD_PART 0 /* XXX should be 2 but bad144.c uses 0 */
+ if (lp->d_partitions[BSD_PART].p_offset != 0)
+ blknum = lp->d_partitions[BAD144_PART].p_offset
+ + lp->d_partitions[BAD144_PART].p_size;
+ else
+ blknum = lp->d_secperunit;
+ blknum -= lp->d_nsectors + i + 1;
+
+ break;
+ }
+ }
+ }
+
+
+ cylin = blknum / secpercyl;
+ head = (blknum % secpercyl) / secpertrk;
+ sector = blknum % secpertrk;
+
+ wdtab[ctrlr].b_active = 1; /* mark controller active */
+
+ /* if starting a multisector transfer, or doing single transfers */
+ if (du->dk_skip == 0 || (du->dk_flags & DKFL_SINGLE)) {
+ u_int command;
+ u_int count;
+
+ if (wdtab[ctrlr].b_errcnt && (bp->b_flags & B_READ) == 0)
+ du->dk_bc += DEV_BSIZE;
+
+#ifdef B_FORMAT
+ if (bp->b_flags & B_FORMAT) {
+ command = WDCC_FORMAT;
+ count = lp->d_nsectors;
+ sector = lp->d_gap3 - 1; /* + 1 later */
+ } else
+#endif
+ {
+ if (du->dk_flags & DKFL_SINGLE)
+ count = 1;
+ else
+ count = howmany(du->dk_bc, DEV_BSIZE);
+ command = (bp->b_flags & B_READ)
+ ? WDCC_READ : WDCC_WRITE;
+ }
+
+ /*
+ * XXX this loop may never terminate. The code to handle
+ * counting down of retries and eventually failing the i/o
+ * is in wdintr() and we can't get there from here.
+ */
+ if (wdtest != 0) {
+ if (--wdtest == 0) {
+ wdtest = 100;
+ printf("dummy wdunwedge\n");
+ wdunwedge(du);
+ }
+ }
+ while (wdcommand(du, cylin, head, sector, count, command)
+ != 0) {
+ wderror(bp, du,
+ "wdstart: timeout waiting to give command");
+ wdunwedge(du);
+ }
+#ifdef WDDEBUG
+ printf("cylin %ld head %ld sector %ld addr %x sts %x\n",
+ cylin, head, sector,
+ (int)bp->b_un.b_addr + du->dk_skip * DEV_BSIZE,
+ inb(du->dk_port + wd_altsts));
+#endif
+ }
+
+ /*
+ * Schedule wdtimeout() to wake up after a few seconds. Retrying
+ * unmarked bad blocks can take 3 seconds! Then it is not good that
+ * we retry 5 times.
+ *
+ * XXX wdtimeout() doesn't increment the error count so we may loop
+ * forever. More seriously, the loop isn't forever but causes a
+ * crash.
+ *
+ * TODO fix b_resid bug elsewhere (fd.c....). Fix short but positive
+ * counts being discarded after there is an error (in physio I
+ * think). Discarding them would be OK if the (special) file offset
+ * was not advanced.
+ */
+ du->dk_timeout = 1 + 3;
+
+ /* If this is a read operation, just go away until it's done. */
+ if (bp->b_flags & B_READ)
+ return;
+
+ /* Ready to send data? */
+ if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT) < 0) {
+ wderror(bp, du, "wdstart: timeout waiting for DRQ");
+ /*
+ * XXX what do we do now? If we've just issued the command,
+ * then we can treat this failure the same as a command
+ * failure. But if we are continuing a multi-sector write,
+ * the command was issued ages ago, so we can't simply
+ * restart it.
+ *
+ * XXX we waste a lot of time unnecessarily translating block
+ * numbers to cylin/head/sector for continued i/o's.
+ */
+ }
+
+ /* then send it! */
+ outsw(du->dk_port + wd_data,
+ (void *)((int)bp->b_un.b_addr + du->dk_skip * DEV_BSIZE),
+ DEV_BSIZE / sizeof(short));
+ du->dk_bc -= DEV_BSIZE;
+}
+
+/* Interrupt routine for the controller. Acknowledge the interrupt, check for
+ * errors on the current operation, mark it done if necessary, and start
+ * the next request. Also check for a partially done transfer, and
+ * continue with the next chunk if so.
+ */
+void
+wdintr(int unit)
+{
+ register struct disk *du;
+ register struct buf *bp, *dp;
+
+ if (wdtab[unit].b_active == 2)
+ return; /* intr in wdflushirq() */
+ if (!wdtab[unit].b_active) {
+#ifndef LAPTOP
+ printf("wdc%d: extra interrupt\n", unit);
+#endif
+ return;
+ }
+
+ dp = wdtab[unit].b_actf;
+ bp = dp->b_actf;
+ du = wddrives[wdunit(bp->b_dev)];
+ du->dk_timeout = 0;
+
+ if (wdwait(du, 0, TIMEOUT) < 0) {
+ wderror(bp, du, "wdintr: timeout waiting for status");
+ du->dk_status |= WDCS_ERR; /* XXX */
+ }
+
+ /* is it not a transfer, but a control operation? */
+ if (du->dk_state < OPEN) {
+ wdtab[unit].b_active = 0;
+ switch (wdcontrol(bp)) {
+ case 0:
+ return;
+ case 1:
+ wdstart(unit);
+ return;
+ case 2:
+ goto done;
+ }
+ }
+
+ /* have we an error? */
+ if (du->dk_status & (WDCS_ERR | WDCS_ECCCOR)) {
+oops:
+#ifdef WDDEBUG
+ wderror(bp, du, "wdintr");
+#endif
+ if ((du->dk_flags & DKFL_SINGLE) == 0) {
+ du->dk_flags |= DKFL_ERROR;
+ goto outt;
+ }
+#ifdef B_FORMAT
+ if (bp->b_flags & B_FORMAT) {
+ bp->b_error = EIO;
+ bp->b_flags |= B_ERROR;
+ goto done;
+ }
+#endif
+
+ /* error or error correction? */
+ if (du->dk_status & WDCS_ERR) {
+ if (++wdtab[unit].b_errcnt < RETRIES) {
+ wdtab[unit].b_active = 0;
+ } else {
+ wderror(bp, du, "hard error");
+ bp->b_error = EIO;
+ bp->b_flags |= B_ERROR; /* flag the error */
+ }
+ } else
+ wderror(bp, du, "soft ecc");
+ }
+
+ /*
+ * If this was a successful read operation, fetch the data.
+ */
+ if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ)
+ && wdtab[unit].b_active) {
+ int chk, dummy;
+
+ chk = min(DEV_BSIZE / sizeof(short), du->dk_bc / sizeof(short));
+
+ /* ready to receive data? */
+ if ((du->dk_status & (WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ))
+ != (WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ))
+ wderror(bp, du, "wdintr: read intr arrived early");
+ if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT) != 0) {
+ wderror(bp, du, "wdintr: read error detected late");
+ goto oops;
+ }
+
+ /* suck in data */
+ insw(du->dk_port + wd_data,
+ (void *)((int)bp->b_un.b_addr + du->dk_skip * DEV_BSIZE),
+ chk);
+ du->dk_bc -= chk * sizeof(short);
+
+ /* XXX for obsolete fractional sector reads. */
+ while (chk++ < DEV_BSIZE / sizeof(short))
+ insw(du->dk_port + wd_data, &dummy, 1);
+ }
+
+ wdxfer[du->dk_lunit]++;
+outt:
+ if (wdtab[unit].b_active) {
+ if ((bp->b_flags & B_ERROR) == 0) {
+ du->dk_skip++; /* add to successful sectors */
+ if (wdtab[unit].b_errcnt)
+ wderror(bp, du, "soft error");
+ wdtab[unit].b_errcnt = 0;
+
+ /* see if more to transfer */
+ if (du->dk_bc > 0 && (du->dk_flags & DKFL_ERROR) == 0) {
+ wdtab[unit].b_active = 0;
+ wdstart(unit);
+ return; /* next chunk is started */
+ } else if ((du->dk_flags & (DKFL_SINGLE | DKFL_ERROR))
+ == DKFL_ERROR) {
+ du->dk_skip = 0;
+ du->dk_flags &= ~DKFL_ERROR;
+ du->dk_flags |= DKFL_SINGLE;
+ wdtab[unit].b_active = 0;
+ wdstart(unit);
+ return; /* redo xfer sector by sector */
+ }
+ }
+
+done: ;
+ /* done with this transfer, with or without error */
+ du->dk_flags &= ~DKFL_SINGLE;
+ wdtab[unit].b_actf = dp->b_forw;
+ wdtab[unit].b_errcnt = 0;
+ bp->b_resid = bp->b_bcount - du->dk_skip * DEV_BSIZE;
+ du->dk_skip = 0;
+ dp->b_active = 0;
+ dp->b_actf = bp->av_forw;
+ dp->b_errcnt = 0;
+ biodone(bp);
+ }
+
+ /* controller idle */
+ wdtab[unit].b_active = 0;
+
+ /* anything more on drive queue? */
+ if (dp->b_actf)
+ wdustart(du);
+ /* anything more for controller to do? */
+ if (wdtab[unit].b_actf)
+ wdstart(unit);
+}
+
+/*
+ * Initialize a drive.
+ */
+int
+wdopen(dev_t dev, int flags, int fmt, struct proc *p)
+{
+ register unsigned int lunit;
+ register struct disk *du;
+ int part = wdpart(dev), mask = 1 << part;
+ struct partition *pp;
+ char *msg;
+ struct disklabel save_label;
+
+ lunit = wdunit(dev);
+ if (lunit >= NWD)
+ return (ENXIO);
+ du = wddrives[lunit];
+ if (du == NULL)
+ return (ENXIO);
+
+ /* Finish flushing IRQs left over from wdattach(). */
+ if (wdtab[du->dk_ctrlr].b_active == 2)
+ wdtab[du->dk_ctrlr].b_active = 0;
+
+ /*
+ * That's all for valid DOS partitions. We don't need a BSD label.
+ * The openmask is only used for checking BSD partitions so we don't
+ * need to maintain it.
+ */
+ if (wddospart(dev)) {
+ /* XXX we do need a disklabel for now. */
+ if ((du->dk_flags & DKFL_BSDLABEL) == 0)
+ return (ENXIO);
+
+ return (part > NDOSPART ? ENXIO : 0);
+ }
+
+ while (du->dk_flags & DKFL_LABELLING)
+ tsleep((caddr_t)&du->dk_flags, PZERO - 1, "wdopen", 1);
+ if ((du->dk_flags & DKFL_BSDLABEL) == 0) {
+ /*
+ * wdtab[ctrlr].b_active != 0 implies
+ * wdutab[lunit].b_actf == NULL (?)
+ * so the following guards most things (until the next i/o).
+ * It doesn't guard against a new i/o starting and being
+ * affected by the label being changed. Sigh.
+ */
+ wdsleep(du->dk_ctrlr, "wdopn1");
+
+ du->dk_flags |= DKFL_LABELLING | DKFL_WRITEPROT;
+ du->dk_state = WANTOPEN;
+ wdutab[lunit].b_actf = NULL;
+
+ /*
+ * Read label using WDRAW partition.
+ *
+ * If the drive has an MBR, then the current geometry (from
+ * wdgetctlr()) is used to read it; then the BIOS/DOS
+ * geometry is inferred and used to read the label off the
+ * 'c' partition. Otherwise the label is read using the
+ * current geometry. The label gives the final geometry.
+ * If bad sector handling is enabled, then this geometry
+ * is used to read the bad sector table. The geometry
+ * changes occur inside readdisklabel() and are propagated
+ * to the driver by resetting the state machine.
+ */
+ save_label = du->dk_dd;
+#define WDSTRATEGY ((int (*)(struct buf *)) wdstrategy) /* XXX */
+ msg = readdisklabel(makewddev(major(dev), lunit, WDRAW),
+ (d_strategy_t *) WDSTRATEGY, &du->dk_dd,
+ du->dk_dospartitions, &du->dk_bad,
+ (struct buf **)NULL);
+ du->dk_flags &= ~DKFL_LABELLING;
+ if (msg != NULL) {
+ du->dk_dd = save_label;
+ log(LOG_WARNING, "wd%d: cannot find label (%s)\n",
+ lunit, msg);
+ if (part != WDRAW)
+ return (EINVAL); /* XXX needs translation */
+ } else {
+ int dospart;
+ unsigned long newsize, offset, size;
+
+ du->dk_flags |= DKFL_BSDLABEL;
+ du->dk_flags &= ~DKFL_WRITEPROT;
+ if (du->dk_dd.d_flags & D_BADSECT) {
+ du->dk_flags |= DKFL_BADSECT;
+ bad144intern(du);
+ }
+
+ /*
+ * Force WDRAW partition to be the whole disk.
+ */
+ offset = du->dk_dd.d_partitions[WDRAW].p_offset;
+ if (offset != 0) {
+ printf(
+ "wd%d: changing offset of 'd' partition from %lu to 0\n",
+ du->dk_lunit, offset);
+ du->dk_dd.d_partitions[WDRAW].p_offset = 0;
+ }
+ size = du->dk_dd.d_partitions[WDRAW].p_size;
+ newsize = du->dk_dd.d_secperunit; /* XXX */
+ if (size != newsize) {
+ printf(
+ "wd%d: changing size of 'd' partition from %lu to %lu\n",
+ du->dk_lunit, size, newsize);
+ du->dk_dd.d_partitions[WDRAW].p_size = newsize;
+ }
+
+ /*
+ * Convert DOS partition data to a label.
+ */
+ du->dk_dd2 = du->dk_dd;
+ bzero(du->dk_dd2.d_partitions,
+ sizeof du->dk_dd2.d_partitions);
+ du->dk_dd2.d_partitions[0].p_size
+ = du->dk_dd.d_secperunit; /* XXX */
+ for (dospart = 1; dospart <= NDOSPART; dospart++) {
+ du->dk_dd2.d_partitions[dospart].p_offset =
+ du->dk_dospartitions[dospart - 1].dp_start;
+ du->dk_dd2.d_partitions[dospart].p_size =
+ du->dk_dospartitions[dospart - 1].dp_size;
+ }
+ }
+
+ /* Pick up changes made by readdisklabel(). */
+ wdsleep(du->dk_ctrlr, "wdopn2");
+ du->dk_state = WANTOPEN;
+ }
+
+ /*
+ * Warn if a partion is opened that overlaps another partition which
+ * is open unless one is the "raw" partition (whole disk).
+ */
+ if ((du->dk_openpart & mask) == 0 && part != WDRAW) {
+ int start, end;
+
+ pp = &du->dk_dd.d_partitions[part];
+ start = pp->p_offset;
+ end = pp->p_offset + pp->p_size;
+ for (pp = du->dk_dd.d_partitions;
+ pp < &du->dk_dd.d_partitions[du->dk_dd.d_npartitions];
+ pp++) {
+ if (pp->p_offset + pp->p_size <= start ||
+ pp->p_offset >= end)
+ continue;
+ if (pp - du->dk_dd.d_partitions == WDRAW)
+ continue;
+ if (du->dk_openpart
+ & (1 << (pp - du->dk_dd.d_partitions)))
+ log(LOG_WARNING,
+ "wd%d%c: overlaps open partition (%c)\n",
+ lunit, part + 'a',
+ pp - du->dk_dd.d_partitions + 'a');
+ }
+ }
+ if (part >= du->dk_dd.d_npartitions && part != WDRAW)
+ return (ENXIO);
+
+ switch (fmt) {
+ case S_IFCHR:
+ du->dk_copenpart |= mask;
+ break;
+ case S_IFBLK:
+ du->dk_bopenpart |= mask;
+ break;
+ }
+ du->dk_openpart = du->dk_copenpart | du->dk_bopenpart;
+
+ return (0);
+}
+
+/*
+ * Implement operations other than read/write.
+ * Called from wdstart or wdintr during opens and formats.
+ * Uses finite-state-machine to track progress of operation in progress.
+ * Returns 0 if operation still in progress, 1 if completed, 2 if error.
+ */
+static int
+wdcontrol(register struct buf *bp)
+{
+ register struct disk *du;
+ int ctrlr;
+
+ du = wddrives[wdunit(bp->b_dev)];
+ ctrlr = du->dk_ctrlr;
+
+ switch (du->dk_state) {
+ case WANTOPEN:
+tryagainrecal:
+ wdtab[ctrlr].b_active = 1;
+ if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0) {
+ wderror(bp, du, "wdcontrol: wdcommand failed");
+ goto maybe_retry;
+ }
+ du->dk_state = RECAL;
+ return (0);
+ case RECAL:
+ if (du->dk_status & WDCS_ERR || wdsetctlr(du) != 0) {
+ wderror(bp, du, "wdcontrol: recal failed");
+maybe_retry:
+ if (du->dk_status & WDCS_ERR)
+ wdunwedge(du);
+ du->dk_state = WANTOPEN;
+ if (++wdtab[ctrlr].b_errcnt < RETRIES)
+ goto tryagainrecal;
+ bp->b_error = ENXIO; /* XXX needs translation */
+ bp->b_flags |= B_ERROR;
+ return (2);
+ }
+ wdtab[ctrlr].b_errcnt = 0;
+ du->dk_state = OPEN;
+ /*
+ * The rest of the initialization can be done by normal
+ * means.
+ */
+ return (1);
+ }
+ panic("wdcontrol");
+ return (2);
+}
+
+/*
+ * Wait uninterruptibly until controller is not busy, then send it a command.
+ * The wait usually terminates immediately because we waited for the previous
+ * command to terminate.
+ */
+static int
+wdcommand(struct disk *du, u_int cylinder, u_int head, u_int sector,
+ u_int count, u_int command)
+{
+ u_int wdc;
+
+ if (wdwait(du, 0, TIMEOUT) < 0)
+ return (1);
+ wdc = du->dk_port;
+ outb(wdc + wd_precomp, du->dk_dd.d_precompcyl / 4);
+ outb(wdc + wd_cyl_lo, cylinder);
+ outb(wdc + wd_cyl_hi, cylinder >> 8);
+ outb(wdc + wd_sdh, WDSD_IBM | (du->dk_unit << 4) | head);
+ outb(wdc + wd_sector, sector + 1);
+ outb(wdc + wd_seccnt, count);
+ if (wdwait(du, command == WDCC_DIAGNOSE || command == WDCC_IDC
+ ? 0 : WDCS_READY, TIMEOUT) < 0)
+ return (1);
+ outb(wdc + wd_command, command);
+ return (0);
+}
+
+/*
+ * issue IDC to drive to tell it just what geometry it is to be.
+ */
+static int
+wdsetctlr(struct disk *du)
+{
+ int error = 0;
+#ifdef WDDEBUG
+ printf("wd(%d,%d): wdsetctlr: C %lu H %lu S %lu\n",
+ du->dk_ctrlr, du->dk_unit,
+ du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks,
+ du->dk_dd.d_nsectors);
+#endif
+ if (du->dk_dd.d_ntracks == 0 || du->dk_dd.d_ntracks > 16) {
+ struct wdparams *wp;
+
+ printf("wd%d: can't handle %lu heads from partition table ",
+ du->dk_lunit, du->dk_dd.d_ntracks);
+ /* obtain parameters */
+ wp = &du->dk_params;
+ if (wp->wdp_heads > 0 && wp->wdp_heads <= 16) {
+ printf("(controller value %lu restored)\n",
+ wp->wdp_heads);
+ du->dk_dd.d_ntracks = wp->wdp_heads;
+ }
+ else {
+ printf("(truncating to 16)\n");
+ du->dk_dd.d_ntracks = 16;
+ }
+ }
+
+ if (du->dk_dd.d_nsectors == 0 || du->dk_dd.d_nsectors > 255) {
+ printf("wd%d: cannot handle %lu sectors (max 255)\n",
+ du->dk_lunit, du->dk_dd.d_nsectors);
+ error = 1;
+ }
+ if (error) {
+ wdtab[du->dk_ctrlr].b_errcnt += RETRIES;
+ return (1);
+ }
+ if (wdcommand(du, du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks - 1, 0,
+ du->dk_dd.d_nsectors, WDCC_IDC) != 0
+ || wdwait(du, WDCS_READY, TIMEOUT) < 0) {
+ wderror((struct buf *)NULL, du, "wdsetctlr failed");
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Wait until driver is inactive, then set up controller.
+ */
+static int
+wdwsetctlr(struct disk *du)
+{
+ int stat;
+ int x;
+
+ wdsleep(du->dk_ctrlr, "wdwset");
+ x = splbio();
+ stat = wdsetctlr(du);
+ wdflushirq(du, x);
+ splx(x);
+ return (stat);
+}
+
+/*
+ * issue READP to drive to ask it what it is.
+ */
+static int
+wdgetctlr(struct disk *du)
+{
+ int i;
+ char tb[DEV_BSIZE];
+ struct wdparams *wp;
+
+ if (wdcommand(du, 0, 0, 0, 0, WDCC_READP) != 0
+ || wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT) != 0) {
+ /* XXX need to check error status after final transfer. */
+ /*
+ * Old drives don't support WDCC_READP. Try a seek to 0.
+ * Some IDE controllers return trash if there is no drive
+ * attached, so first test that the drive can be selected.
+ * This also avoids long waits for nonexistent drives.
+ */
+ if (wdwait(du, 0, TIMEOUT) < 0)
+ return (1);
+ outb(du->dk_port + wd_sdh, WDSD_IBM | (du->dk_unit << 4));
+ DELAY(5000); /* usually unnecessary; drive select is fast */
+ if ((inb(du->dk_port + wd_status) & (WDCS_BUSY | WDCS_READY))
+ != WDCS_READY
+ || wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0
+ || wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0)
+ return (1);
+
+ /*
+ * Fake minimal drive geometry for reading the MBR.
+ * readdisklabel() may enlarge it to read the label and the
+ * bad sector table.
+ */
+ du->dk_dd.d_secsize = DEV_BSIZE;
+ du->dk_dd.d_nsectors = 17;
+ du->dk_dd.d_ntracks = 1;
+ du->dk_dd.d_ncylinders = 1;
+ du->dk_dd.d_secpercyl = 17;
+ du->dk_dd.d_secperunit = 17;
+
+ /*
+ * Fake maximal drive size for writing the label.
+ */
+ du->dk_dd.d_partitions[WDRAW].p_size = 64 * 16 * 1024;
+
+ /*
+ * Fake some more of the label for printing by disklabel(1)
+ * in case there is no real label.
+ */
+ du->dk_dd.d_type = DTYPE_ST506;
+ du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
+ strncpy(du->dk_dd.d_typename, "Fake geometry",
+ sizeof du->dk_dd.d_typename);
+
+ /* Fake the model name for printing by wdattach(). */
+ strncpy(du->dk_params.wdp_model, "unknown",
+ sizeof du->dk_params.wdp_model);
+
+ return (0);
+ }
+
+ /* obtain parameters */
+ wp = &du->dk_params;
+ insw(du->dk_port + wd_data, tb, sizeof(tb) / sizeof(short));
+ bcopy(tb, wp, sizeof(struct wdparams));
+
+ /* shuffle string byte order */
+ for (i = 0; i < sizeof(wp->wdp_model); i += 2) {
+ u_short *p;
+
+ p = (u_short *) (wp->wdp_model + i);
+ *p = ntohs(*p);
+ }
+ /*
+ * Clean up the wdp_model by converting nulls to spaces, and
+ * then removing the trailing spaces.
+ */
+ for (i=0; i < sizeof(wp->wdp_model); i++) {
+ if (wp->wdp_model[i] == '\0') {
+ wp->wdp_model[i] = ' ';
+ }
+ }
+ for (i=sizeof(wp->wdp_model)-1; i>=0 && wp->wdp_model[i]==' '; i--) {
+ wp->wdp_model[i] = '\0';
+ }
+
+#ifdef WDDEBUG
+ printf(
+"\nwd(%d,%d): wdgetctlr: gc %x cyl %d trk %d sec %d type %d sz %d model %s\n",
+ du->dk_ctrlr, du->dk_unit, wp->wdp_config,
+ wp->wdp_fixedcyl + wp->wdp_removcyl, wp->wdp_heads,
+ wp->wdp_sectors, wp->wdp_cntype, wp->wdp_cnsbsz,
+ wp->wdp_model);
+#endif
+
+ /* update disklabel given drive information */
+ du->dk_dd.d_secsize = DEV_BSIZE;
+ du->dk_dd.d_ncylinders = wp->wdp_fixedcyl + wp->wdp_removcyl /*+- 1*/ ;
+ du->dk_dd.d_ntracks = wp->wdp_heads;
+ du->dk_dd.d_nsectors = wp->wdp_sectors;
+ du->dk_dd.d_secpercyl = du->dk_dd.d_ntracks * du->dk_dd.d_nsectors;
+ du->dk_dd.d_partitions[WDRAW].p_size = du->dk_dd.d_secperunit
+ = du->dk_dd.d_secpercyl * du->dk_dd.d_ncylinders;
+ /* dubious ... */
+ bcopy("ESDI/IDE", du->dk_dd.d_typename, 9);
+ bcopy(wp->wdp_model + 20, du->dk_dd.d_packname, 14 - 1);
+ /* better ... */
+ du->dk_dd.d_type = DTYPE_ESDI;
+ du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
+
+ return (0);
+}
+
+
+/* ARGSUSED */
+int
+wdclose(dev_t dev, int flags, int fmt)
+{
+ register struct disk *du;
+ int part = wdpart(dev), mask = 1 << part;
+
+ if (wddospart(dev))
+ return (0);
+
+ du = wddrives[wdunit(dev)];
+
+ switch (fmt) {
+ case S_IFCHR:
+ du->dk_copenpart &= ~mask;
+ break;
+ case S_IFBLK:
+ du->dk_bopenpart &= ~mask;
+ break;
+ }
+ du->dk_openpart = du->dk_copenpart | du->dk_bopenpart;
+
+ return (0);
+}
+
+int
+wdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
+{
+ int lunit = wdunit(dev);
+ register struct disk *du;
+ int error = 0;
+#ifdef notyet
+ struct uio auio;
+ struct iovec aiov;
+#endif
+
+ du = wddrives[lunit];
+
+ switch (cmd) {
+
+ case DIOCSBAD:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else
+ du->dk_bad = *(struct dkbad *)addr;
+ break;
+
+ case DIOCGDINFO:
+ *(struct disklabel *)addr = du->dk_dd;
+ break;
+
+ case DIOCGPART:
+ if (wddospart(dev))
+ return (EINVAL);
+ ((struct partinfo *)addr)->disklab = &du->dk_dd;
+ ((struct partinfo *)addr)->part =
+ &du->dk_dd.d_partitions[wdpart(dev)];
+ break;
+
+ case DIOCSDINFO:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else
+ error = setdisklabel(&du->dk_dd,
+ (struct disklabel *)addr,
+#if 0
+ /*
+ * XXX setdisklabel() uses the
+ * openmask to allow it to reject
+ * changing open partitions. Why
+ * are we pretending nothing is
+ * open?
+ */
+ du->dk_flags & DKFL_BSDLABEL
+ ? du->dk_openpart :
+#endif
+ 0,
+ du->dk_dospartitions);
+ if (error == 0) {
+ du->dk_flags |= DKFL_BSDLABEL;
+ wdwsetctlr(du); /* XXX - check */
+ }
+ break;
+
+ case DIOCWLABEL:
+ du->dk_flags &= ~DKFL_WRITEPROT;
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else
+ du->dk_wlabel = *(int *)addr;
+ break;
+
+ case DIOCWDINFO:
+ du->dk_flags &= ~DKFL_WRITEPROT;
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else if ((error = setdisklabel(&du->dk_dd,
+ (struct disklabel *)addr,
+#if 0
+ du->dk_flags & DKFL_BSDLABEL
+ ? du->dk_openpart :
+#endif
+ 0,
+ du->dk_dospartitions)) == 0) {
+ int wlab;
+
+ du->dk_flags |= DKFL_BSDLABEL;
+ wdwsetctlr(du); /* XXX - check */
+
+ /* simulate opening partition 0 so write succeeds */
+ du->dk_openpart |= (1 << 0); /* XXX */
+ wlab = du->dk_wlabel;
+ du->dk_wlabel = 1;
+ error = writedisklabel(dev, (d_strategy_t *) WDSTRATEGY,
+ &du->dk_dd, du->dk_dospartitions);
+ du->dk_openpart = du->dk_copenpart | du->dk_bopenpart;
+ du->dk_wlabel = wlab;
+ }
+ break;
+
+#ifdef notyet
+ case DIOCGDINFOP:
+ *(struct disklabel **)addr = &(du->dk_dd);
+ break;
+
+ case DIOCWFORMAT:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else {
+ register struct format_op *fop;
+
+ fop = (struct format_op *)addr;
+ aiov.iov_base = fop->df_buf;
+ aiov.iov_len = fop->df_count;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_resid = fop->df_count;
+ auio.uio_segflg = 0;
+ auio.uio_offset =
+ fop->df_startblk * du->dk_dd.d_secsize;
+#error /* XXX the 386BSD interface is different */
+ error = physio(wdformat, &rwdbuf[lunit], 0, dev,
+ B_WRITE, minphys, &auio);
+ fop->df_count -= auio.uio_resid;
+ fop->df_reg[0] = du->dk_status;
+ fop->df_reg[1] = du->dk_error;
+ }
+ break;
+#endif
+
+ default:
+ error = ENOTTY;
+ break;
+ }
+ return (error);
+}
+
+#ifdef B_FORMAT
+int
+wdformat(struct buf *bp)
+{
+
+ bp->b_flags |= B_FORMAT;
+ return (wdstrategy(bp));
+}
+#endif
+
+int
+wdsize(dev_t dev)
+{
+ int lunit = wdunit(dev), part = wdpart(dev), val;
+ struct disk *du;
+
+ if (lunit >= NWD || wddospart(dev) || (du = wddrives[lunit]) == NULL)
+ return (-1);
+ val = 0;
+ if (du->dk_state == CLOSED)
+ val = wdopen(makewddev(major(dev), lunit, WDRAW),
+ FREAD, S_IFBLK, 0);
+ if (val != 0 || du->dk_flags & DKFL_WRITEPROT)
+ return (-1);
+ return ((int)du->dk_dd.d_partitions[part].p_size);
+}
+
+extern char *vmmap; /* poor name! */
+
+/*
+ * Dump core after a system crash.
+ */
+int
+wddump(dev_t dev)
+{
+ register struct disk *du;
+ register struct bt_bad *bt_ptr;
+ struct disklabel *lp;
+ long num; /* number of sectors to write */
+ int lunit, part;
+ long blkoff, blknum;
+ long blkchk, blkcnt, blknext;
+ long cylin, head, sector;
+ long secpertrk, secpercyl, nblocks;
+ char *addr;
+ extern int Maxmem;
+ static int wddoingadump = 0;
+ extern caddr_t CADDR1;
+
+ /* Toss any characters present prior to dump. */
+ while (sgetc(1))
+ ;
+
+ /* Check for acceptable device. */
+ /* XXX should reset to maybe allow du->dk_state < OPEN. */
+ lunit = wdunit(dev); /* eventually support floppies? */
+ part = wdpart(dev);
+ if (lunit >= NWD || wddospart(dev) || (du = wddrives[lunit]) == NULL
+ || du->dk_state < OPEN || du->dk_flags & DKFL_WRITEPROT)
+ return (ENXIO);
+
+ /* Size of memory to dump, in disk sectors. */
+ num = (u_long)Maxmem * NBPG / du->dk_dd.d_secsize;
+
+ secpertrk = du->dk_dd.d_nsectors;
+ secpercyl = du->dk_dd.d_secpercyl;
+ nblocks = du->dk_dd.d_partitions[part].p_size;
+ blkoff = du->dk_dd.d_partitions[part].p_offset;
+
+#if 0
+ pg("part %x, nblocks %d, dumplo %d num %d\n",
+ part, nblocks, dumplo, num);
+#endif
+
+ /* Check transfer bounds against partition size. */
+ if (dumplo < 0 || dumplo + num > nblocks)
+ return (EINVAL);
+
+ /* Check if we are being called recursively. */
+ if (wddoingadump)
+ return (EFAULT);
+
+#if 0
+ /* Mark controller active for if we panic during the dump. */
+ wdtab[du->dk_ctrlr].b_active = 1;
+#endif
+ wddoingadump = 1;
+
+ /* Recalibrate the drive. */
+ DELAY(5); /* ATA spec XXX NOT */
+ if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) != 0
+ || wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0
+ || wdsetctlr(du) != 0) {
+ wderror((struct buf *)NULL, du, "wddump: recalibrate failed");
+ return (EIO);
+ }
+
+ du->dk_flags |= DKFL_SINGLE;
+ addr = (char *) 0;
+ blknum = dumplo + blkoff;
+ while (num > 0) {
+ blkcnt = num;
+ if (blkcnt > MAXTRANSFER)
+ blkcnt = MAXTRANSFER;
+ /* Keep transfer within current cylinder. */
+ if ((blknum + blkcnt - 1) / secpercyl != blknum / secpercyl)
+ blkcnt = secpercyl - (blknum % secpercyl);
+ blknext = blknum + blkcnt;
+
+ /*
+ * See if one of the sectors is in the bad sector list
+ * (if we have one). If the first sector is bad, then
+ * reduce the transfer to this one bad sector; if another
+ * sector is bad, then reduce reduce the transfer to
+ * avoid any bad sectors.
+ */
+ if ((du->dk_flags & (DKFL_SINGLE | DKFL_BADSECT))
+ == (DKFL_SINGLE | DKFL_BADSECT))
+ for (blkchk = blknum; blkchk < blknum + blkcnt; blkchk++) {
+ cylin = blkchk / secpercyl;
+ head = (blkchk % secpercyl) / secpertrk;
+ sector = blkchk % secpertrk;
+ for (bt_ptr = du->dk_bad.bt_bad;
+ bt_ptr->bt_cyl != BAD144_NO_CYL; bt_ptr++) {
+ if (bt_ptr->bt_cyl > cylin)
+ /*
+ * Sorted list, and we passed our cylinder.
+ * quit.
+ */
+ break;
+ if (bt_ptr->bt_cyl == cylin &&
+ bt_ptr->bt_trksec == (head << 8) + sector) {
+ /* Found bad block. */
+ blkcnt = blkchk - blknum;
+ if (blkcnt > 0) {
+ blknext = blknum + blkcnt;
+ goto out;
+ }
+ blkcnt = 1;
+ blknext = blknum + blkcnt;
+ /*
+ * Found bad block. Calculate new block number.
+ * This starts at the end of the disk (skip the
+ * last track which is used for the bad block list),
+ * and works backwards to the front of the disk.
+ */
+ /* XXX as usual. */
+#ifdef WDDEBUG
+ printf("--- badblock code -> Old = %ld; ",
+ blknum);
+#endif
+ lp = &du->dk_dd;
+ if (lp->d_partitions[BSD_PART].p_offset != 0)
+ blknum = lp->d_partitions[BAD144_PART]
+ .p_offset
+ + lp->d_partitions[BAD144_PART]
+ .p_size;
+ else
+ blknum = lp->d_secperunit;
+ blknum -= lp->d_nsectors
+ + (bt_ptr - du->dk_bad.bt_bad) + 1;
+#ifdef WDDEBUG
+ printf("new = %ld\n", blknum);
+#endif
+ break;
+ }
+ }
+ }
+out:
+
+ /* Compute disk address. */
+ cylin = blknum / secpercyl;
+ head = (blknum % secpercyl) / secpertrk;
+ sector = blknum % secpertrk;
+
+#if 0
+ /* Let's just talk about this first... */
+ pg("cylin l%d head %ld sector %ld addr 0x%x count %ld",
+ cylin, head, sector, addr, blkcnt);
+#endif
+
+ /* Do the write. */
+ if (wdcommand(du, cylin, head, sector, blkcnt, WDCC_WRITE)
+ != 0) {
+ wderror((struct buf *)NULL, du,
+ "wddump: timeout waiting to to give command");
+ return (EIO);
+ }
+ while (blkcnt != 0) {
+ pmap_enter(kernel_pmap, CADDR1, trunc_page(addr),
+ VM_PROT_READ, TRUE);
+
+ /* Ready to send data? */
+ DELAY(5); /* ATA spec */
+ if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ, TIMEOUT)
+ < 0) {
+ wderror((struct buf *)NULL, du,
+ "wddump: timeout waiting for DRQ");
+ return (EIO);
+ }
+ outsw(du->dk_port + wd_data,
+ CADDR1 + ((int)addr & (NBPG - 1)),
+ DEV_BSIZE / sizeof(short));
+ addr += DEV_BSIZE;
+ if ((unsigned)addr % (1024 * 1024) == 0)
+ printf("%ld ", num / (1024 * 1024 / DEV_BSIZE));
+ num--;
+ blkcnt--;
+ }
+
+ /* Wait for completion. */
+ DELAY(5); /* ATA spec XXX NOT */
+ if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) < 0) {
+ wderror((struct buf *)NULL, du,
+ "wddump: timeout waiting for status");
+ return (EIO);
+ }
+
+ /* Check final status. */
+ if (du->dk_status
+ & (WDCS_READY | WDCS_SEEKCMPLT | WDCS_DRQ | WDCS_ERR)
+ != (WDCS_READY | WDCS_SEEKCMPLT)) {
+ wderror((struct buf *)NULL, du,
+ "wddump: extra DRQ, or error");
+ return (EIO);
+ }
+
+ /* Update block count. */
+ blknum = blknext;
+
+ /* Operator aborting dump? */
+ if (sgetc(1) & 0xff) /* EWS: A hack to work with syscons */
+ return (EINTR);
+ }
+ return (0);
+}
+
+static void
+wderror(struct buf *bp, struct disk *du, char *mesg)
+{
+ if (bp == NULL)
+ printf("wd%d: %s:\n", du->dk_lunit, mesg);
+ else
+ diskerr(bp, "wd", mesg, LOG_PRINTF, du->dk_skip, &du->dk_dd);
+ printf("wd%d: status %b error %b\n", du->dk_lunit,
+ du->dk_status, WDCS_BITS, du->dk_error, WDERR_BITS);
+}
+
+/*
+ * Discard any interrupts that were latched by the interrupt system while
+ * we were doing polled i/o.
+ */
+static void
+wdflushirq(struct disk *du, int old_ipl)
+{
+ wdtab[du->dk_ctrlr].b_active = 2;
+ splx(old_ipl);
+ (void)splbio();
+ wdtab[du->dk_ctrlr].b_active = 0;
+}
+
+/*
+ * Reset the controller.
+ */
+static int
+wdreset(struct disk *du)
+{
+ int wdc;
+
+ wdc = du->dk_port;
+ (void)wdwait(du, 0, TIMEOUT);
+ outb(wdc + wd_ctlr, WDCTL_IDS | WDCTL_RST);
+ DELAY(10 * 1000);
+ outb(wdc + wd_ctlr, WDCTL_IDS);
+ if (wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) != 0
+ || (du->dk_error = inb(wdc + wd_error)) != 0x01)
+ return (1);
+ outb(wdc + wd_ctlr, WDCTL_4BIT);
+ return (0);
+}
+
+/*
+ * Sleep until driver is inactive.
+ * This is used only for avoiding rare race conditions, so it is unimportant
+ * that the sleep may be far too short or too long.
+ */
+static void
+wdsleep(int ctrlr, char *wmesg)
+{
+ while (wdtab[ctrlr].b_active)
+ tsleep((caddr_t)&wdtab[ctrlr].b_active, PZERO - 1, wmesg, 1);
+}
+
+static void
+wdtimeout(caddr_t cdu, int ticks)
+{
+ struct disk *du;
+ int x;
+
+ du = (struct disk *)cdu;
+ x = splbio();
+ if (du->dk_timeout != 0 && --du->dk_timeout == 0) {
+ wderror((struct buf *)NULL, du, "interrupt timeout");
+ wdunwedge(du);
+ wdflushirq(du, x);
+ du->dk_skip = 0;
+ du->dk_flags |= DKFL_SINGLE;
+ wdstart(du->dk_ctrlr);
+ }
+ timeout(wdtimeout, cdu, hz);
+ splx(x);
+}
+
+/*
+ * Reset the controller after it has become wedged. This is different from
+ * wdreset() so that wdreset() can be used in the probe and so that this
+ * can restore the geometry .
+ */
+static int
+wdunwedge(struct disk *du)
+{
+ struct disk *du1;
+ int lunit;
+
+ /* Schedule other drives for recalibration. */
+ for (lunit = 0; lunit < NWD; lunit++)
+ if ((du1 = wddrives[lunit]) != NULL && du1 != du
+ && du1->dk_ctrlr == du->dk_ctrlr
+ && du1->dk_state > WANTOPEN)
+ du1->dk_state = WANTOPEN;
+
+ DELAY(RECOVERYTIME);
+ if (wdreset(du) == 0) {
+ /*
+ * XXX - recalibrate current drive now because some callers
+ * aren't prepared to have its state change.
+ */
+ if (wdcommand(du, 0, 0, 0, 0, WDCC_RESTORE | WD_STEP) == 0
+ && wdwait(du, WDCS_READY | WDCS_SEEKCMPLT, TIMEOUT) == 0
+ && wdsetctlr(du) == 0)
+ return (0);
+ }
+ wderror((struct buf *)NULL, du, "wdunwedge failed");
+ return (1);
+}
+
+/*
+ * Wait uninterruptibly until controller is not busy and either certain
+ * status bits are set or an error has occurred.
+ * The wait is usually short unless it is for the controller to process
+ * an entire critical command.
+ * Return 1 for (possibly stale) controller errors, -1 for timeout errors,
+ * or 0 for no errors.
+ * Return controller status in du->dk_status and, if there was a controller
+ * error, return the error code in du->dk_error.
+ */
+#ifdef WD_COUNT_RETRIES
+static int min_retries[NWDC];
+#endif
+
+static int
+wdwait(struct disk *du, u_char bits_wanted, int timeout)
+{
+ int wdc;
+ u_char status;
+
+#define POLLING 1000
+
+ wdc = du->dk_port;
+ timeout += POLLING;
+ do {
+#ifdef WD_COUNT_RETRIES
+ if (min_retries[du->dk_ctrlr] > timeout
+ || min_retries[du->dk_ctrlr] == 0)
+ min_retries[du->dk_ctrlr] = timeout;
+#endif
+ DELAY(5); /* ATA spec XXX NOT */
+ du->dk_status = status = inb(wdc + wd_status);
+ if (!(status & WDCS_BUSY)) {
+ if (status & WDCS_ERR) {
+ du->dk_error = inb(wdc + wd_error);
+ /*
+ * We once returned here. This is wrong
+ * because the error bit is apparently only
+ * valid after the controller has interrupted
+ * (e.g., the error bit is stale when we wait
+ * for DRQ for writes). So we can't depend
+ * on the error bit at all when polling for
+ * command completion.
+ */
+ }
+ if ((status & bits_wanted) == bits_wanted)
+ return (status & WDCS_ERR);
+ }
+ if (timeout < TIMEOUT)
+ /*
+ * Switch to a polling rate of about 1 KHz so that
+ * the timeout is almost machine-independent. The
+ * controller is taking a long time to respond, so
+ * an extra msec won't matter.
+ */
+ DELAY(1000);
+ } while (--timeout != 0);
+ return (-1);
+}
+
+/*
+ * Internalize the bad sector table.
+ */
+void bad144intern(struct disk *du) {
+ int i;
+ if (du->dk_flags & DKFL_BADSECT) {
+ for (i = 0; i < 127; i++) {
+ du->dk_badsect[i] = -1;
+ }
+ for (i = 0; i < 126; i++) {
+ if (du->dk_bad.bt_bad[i].bt_cyl == 0xffff) {
+ break;
+ } else {
+ du->dk_badsect[i] =
+ du->dk_bad.bt_bad[i].bt_cyl * du->dk_dd.d_secpercyl +
+ (du->dk_bad.bt_bad[i].bt_trksec >> 8) * du->dk_dd.d_nsectors
++
+ (du->dk_bad.bt_bad[i].bt_trksec & 0x00ff);
+ }
+ }
+ }
+}
+
+#endif /* NWDC > 0 */
diff --git a/sys/i386/isa/wdreg.h b/sys/i386/isa/wdreg.h
new file mode 100644
index 0000000..2694bed
--- /dev/null
+++ b/sys/i386/isa/wdreg.h
@@ -0,0 +1,144 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)wdreg.h 7.1 (Berkeley) 5/9/91
+ * $Id: wxreg.h,v 1.1 1993/10/26 22:26:39 nate Exp $
+ */
+
+/*
+ * Disk Controller register definitions.
+ */
+#define wd_data 0x0 /* data register (R/W - 16 bits) */
+#define wd_error 0x1 /* error register (R) */
+#define wd_precomp wd_error /* write precompensation (W) */
+#define wd_seccnt 0x2 /* sector count (R/W) */
+#define wd_sector 0x3 /* first sector number (R/W) */
+#define wd_cyl_lo 0x4 /* cylinder address, low byte (R/W) */
+#define wd_cyl_hi 0x5 /* cylinder address, high byte (R/W)*/
+#define wd_sdh 0x6 /* sector size/drive/head (R/W)*/
+#define wd_command 0x7 /* command register (W) */
+#define wd_status wd_command /* immediate status (R) */
+
+#define wd_altsts 0x206 /*alternate fixed disk status(via 1015) (R)*/
+#define wd_ctlr 0x206 /*fixed disk controller control(via 1015) (W)*/
+#define WDCTL_4BIT 0x8 /* use four head bits (wd1003) */
+#define WDCTL_RST 0x4 /* reset the controller */
+#define WDCTL_IDS 0x2 /* disable controller interrupts */
+#define wd_digin 0x207 /* disk controller input(via 1015) (R)*/
+
+/*
+ * Status Bits.
+ */
+#define WDCS_BUSY 0x80 /* Controller busy bit. */
+#define WDCS_READY 0x40 /* Selected drive is ready */
+#define WDCS_WRTFLT 0x20 /* Write fault */
+#define WDCS_SEEKCMPLT 0x10 /* Seek complete */
+#define WDCS_DRQ 0x08 /* Data request bit. */
+#define WDCS_ECCCOR 0x04 /* ECC correction made in data */
+#define WDCS_INDEX 0x02 /* Index pulse from selected drive */
+#define WDCS_ERR 0x01 /* Error detect bit. */
+
+#define WDCS_BITS "\020\010busy\006rdy\006wrtflt\005seekdone\004drq\003ecc_cor\002index\001err"
+
+#define WDERR_BITS "\020\010badblk\007uncorr\006id_crc\005no_id\003abort\002tr000\001no_dam"
+
+/*
+ * Commands for Disk Controller.
+ */
+#define WDCC_RESTORE 0x10 /* disk restore code -- resets cntlr */
+
+#define WDCC_READ 0x20 /* disk read code */
+#define WDCC_WRITE 0x30 /* disk write code */
+#define WDCC__LONG 0x02 /* modifier -- access ecc bytes */
+#define WDCC__NORETRY 0x01 /* modifier -- no retrys */
+
+#define WDCC_FORMAT 0x50 /* disk format code */
+#define WDCC_DIAGNOSE 0x90 /* controller diagnostic */
+#define WDCC_IDC 0x91 /* initialize drive command */
+
+#define WDCC_EXTDCMD 0xE0 /* send extended command */
+#define WDCC_READP 0xEC /* read parameters from controller */
+#define WDCC_CACHEC 0xEF /* cache control */
+
+#define WD_STEP 0 /* winchester- default 35us step */
+
+#define WDSD_IBM 0xa0 /* forced to 512 byte sector, ecc */
+
+
+#ifdef KERNEL
+/*
+ * read parameters command returns this:
+ */
+struct wdparams {
+ /* drive info */
+ short wdp_config; /* general configuration */
+ short wdp_fixedcyl; /* number of non-removable cylinders */
+ short wdp_removcyl; /* number of removable cylinders */
+ short wdp_heads; /* number of heads */
+ short wdp_unfbytespertrk; /* number of unformatted bytes/track */
+ short wdp_unfbytes; /* number of unformatted bytes/sector */
+ short wdp_sectors; /* number of sectors */
+ short wdp_minisg; /* minimum bytes in inter-sector gap*/
+ short wdp_minplo; /* minimum bytes in postamble */
+ short wdp_vendstat; /* number of words of vendor status */
+ /* controller info */
+ char wdp_cnsn[20]; /* controller serial number */
+ short wdp_cntype; /* controller type */
+#define WDTYPE_SINGLEPORTSECTOR 1 /* single port, single sector buffer */
+#define WDTYPE_DUALPORTMULTI 2 /* dual port, multiple sector buffer */
+#define WDTYPE_DUALPORTMULTICACHE 3 /* above plus track cache */
+ short wdp_cnsbsz; /* sector buffer size, in sectors */
+ short wdp_necc; /* ecc bytes appended */
+ char wdp_rev[8]; /* firmware revision */
+ char wdp_model[40]; /* model name */
+ short wdp_nsecperint; /* sectors per interrupt */
+ short wdp_usedmovsd; /* can use double word read/write? */
+};
+
+/*
+ * wd driver entry points
+ */
+void wdstrategy(struct buf *bp);
+void wdintr(int unit);
+int wdopen(dev_t dev, int flags, int fmt, struct proc *p);
+int wdclose(dev_t dev, int flags, int fmt);
+int wdioctl(dev_t dev, int cmd, caddr_t addr, int flag);
+#ifdef B_FORMAT
+int wdformat(struct buf *bp);
+#endif
+int wdsize(dev_t dev);
+int wddump(dev_t dev);
+
+#endif KERNEL
diff --git a/sys/i386/isa/wt.c b/sys/i386/isa/wt.c
new file mode 100644
index 0000000..1e97553
--- /dev/null
+++ b/sys/i386/isa/wt.c
@@ -0,0 +1,902 @@
+/*
+ * Streamer tape driver for 386bsd and FreeBSD.
+ * Supports Archive and Wangtek compatible QIC-02/QIC-36 boards.
+ *
+ * Copyright (C) 1993 by:
+ * Sergey Ryzhkov <sir@kiae.su>
+ * Serge Vakulenko <vak@zebub.msk.su>
+ *
+ * This software is distributed with NO WARRANTIES, not even the implied
+ * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Authors grant any other persons or organisations permission to use
+ * or modify this software as long as this message is kept with the software,
+ * all derivative works or modified versions.
+ *
+ * This driver is derived from the old 386bsd Wangtek streamer tape driver,
+ * made by Robert Baron at CMU, based on Intel sources.
+ * Authors thank Robert Baron, CMU and Intel and retain here
+ * the original CMU copyright notice.
+ *
+ * Version 1.3, Thu Nov 11 12:09:13 MSK 1993
+ * $Id: wt.c,v 1.4 1993/12/13 18:38:43 alm Exp $
+ *
+ */
+
+/*
+ * Copyright (c) 1989 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Robert Baron
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include "wt.h"
+#if NWT > 0
+
+#include "sys/param.h"
+#include "systm.h"
+#include "kernel.h"
+#include "sys/buf.h"
+#include "sys/fcntl.h"
+#include "sys/malloc.h"
+#include "sys/ioctl.h"
+#include "sys/mtio.h"
+#include "vm/vm_param.h"
+#include "i386/include/pio.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/wtreg.h"
+
+/*
+ * Uncomment this to enable internal device tracing.
+ */
+#define DEBUG(s) /* printf s */
+
+#define WTPRI (PZERO+10) /* sleep priority */
+
+/*
+ * Wangtek controller ports
+ */
+#define WT_CTLPORT(base) ((base)+0) /* control, write only */
+#define WT_STATPORT(base) ((base)+0) /* status, read only */
+#define WT_CMDPORT(base) ((base)+1) /* command, write only */
+#define WT_DATAPORT(base) ((base)+1) /* data, read only */
+#define WT_NPORT 2 /* 2 i/o ports */
+
+/* status port bits */
+#define WT_BUSY 0x01 /* not ready bit define */
+#define WT_NOEXCEP 0x02 /* no exception bit define */
+#define WT_RESETMASK 0x07 /* to check after reset */
+#define WT_RESETVAL 0x05 /* state after reset */
+
+/* control port bits */
+#define WT_ONLINE 0x01 /* device selected */
+#define WT_RESET 0x02 /* reset command */
+#define WT_REQUEST 0x04 /* request command */
+#define WT_IEN 0x08 /* enable dma */
+
+/*
+ * Archive controller ports
+ */
+#define AV_DATAPORT(base) ((base)+0) /* data, read only */
+#define AV_CMDPORT(base) ((base)+0) /* command, write only */
+#define AV_STATPORT(base) ((base)+1) /* status, read only */
+#define AV_CTLPORT(base) ((base)+1) /* control, write only */
+#define AV_SDMAPORT(base) ((base)+2) /* start dma */
+#define AV_RDMAPORT(base) ((base)+3) /* reset dma */
+#define AV_NPORT 4 /* 4 i/o ports */
+
+/* status port bits */
+#define AV_BUSY 0x40 /* not ready bit define */
+#define AV_NOEXCEP 0x20 /* no exception bit define */
+#define AV_RESETMASK 0xf8 /* to check after reset */
+#define AV_RESETVAL 0x50 /* state after reset */
+
+/* control port bits */
+#define AV_RESET 0x80 /* reset command */
+#define AV_REQUEST 0x40 /* request command */
+#define AV_IEN 0x20 /* enable interrupts */
+
+enum wttype {
+ UNKNOWN = 0, /* unknown type, driver disabled */
+ ARCHIVE, /* Archive Viper SC499, SC402 etc */
+ WANGTEK, /* Wangtek */
+};
+
+typedef struct {
+ unsigned short err; /* code for error encountered */
+ unsigned short ercnt; /* number of error blocks */
+ unsigned short urcnt; /* number of underruns */
+} wtstatus_t;
+
+typedef struct {
+ enum wttype type; /* type of controller */
+ unsigned unit; /* unit number */
+ unsigned port; /* base i/o port */
+ unsigned chan; /* dma channel number, 1..3 */
+ unsigned flags; /* state of tape drive */
+ unsigned dens; /* tape density */
+ int bsize; /* tape block size */
+ void *buf; /* internal i/o buffer */
+
+ void *dmavaddr; /* virtual address of dma i/o buffer */
+ unsigned dmatotal; /* size of i/o buffer */
+ unsigned dmaflags; /* i/o direction, B_READ or B_WRITE */
+ unsigned dmacount; /* resulting length of dma i/o */
+
+ wtstatus_t error; /* status of controller */
+
+ unsigned short DATAPORT, CMDPORT, STATPORT, CTLPORT, SDMAPORT, RDMAPORT;
+ unsigned char BUSY, NOEXCEP, RESETMASK, RESETVAL;
+ unsigned char ONLINE, RESET, REQUEST, IEN;
+} wtinfo_t;
+
+wtinfo_t wttab[NWT]; /* tape info by unit number */
+
+static int wtwait (wtinfo_t *t, int catch, char *msg);
+static int wtcmd (wtinfo_t *t, int cmd);
+static int wtstart (wtinfo_t *t, unsigned mode, void *vaddr, unsigned len);
+static void wtdma (wtinfo_t *t);
+static void wtimer (caddr_t, int);
+static void wtclock (wtinfo_t *t);
+static int wtreset (wtinfo_t *t);
+static int wtsense (wtinfo_t *t, int verb, int ignor);
+static int wtstatus (wtinfo_t *t);
+static void wtrewind (wtinfo_t *t);
+static int wtreadfm (wtinfo_t *t);
+static int wtwritefm (wtinfo_t *t);
+static int wtpoll (wtinfo_t *t, int mask, int bits);
+
+/* XXX */
+extern void DELAY (int usec);
+
+/*
+ * Probe for the presence of the device.
+ */
+int wtprobe (struct isa_device *id)
+{
+ wtinfo_t *t = wttab + id->id_unit;
+
+ t->unit = id->id_unit;
+ t->chan = id->id_drq;
+ t->port = id->id_iobase;
+ if (t->chan<1 || t->chan>3) {
+ printf ("wt%d: Bad drq=%d, should be 1..3\n", t->unit, t->chan);
+ return (0);
+ }
+
+ /* Try Wangtek. */
+ t->type = WANGTEK;
+ t->CTLPORT = WT_CTLPORT (t->port); t->STATPORT = WT_STATPORT (t->port);
+ t->CMDPORT = WT_CMDPORT (t->port); t->DATAPORT = WT_DATAPORT (t->port);
+ t->SDMAPORT = 0; t->RDMAPORT = 0;
+ t->BUSY = WT_BUSY; t->NOEXCEP = WT_NOEXCEP;
+ t->RESETMASK = WT_RESETMASK; t->RESETVAL = WT_RESETVAL;
+ t->ONLINE = WT_ONLINE; t->RESET = WT_RESET;
+ t->REQUEST = WT_REQUEST; t->IEN = WT_IEN;
+ if (wtreset (t))
+ return (WT_NPORT);
+
+ /* Try Archive. */
+ t->type = ARCHIVE;
+ t->CTLPORT = AV_CTLPORT (t->port); t->STATPORT = AV_STATPORT (t->port);
+ t->CMDPORT = AV_CMDPORT (t->port); t->DATAPORT = AV_DATAPORT (t->port);
+ t->SDMAPORT = AV_SDMAPORT (t->port); t->RDMAPORT = AV_RDMAPORT (t->port);
+ t->BUSY = AV_BUSY; t->NOEXCEP = AV_NOEXCEP;
+ t->RESETMASK = AV_RESETMASK; t->RESETVAL = AV_RESETVAL;
+ t->ONLINE = 0; t->RESET = AV_RESET;
+ t->REQUEST = AV_REQUEST; t->IEN = AV_IEN;
+ if (wtreset (t))
+ return (AV_NPORT);
+
+ /* Tape controller not found. */
+ t->type = UNKNOWN;
+ return (0);
+}
+
+/*
+ * Device is found, configure it.
+ */
+int wtattach (struct isa_device *id)
+{
+ wtinfo_t *t = wttab + id->id_unit;
+
+ if (t->type == ARCHIVE) {
+ printf ("wt%d: type <Archive>\n", t->unit);
+ outb (t->RDMAPORT, 0); /* reset dma */
+ } else
+ printf ("wt%d: type <Wangtek>\n", t->unit);
+ t->flags = TPSTART; /* tape is rewound */
+ t->dens = -1; /* unknown density */
+ return (1);
+}
+
+struct isa_driver wtdriver = { wtprobe, wtattach, "wt", };
+
+int wtdump (int dev)
+{
+ /* Not implemented */
+ return (EINVAL);
+}
+
+int wtsize (int dev)
+{
+ /* Not implemented */
+ return (-1);
+}
+
+/*
+ * Open routine, called on every device open.
+ */
+int wtopen (int dev, int flag)
+{
+ int u = minor (dev) & T_UNIT;
+ wtinfo_t *t = wttab + u;
+ int error;
+
+ if (u >= NWT || t->type == UNKNOWN)
+ return (ENXIO);
+
+ /* Check that device is not in use */
+ if (t->flags & TPINUSE)
+ return (EBUSY);
+
+ /* If the tape is in rewound state, check the status and set density. */
+ if (t->flags & TPSTART) {
+ /* If rewind is going on, wait */
+ if (error = wtwait (t, PCATCH, "wtrew"))
+ return (error);
+
+ /* Check the controller status */
+ if (! wtsense (t, 0, (flag & FWRITE) ? 0 : TP_WRP)) {
+ /* Bad status, reset the controller */
+ if (! wtreset (t))
+ return (EIO);
+ if (! wtsense (t, 1, (flag & FWRITE) ? 0 : TP_WRP))
+ return (EIO);
+ }
+
+ /* Set up tape density. */
+ if (t->dens != (minor (dev) & WT_DENSEL)) {
+ int d = 0;
+
+ switch (minor (dev) & WT_DENSEL) {
+ case WT_DENSDFLT: default: break; /* default density */
+ case WT_QIC11: d = QIC_FMT11; break; /* minor 010 */
+ case WT_QIC24: d = QIC_FMT24; break; /* minor 020 */
+ case WT_QIC120: d = QIC_FMT120; break; /* minor 030 */
+ case WT_QIC150: d = QIC_FMT150; break; /* minor 040 */
+ case WT_QIC300: d = QIC_FMT300; break; /* minor 050 */
+ case WT_QIC600: d = QIC_FMT600; break; /* minor 060 */
+ }
+ if (d) {
+ /* Change tape density. */
+ if (! wtcmd (t, d))
+ return (EIO);
+ if (! wtsense (t, 1, TP_WRP | TP_ILL))
+ return (EIO);
+
+ /* Check the status of the controller. */
+ if (t->error.err & TP_ILL) {
+ printf ("wt%d: invalid tape density\n", t->unit);
+ return (ENODEV);
+ }
+ }
+ t->dens = minor (dev) & WT_DENSEL;
+ }
+ t->flags &= ~TPSTART;
+ } else if (t->dens != (minor (dev) & WT_DENSEL))
+ return (ENXIO);
+
+ t->bsize = (minor (dev) & WT_BSIZE) ? 1024 : 512;
+ t->buf = malloc (t->bsize, M_TEMP, M_WAITOK);
+ if (! t->buf)
+ return (EAGAIN);
+
+ t->flags = TPINUSE;
+ if (flag & FREAD)
+ t->flags |= TPREAD;
+ if (flag & FWRITE)
+ t->flags |= TPWRITE;
+ return (0);
+}
+
+/*
+ * Close routine, called on last device close.
+ */
+int wtclose (int dev)
+{
+ int u = minor (dev) & T_UNIT;
+ wtinfo_t *t = wttab + u;
+
+ if (u >= NWT || t->type == UNKNOWN)
+ return (ENXIO);
+
+ /* If rewind is pending, do nothing */
+ if (t->flags & TPREW)
+ goto done;
+
+ /* If seek forward is pending and no rewind on close, do nothing */
+ if (t->flags & TPRMARK) {
+ if (minor (dev) & T_NOREWIND)
+ goto done;
+
+ /* If read file mark is going on, wait */
+ wtwait (t, 0, "wtrfm");
+ }
+
+ if (t->flags & TPWANY)
+ /* Tape was written. Write file mark. */
+ wtwritefm (t);
+
+ if (! (minor (dev) & T_NOREWIND)) {
+ /* Rewind tape to beginning of tape. */
+ /* Don't wait until rewind, though. */
+ wtrewind (t);
+ goto done;
+ }
+ if ((t->flags & TPRANY) && ! (t->flags & (TPVOL | TPWANY)))
+ /* Space forward to after next file mark if no writing done. */
+ /* Don't wait for completion. */
+ wtreadfm (t);
+done:
+ t->flags &= TPREW | TPRMARK | TPSTART | TPTIMER;
+ free (t->buf, M_TEMP);
+ return (0);
+}
+
+/*
+ * Ioctl routine. Compatible with BSD ioctls.
+ * Direct QIC-02 commands ERASE and RETENSION added.
+ * There are three possible ioctls:
+ * ioctl (int fd, MTIOCGET, struct mtget *buf) -- get status
+ * ioctl (int fd, MTIOCTOP, struct mtop *buf) -- do BSD-like op
+ * ioctl (int fd, WTQICMD, int qicop) -- do QIC op
+ */
+int wtioctl (int dev, int cmd, void *arg, int mode)
+{
+ int u = minor (dev) & T_UNIT;
+ wtinfo_t *t = wttab + u;
+ int error, count, op;
+
+ if (u >= NWT || t->type == UNKNOWN)
+ return (ENXIO);
+
+ switch (cmd) {
+ default:
+ return (EINVAL);
+ case WTQICMD: /* direct QIC command */
+ op = (int) *(void**)arg;
+ switch (op) {
+ default:
+ return (EINVAL);
+ case QIC_ERASE: /* erase the whole tape */
+ if (! (t->flags & TPWRITE) || (t->flags & TPWP))
+ return (EACCES);
+ if (error = wtwait (t, PCATCH, "wterase"))
+ return (error);
+ break;
+ case QIC_RETENS: /* retension the tape */
+ if (error = wtwait (t, PCATCH, "wtretens"))
+ return (error);
+ break;
+ }
+ /* Both ERASE and RETENS operations work like REWIND. */
+ /* Simulate the rewind operation here. */
+ t->flags &= ~(TPRO | TPWO | TPVOL);
+ if (! wtcmd (t, op))
+ return (EIO);
+ t->flags |= TPSTART | TPREW;
+ if (op == QIC_ERASE)
+ t->flags |= TPWANY;
+ wtclock (t);
+ return (0);
+ case MTIOCIEOT: /* ignore EOT errors */
+ case MTIOCEEOT: /* enable EOT errors */
+ return (0);
+ case MTIOCGET:
+ ((struct mtget*)arg)->mt_type =
+ t->type == ARCHIVE ? MT_ISVIPER1 : 0x11;
+ ((struct mtget*)arg)->mt_dsreg = t->flags; /* status */
+ ((struct mtget*)arg)->mt_erreg = t->error.err; /* errors */
+ ((struct mtget*)arg)->mt_resid = 0;
+ ((struct mtget*)arg)->mt_fileno = 0; /* file */
+ ((struct mtget*)arg)->mt_blkno = 0; /* block */
+ return (0);
+ case MTIOCTOP:
+ break;
+ }
+ switch ((short) ((struct mtop*)arg)->mt_op) {
+ default:
+ case MTFSR: /* forward space record */
+ case MTBSR: /* backward space record */
+ case MTBSF: /* backward space file */
+ break;
+ case MTNOP: /* no operation, sets status only */
+ case MTCACHE: /* enable controller cache */
+ case MTNOCACHE: /* disable controller cache */
+ return (0);
+ case MTREW: /* rewind */
+ case MTOFFL: /* rewind and put the drive offline */
+ if (t->flags & TPREW) /* rewind is running */
+ return (0);
+ if (error = wtwait (t, PCATCH, "wtorew"))
+ return (error);
+ wtrewind (t);
+ return (0);
+ case MTFSF: /* forward space file */
+ for (count=((struct mtop*)arg)->mt_count; count>0; --count) {
+ if (error = wtwait (t, PCATCH, "wtorfm"))
+ return (error);
+ if (error = wtreadfm (t))
+ return (error);
+ }
+ return (0);
+ case MTWEOF: /* write an end-of-file record */
+ if (! (t->flags & TPWRITE) || (t->flags & TPWP))
+ return (EACCES);
+ if (error = wtwait (t, PCATCH, "wtowfm"))
+ return (error);
+ if (error = wtwritefm (t))
+ return (error);
+ return (0);
+ }
+ return (EINVAL);
+}
+
+/*
+ * Strategy routine.
+ */
+void wtstrategy (struct buf *bp)
+{
+ int u = minor (bp->b_dev) & T_UNIT;
+ wtinfo_t *t = wttab + u;
+ int s;
+
+ bp->b_resid = bp->b_bcount;
+ if (u >= NWT || t->type == UNKNOWN)
+ goto errxit;
+
+ /* at file marks and end of tape, we just return '0 bytes available' */
+ if (t->flags & TPVOL)
+ goto xit;
+
+ if (bp->b_flags & B_READ) {
+ /* Check read access and no previous write to this tape. */
+ if (! (t->flags & TPREAD) || (t->flags & TPWANY))
+ goto errxit;
+
+ /* For now, we assume that all data will be copied out */
+ /* If read command outstanding, just skip down */
+ if (! (t->flags & TPRO)) {
+ if (! wtsense (t, 1, TP_WRP)) /* clear status */
+ goto errxit;
+ if (! wtcmd (t, QIC_RDDATA)) { /* sed read mode */
+ wtsense (t, 1, TP_WRP);
+ goto errxit;
+ }
+ t->flags |= TPRO | TPRANY;
+ }
+ } else {
+ /* Check write access and write protection. */
+ /* No previous read from this tape allowed. */
+ if (! (t->flags & TPWRITE) || (t->flags & (TPWP | TPRANY)))
+ goto errxit;
+
+ /* If write command outstanding, just skip down */
+ if (! (t->flags & TPWO)) {
+ if (! wtsense (t, 1, 0)) /* clear status */
+ goto errxit;
+ if (! wtcmd (t, QIC_WRTDATA)) { /* set write mode */
+ wtsense (t, 1, 0);
+ goto errxit;
+ }
+ t->flags |= TPWO | TPWANY;
+ }
+ }
+
+ if (! bp->b_bcount)
+ goto xit;
+
+ t->flags &= ~TPEXCEP;
+ s = splbio ();
+ if (wtstart (t, bp->b_flags, bp->b_un.b_addr, bp->b_bcount)) {
+ wtwait (t, 0, (bp->b_flags & B_READ) ? "wtread" : "wtwrite");
+ bp->b_resid -= t->dmacount;
+ }
+ splx (s);
+
+ if (t->flags & TPEXCEP) {
+errxit: bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ }
+xit: biodone (bp);
+ return;
+}
+
+/*
+ * Interrupt routine.
+ */
+void wtintr (int u)
+{
+ wtinfo_t *t = wttab + u;
+ unsigned char s;
+
+ if (u >= NWT || t->type == UNKNOWN) {
+ DEBUG (("wtintr() -- device not configured\n"));
+ return;
+ }
+
+ s = inb (t->STATPORT); /* get status */
+ DEBUG (("wtintr() status=0x%x -- ", s));
+ if ((s & (t->BUSY | t->NOEXCEP)) == (t->BUSY | t->NOEXCEP)) {
+ DEBUG (("busy\n"));
+ return; /* device is busy */
+ }
+
+ /*
+ * Check if rewind finished.
+ */
+ if (t->flags & TPREW) {
+ DEBUG (((s & (t->BUSY | t->NOEXCEP)) == (t->BUSY | t->NOEXCEP) ?
+ "rewind busy?\n" : "rewind finished\n"));
+ t->flags &= ~TPREW; /* Rewind finished. */
+ wtsense (t, 1, TP_WRP);
+ wakeup ((caddr_t)t);
+ return;
+ }
+
+ /*
+ * Check if writing/reading of file mark finished.
+ */
+ if (t->flags & (TPRMARK | TPWMARK)) {
+ DEBUG (((s & (t->BUSY | t->NOEXCEP)) == (t->BUSY | t->NOEXCEP) ?
+ "marker r/w busy?\n" : "marker r/w finished\n"));
+ if (! (s & t->NOEXCEP)) /* operation failed */
+ wtsense (t, 1, (t->flags & TPRMARK) ? TP_WRP : 0);
+ t->flags &= ~(TPRMARK | TPWMARK); /* operation finished */
+ wakeup ((caddr_t)t);
+ return;
+ }
+
+ /*
+ * Do we started any i/o? If no, just return.
+ */
+ if (! (t->flags & TPACTIVE)) {
+ DEBUG (("unexpected interrupt\n"));
+ return;
+ }
+ t->flags &= ~TPACTIVE;
+ t->dmacount += t->bsize; /* increment counter */
+
+ /*
+ * Clean up dma.
+ */
+ if ((t->dmaflags & B_READ) && (t->dmatotal - t->dmacount) < t->bsize) {
+ /* If reading short block, copy the internal buffer
+ * to the user memory. */
+ isa_dmadone (t->dmaflags, t->buf, t->bsize, t->chan);
+ bcopy (t->buf, t->dmavaddr, t->dmatotal - t->dmacount);
+ } else
+ isa_dmadone (t->dmaflags, t->dmavaddr, t->bsize, t->chan);
+
+ /*
+ * On exception, check for end of file and end of volume.
+ */
+ if (! (s & t->NOEXCEP)) {
+ DEBUG (("i/o exception\n"));
+ wtsense (t, 1, (t->dmaflags & B_READ) ? TP_WRP : 0);
+ if (t->error.err & (TP_EOM | TP_FIL))
+ t->flags |= TPVOL; /* end of file */
+ else
+ t->flags |= TPEXCEP; /* i/o error */
+ wakeup ((caddr_t)t);
+ return;
+ }
+
+ if (t->dmacount < t->dmatotal) { /* continue i/o */
+ t->dmavaddr += t->bsize;
+ wtdma (t);
+ DEBUG (("continue i/o, %d\n", t->dmacount));
+ return;
+ }
+ if (t->dmacount > t->dmatotal) /* short last block */
+ t->dmacount = t->dmatotal;
+ wakeup ((caddr_t)t); /* wake up user level */
+ DEBUG (("i/o finished, %d\n", t->dmacount));
+}
+
+/* start the rewind operation */
+static void wtrewind (wtinfo_t *t)
+{
+ int rwmode = (t->flags & (TPRO | TPWO));
+
+ t->flags &= ~(TPRO | TPWO | TPVOL);
+ /*
+ * Wangtek strictly follows QIC-02 standard:
+ * clearing ONLINE in read/write modes causes rewind.
+ * REWIND command is not allowed in read/write mode
+ * and gives `illegal command' error.
+ */
+ if (t->type==WANGTEK && rwmode) {
+ outb (t->CTLPORT, 0);
+ } else if (! wtcmd (t, QIC_REWIND))
+ return;
+ t->flags |= TPSTART | TPREW;
+ wtclock (t);
+}
+
+/* start the `read marker' operation */
+static int wtreadfm (wtinfo_t *t)
+{
+ t->flags &= ~(TPRO | TPWO | TPVOL);
+ if (! wtcmd (t, QIC_READFM)) {
+ wtsense (t, 1, TP_WRP);
+ return (EIO);
+ }
+ t->flags |= TPRMARK | TPRANY;
+ wtclock (t);
+ /* Don't wait for completion here. */
+ return (0);
+}
+
+/* write marker to the tape */
+static int wtwritefm (wtinfo_t *t)
+{
+ tsleep ((caddr_t)wtwritefm, WTPRI, "wtwfm", hz); /* timeout: 1 second */
+ t->flags &= ~(TPRO | TPWO);
+ if (! wtcmd (t, QIC_WRITEFM)) {
+ wtsense (t, 1, 0);
+ return (EIO);
+ }
+ t->flags |= TPWMARK | TPWANY;
+ wtclock (t);
+ return (wtwait (t, 0, "wtwfm"));
+}
+
+/* while controller status & mask == bits continue waiting */
+static int wtpoll (wtinfo_t *t, int mask, int bits)
+{
+ int s, i;
+
+ /* Poll status port, waiting for specified bits. */
+ for (i=0; i<1000; ++i) { /* up to 1 msec */
+ s = inb (t->STATPORT);
+ if ((s & mask) != bits)
+ return (s);
+ DELAY (1);
+ }
+ for (i=0; i<100; ++i) { /* up to 10 msec */
+ s = inb (t->STATPORT);
+ if ((s & mask) != bits)
+ return (s);
+ DELAY (100);
+ }
+ for (;;) { /* forever */
+ s = inb (t->STATPORT);
+ if ((s & mask) != bits)
+ return (s);
+ tsleep ((caddr_t)wtpoll, WTPRI, "wtpoll", 1); /* timeout: 1 tick */
+ }
+}
+
+/* execute QIC command */
+static int wtcmd (wtinfo_t *t, int cmd)
+{
+ int s;
+
+ DEBUG (("wtcmd() cmd=0x%x\n", cmd));
+ s = wtpoll (t, t->BUSY | t->NOEXCEP, t->BUSY | t->NOEXCEP); /* ready? */
+ if (! (s & t->NOEXCEP)) /* error */
+ return (0);
+
+ outb (t->CMDPORT, cmd); /* output the command */
+
+ outb (t->CTLPORT, t->REQUEST | t->ONLINE); /* set request */
+ wtpoll (t, t->BUSY, t->BUSY); /* wait for ready */
+ outb (t->CTLPORT, t->IEN | t->ONLINE); /* reset request */
+ wtpoll (t, t->BUSY, 0); /* wait for not ready */
+ return (1);
+}
+
+/* wait for the end of i/o, seeking marker or rewind operation */
+static int wtwait (wtinfo_t *t, int catch, char *msg)
+{
+ int error;
+
+ DEBUG (("wtwait() `%s'\n", msg));
+ while (t->flags & (TPACTIVE | TPREW | TPRMARK | TPWMARK))
+ if (error = tsleep ((caddr_t)t, WTPRI | catch, msg, 0))
+ return (error);
+ return (0);
+}
+
+/* initialize dma for the i/o operation */
+static void wtdma (wtinfo_t *t)
+{
+ t->flags |= TPACTIVE;
+ wtclock (t);
+
+ if (t->type == ARCHIVE)
+ outb (t->SDMAPORT, 0); /* set dma */
+
+ if ((t->dmaflags & B_READ) && (t->dmatotal - t->dmacount) < t->bsize)
+ /* Reading short block. Do it through the internal buffer. */
+ isa_dmastart (t->dmaflags, t->buf, t->bsize, t->chan);
+ else
+ isa_dmastart (t->dmaflags, t->dmavaddr, t->bsize, t->chan);
+}
+
+/* start i/o operation */
+static int wtstart (wtinfo_t *t, unsigned flags, void *vaddr, unsigned len)
+{
+ int s;
+
+ DEBUG (("wtstart()\n"));
+ s = wtpoll (t, t->BUSY | t->NOEXCEP, t->BUSY | t->NOEXCEP); /* ready? */
+ if (! (s & t->NOEXCEP)) {
+ t->flags |= TPEXCEP; /* error */
+ return (0);
+ }
+ t->flags &= ~TPEXCEP; /* clear exception flag */
+ t->dmavaddr = vaddr;
+ t->dmatotal = len;
+ t->dmacount = 0;
+ t->dmaflags = flags;
+ wtdma (t);
+ return (1);
+}
+
+/* start timer */
+static void wtclock (wtinfo_t *t)
+{
+ if (! (t->flags & TPTIMER)) {
+ t->flags |= TPTIMER;
+ /* Some controllers seem to lose dma interrupts too often.
+ * To make the tape stream we need 1 tick timeout. */
+ timeout (wtimer, (caddr_t)t, (t->flags & TPACTIVE) ? 1 : hz);
+ }
+}
+
+/*
+ * Simulate an interrupt periodically while i/o is going.
+ * This is necessary in case interrupts get eaten due to
+ * multiple devices on a single IRQ line.
+ */
+static void wtimer (caddr_t xt, int dummy)
+{
+ wtinfo_t *t = (wtinfo_t *)xt;
+ int s;
+
+ t->flags &= ~TPTIMER;
+ if (! (t->flags & (TPACTIVE | TPREW | TPRMARK | TPWMARK)))
+ return;
+
+ /* If i/o going, simulate interrupt. */
+ s = splbio ();
+ if ((inb (t->STATPORT) & (t->BUSY | t->NOEXCEP)) != (t->BUSY | t->NOEXCEP)) {
+ DEBUG (("wtimer() -- "));
+ wtintr (t->unit);
+ }
+ splx (s);
+
+ /* Restart timer if i/o pending. */
+ if (t->flags & (TPACTIVE | TPREW | TPRMARK | TPWMARK))
+ wtclock (t);
+}
+
+/* reset the controller */
+static int wtreset (wtinfo_t *t)
+{
+ /* Perform QIC-02 and QIC-36 compatible reset sequence. */
+ /* Thanks to Mikael Hybsch <micke@dynas.se>. */
+ int s, i;
+
+ outb (t->CTLPORT, t->RESET | t->ONLINE); /* send reset */
+ DELAY (30);
+ outb (t->CTLPORT, t->ONLINE); /* turn off reset */
+ DELAY (30);
+
+ /* Read the controller status. */
+ s = inb (t->STATPORT);
+ if (s == 0xff) /* no port at this address? */
+ return (0);
+
+ /* Wait 3 sec for reset to complete. Needed for QIC-36 boards? */
+ for (i=0; i<3000; ++i) {
+ if (! (s & t->BUSY) || ! (s & t->NOEXCEP))
+ break;
+ DELAY (1000);
+ s = inb (t->STATPORT);
+ }
+ return ((s & t->RESETMASK) == t->RESETVAL);
+}
+
+/* get controller status information */
+/* return 0 if user i/o request should receive an i/o error code */
+static int wtsense (wtinfo_t *t, int verb, int ignor)
+{
+ char *msg = 0;
+ int err;
+
+ DEBUG (("wtsense() ignor=0x%x\n", ignor));
+ t->flags &= ~(TPRO | TPWO);
+ if (! wtstatus (t))
+ return (0);
+ if (! (t->error.err & TP_ST0))
+ t->error.err &= ~TP_ST0MASK;
+ if (! (t->error.err & TP_ST1))
+ t->error.err &= ~TP_ST1MASK;
+ t->error.err &= ~ignor; /* ignore certain errors */
+ err = t->error.err & (TP_FIL | TP_BNL | TP_UDA | TP_EOM | TP_WRP |
+ TP_USL | TP_CNI | TP_MBD | TP_NDT | TP_ILL);
+ if (! err)
+ return (1);
+ if (! verb)
+ return (0);
+
+ /* lifted from tdriver.c from Wangtek */
+ if (err & TP_USL) msg = "Drive not online";
+ else if (err & TP_CNI) msg = "No cartridge";
+ else if ((err & TP_WRP) && !(t->flags & TPWP)) {
+ msg = "Tape is write protected";
+ t->flags |= TPWP;
+ }
+ else if (err & TP_FIL) msg = 0 /*"Filemark detected"*/;
+ else if (err & TP_EOM) msg = 0 /*"End of tape"*/;
+ else if (err & TP_BNL) msg = "Block not located";
+ else if (err & TP_UDA) msg = "Unrecoverable data error";
+ else if (err & TP_NDT) msg = "No data detected";
+ else if (err & TP_ILL) msg = "Illegal command";
+ if (msg)
+ printf ("wt%d: %s\n", t->unit, msg);
+ return (0);
+}
+
+/* get controller status information */
+static int wtstatus (wtinfo_t *t)
+{
+ char *p;
+
+ wtpoll (t, t->BUSY | t->NOEXCEP, t->BUSY | t->NOEXCEP); /* ready? */
+ outb (t->CMDPORT, QIC_RDSTAT); /* send `read status' command */
+
+ outb (t->CTLPORT, t->REQUEST | t->ONLINE); /* set request */
+ wtpoll (t, t->BUSY, t->BUSY); /* wait for ready */
+ outb (t->CTLPORT, t->ONLINE); /* reset request */
+ wtpoll (t, t->BUSY, 0); /* wait for not ready */
+
+ p = (char*) &t->error;
+ while (p < (char*)&t->error + 6) {
+ int s = wtpoll (t, t->BUSY | t->NOEXCEP, t->BUSY | t->NOEXCEP);
+ if (! (s & t->NOEXCEP)) /* error */
+ return (0);
+
+ *p++ = inb (t->DATAPORT); /* read status byte */
+
+ outb (t->CTLPORT, t->REQUEST | t->ONLINE); /* set request */
+ wtpoll (t, t->BUSY, 0); /* wait for not ready */
+ outb (t->CTLPORT, t->ONLINE); /* unset request */
+ }
+ return (1);
+}
+#endif /* NWT */
diff --git a/sys/i386/isa/wtreg.h b/sys/i386/isa/wtreg.h
new file mode 100644
index 0000000..e45e514
--- /dev/null
+++ b/sys/i386/isa/wtreg.h
@@ -0,0 +1,125 @@
+/*
+ * Streamer tape driver for 386bsd and FreeBSD.
+ * Supports Archive and Wangtek compatible QIC-02/QIC-36 boards.
+ *
+ * Copyright (C) 1993 by:
+ * Sergey Ryzhkov <sir@kiae.su>
+ * Serge Vakulenko <vak@zebub.msk.su>
+ *
+ * This software is distributed with NO WARRANTIES, not even the implied
+ * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Authors grant any other persons or organisations permission to use
+ * or modify this software as long as this message is kept with the software,
+ * all derivative works or modified versions.
+ *
+ * This driver is derived from the old 386bsd Wangtek streamer tape driver,
+ * made by Robert Baron at CMU, based on Intel sources.
+ * Authors thank Robert Baron, CMU and Intel and retain here
+ * the original CMU copyright notice.
+ *
+ * Version 1.3, Thu Nov 11 12:09:13 MSK 1993
+ * $Id$
+ *
+ */
+
+/*
+ * Copyright (c) 1989 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Authors: Robert Baron
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/* ioctl for direct QIC commands */
+#define WTQICMD _IO('W', 0)
+
+/* QIC-02 commands allowed for WTQICMD */
+#define QIC_ERASE 0x22 /* erase the tape */
+#define QIC_RETENS 0x24 /* retension the tape */
+
+/* internal QIC-02 commands */
+#define QIC_RDDATA 0x80 /* read data */
+#define QIC_READFM 0xa0 /* read file mark */
+#define QIC_WRTDATA 0x40 /* write data */
+#define QIC_WRITEFM 0x60 /* write file mark */
+#define QIC_RDSTAT 0xc0 /* read status command */
+#define QIC_REWIND 0x21 /* rewind command (position+bot) */
+#define QIC_FMT11 0x26 /* set format QIC-11 */
+#define QIC_FMT24 0x27 /* set format QIC-24 */
+#define QIC_FMT120 0x28 /* set format QIC-120 */
+#define QIC_FMT150 0x29 /* set format QIC-150 */
+#define QIC_FMT300 0x2a /* set format QIC-300/QIC-2100 */
+#define QIC_FMT600 0x2b /* set format QIC-600/QIC-2200 */
+
+/* tape driver flags */
+#define TPINUSE 0x0001 /* tape is already open */
+#define TPREAD 0x0002 /* tape is only open for reading */
+#define TPWRITE 0x0004 /* tape is only open for writing */
+#define TPSTART 0x0008 /* tape must be rewound and reset */
+#define TPRMARK 0x0010 /* read file mark command outstanding */
+#define TPWMARK 0x0020 /* write file mark command outstanding */
+#define TPREW 0x0040 /* rewind command outstanding */
+#define TPEXCEP 0x0080 /* i/o exception flag */
+#define TPVOL 0x0100 /* read file mark or hit end of tape */
+#define TPWO 0x0200 /* write command outstanding */
+#define TPRO 0x0400 /* read command outstanding */
+#define TPWANY 0x0800 /* write command requested */
+#define TPRANY 0x1000 /* read command requested */
+#define TPWP 0x2000 /* write protect error seen */
+#define TPTIMER 0x4000 /* timer() is active */
+#define TPACTIVE 0x8000 /* dma i/o active */
+
+/* controller error register bits */
+#define TP_FIL 0x0001 /* File mark detected */
+#define TP_BNL 0x0002 /* Block not located */
+#define TP_UDA 0x0004 /* Unrecoverable data error */
+#define TP_EOM 0x0008 /* End of media */
+#define TP_WRP 0x0010 /* Write protected cartridge */
+#define TP_USL 0x0020 /* Unselected drive */
+#define TP_CNI 0x0040 /* Cartridge not in place */
+#define TP_ST0 0x0080 /* Status byte 0 bits */
+#define TP_ST0MASK 0x00ff /* Status byte 0 mask */
+#define TP_POR 0x0100 /* Power on/reset occurred */
+#define TP_ERM 0x0200 /* Reserved for end of recorded media */
+#define TP_BPE 0x0400 /* Reserved for bus parity error */
+#define TP_BOM 0x0800 /* Beginning of media */
+#define TP_MBD 0x1000 /* Marginal block detected */
+#define TP_NDT 0x2000 /* No data detected */
+#define TP_ILL 0x4000 /* Illegal command - should not happen! */
+#define TP_ST1 0x8000 /* Status byte 1 bits */
+#define TP_ST1MASK 0xff00 /* Status byte 1 mask */
+
+/* formats for printing flags and error values */
+#define WTDS_BITS "\20\1inuse\2read\3write\4start\5rmark\6wmark\7rew\10excep\11vol\12wo\13ro\14wany\15rany\16wp\17timer\20active"
+#define WTER_BITS "\20\1eof\2bnl\3uda\4eom\5wrp\6usl\7cni\11por\12erm\13bpe\14bom\15mbd\16ndt\17ill"
+
+/* device minor number */
+#define WT_BSIZE 0100 /* long block flag */
+#define WT_DENSEL 0070 /* density select mask */
+#define WT_DENSDFLT 0000 /* default density */
+#define WT_QIC11 0010 /* 11 megabytes? */
+#define WT_QIC24 0020 /* 60 megabytes */
+#define WT_QIC120 0030 /* 120 megabytes */
+#define WT_QIC150 0040 /* 150 megabytes */
+#define WT_QIC300 0050 /* 300 megabytes? */
+#define WT_QIC600 0060 /* 600 megabytes? */
diff --git a/sys/isa/atrtc.c b/sys/isa/atrtc.c
new file mode 100644
index 0000000..d338cd5
--- /dev/null
+++ b/sys/isa/atrtc.c
@@ -0,0 +1,430 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz and Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)clock.c 7.2 (Berkeley) 5/12/91
+ * $Id: clock.c,v 1.6 1994/02/06 22:48:13 davidg Exp $
+ */
+
+/*
+ * Primitive clock interrupt routines.
+ */
+#include "param.h"
+#include "systm.h"
+#include "time.h"
+#include "kernel.h"
+#include "machine/segments.h"
+#include "machine/frame.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/rtc.h"
+#include "i386/isa/timerreg.h"
+
+/* X-tals being what they are, it's nice to be able to fudge this one... */
+/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */
+#ifndef TIMER_FREQ
+#define TIMER_FREQ 1193182 /* XXX - should be in isa.h */
+#endif
+#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
+
+void hardclock();
+static int beeping;
+int timer0_divisor = TIMER_DIV(100); /* XXX should be hz */
+u_int timer0_prescale;
+static char timer0_state = 0, timer2_state = 0;
+static char timer0_reprogram = 0;
+static void (*timer_func)() = hardclock;
+static void (*new_function)();
+static u_int new_rate;
+static u_int hardclock_divisor;
+
+
+void
+timerintr(struct intrframe frame)
+{
+ timer_func(frame);
+ switch (timer0_state) {
+ case 0:
+ break;
+ case 1:
+ if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
+ hardclock(frame);
+ timer0_prescale = 0;
+ }
+ break;
+ case 2:
+ disable_intr();
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+ outb(TIMER_CNTR0, TIMER_DIV(new_rate)%256);
+ outb(TIMER_CNTR0, TIMER_DIV(new_rate)/256);
+ enable_intr();
+ timer0_divisor = TIMER_DIV(new_rate);
+ timer0_prescale = 0;
+ timer_func = new_function;
+ timer0_state = 1;
+ break;
+ case 3:
+ if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
+ hardclock(frame);
+ disable_intr();
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+ outb(TIMER_CNTR0, TIMER_DIV(hz)%256);
+ outb(TIMER_CNTR0, TIMER_DIV(hz)/256);
+ enable_intr();
+ timer0_divisor = TIMER_DIV(hz);
+ timer0_prescale = 0;
+ timer_func = hardclock;;
+ timer0_state = 0;
+ }
+ break;
+ }
+}
+
+
+int
+acquire_timer0(int rate, void (*function)() )
+{
+ if (timer0_state || !function)
+ return -1;
+
+ new_function = function;
+ new_rate = rate;
+ timer0_state = 2;
+ return 0;
+}
+
+
+int
+acquire_timer2(int mode)
+{
+ if (timer2_state)
+ return -1;
+ timer2_state = 1;
+ outb(TIMER_MODE, TIMER_SEL2 | (mode &0x3f));
+ return 0;
+}
+
+
+int
+release_timer0()
+{
+ if (!timer0_state)
+ return -1;
+ timer0_state = 3;
+ return 0;
+}
+
+
+int
+release_timer2()
+{
+ if (!timer2_state)
+ return -1;
+ timer2_state = 0;
+ outb(TIMER_MODE, TIMER_SEL2|TIMER_SQWAVE|TIMER_16BIT);
+ return 0;
+}
+
+
+static int
+getit()
+{
+ int high, low;
+
+ disable_intr();
+ /* select timer0 and latch counter value */
+ outb(TIMER_MODE, TIMER_SEL0);
+ low = inb(TIMER_CNTR0);
+ high = inb(TIMER_CNTR0);
+ enable_intr();
+ return ((high << 8) | low);
+}
+
+
+/*
+ * Wait "n" microseconds.
+ * Relies on timer 1 counting down from (TIMER_FREQ / hz)
+ * Note: timer had better have been programmed before this is first used!
+ */
+void
+DELAY(int n)
+{
+ int counter_limit, prev_tick, tick, ticks_left, sec, usec;
+
+#ifdef DELAYDEBUG
+ int getit_calls = 1;
+ int n1;
+ static int state = 0;
+
+ if (state == 0) {
+ state = 1;
+ for (n1 = 1; n1 <= 10000000; n1 *= 10)
+ DELAY(n1);
+ state = 2;
+ }
+ if (state == 1)
+ printf("DELAY(%d)...", n);
+#endif
+ /*
+ * Read the counter first, so that the rest of the setup overhead is
+ * counted. Guess the initial overhead is 20 usec (on most systems it
+ * takes about 1.5 usec for each of the i/o's in getit(). The loop
+ * takes about 6 usec on a 486/33 and 13 usec on a 386/20. The
+ * multiplications and divisions to scale the count take a while).
+ */
+ prev_tick = getit(0, 0);
+ n -= 20;
+ /*
+ * Calculate (n * (TIMER_FREQ / 1e6)) without using floating point
+ * and without any avoidable overflows.
+ */
+ sec = n / 1000000;
+ usec = n - sec * 1000000;
+ ticks_left = sec * TIMER_FREQ
+ + usec * (TIMER_FREQ / 1000000)
+ + usec * ((TIMER_FREQ % 1000000) / 1000) / 1000
+ + usec * (TIMER_FREQ % 1000) / 1000000;
+
+ while (ticks_left > 0) {
+ tick = getit(0, 0);
+#ifdef DELAYDEBUG
+ ++getit_calls;
+#endif
+ if (tick > prev_tick)
+ ticks_left -= prev_tick - (tick - timer0_divisor);
+ else
+ ticks_left -= prev_tick - tick;
+ prev_tick = tick;
+ }
+#ifdef DELAYDEBUG
+ if (state == 1)
+ printf(" %d calls to getit() at %d usec each\n",
+ getit_calls, (n + 5) / getit_calls);
+#endif
+}
+
+
+static void
+sysbeepstop()
+{
+ outb(IO_PPI, inb(IO_PPI)&0xFC); /* disable counter2 output to speaker */
+ release_timer2();
+ beeping = 0;
+}
+
+
+int
+sysbeep(int pitch, int period)
+{
+
+ if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT))
+ return -1;
+ disable_intr();
+ outb(TIMER_CNTR2, pitch);
+ outb(TIMER_CNTR2, (pitch>>8));
+ enable_intr();
+ if (!beeping) {
+ outb(IO_PPI, inb(IO_PPI) | 3); /* enable counter2 output to speaker */
+ beeping = period;
+ timeout(sysbeepstop, 0, period);
+ }
+ return 0;
+}
+
+
+void
+startrtclock()
+{
+ int s;
+
+ /* initialize 8253 clock */
+ outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
+
+ /* Correct rounding will buy us a better precision in timekeeping */
+ outb (IO_TIMER1, TIMER_DIV(hz)%256);
+ outb (IO_TIMER1, TIMER_DIV(hz)/256);
+ timer0_divisor = hardclock_divisor = TIMER_DIV(hz);
+
+ /* initialize brain-dead battery powered clock */
+ outb (IO_RTC, RTC_STATUSA);
+ outb (IO_RTC+1, 0x26);
+ outb (IO_RTC, RTC_STATUSB);
+ outb (IO_RTC+1, 2);
+
+ outb (IO_RTC, RTC_DIAG);
+ if (s = inb (IO_RTC+1))
+ printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS);
+}
+
+
+/* convert 2 digit BCD number */
+int
+bcd(int i)
+{
+ return ((i/16)*10 + (i%16));
+}
+
+
+/* convert years to seconds (from 1970) */
+unsigned long
+ytos(int y)
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i = 1970; i < y; i++) {
+ if (i % 4) ret += 365*24*60*60;
+ else ret += 366*24*60*60;
+ }
+ return ret;
+}
+
+
+/* convert months to seconds */
+unsigned long
+mtos(int m, int leap)
+{
+ int i;
+ unsigned long ret;
+
+ ret = 0;
+ for(i=1; i<m; i++) {
+ switch(i){
+ case 1: case 3: case 5: case 7: case 8: case 10: case 12:
+ ret += 31*24*60*60; break;
+ case 4: case 6: case 9: case 11:
+ ret += 30*24*60*60; break;
+ case 2:
+ if (leap) ret += 29*24*60*60;
+ else ret += 28*24*60*60;
+ }
+ }
+ return ret;
+}
+
+
+/*
+ * Initialize the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+void
+inittodr(time_t base)
+{
+ unsigned long sec;
+ int leap, day_week, t, yd;
+ int sa,s;
+
+ /* do we have a realtime clock present? (otherwise we loop below) */
+ sa = rtcin(RTC_STATUSA);
+ if (sa == 0xff || sa == 0) return;
+
+ /* ready for a read? */
+ while ((sa&RTCSA_TUP) == RTCSA_TUP)
+ sa = rtcin(RTC_STATUSA);
+
+ sec = bcd(rtcin(RTC_YEAR)) + 1900;
+ if (sec < 1970)
+ sec += 100;
+
+ leap = !(sec % 4); sec = ytos(sec); /* year */
+ yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec+=yd; /* month */
+ t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec+=t; yd+=t; /* date */
+ day_week = rtcin(RTC_WDAY); /* day */
+ sec += bcd(rtcin(RTC_HRS)) * 60*60; /* hour */
+ sec += bcd(rtcin(RTC_MIN)) * 60; /* minutes */
+ sec += bcd(rtcin(RTC_SEC)); /* seconds */
+ sec += tz.tz_minuteswest * 60;
+ time.tv_sec = sec;
+}
+
+
+#ifdef garbage
+/*
+ * Initialze the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+test_inittodr(time_t base)
+{
+
+ outb(IO_RTC,9); /* year */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,8); /* month */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,7); /* day */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,4); /* hour */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,2); /* minutes */
+ printf("%d ",bcd(inb(IO_RTC+1)));
+ outb(IO_RTC,0); /* seconds */
+ printf("%d\n",bcd(inb(IO_RTC+1)));
+
+ time.tv_sec = base;
+}
+#endif
+
+
+/*
+ * Restart the clock.
+ */
+void
+resettodr()
+{
+}
+
+
+/*
+ * Wire clock interrupt in.
+ */
+#define V(s) __CONCAT(V, s)
+extern void V(clk)();
+
+
+void
+enablertclock()
+{
+ setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL);
+ INTREN(IRQ0);
+}
+
+
+/*
+ * Delay for some number of milliseconds.
+ */
+void
+spinwait(int millisecs)
+{
+ DELAY(1000 * millisecs);
+}
diff --git a/sys/isa/fd.c b/sys/isa/fd.c
new file mode 100644
index 0000000..d05c361
--- /dev/null
+++ b/sys/isa/fd.c
@@ -0,0 +1,1255 @@
+/*#define DEBUG 1*/
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)fd.c 7.4 (Berkeley) 5/25/91
+ * $Id: fd.c,v 1.24 1994/03/08 16:25:29 nate Exp $
+ *
+ */
+
+#include "ft.h"
+#if NFT < 1
+#undef NFDC
+#endif
+#include "fd.h"
+
+#if NFDC > 0
+
+#include <sys/param.h>
+#include <sys/dkbad.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <machine/ioctl_fd.h>
+#include <sys/disklabel.h>
+#include <sys/buf.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+#include <sys/syslog.h>
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/fdreg.h"
+#include "i386/isa/fdc.h"
+#include "i386/isa/icu.h"
+#include "i386/isa/rtc.h"
+
+#if NFT > 0
+extern int ftopen(), ftintr(), ftattach(), ftclose(), ftioctl();
+#endif
+
+#define b_cylin b_resid
+#define FDBLK 512
+
+/* misuse a flag to identify format operation */
+#define B_FORMAT B_XXX
+
+#define NUMTYPES 14
+#define NUMDENS (NUMTYPES - 6)
+
+/* This defines (-1) must match index for fd_types */
+#define F_TAPE_TYPE 0x020 /* bit for fd_types to indicate tape */
+#define NO_TYPE 0 /* must match NO_TYPE in ft.c */
+#define FD_1720 1
+#define FD_1480 2
+#define FD_1440 3
+#define FD_1200 4
+#define FD_820 5
+#define FD_800 6
+#define FD_720 7
+#define FD_360 8
+
+#define FD_1480in5_25 9
+#define FD_1440in5_25 10
+#define FD_820in5_25 11
+#define FD_800in5_25 12
+#define FD_720in5_25 13
+#define FD_360in5_25 14
+
+
+struct fd_type fd_types[NUMTYPES] =
+{
+{ 21,2,0xFF,0x04,82,3444,1,FDC_500KBPS,2,0x0C,2 }, /* 1.72M in HD 3.5in */
+{ 18,2,0xFF,0x1B,82,2952,1,FDC_500KBPS,2,0x6C,1 }, /* 1.48M in HD 3.5in */
+{ 18,2,0xFF,0x1B,80,2880,1,FDC_500KBPS,2,0x6C,1 }, /* 1.44M in HD 3.5in */
+{ 15,2,0xFF,0x1B,80,2400,1,FDC_500KBPS,2,0x54,1 }, /* 1.2M in HD 5.25/3.5 */
+{ 10,2,0xFF,0x10,82,1640,1,FDC_250KBPS,2,0x2E,1 }, /* 820K in HD 3.5in */
+{ 10,2,0xFF,0x10,80,1600,1,FDC_250KBPS,2,0x2E,1 }, /* 800K in HD 3.5in */
+{ 9,2,0xFF,0x20,80,1440,1,FDC_250KBPS,2,0x50,1 }, /* 720K in HD 3.5in */
+{ 9,2,0xFF,0x2A,40, 720,1,FDC_250KBPS,2,0x50,1 }, /* 360K in DD 5.25in */
+
+{ 18,2,0xFF,0x02,82,2952,1,FDC_500KBPS,2,0x02,2 }, /* 1.48M in HD 5.25in */
+{ 18,2,0xFF,0x02,80,2880,1,FDC_500KBPS,2,0x02,2 }, /* 1.44M in HD 5.25in */
+{ 10,2,0xFF,0x10,82,1640,1,FDC_300KBPS,2,0x2E,1 }, /* 820K in HD 5.25in */
+{ 10,2,0xFF,0x10,80,1600,1,FDC_300KBPS,2,0x2E,1 }, /* 800K in HD 5.25in */
+{ 9,2,0xFF,0x20,80,1440,1,FDC_300KBPS,2,0x50,1 }, /* 720K in HD 5.25in */
+{ 9,2,0xFF,0x23,40, 720,2,FDC_300KBPS,2,0x50,1 }, /* 360K in HD 5.25in */
+};
+
+#define DRVS_PER_CTLR 2 /* 2 floppies */
+/***********************************************************************\
+* Per controller structure. *
+\***********************************************************************/
+struct fdc_data fdc_data[NFDC];
+
+/***********************************************************************\
+* Per drive structure. *
+* N per controller (DRVS_PER_CTLR) *
+\***********************************************************************/
+struct fd_data {
+ struct fdc_data *fdc; /* pointer to controller structure */
+ int fdsu; /* this units number on this controller */
+ int type; /* Drive type (HD, DD */
+ struct fd_type *ft; /* pointer to the type descriptor */
+ int flags;
+#define FD_OPEN 0x01 /* it's open */
+#define FD_ACTIVE 0x02 /* it's active */
+#define FD_MOTOR 0x04 /* motor should be on */
+#define FD_MOTOR_WAIT 0x08 /* motor coming up */
+ int skip;
+ int hddrv;
+ int track; /* where we think the head is */
+} fd_data[NFD];
+
+/***********************************************************************\
+* Throughout this file the following conventions will be used: *
+* fd is a pointer to the fd_data struct for the drive in question *
+* fdc is a pointer to the fdc_data struct for the controller *
+* fdu is the floppy drive unit number *
+* fdcu is the floppy controller unit number *
+* fdsu is the floppy drive unit number on that controller. (sub-unit) *
+\***********************************************************************/
+
+#define id_physid id_scsiid /* this biotab field doubles as a field */
+ /* for the physical unit number on the controller */
+
+static int retrier(fdcu_t);
+
+#define DEVIDLE 0
+#define FINDWORK 1
+#define DOSEEK 2
+#define SEEKCOMPLETE 3
+#define IOCOMPLETE 4
+#define RECALCOMPLETE 5
+#define STARTRECAL 6
+#define RESETCTLR 7
+#define SEEKWAIT 8
+#define RECALWAIT 9
+#define MOTORWAIT 10
+#define IOTIMEDOUT 11
+
+#ifdef DEBUG
+char *fdstates[] =
+{
+"DEVIDLE",
+"FINDWORK",
+"DOSEEK",
+"SEEKCOMPLETE",
+"IOCOMPLETE",
+"RECALCOMPLETE",
+"STARTRECAL",
+"RESETCTLR",
+"SEEKWAIT",
+"RECALWAIT",
+"MOTORWAIT",
+"IOTIMEDOUT"
+};
+
+
+int fd_debug = 1;
+#define TRACE0(arg) if(fd_debug) printf(arg)
+#define TRACE1(arg1,arg2) if(fd_debug) printf(arg1,arg2)
+#else /* DEBUG */
+#define TRACE0(arg)
+#define TRACE1(arg1,arg2)
+#endif /* DEBUG */
+
+static void fdstart(fdcu_t);
+void fdintr(fdcu_t);
+static void fd_turnoff(caddr_t, int);
+
+/****************************************************************************/
+/* autoconfiguration stuff */
+/****************************************************************************/
+static int fdprobe(struct isa_device *);
+static int fdattach(struct isa_device *);
+
+struct isa_driver fdcdriver = {
+ fdprobe, fdattach, "fdc",
+};
+
+/*
+ * probe for existance of controller
+ */
+int
+fdprobe(dev)
+ struct isa_device *dev;
+{
+ fdcu_t fdcu = dev->id_unit;
+ if(fdc_data[fdcu].flags & FDC_ATTACHED)
+ {
+ printf("fdc: same unit (%d) used multiple times\n",fdcu);
+ return 0;
+ }
+
+ fdc_data[fdcu].baseport = dev->id_iobase;
+
+ /* First - lets reset the floppy controller */
+
+ outb(dev->id_iobase+fdout,0);
+ DELAY(100);
+ outb(dev->id_iobase+fdout,FDO_FRST);
+
+ /* see if it can handle a command */
+ if (out_fdc(fdcu,NE7CMD_SPECIFY) < 0)
+ {
+ return(0);
+ }
+ out_fdc(fdcu,0xDF);
+ out_fdc(fdcu,2);
+ return (IO_FDCSIZE);
+}
+
+/*
+ * wire controller into system, look for floppy units
+ */
+int
+fdattach(dev)
+ struct isa_device *dev;
+{
+ unsigned fdt,st0, cyl;
+ int hdr;
+ fdu_t fdu;
+ fdcu_t fdcu = dev->id_unit;
+ fdc_p fdc = fdc_data + fdcu;
+ fd_p fd;
+ int fdsu;
+ struct isa_device *fdup;
+
+ fdc->fdcu = fdcu;
+ fdc->flags |= FDC_ATTACHED;
+ fdc->dmachan = dev->id_drq;
+ fdc->state = DEVIDLE;
+ hdr = 0;
+ printf("fdc%d:", fdcu);
+
+ /* check for each floppy drive */
+ for (fdup = isa_biotab_fdc; fdup->id_driver != 0; fdup++) {
+ if (fdup->id_iobase != dev->id_iobase)
+ continue;
+ fdu = fdup->id_unit;
+ fd = &fd_data[fdu];
+ if (fdu >= (NFD+NFT))
+ continue;
+ fdsu = fdup->id_physid;
+ /* look up what bios thinks we have */
+ switch (fdu) {
+ case 0: fdt = (rtcin(RTC_FDISKETTE) & 0xf0);
+ break;
+ case 1: fdt = ((rtcin(RTC_FDISKETTE) << 4) & 0xf0);
+ break;
+ default: fdt = RTCFDT_NONE;
+ break;
+ }
+ /* is there a unit? */
+ if ((fdt == RTCFDT_NONE)
+#if NFT > 0
+ || (fdsu >= DRVS_PER_CTLR)) {
+#else
+ ) {
+ fd->type = NO_TYPE;
+#endif
+#if NFT > 0
+ /* If BIOS says no floppy, or > 2nd device */
+ /* Probe for and attach a floppy tape. */
+ if (ftattach(dev, fdup))
+ continue;
+ if (fdsu < DRVS_PER_CTLR)
+ fd->type = NO_TYPE;
+#endif
+ continue;
+ }
+
+#ifdef notyet
+ /* select it */
+ fd_turnon1(fdu);
+ spinwait(1000); /* 1 sec */
+ out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
+ out_fdc(fdcu,fdsu);
+ spinwait(1000); /* 1 sec */
+
+ /* anything responding */
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (st0 & 0xd0)
+ continue;
+
+#endif
+ fd->track = -2;
+ fd->fdc = fdc;
+ fd->fdsu = fdsu;
+ printf(" [%d: fd%d: ", fdsu, fdu);
+
+ switch (fdt) {
+ case RTCFDT_12M:
+ printf("1.2MB 5.25in]");
+ fd->type = FD_1200;
+ break;
+ case RTCFDT_144M:
+ printf("1.44MB 3.5in]");
+ fd->type = FD_1440;
+ break;
+ case RTCFDT_360K:
+ printf("360KB 5.25in]");
+ fd->type = FD_360;
+ break;
+ case RTCFDT_720K:
+ printf("720KB 3.5in]");
+ fd->type = FD_720;
+ break;
+ default:
+ printf("unknown]");
+ fd->type = NO_TYPE;
+ break;
+ }
+
+ fd_turnoff((caddr_t)fdu, 0);
+ hdr = 1;
+ }
+ printf("\n");
+
+ /* Set transfer to 500kbps */
+ outb(fdc->baseport+fdctl,0); /*XXX*/
+ return 1;
+}
+
+int
+fdsize(dev)
+ dev_t dev;
+{
+ return(0);
+}
+
+/****************************************************************************/
+/* fdstrategy */
+/****************************************************************************/
+void fdstrategy(struct buf *bp)
+{
+ register struct buf *dp,*dp0,*dp1;
+ long nblocks,blknum;
+ int s;
+ fdcu_t fdcu;
+ fdu_t fdu;
+ fdc_p fdc;
+ fd_p fd;
+
+ fdu = FDUNIT(minor(bp->b_dev));
+ fd = &fd_data[fdu];
+ fdc = fd->fdc;
+ fdcu = fdc->fdcu;
+
+#if NFT > 0
+ /* check for controller already busy with tape */
+ if (fdc->flags & FDC_TAPE_BUSY) {
+ bp->b_error = EBUSY;
+ bp->b_flags |= B_ERROR;
+ return;
+ }
+#endif
+ if ((fdu >= NFD) || (bp->b_blkno < 0)) {
+ printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n",
+ fdu, bp->b_blkno, bp->b_bcount);
+ pg("fd:error in fdstrategy");
+ bp->b_error = EINVAL;
+ bp->b_flags |= B_ERROR;
+ goto bad;
+ }
+ /*
+ * Set up block calculations.
+ */
+ blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK;
+ nblocks = fd->ft->size;
+ if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
+ if (blknum == nblocks) {
+ bp->b_resid = bp->b_bcount;
+ } else {
+ bp->b_error = ENOSPC;
+ bp->b_flags |= B_ERROR;
+ }
+ goto bad;
+ }
+ bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads);
+ bp->b_pblkno = bp->b_blkno;
+ dp = &(fdc->head);
+ s = splbio();
+ disksort(dp, bp);
+ untimeout(fd_turnoff, (caddr_t)fdu); /* a good idea */
+ fdstart(fdcu);
+ splx(s);
+ return;
+
+bad:
+ biodone(bp);
+ return;
+}
+
+/****************************************************************************/
+/* motor control stuff */
+/* remember to not deselect the drive we're working on */
+/****************************************************************************/
+void
+set_motor(fdcu, fdu, reset)
+ fdcu_t fdcu;
+ fdu_t fdu;
+ int reset;
+{
+ int m0,m1;
+ int selunit;
+ fd_p fd;
+ if(fd = fdc_data[fdcu].fd)/* yes an assign! */
+ {
+ selunit = fd->fdsu;
+ }
+ else
+ {
+ selunit = 0;
+ }
+ m0 = fd_data[fdcu * DRVS_PER_CTLR + 0].flags & FD_MOTOR;
+ m1 = fd_data[fdcu * DRVS_PER_CTLR + 1].flags & FD_MOTOR;
+ outb(fdc_data[fdcu].baseport+fdout,
+ selunit
+ | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
+ | (m0 ? FDO_MOEN0 : 0)
+ | (m1 ? FDO_MOEN1 : 0));
+ TRACE1("[0x%x->fdout]",(
+ selunit
+ | (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
+ | (m0 ? FDO_MOEN0 : 0)
+ | (m1 ? FDO_MOEN1 : 0)));
+}
+
+static void
+fd_turnoff(caddr_t arg1, int arg2)
+{
+ fdu_t fdu = (fdu_t)arg1;
+ int s;
+
+ fd_p fd = fd_data + fdu;
+ s = splbio();
+ fd->flags &= ~FD_MOTOR;
+ set_motor(fd->fdc->fdcu,fd->fdsu,0);
+ splx(s);
+}
+
+void
+fd_motor_on(caddr_t arg1, int arg2)
+{
+ fdu_t fdu = (fdu_t)arg1;
+ int s;
+
+ fd_p fd = fd_data + fdu;
+ s = splbio();
+ fd->flags &= ~FD_MOTOR_WAIT;
+ if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT))
+ {
+ fdintr(fd->fdc->fdcu);
+ }
+ splx(s);
+}
+
+static void fd_turnon1(fdu_t);
+
+void
+fd_turnon(fdu)
+ fdu_t fdu;
+{
+ fd_p fd = fd_data + fdu;
+ if(!(fd->flags & FD_MOTOR))
+ {
+ fd_turnon1(fdu);
+ fd->flags |= FD_MOTOR_WAIT;
+ timeout(fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */
+ }
+}
+
+static void
+fd_turnon1(fdu_t fdu)
+{
+ fd_p fd = fd_data + fdu;
+ fd->flags |= FD_MOTOR;
+ set_motor(fd->fdc->fdcu,fd->fdsu,0);
+}
+
+/****************************************************************************/
+/* fdc in/out */
+/****************************************************************************/
+int
+in_fdc(fdcu)
+ fdcu_t fdcu;
+{
+ int baseport = fdc_data[fdcu].baseport;
+ int i, j = 100000;
+ while ((i = inb(baseport+fdsts) & (NE7_DIO|NE7_RQM))
+ != (NE7_DIO|NE7_RQM) && j-- > 0)
+ if (i == NE7_RQM) return -1;
+ if (j <= 0)
+ return(-1);
+#ifdef DEBUG
+ i = inb(baseport+fddata);
+ TRACE1("[fddata->0x%x]",(unsigned char)i);
+ return(i);
+#else
+ return inb(baseport+fddata);
+#endif
+}
+
+int
+out_fdc(fdcu, x)
+ fdcu_t fdcu;
+ int x;
+{
+ int baseport = fdc_data[fdcu].baseport;
+ int i;
+
+ /* Check that the direction bit is set */
+ i = 100000;
+ while ((inb(baseport+fdsts) & NE7_DIO) && i-- > 0);
+ if (i <= 0) return (-1); /* Floppy timed out */
+
+ /* Check that the floppy controller is ready for a command */
+ i = 100000;
+ while ((inb(baseport+fdsts) & NE7_RQM) == 0 && i-- > 0);
+ if (i <= 0) return (-1); /* Floppy timed out */
+
+ /* Send the command and return */
+ outb(baseport+fddata,x);
+ TRACE1("[0x%x->fddata]",x);
+ return (0);
+}
+
+/****************************************************************************/
+/* fdopen/fdclose */
+/****************************************************************************/
+int
+Fdopen(dev, flags)
+ dev_t dev;
+ int flags;
+{
+ fdu_t fdu = FDUNIT(minor(dev));
+ int type = FDTYPE(minor(dev));
+ fdc_p fdc;
+
+#if NFT > 0
+ /* check for a tape open */
+ if (type & F_TAPE_TYPE)
+ return(ftopen(dev, flags));
+#endif
+ /* check bounds */
+ if (fdu >= NFD)
+ return(ENXIO);
+ fdc = fd_data[fdu].fdc;
+ if ((fdc == NULL) || (fd_data[fdu].type == NO_TYPE))
+ return(ENXIO);
+ if (type > NUMDENS)
+ return(ENXIO);
+ if (type == 0)
+ type = fd_data[fdu].type;
+ else {
+ if (type != fd_data[fdu].type) {
+ switch (fd_data[fdu].type) {
+ case FD_360:
+ return(ENXIO);
+ case FD_720:
+ if ( type != FD_820
+ && type != FD_800
+ )
+ return(ENXIO);
+ break;
+ case FD_1200:
+ switch (type) {
+ case FD_1480:
+ type = FD_1480in5_25;
+ break;
+ case FD_1440:
+ type = FD_1440in5_25;
+ break;
+ case FD_820:
+ type = FD_820in5_25;
+ break;
+ case FD_800:
+ type = FD_800in5_25;
+ break;
+ case FD_720:
+ type = FD_720in5_25;
+ break;
+ case FD_360:
+ type = FD_360in5_25;
+ break;
+ default:
+ return(ENXIO);
+ }
+ break;
+ case FD_1440:
+ if ( type != FD_1720
+ && type != FD_1480
+ && type != FD_1200
+ && type != FD_820
+ && type != FD_800
+ && type != FD_720
+ )
+ return(ENXIO);
+ break;
+ }
+ }
+ }
+ fd_data[fdu].ft = fd_types + type - 1;
+ fd_data[fdu].flags |= FD_OPEN;
+
+ return 0;
+}
+
+int
+fdclose(dev, flags)
+ dev_t dev;
+ int flags;
+{
+ fdu_t fdu = FDUNIT(minor(dev));
+ int type = FDTYPE(minor(dev));
+
+#if NFT > 0
+ if (type & F_TAPE_TYPE)
+ return ftclose(0);
+#endif
+ fd_data[fdu].flags &= ~FD_OPEN;
+ return(0);
+}
+
+
+/***************************************************************\
+* fdstart *
+* We have just queued something.. if the controller is not busy *
+* then simulate the case where it has just finished a command *
+* So that it (the interrupt routine) looks on the queue for more*
+* work to do and picks up what we just added. *
+* If the controller is already busy, we need do nothing, as it *
+* will pick up our work when the present work completes *
+\***************************************************************/
+static void
+fdstart(fdcu)
+ fdcu_t fdcu;
+{
+ register struct buf *dp,*bp;
+ int s;
+ fdu_t fdu;
+
+ s = splbio();
+ if(fdc_data[fdcu].state == DEVIDLE)
+ {
+ fdintr(fdcu);
+ }
+ splx(s);
+}
+
+static void
+fd_timeout(caddr_t arg1, int arg2)
+{
+ fdcu_t fdcu = (fdcu_t)arg1;
+ fdu_t fdu = fdc_data[fdcu].fdu;
+ int st0, st3, cyl;
+ struct buf *dp,*bp;
+ int s;
+
+ dp = &fdc_data[fdcu].head;
+ s = splbio();
+ bp = dp->b_actf;
+
+ out_fdc(fdcu,NE7CMD_SENSED);
+ out_fdc(fdcu,fd_data[fdu].hddrv);
+ st3 = in_fdc(fdcu);
+
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ printf("fd%d: Operation timeout ST0 %b cyl %d ST3 %b\n",
+ fdu,
+ st0,
+ NE7_ST0BITS,
+ cyl,
+ st3,
+ NE7_ST3BITS);
+
+ if (bp)
+ {
+ retrier(fdcu);
+ fdc_data[fdcu].status[0] = 0xc0;
+ fdc_data[fdcu].state = IOTIMEDOUT;
+ if( fdc_data[fdcu].retry < 6)
+ fdc_data[fdcu].retry = 6;
+ }
+ else
+ {
+ fdc_data[fdcu].fd = (fd_p) 0;
+ fdc_data[fdcu].fdu = -1;
+ fdc_data[fdcu].state = DEVIDLE;
+ }
+ fdintr(fdcu);
+ splx(s);
+}
+
+/* just ensure it has the right spl */
+static void
+fd_pseudointr(caddr_t arg1, int arg2)
+{
+ fdcu_t fdcu = (fdcu_t)arg1;
+ int s;
+ s = splbio();
+ fdintr(fdcu);
+ splx(s);
+}
+
+/***********************************************************************\
+* fdintr *
+* keep calling the state machine until it returns a 0 *
+* ALWAYS called at SPLBIO *
+\***********************************************************************/
+void
+fdintr(fdcu_t fdcu)
+{
+ fdc_p fdc = fdc_data + fdcu;
+#if NFT > 0
+ fdu_t fdu = fdc->fdu;
+
+ if (fdc->flags & FDC_TAPE_BUSY)
+ (ftintr(fdu));
+ else
+#endif
+ while(fdstate(fdcu, fdc))
+ ;
+}
+
+/***********************************************************************\
+* The controller state machine. *
+* if it returns a non zero value, it should be called again immediatly *
+\***********************************************************************/
+int
+fdstate(fdcu, fdc)
+ fdcu_t fdcu;
+ fdc_p fdc;
+{
+ int read, format, head, trac, sec = 0, i = 0, s, sectrac, cyl, st0;
+ unsigned long blknum;
+ fdu_t fdu = fdc->fdu;
+ fd_p fd;
+ register struct buf *dp,*bp;
+ struct fd_formb *finfo = NULL;
+
+ dp = &(fdc->head);
+ bp = dp->b_actf;
+ if(!bp)
+ {
+ /***********************************************\
+ * nothing left for this controller to do *
+ * Force into the IDLE state, *
+ \***********************************************/
+ fdc->state = DEVIDLE;
+ if(fdc->fd)
+ {
+ printf("unexpected valid fd pointer (fdu = %d)\n"
+ ,fdc->fdu);
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ }
+ TRACE1("[fdc%d IDLE]",fdcu);
+ return(0);
+ }
+ fdu = FDUNIT(minor(bp->b_dev));
+ fd = fd_data + fdu;
+ if (fdc->fd && (fd != fdc->fd))
+ {
+ printf("confused fd pointers\n");
+ }
+ read = bp->b_flags & B_READ;
+ format = bp->b_flags & B_FORMAT;
+ if(format)
+ finfo = (struct fd_formb *)bp->b_un.b_addr;
+ TRACE1("fd%d",fdu);
+ TRACE1("[%s]",fdstates[fdc->state]);
+ TRACE1("(0x%x)",fd->flags);
+ untimeout(fd_turnoff, (caddr_t)fdu);
+ timeout(fd_turnoff, (caddr_t)fdu, 4 * hz);
+ switch (fdc->state)
+ {
+ case DEVIDLE:
+ case FINDWORK: /* we have found new work */
+ fdc->retry = 0;
+ fd->skip = 0;
+ fdc->fd = fd;
+ fdc->fdu = fdu;
+ outb(fdc->baseport+fdctl, fd->ft->trans);
+ /*******************************************************\
+ * If the next drive has a motor startup pending, then *
+ * it will start up in it's own good time *
+ \*******************************************************/
+ if(fd->flags & FD_MOTOR_WAIT)
+ {
+ fdc->state = MOTORWAIT;
+ return(0); /* come back later */
+ }
+ /*******************************************************\
+ * Maybe if it's not starting, it SHOULD be starting *
+ \*******************************************************/
+ if (!(fd->flags & FD_MOTOR))
+ {
+ fdc->state = MOTORWAIT;
+ fd_turnon(fdu);
+ return(0);
+ }
+ else /* at least make sure we are selected */
+ {
+ set_motor(fdcu,fd->fdsu,0);
+ }
+ fdc->state = DOSEEK;
+ break;
+ case DOSEEK:
+ if (bp->b_cylin == fd->track)
+ {
+ fdc->state = SEEKCOMPLETE;
+ break;
+ }
+ out_fdc(fdcu,NE7CMD_SEEK); /* Seek function */
+ out_fdc(fdcu,fd->fdsu); /* Drive number */
+ out_fdc(fdcu,bp->b_cylin * fd->ft->steptrac);
+ fd->track = -2;
+ fdc->state = SEEKWAIT;
+ timeout(fd_timeout, (caddr_t)fdcu, 2 * hz);
+ return(0); /* will return later */
+ case SEEKWAIT:
+ untimeout(fd_timeout, (caddr_t)fdcu);
+ /* allow heads to settle */
+ timeout(fd_pseudointr, (caddr_t)fdcu, hz / 50);
+ fdc->state = SEEKCOMPLETE;
+ return(0); /* will return later */
+ break;
+
+ case SEEKCOMPLETE : /* SEEK DONE, START DMA */
+ /* Make sure seek really happened*/
+ if(fd->track == -2)
+ {
+ int descyl = bp->b_cylin * fd->ft->steptrac;
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ i = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (cyl != descyl)
+ {
+ printf("fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n",
+ fdu, descyl, cyl, i, NE7_ST0BITS);
+ return(retrier(fdcu));
+ }
+ }
+
+ fd->track = bp->b_cylin;
+ if(format)
+ fd->skip = (char *)&(finfo->fd_formb_cylno(0))
+ - (char *)finfo;
+ isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip,
+ format ? bp->b_bcount : FDBLK, fdc->dmachan);
+ blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
+ + fd->skip/FDBLK;
+ sectrac = fd->ft->sectrac;
+ sec = blknum % (sectrac * fd->ft->heads);
+ head = sec / sectrac;
+ sec = sec % sectrac + 1;
+/*XXX*/ fd->hddrv = ((head&1)<<2)+fdu;
+
+ if(format)
+ {
+ /* formatting */
+ out_fdc(fdcu,/* NE7CMD_FORMAT */ 0x4d);
+ out_fdc(fdcu,head << 2 | fdu);
+ out_fdc(fdcu,finfo->fd_formb_secshift);
+ out_fdc(fdcu,finfo->fd_formb_nsecs);
+ out_fdc(fdcu,finfo->fd_formb_gaplen);
+ out_fdc(fdcu,finfo->fd_formb_fillbyte);
+ }
+ else
+ {
+ if (read)
+ {
+ out_fdc(fdcu,NE7CMD_READ); /* READ */
+ }
+ else
+ {
+ out_fdc(fdcu,NE7CMD_WRITE); /* WRITE */
+ }
+ out_fdc(fdcu,head << 2 | fdu); /* head & unit */
+ out_fdc(fdcu,fd->track); /* track */
+ out_fdc(fdcu,head);
+ out_fdc(fdcu,sec); /* sector XXX +1? */
+ out_fdc(fdcu,fd->ft->secsize); /* sector size */
+ out_fdc(fdcu,sectrac); /* sectors/track */
+ out_fdc(fdcu,fd->ft->gap); /* gap size */
+ out_fdc(fdcu,fd->ft->datalen); /* data length */
+ }
+ fdc->state = IOCOMPLETE;
+ timeout(fd_timeout, (caddr_t)fdcu, 2 * hz);
+ return(0); /* will return later */
+ case IOCOMPLETE: /* IO DONE, post-analyze */
+ untimeout(fd_timeout, (caddr_t)fdcu);
+ for(i=0;i<7;i++)
+ {
+ fdc->status[i] = in_fdc(fdcu);
+ }
+ case IOTIMEDOUT: /*XXX*/
+ isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip,
+ format ? bp->b_bcount : FDBLK, fdc->dmachan);
+ if (fdc->status[0]&0xF8)
+ {
+ if (fdc->status[1] & 0x10) {
+ /*
+ * Operation not completed in reasonable time.
+ * Just restart it, don't increment retry count.
+ * (vak)
+ */
+ fdc->state = SEEKCOMPLETE;
+ return (1);
+ }
+ return(retrier(fdcu));
+ }
+ /* All OK */
+ fd->skip += FDBLK;
+ if (!format && fd->skip < bp->b_bcount)
+ {
+ /* set up next transfer */
+ blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
+ + fd->skip/FDBLK;
+ bp->b_cylin = (blknum / (fd->ft->sectrac * fd->ft->heads));
+ fdc->state = DOSEEK;
+ }
+ else
+ {
+ /* ALL DONE */
+ fd->skip = 0;
+ bp->b_resid = 0;
+ dp->b_actf = bp->av_forw;
+ biodone(bp);
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ fdc->state = FINDWORK;
+ }
+ return(1);
+ case RESETCTLR:
+ /* Try a reset, keep motor on */
+ set_motor(fdcu,fd->fdsu,1);
+ DELAY(100);
+ set_motor(fdcu,fd->fdsu,0);
+ outb(fdc->baseport+fdctl,fd->ft->trans);
+ TRACE1("[0x%x->fdctl]",fd->ft->trans);
+ fdc->retry++;
+ fdc->state = STARTRECAL;
+ break;
+ case STARTRECAL:
+ out_fdc(fdcu,NE7CMD_SPECIFY); /* specify command */
+ out_fdc(fdcu,0xDF);
+ out_fdc(fdcu,2);
+ out_fdc(fdcu,NE7CMD_RECAL); /* Recalibrate Function */
+ out_fdc(fdcu,fdu);
+ fdc->state = RECALWAIT;
+ return(0); /* will return later */
+ case RECALWAIT:
+ /* allow heads to settle */
+ timeout(fd_pseudointr, (caddr_t)fdcu, hz / 30);
+ fdc->state = RECALCOMPLETE;
+ return(0); /* will return later */
+ case RECALCOMPLETE:
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ if (cyl != 0)
+ {
+ printf("fd%d: recal failed ST0 %b cyl %d\n", fdu,
+ st0, NE7_ST0BITS, cyl);
+ return(retrier(fdcu));
+ }
+ fd->track = 0;
+ /* Seek (probably) necessary */
+ fdc->state = DOSEEK;
+ return(1); /* will return immediatly */
+ case MOTORWAIT:
+ if(fd->flags & FD_MOTOR_WAIT)
+ {
+ return(0); /* time's not up yet */
+ }
+ fdc->state = DOSEEK;
+ return(1); /* will return immediatly */
+ default:
+ printf("Unexpected FD int->");
+ out_fdc(fdcu,NE7CMD_SENSEI);
+ st0 = in_fdc(fdcu);
+ cyl = in_fdc(fdcu);
+ printf("ST0 = %lx, PCN = %lx\n",i,sec);
+ out_fdc(fdcu,0x4A);
+ out_fdc(fdcu,fd->fdsu);
+ for(i=0;i<7;i++) {
+ fdc->status[i] = in_fdc(fdcu);
+ }
+ printf("intr status :%lx %lx %lx %lx %lx %lx %lx ",
+ fdc->status[0],
+ fdc->status[1],
+ fdc->status[2],
+ fdc->status[3],
+ fdc->status[4],
+ fdc->status[5],
+ fdc->status[6] );
+ return(0);
+ }
+ return(1); /* Come back immediatly to new state */
+}
+
+static int
+retrier(fdcu)
+ fdcu_t fdcu;
+{
+ fdc_p fdc = fdc_data + fdcu;
+ register struct buf *dp,*bp;
+
+ dp = &(fdc->head);
+ bp = dp->b_actf;
+
+ switch(fdc->retry)
+ {
+ case 0: case 1: case 2:
+ fdc->state = SEEKCOMPLETE;
+ break;
+ case 3: case 4: case 5:
+ fdc->state = STARTRECAL;
+ break;
+ case 6:
+ fdc->state = RESETCTLR;
+ break;
+ case 7:
+ break;
+ default:
+ {
+ dev_t sav_b_dev = bp->b_dev;
+ /* Trick diskerr */
+ bp->b_dev = makedev(major(bp->b_dev), (FDUNIT(minor(bp->b_dev))<<3)|3);
+ diskerr(bp, "fd", "hard error", LOG_PRINTF,
+ fdc->fd->skip, (struct disklabel *)NULL);
+ bp->b_dev = sav_b_dev;
+ printf(" (ST0 %b ", fdc->status[0], NE7_ST0BITS);
+ printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS);
+ printf(" ST2 %b ", fdc->status[2], NE7_ST2BITS);
+ printf("cyl %d hd %d sec %d)\n",
+ fdc->status[3], fdc->status[4], fdc->status[5]);
+ }
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ bp->b_resid = bp->b_bcount - fdc->fd->skip;
+ dp->b_actf = bp->av_forw;
+ fdc->fd->skip = 0;
+ biodone(bp);
+ fdc->state = FINDWORK;
+ fdc->fd = (fd_p) 0;
+ fdc->fdu = -1;
+ /* XXX abort current command, if any. */
+ return(1);
+ }
+ fdc->retry++;
+ return(1);
+}
+
+static int
+fdformat(dev, finfo, p)
+ dev_t dev;
+ struct fd_formb *finfo;
+ struct proc *p;
+{
+ fdu_t fdu;
+ fd_p fd;
+
+ struct buf *bp;
+ int rv = 0, s;
+
+ fdu = FDUNIT(minor(dev));
+ fd = &fd_data[fdu];
+
+ /* set up a buffer header for fdstrategy() */
+ bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
+ if(bp == 0)
+ return ENOBUFS;
+ bzero((void *)bp, sizeof(struct buf));
+ bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
+ bp->b_proc = p;
+ bp->b_dev = dev;
+
+ /*
+ * calculate a fake blkno, so fdstrategy() would initiate a
+ * seek to the requested cylinder
+ */
+ bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads)
+ + finfo->head * fd->ft->sectrac) * FDBLK / DEV_BSIZE;
+
+ bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
+ bp->b_un.b_addr = (caddr_t)finfo;
+
+ /* now do the format */
+ fdstrategy(bp);
+
+ /* ...and wait for it to complete */
+ s = splbio();
+ while(!(bp->b_flags & B_DONE))
+ {
+ rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
+ if(rv == EWOULDBLOCK)
+ break;
+ }
+ splx(s);
+
+ if(rv == EWOULDBLOCK)
+ {
+ /* timed out */
+ biodone(bp);
+ rv = EIO;
+ }
+ free(bp, M_TEMP);
+ return rv;
+}
+
+/*
+ * fdioctl() from jc@irbs.UUCP (John Capo)
+ * i386/i386/conf.c needs to have fdioctl() declared and remove the line that
+ * defines fdioctl to be enxio.
+ *
+ * TODO: Reformat.
+ * Think about allocating buffer off stack.
+ * Don't pass uncast 0's and NULL's to read/write/setdisklabel().
+ * Watch out for NetBSD's different *disklabel() interface.
+ *
+ * Added functionality for floppy formatting
+ * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
+ */
+
+int
+fdioctl (dev, cmd, addr, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t addr;
+ int flag;
+ struct proc *p;
+{
+ struct fd_type *fdt;
+ struct disklabel *dl;
+ char buffer[DEV_BSIZE];
+ int error;
+
+#if NFT > 0
+ int type = FDTYPE(minor(dev));
+
+ /* check for a tape ioctl */
+ if (type & F_TAPE_TYPE)
+ return ftioctl(dev, cmd, addr, flag, p);
+#endif
+
+ error = 0;
+
+ switch (cmd)
+ {
+ case DIOCGDINFO:
+ bzero(buffer, sizeof (buffer));
+ dl = (struct disklabel *)buffer;
+ dl->d_secsize = FDBLK;
+ fdt = fd_data[FDUNIT(minor(dev))].ft;
+ dl->d_secpercyl = fdt->size / fdt->tracks;
+ dl->d_type = DTYPE_FLOPPY;
+
+ if (readdisklabel(dev, fdstrategy, dl, NULL, 0, 0) == NULL)
+ error = 0;
+ else
+ error = EINVAL;
+
+ *(struct disklabel *)addr = *dl;
+ break;
+
+ case DIOCSDINFO:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ break;
+
+ case DIOCWLABEL:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ break;
+
+ case DIOCWDINFO:
+ if ((flag & FWRITE) == 0)
+ {
+ error = EBADF;
+ break;
+ }
+
+ dl = (struct disklabel *)addr;
+
+ if (error = setdisklabel ((struct disklabel *)buffer,
+ dl, 0, NULL))
+ break;
+
+ error = writedisklabel(dev, fdstrategy,
+ (struct disklabel *)buffer, NULL);
+ break;
+
+ case FD_FORM:
+ if((flag & FWRITE) == 0)
+ error = EBADF; /* must be opened for writing */
+ else if(((struct fd_formb *)addr)->format_version !=
+ FD_FORMAT_VERSION)
+ error = EINVAL; /* wrong version of formatting prog */
+ else
+ error = fdformat(dev, (struct fd_formb *)addr, p);
+ break;
+
+ case FD_GTYPE: /* get drive type */
+ *(struct fd_type *)addr = *fd_data[FDUNIT(minor(dev))].ft;
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ return (error);
+}
+
+#endif
diff --git a/sys/isa/fdc.h b/sys/isa/fdc.h
new file mode 100644
index 0000000..1542f0e
--- /dev/null
+++ b/sys/isa/fdc.h
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)fd.c 7.4 (Berkeley) 5/25/91
+ * $Id:$
+ *
+ */
+
+
+/***********************************************************************\
+* Per controller structure. *
+\***********************************************************************/
+struct fdc_data
+{
+ int fdcu; /* our unit number */
+ int baseport;
+ int dmachan;
+ int flags;
+#define FDC_ATTACHED 0x01
+#define FDC_HASFTAPE 0x02
+#define FDC_TAPE_BUSY 0x04
+ struct fd_data *fd;
+ int fdu; /* the active drive */
+ struct buf head; /* Head of buf chain */
+ struct buf rhead; /* Raw head of buf chain */
+ int state;
+ int retry;
+ int status[7]; /* copy of the registers */
+};
+
+/***********************************************************************\
+* Throughout this file the following conventions will be used: *
+* fd is a pointer to the fd_data struct for the drive in question *
+* fdc is a pointer to the fdc_data struct for the controller *
+* fdu is the floppy drive unit number *
+* fdcu is the floppy controller unit number *
+* fdsu is the floppy drive unit number on that controller. (sub-unit) *
+\***********************************************************************/
+typedef int fdu_t;
+typedef int fdcu_t;
+typedef int fdsu_t;
+typedef struct fd_data *fd_p;
+typedef struct fdc_data *fdc_p;
+
+#define FDUNIT(s) (((s)>>6)&03)
+#define FDTYPE(s) ((s)&077)
diff --git a/sys/isa/fdreg.h b/sys/isa/fdreg.h
new file mode 100644
index 0000000..5deb02c
--- /dev/null
+++ b/sys/isa/fdreg.h
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)fdreg.h 7.1 (Berkeley) 5/9/91
+ * $Id: fdreg.h,v 1.3 1994/02/07 04:27:10 alm Exp $
+ */
+
+/*
+ * AT floppy controller registers and bitfields
+ */
+
+/* uses NEC765 controller */
+#include "../i386/isa/ic/nec765.h"
+
+/* registers */
+#define fdout 2 /* Digital Output Register (W) */
+#define FDO_FDSEL 0x03 /* floppy device select */
+#define FDO_FRST 0x04 /* floppy controller reset */
+#define FDO_FDMAEN 0x08 /* enable floppy DMA and Interrupt */
+#define FDO_MOEN0 0x10 /* motor enable drive 0 */
+#define FDO_MOEN1 0x20 /* motor enable drive 1 */
+#define FDO_MOEN2 0x30 /* motor enable drive 2 */
+#define FDO_MOEN3 0x40 /* motor enable drive 3 */
+
+#define fdsts 4 /* NEC 765 Main Status Register (R) */
+#define fddata 5 /* NEC 765 Data Register (R/W) */
+
+#define fdctl 7 /* Control Register (W) */
+#define FDC_500KBPS 0x00 /* 500KBPS MFM drive transfer rate */
+#define FDC_300KBPS 0x01 /* 300KBPS MFM drive transfer rate */
+#define FDC_250KBPS 0x02 /* 250KBPS MFM drive transfer rate */
+#define FDC_125KBPS 0x03 /* 125KBPS FM drive transfer rate */
+
+#define fdin 7 /* Digital Input Register (R) */
+#define FDI_DCHG 0x80 /* diskette has been changed */
+
diff --git a/sys/isa/ic/nec765.h b/sys/isa/ic/nec765.h
new file mode 100644
index 0000000..1895db7
--- /dev/null
+++ b/sys/isa/ic/nec765.h
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)nec765.h 7.1 (Berkeley) 5/9/91
+ * $Id$
+ */
+
+/*
+ * Nec 765 floppy disc controller definitions
+ */
+
+/* Main status register */
+#define NE7_DAB 0x01 /* Diskette drive A is seeking, thus busy */
+#define NE7_DBB 0x02 /* Diskette drive B is seeking, thus busy */
+#define NE7_CB 0x10 /* Diskette Controller Busy */
+#define NE7_NDM 0x20 /* Diskette Controller in Non Dma Mode */
+#define NE7_DIO 0x40 /* Diskette Controller Data register I/O */
+#define NE7_RQM 0x80 /* Diskette Controller ReQuest for Master */
+
+/* Status register ST0 */
+#define NE7_ST0BITS "\020\010invld\007abnrml\006seek_cmplt\005drv_chck\004drive_rdy\003top_head"
+
+/* Status register ST1 */
+#define NE7_ST1BITS "\020\010end_of_cyl\006bad_crc\005data_overrun\003sec_not_fnd\002write_protect\001no_am"
+
+/* Status register ST2 */
+#define NE7_ST2BITS "\020\007ctrl_mrk\006bad_crc\005wrong_cyl\004scn_eq\003scn_not_fnd\002bad_cyl\001no_dam"
+
+/* Status register ST3 */
+#define NE7_ST3BITS "\020\010fault\007write_protect\006drdy\005tk0\004two_side\003side_sel\002"
+
+/* Commands */
+#define NE7CMD_SPECIFY 3 /* specify drive parameters - requires unit
+ parameters byte */
+#define NE7CMD_SENSED 4 /* sense drive - requires unit select byte */
+#define NE7CMD_WRITE 0xc5 /* write - requires eight additional bytes */
+#define NE7CMD_READ 0xe6 /* read - requires eight additional bytes */
+#define NE7CMD_FORMAT 0x4c /* format - requires five additional bytes */
+#define NE7CMD_RECAL 7 /* recalibrate drive - requires
+ unit select byte */
+#define NE7CMD_SENSEI 8 /* sense controller interrupt status */
+#define NE7CMD_SEEK 15 /* seek drive - requires unit select byte
+ and new cyl byte */
diff --git a/sys/isa/ic/ns16550.h b/sys/isa/ic/ns16550.h
new file mode 100644
index 0000000..ff59757
--- /dev/null
+++ b/sys/isa/ic/ns16550.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)ns16550.h 7.1 (Berkeley) 5/9/91
+ * $Id$
+ */
+
+/*
+ * NS16550 UART registers
+ */
+
+#define com_data 0 /* data register (R/W) */
+#define com_dlbl 0 /* divisor latch low (W) */
+#define com_dlbh 1 /* divisor latch high (W) */
+#define com_ier 1 /* interrupt enable (W) */
+#define com_iir 2 /* interrupt identification (R) */
+#define com_fifo 2 /* FIFO control (W) */
+#define com_lctl 3 /* line control register (R/W) */
+#define com_cfcr 3 /* line control register (R/W) */
+#define com_mcr 4 /* modem control register (R/W) */
+#define com_lsr 5 /* line status register (R/W) */
+#define com_msr 6 /* modem status register (R/W) */
diff --git a/sys/isa/kbdtables.h b/sys/isa/kbdtables.h
new file mode 100644
index 0000000..a923c45
--- /dev/null
+++ b/sys/isa/kbdtables.h
@@ -0,0 +1,859 @@
+/*
+ * Copyright (C) 1992, 1993, 1994 Søren Schmidt
+ *
+ * This program is free software; you may redistribute it and/or
+ * modify it, provided that it retain the above copyright notice
+ * and the following disclaimer.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Søren Schmidt Email: sos@login.dkuug.dk
+ * Tritonvej 36 UUCP: ...uunet!dkuug!login!sos
+ * DK9210 Aalborg SO Phone: +45 9814 8076
+ *
+ * @(#)kbdtables.h 1.3 940123
+ * $Id: kbdtables.h,v 1.11 1994/02/01 09:27:43 ache Exp $
+ */
+
+#define SET8 0x80 /* eight bit for emacs SET8-key */
+
+#ifdef DKKEYMAP
+keymap_t key_map = { 0x69, /* DK iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, '1', '!', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '"', 0x00, 0x00, '@', '"', 0x00, 0x00, 0x00, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, 0x9E, '#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', 0xA4, NOP, NOP, '$', 0xA4, NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, '5', '%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '&', NOP, NOP, '6', '&', NOP, NOP, 0x33, 0x00,
+/* sc=08 */ '7', '/', NOP, NOP, '{', '/', NOP, NOP, 0x33, 0x00,
+/* sc=09 */ '8', '(', 0x1B, 0x1B, '[', '(', 0x1B, 0x1B, 0x00, 0x00,
+/* sc=0a */ '9', ')', 0x1D, 0x1D, ']', ')', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=0b */ '0', '=', NOP, NOP, '}', '=', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '+', '?', NOP, NOP, '+', '?', NOP, NOP, 0x33, 0x00,
+/* sc=0d */ '\'', '`', NOP, NOP, '|', '`', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x33, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ 0xE5, 0xC5, NOP, NOP, 0x86, 0x8F, NOP, NOP, 0x33, 0x01,
+/* sc=1b */ '"', '^', 0x1E, 0x1E, '~', '^', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ 0xE6, 0xC6, NOP, NOP, 0x91, 0x92, NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xF8, 0xD8, NOP, NOP, 0x9B, 0x9D, NOP, NOP, 0x33, 0x01,
+/* sc=29 */ 0xBD, 0xA7, NOP, NOP, 0xBD, 0xA7, NOP, NOP, 0x33, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\'', '*', NOP, NOP, '\'', '*', NOP, NOP, 0x33, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', ';', NOP, NOP, ',', ';', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', ':', NOP, NOP, '.', ':', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '-', '_', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, 0x00, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', '*', '*', '*', '*', '*', '*', 0x00, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, 0xFF, 0x00,
+/* sc=46 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', '-', '-', '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ NOP, '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', '6', '6', '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ '<', '>', 0x1C, 0x1C, '\\', '>', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x00, 0x02,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x00,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+#endif
+
+#ifdef UKKEYMAP
+keymap_t key_map = { 0x69, /* uk iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, '`', '`', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '"', 0x00, 0x00, '@', '@', 0x00, 0x00, 0x00, 0x00,
+/* sc=04 */ '3', 0xA3, NOP, NOP, '#', '#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, '4', '$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, '5', '%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '^', 0x1E, 0x1E, '^', '^', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=08 */ '7', '&', NOP, NOP, '[', '[', 0x1B, 0x1B, 0x30, 0x00,
+/* sc=09 */ '8', '*', NOP, NOP, '8', '*', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '9', '(', NOP, NOP, ']', ']', 0x1D, 0x1D, 0x30, 0x00,
+/* sc=0b */ '0', ')', NOP, NOP, '{', '{', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '-', '_', 0x1F, 0x1F, '|', '|', 0x1F, 0x1F, 0x00, 0x00,
+/* sc=0d */ '=', '+', NOP, NOP, '}', '}', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ '[', '{', 0x1B, 0x1B, '[', '{', 0x1B, 0x1B, 0x00, 0x00,
+/* sc=1b */ ']', '}', 0x1D, 0x1D, ']', '}', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ ';', ':', NOP, NOP, ';', ':', NOP, NOP, 0x33, 0x00,
+/* sc=28 */ '\'', '@', 0x00, 0x00, '\'', '@', 0x00, 0x00, 0x00, 0x00,
+/* sc=29 */ '\\', '|', 0x1C, 0x1C, '\\', '\\', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '#', '~', NOP, NOP, '~', '~', NOP, NOP, 0x33, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', '<', NOP, NOP, ',', '<', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', '>', NOP, NOP, '.', '>', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '/', '?', NOP, NOP, '/', '?', NOP, NOP, 0x33, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, 0x13, 0x13, NLK, NLK, 0x13, 0x13, 0xCC, 0x00,
+/* sc=46 */ SLK, SLK, 0x7F, 0x7F, SLK, SLK, 0x7F, 0x7F, 0xCC, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', 0x1F, 0x1F, '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ F(54), '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', 0x1E, 0x1E, '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ '\\', '|', 0x1C, 0x1C, '\\', '|', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0xFF, 0x02,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x02,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+#endif
+
+#ifdef GRKEYMAP
+keymap_t key_map = { 0x69, /* german iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, '`', '`', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '"', 0x00, 0x00, '@', '@', 0x00, 0x00, 0x00, 0x00,
+/* sc=04 */ '3', 0xA7, NOP, NOP, '#', '#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, '4', '$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, '5', '%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '&', 0x1E, 0x1E, '^', '^', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=08 */ '7', '/', 0x1B, 0x1B, '[', '[', 0x1B, 0x1B, 0x00, 0x00,
+/* sc=09 */ '8', '(', NOP, NOP, '8', '(', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '9', ')', 0x1D, 0x1D, ']', ']', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=0b */ '0', '=', NOP, NOP, '{', '{', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ 0xDF, '?', NOP, NOP, '|', '|', NOP, NOP, 0x33, 0x00,
+/* sc=0d */ 0x92, 0x93, NOP, NOP, '\'', '`', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ 0xFC, 0xDC, 0x1B, 0x1B, '[', '{', 0x1B, 0x1B, 0x00, 0x01,
+/* sc=1b */ '+', '*', 0x1D, 0x1D, ']', '}', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ 0xF6, 0xD6, NOP, NOP, 0xF6, 0xD6, NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xE4, 0xC4, NOP, NOP, 0xE4, 0xC4, NOP, NOP, 0x33, 0x01,
+/* sc=29 */ '<', '>', 0x1C, 0x1C, '\\', '|', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '#', '^', 0x1E, 0x1E, '`', '~', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=2c */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', ';', NOP, NOP, ',', ';', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', ':', NOP, NOP, '.', ':', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '-', '_', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, 0x00, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, 0x13, 0x13, NLK, NLK, 0x13, 0x13, 0xCC, 0x00,
+/* sc=46 */ SLK, SLK, 0x7F, 0x7F, SLK, SLK, 0x7F, 0x7F, 0xCC, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', 0x1F, 0x1F, '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ F(54), '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', 0x1E, 0x1E, '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0xFF, 0x02,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x02,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+#endif
+
+#ifdef SWKEYMAP
+keymap_t key_map = { 0x69, /* swedish iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=03 */ '2', '"', NOP, NOP, '@', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, 0xA3, NOP, NOP, NOP, 0x37, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, 0xA4, NOP, NOP, NOP, 0x37, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=07 */ '6', '&', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=08 */ '7', '/', NOP, NOP, '{', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=09 */ '8', '(', NOP, NOP, '[', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0a */ '9', ')', NOP, NOP, ']', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0b */ '0', '=', NOP, NOP, '}', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=0c */ '+', '?', NOP, NOP, '\\', NOP, 0x1C, NOP, 0x35, 0x00,
+/* sc=0d */ 0x180, '`', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ 0xE5, 0xC5, NOP, NOP, '}', ']', NOP, NOP, 0x33, 0x01,
+/* sc=1b */ 0xA8, '^', NOP, NOP, '~', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ 0xF6, 0xD6, NOP, NOP, '|', '\\', NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xE4, 0xC4, NOP, NOP, '{', '[', NOP, NOP, 0x33, 0x01,
+/* sc=29 */ 0xA7, 0xBD, NOP, NOP, '\\', '|', NOP, NOP, 0x33, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\'', '*', NOP, NOP, NOP, NOP, NOP, NOP, 0x3F, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', ';', NOP, NOP, NOP, '<', NOP, NOP, 0x3B, 0x00,
+/* sc=34 */ '.', ':', NOP, NOP, NOP, '>', NOP, NOP, 0x3B, 0x00,
+/* sc=35 */ '-', '_', 0x1F, NOP, '/', '?', NOP, NOP, 0x13, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, 0x13, 0x13, NLK, NLK, 0x13, 0x13, 0xCC, 0x00,
+/* sc=46 */ SLK, SLK, 0x7F, 0x7F, SLK, SLK, 0x7F, 0x7F, 0xCC, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', 0x1F, 0x1F, '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ F(54), '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', 0x1E, 0x1E, '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ '<', '>', NOP, NOP, '|', NOP, NOP, NOP, 0x37, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0xFF, 0x02,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x02,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+#endif
+
+#ifdef RUKEYMAP
+keymap_t key_map = { 0xe9, /* keys number */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * -------------------------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, NOP, NOP, SET8|0x1B, SET8|0x1B, DBG, NOP, 0x33, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, SET8|'1', SET8|'!', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '@', 0x00, 0x00, SET8|'2', SET8|'@', SET8|0x00, SET8|0x00, 0x00, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, SET8|'3', SET8|'#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, SET8|'4', SET8|'$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, SET8|'5', SET8|'%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '^', 0x1E, 0x1E, SET8|'6', SET8|'^', SET8|0x1E, SET8|0x1E, 0x00, 0x00,
+/* sc=08 */ '7', '&', NOP, NOP, SET8|'7', SET8|'&', NOP, NOP, 0x33, 0x00,
+/* sc=09 */ '8', '*', NOP, NOP, SET8|'8', SET8|'*', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '9', '(', NOP, NOP, SET8|'9', SET8|'(', NOP, NOP, 0x33, 0x00,
+/* sc=0b */ '0', ')', NOP, NOP, SET8|'0', SET8|')', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '-', '_', 0x1F, 0x1F, SET8|'-', SET8|'_', SET8|0x1F, SET8|0x1F, 0x00, 0x00,
+/* sc=0d */ '=', '+', NOP, NOP, SET8|'=', SET8|'+', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, SET8|0x08, SET8|0x08, SET8|0x7F, SET8|0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, F(16), NOP, NOP, SET8|0x09, F(16), NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, SET8|'q', SET8|'Q', SET8|0x11, SET8|0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, SET8|'w', SET8|'W', SET8|0x17, SET8|0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, SET8|'e', SET8|'E', SET8|0x05, SET8|0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, SET8|'r', SET8|'R', SET8|0x12, SET8|0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, SET8|'t', SET8|'T', SET8|0x14, SET8|0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, SET8|'y', SET8|'Y', SET8|0x19, SET8|0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, SET8|'u', SET8|'U', SET8|0x15, SET8|0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, SET8|'i', SET8|'I', SET8|0x09, SET8|0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, SET8|'o', SET8|'O', SET8|0x0F, SET8|0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, SET8|'p', SET8|'P', SET8|0x10, SET8|0x10, 0x00, 0x01,
+/* sc=1a */ '[', '{', 0x1B, 0x1B, SET8|'[', SET8|'{', SET8|0x1B, SET8|0x1B, 0x00, 0x00,
+/* sc=1b */ ']', '}', 0x1D, 0x1D, SET8|']', SET8|'}', SET8|0x1D, SET8|0x1D, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, SET8|0x0D, SET8|0x0D, SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, SET8|'a', SET8|'A', SET8|0x01, SET8|0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, SET8|'s', SET8|'S', SET8|0x13, SET8|0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, SET8|'d', SET8|'D', SET8|0x04, SET8|0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, SET8|'f', SET8|'F', SET8|0x06, SET8|0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, SET8|'g', SET8|'G', SET8|0x07, SET8|0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, SET8|'h', SET8|'H', SET8|0x08, SET8|0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, SET8|'j', SET8|'J', SET8|0x0A, SET8|0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, SET8|'k', SET8|'K', SET8|0x0B, SET8|0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, SET8|'l', SET8|'L', SET8|0x0C, SET8|0x0C, 0x00, 0x01,
+/* sc=27 */ ';', ':', NOP, NOP, SET8|';', SET8|':', NOP, NOP, 0x33, 0x00,
+/* sc=28 */ '\'', '"', NOP, NOP, SET8|'\'', SET8|'"', NOP, NOP, 0x33, 0x00,
+/* sc=29 */ '`', '~', NOP, NOP, SET8|'`', SET8|'~', NOP, NOP, 0x33, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\\', '|', 0x1C, 0x1C, SET8|'\\', SET8|'|', SET8|0x1C, SET8|0x1C, 0x00, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, SET8|'z', SET8|'Z', SET8|0x1A, SET8|0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, SET8|'x', SET8|'X', SET8|0x18, SET8|0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, SET8|'c', SET8|'C', SET8|0x03, SET8|0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, SET8|'v', SET8|'V', SET8|0x16, SET8|0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, SET8|'b', SET8|'B', SET8|0x02, SET8|0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, SET8|'n', SET8|'N', SET8|0x0E, SET8|0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, SET8|'m', SET8|'M', SET8|0x0D, SET8|0x0D, 0x00, 0x01,
+/* sc=33 */ ',', '<', NOP, NOP, SET8|',', SET8|'<', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', '>', NOP, NOP, SET8|'.', SET8|'>', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '/', '?', NOP, NOP, SET8|'/', SET8|'?', NOP, NOP, 0x33, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, SET8|'*', SET8|'*', SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', SET8|' ', SET8|' ', SET8|' ', SET8|' ', 0x00, 0x00,
+/* sc=3a */ ALK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, 0xFF, 0x00,
+/* sc=46 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', SET8|'7', SET8|'7', SET8|'7', SET8|'7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', SET8|'8', SET8|'8', SET8|'8', SET8|'8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', SET8|'9', SET8|'9', SET8|'9', SET8|'9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', '-', '-', SET8|'-', SET8|'-', SET8|'-', SET8|'-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', SET8|'4', SET8|'4', SET8|'4', SET8|'4', 0x80, 0x02,
+/* sc=4c */ F(48), '5', '5', '5', SET8|'5', SET8|'5', SET8|'5', SET8|'5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', '6', '6', SET8|'6', SET8|'6', SET8|'6', SET8|'6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', SET8|'+', SET8|'+', SET8|'+', SET8|'+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', SET8|'1', SET8|'1', SET8|'1', SET8|'1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', SET8|'2', SET8|'2', SET8|'2', SET8|'2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', SET8|'3', SET8|'3', SET8|'3', SET8|'3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', SET8|'0', SET8|'0', SET8|'0', SET8|'0', 0x80, 0x02,
+/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0x82, 0x02,
+/* sc=54 */ ALK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0A, 0x0A, SET8|0x0D, SET8|0x0D, SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', NOP, NOP, SET8|'/', SET8|'/', NOP, NOP, 0x33, 0x00,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0xC2, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=69 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6a */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6b */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6c */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6d */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6e */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=6f */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=70 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=71 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=72 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=73 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=74 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=75 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=76 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=77 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=78 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=79 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7a */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7b */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7c */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7d */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7e */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=7f */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* extended (ALTGR LOCK keys) */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, NOP, NOP, SET8|0x1B, SET8|0x1B, DBG, NOP, 0x33, 0x00,
+/* sc=02 */ '!', '1', NOP, NOP, SET8|'1', SET8|'!', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '"', '2', 0x00, 0x00, SET8|'2', SET8|'@', SET8|0x00, SET8|0x00, 0x00, 0x00,
+/* sc=04 */ '\'', '3', NOP, NOP, SET8|'3', SET8|'#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ ';', '4', NOP, NOP, SET8|'4', SET8|'$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ ':', '5', NOP, NOP, SET8|'5', SET8|'%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ ',', '6', 0x1E, 0x1E, SET8|'6', SET8|'^', SET8|0x1E, SET8|0x1E, 0x00, 0x00,
+/* sc=08 */ '.', '7', NOP, NOP, SET8|'7', SET8|'&', NOP, NOP, 0x33, 0x00,
+/* sc=09 */ '*', '8', NOP, NOP, SET8|'8', SET8|'*', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '(', '9', NOP, NOP, SET8|'9', SET8|'(', NOP, NOP, 0x33, 0x00,
+/* sc=0b */ ')', '0', NOP, NOP, SET8|'0', SET8|')', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '-', '_', 0x1F, 0x1F, SET8|'-', SET8|'_', SET8|0x1F, SET8|0x1F, 0x00, 0x00,
+/* sc=0d */ '=', '+', NOP, NOP, SET8|'=', SET8|'+', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, SET8|0x08, SET8|0x08, SET8|0x7F, SET8|0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, F(16), NOP, NOP, SET8|0x09, F(16), NOP, NOP, 0x77, 0x00,
+/* sc=10 */ 0xca, 0xea, 0x11, 0x11, SET8|'q', SET8|'Q', SET8|0x11, SET8|0x11, 0x00, 0x01,
+/* sc=11 */ 0xc3, 0xe3, 0x17, 0x17, SET8|'w', SET8|'W', SET8|0x17, SET8|0x17, 0x00, 0x01,
+/* sc=12 */ 0xd5, 0xf5, 0x05, 0x05, SET8|'e', SET8|'E', SET8|0x05, SET8|0x05, 0x00, 0x01,
+/* sc=13 */ 0xcb, 0xeb, 0x12, 0x12, SET8|'r', SET8|'R', SET8|0x12, SET8|0x12, 0x00, 0x01,
+/* sc=14 */ 0xc5, 0xe5, 0x14, 0x14, SET8|'t', SET8|'T', SET8|0x14, SET8|0x14, 0x00, 0x01,
+/* sc=15 */ 0xce, 0xee, 0x19, 0x19, SET8|'y', SET8|'Y', SET8|0x19, SET8|0x19, 0x00, 0x01,
+/* sc=16 */ 0xc7, 0xe7, 0x15, 0x15, SET8|'u', SET8|'U', SET8|0x15, SET8|0x15, 0x00, 0x01,
+/* sc=17 */ 0xdb, 0xfb, 0x09, 0x09, SET8|'i', SET8|'I', SET8|0x09, SET8|0x09, 0x00, 0x01,
+/* sc=18 */ 0xdd, 0xfd, 0x0F, 0x0F, SET8|'o', SET8|'O', SET8|0x0F, SET8|0x0F, 0x00, 0x01,
+/* sc=19 */ 0xda, 0xfa, 0x10, 0x10, SET8|'p', SET8|'P', SET8|0x10, SET8|0x10, 0x00, 0x01,
+/* sc=1a */ 0xc8, 0xe8, 0x1B, 0x1B, SET8|'[', SET8|'{', SET8|0x1B, SET8|0x1B, 0x00, 0x01,
+/* sc=1b */ 0xdf, 0xff, 0x1D, 0x1D, SET8|']', SET8|'}', SET8|0x1D, SET8|0x1D, 0x00, 0x01,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, SET8|0x0D, SET8|0x0D, SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 0xc6, 0xe6, 0x01, 0x01, SET8|'a', SET8|'A', SET8|0x01, SET8|0x01, 0x00, 0x01,
+/* sc=1f */ 0xd9, 0xf9, 0x13, 0x13, SET8|'s', SET8|'S', SET8|0x13, SET8|0x13, 0x00, 0x01,
+/* sc=20 */ 0xd7, 0xf7, 0x04, 0x04, SET8|'d', SET8|'D', SET8|0x04, SET8|0x04, 0x00, 0x01,
+/* sc=21 */ 0xc1, 0xe1, 0x06, 0x06, SET8|'f', SET8|'F', SET8|0x06, SET8|0x06, 0x00, 0x01,
+/* sc=22 */ 0xd0, 0xf0, 0x07, 0x07, SET8|'g', SET8|'G', SET8|0x07, SET8|0x07, 0x00, 0x01,
+/* sc=23 */ 0xd2, 0xf2, 0x08, 0x08, SET8|'h', SET8|'H', SET8|0x08, SET8|0x08, 0x00, 0x01,
+/* sc=24 */ 0xcf, 0xef, 0x0A, 0x0A, SET8|'j', SET8|'J', SET8|0x0A, SET8|0x0A, 0x00, 0x01,
+/* sc=25 */ 0xcc, 0xec, 0x0B, 0x0B, SET8|'k', SET8|'K', SET8|0x0B, SET8|0x0B, 0x00, 0x01,
+/* sc=26 */ 0xc4, 0xe4, 0x0C, 0x0C, SET8|'l', SET8|'L', SET8|0x0C, SET8|0x0C, 0x00, 0x01,
+/* sc=27 */ 0xd6, 0xf6, NOP, NOP, SET8|';', SET8|':', NOP, NOP, 0x33, 0x01,
+/* sc=28 */ 0xdc, 0xfc, NOP, NOP, SET8|'\'', SET8|'"', NOP, NOP, 0x33, 0x01,
+/* sc=29 */ 0xa3, 0xb3, NOP, NOP, SET8|'`', SET8|'~', NOP, NOP, 0x33, 0x01,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\\', '|', 0x1C, 0x1C, SET8|'\\', SET8|'|', SET8|0x1C, SET8|0x1C, 0x00, 0x00,
+/* sc=2c */ 0xd1, 0xf1, 0x1A, 0x1A, SET8|'z', SET8|'Z', SET8|0x1A, SET8|0x1A, 0x00, 0x01,
+/* sc=2d */ 0xde, 0xfe, 0x18, 0x18, SET8|'x', SET8|'X', SET8|0x18, SET8|0x18, 0x00, 0x01,
+/* sc=2e */ 0xd3, 0xf3, 0x03, 0x03, SET8|'c', SET8|'C', SET8|0x03, SET8|0x03, 0x00, 0x01,
+/* sc=2f */ 0xcd, 0xed, 0x16, 0x16, SET8|'v', SET8|'V', SET8|0x16, SET8|0x16, 0x00, 0x01,
+/* sc=30 */ 0xc9, 0xe9, 0x02, 0x02, SET8|'b', SET8|'B', SET8|0x02, SET8|0x02, 0x00, 0x01,
+/* sc=31 */ 0xd4, 0xf4, 0x0E, 0x0E, SET8|'n', SET8|'N', SET8|0x0E, SET8|0x0E, 0x00, 0x01,
+/* sc=32 */ 0xd8, 0xf8, 0x0D, 0x0D, SET8|'m', SET8|'M', SET8|0x0D, SET8|0x0D, 0x00, 0x01,
+/* sc=33 */ 0xc2, 0xe2, NOP, NOP, SET8|',', SET8|'<', NOP, NOP, 0x33, 0x01,
+/* sc=34 */ 0xc0, 0xe0, NOP, NOP, SET8|'.', SET8|'>', NOP, NOP, 0x33, 0x01,
+/* sc=35 */ '/', '?', NOP, NOP, SET8|'/', SET8|'?', NOP, NOP, 0x33, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, SET8|'*', SET8|'*', SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', SET8|' ', SET8|' ', SET8|' ', SET8|' ', 0x00, 0x00,
+/* sc=3a */ ALK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, 0xFF, 0x00,
+/* sc=46 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', SET8|'7', SET8|'7', SET8|'7', SET8|'7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', SET8|'8', SET8|'8', SET8|'8', SET8|'8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', SET8|'9', SET8|'9', SET8|'9', SET8|'9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', '-', '-', SET8|'-', SET8|'-', SET8|'-', SET8|'-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', SET8|'4', SET8|'4', SET8|'4', SET8|'4', 0x80, 0x02,
+/* sc=4c */ F(48), '5', '5', '5', SET8|'5', SET8|'5', SET8|'5', SET8|'5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', '6', '6', SET8|'6', SET8|'6', SET8|'6', SET8|'6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', SET8|'+', SET8|'+', SET8|'+', SET8|'+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', SET8|'1', SET8|'1', SET8|'1', SET8|'1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', SET8|'2', SET8|'2', SET8|'2', SET8|'2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', SET8|'3', SET8|'3', SET8|'3', SET8|'3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', SET8|'0', SET8|'0', SET8|'0', SET8|'0', 0x80, 0x02,
+/* sc=53 */ F(54), '.', 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0x82, 0x02,
+/* sc=54 */ ALK, ALK, ALK, ALK, ALK, ALK, ALK, ALK, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0A, 0x0A, SET8|0x0D, SET8|0x0D, SET8|0x0A, SET8|0x0A, 0x00, 0x00,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', NOP, NOP, SET8|'/', SET8|'/', NOP, NOP, 0x33, 0x00,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), 0x7F, 0x7F, SET8|0x7F, SET8|0x7F, RBT, SET8|0x7F, 0xC2, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+
+#endif
+
+#if !defined(DKKEYMAP) && !defined(UKKEYMAP) && !defined(GRKEYMAP) && !defined(SWKEYMAP) && !defined(RUKEYMAP)
+keymap_t key_map = { 0x69, /* US iso8859 keymap */
+/* alt
+ * scan cntrl alt alt cntrl
+ * code base shift cntrl shift alt shift cntrl shift spcl flgs
+ * ---------------------------------------------------------------------------
+ */
+/* sc=00 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=01 */ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, 0x02, 0x00,
+/* sc=02 */ '1', '!', NOP, NOP, '1', '!', NOP, NOP, 0x33, 0x00,
+/* sc=03 */ '2', '@', 0x00, 0x00, '2', '@', 0x00, 0x00, 0x00, 0x00,
+/* sc=04 */ '3', '#', NOP, NOP, '3', '#', NOP, NOP, 0x33, 0x00,
+/* sc=05 */ '4', '$', NOP, NOP, '4', '$', NOP, NOP, 0x33, 0x00,
+/* sc=06 */ '5', '%', NOP, NOP, '5', '%', NOP, NOP, 0x33, 0x00,
+/* sc=07 */ '6', '^', 0x1E, 0x1E, '6', '^', 0x1E, 0x1E, 0x00, 0x00,
+/* sc=08 */ '7', '&', NOP, NOP, '7', '&', NOP, NOP, 0x33, 0x00,
+/* sc=09 */ '8', '*', NOP, NOP, '8', '*', NOP, NOP, 0x33, 0x00,
+/* sc=0a */ '9', '(', NOP, NOP, '9', '(', NOP, NOP, 0x33, 0x00,
+/* sc=0b */ '0', ')', NOP, NOP, '0', ')', NOP, NOP, 0x33, 0x00,
+/* sc=0c */ '-', '_', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, 0x00, 0x00,
+/* sc=0d */ '=', '+', NOP, NOP, '=', '+', NOP, NOP, 0x33, 0x00,
+/* sc=0e */ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
+/* sc=0f */ 0x09, 0x08, NOP, NOP, 0x09, 0x08, NOP, NOP, 0x33, 0x00,
+/* sc=10 */ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, 0x00, 0x01,
+/* sc=11 */ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, 0x00, 0x01,
+/* sc=12 */ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, 0x00, 0x01,
+/* sc=13 */ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, 0x00, 0x01,
+/* sc=14 */ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, 0x00, 0x01,
+/* sc=15 */ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, 0x00, 0x01,
+/* sc=16 */ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, 0x00, 0x01,
+/* sc=17 */ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, 0x00, 0x01,
+/* sc=18 */ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, 0x00, 0x01,
+/* sc=19 */ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, 0x00, 0x01,
+/* sc=1a */ '[', '{', 0x1B, 0x1B, '[', '{', 0x1B, 0x1B, 0x00, 0x00,
+/* sc=1b */ ']', '}', 0x1D, 0x1D, ']', '}', 0x1D, 0x1D, 0x00, 0x00,
+/* sc=1c */ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, 0x00, 0x00,
+/* sc=1d */ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, 0xFF, 0x00,
+/* sc=1e */ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, 0x00, 0x01,
+/* sc=1f */ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, 0x00, 0x01,
+/* sc=20 */ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, 0x00, 0x01,
+/* sc=21 */ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, 0x00, 0x01,
+/* sc=22 */ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, 0x00, 0x01,
+/* sc=23 */ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, 0x00, 0x01,
+/* sc=24 */ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, 0x00, 0x01,
+/* sc=25 */ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, 0x00, 0x01,
+/* sc=26 */ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, 0x00, 0x01,
+/* sc=27 */ ';', ':', NOP, NOP, ';', ':', NOP, NOP, 0x33, 0x00,
+/* sc=28 */ '\'', '"', NOP, NOP, '\'', '"', NOP, NOP, 0x33, 0x00,
+/* sc=29 */ '`', '~', NOP, NOP, '`', '~', NOP, NOP, 0x33, 0x00,
+/* sc=2a */ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, 0xFF, 0x00,
+/* sc=2b */ '\\', '|', 0x1C, 0x1C, '\\', '|', 0x1C, 0x1C, 0x00, 0x00,
+/* sc=2c */ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, 0x00, 0x01,
+/* sc=2d */ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, 0x00, 0x01,
+/* sc=2e */ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, 0x00, 0x01,
+/* sc=2f */ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, 0x00, 0x01,
+/* sc=30 */ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, 0x00, 0x01,
+/* sc=31 */ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, 0x00, 0x01,
+/* sc=32 */ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, 0x00, 0x01,
+/* sc=33 */ ',', '<', NOP, NOP, ',', '<', NOP, NOP, 0x33, 0x00,
+/* sc=34 */ '.', '>', NOP, NOP, '.', '>', NOP, NOP, 0x33, 0x00,
+/* sc=35 */ '/', '?', NOP, NOP, '/', '?', NOP, NOP, 0x33, 0x00,
+/* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00,
+/* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00,
+/* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00,
+/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00,
+/* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00,
+/* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00,
+/* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00,
+/* sc=3d */ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13), 0xFF, 0x00,
+/* sc=3e */ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14), 0xFF, 0x00,
+/* sc=3f */ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15), 0xFF, 0x00,
+/* sc=40 */ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16), 0xFF, 0x00,
+/* sc=41 */ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7), 0xFF, 0x00,
+/* sc=42 */ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8), 0xFF, 0x00,
+/* sc=43 */ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9), 0xFF, 0x00,
+/* sc=44 */ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10), 0xFF, 0x00,
+/* sc=45 */ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, 0xFF, 0x00,
+/* sc=46 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+/* sc=47 */ F(49), '7', '7', '7', '7', '7', '7', '7', 0x80, 0x02,
+/* sc=48 */ F(50), '8', '8', '8', '8', '8', '8', '8', 0x80, 0x02,
+/* sc=49 */ F(51), '9', '9', '9', '9', '9', '9', '9', 0x80, 0x02,
+/* sc=4a */ F(52), '-', '-', '-', '-', '-', '-', '-', 0x80, 0x02,
+/* sc=4b */ F(53), '4', '4', '4', '4', '4', '4', '4', 0x80, 0x02,
+/* sc=4c */ NOP, '5', '5', '5', '5', '5', '5', '5', 0x80, 0x02,
+/* sc=4d */ F(55), '6', '6', '6', '6', '6', '6', '6', 0x80, 0x02,
+/* sc=4e */ F(56), '+', '+', '+', '+', '+', '+', '+', 0x80, 0x02,
+/* sc=4f */ F(57), '1', '1', '1', '1', '1', '1', '1', 0x80, 0x02,
+/* sc=50 */ F(58), '2', '2', '2', '2', '2', '2', '2', 0x80, 0x02,
+/* sc=51 */ F(59), '3', '3', '3', '3', '3', '3', '3', 0x80, 0x02,
+/* sc=52 */ F(60), '0', '0', '0', '0', '0', '0', '0', 0x80, 0x02,
+/* sc=53 */ 0x7F, '.', 0x7F, 0x7F, 0x7F, 0x7F, RBT, 0x7F, 0x02, 0x02,
+/* sc=54 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=55 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=56 */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=57 */ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11), 0xFF, 0x00,
+/* sc=58 */ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12), 0xFF, 0x00,
+/* sc=59 */ 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x00, 0x00,
+/* sc=5a */ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, 0xFF, 0x00,
+/* sc=5b */ '/', '/', '/', '/', '/', '/', '/', '/', 0x00, 0x00,
+/* sc=5c */ NEXT, NOP, DBG, NOP, NOP, NOP, NOP, NOP, 0xFF, 0x00,
+/* sc=5d */ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, 0xFF, 0x00,
+/* sc=5e */ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49), 0xFF, 0x00,
+/* sc=5f */ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50), 0xFF, 0x00,
+/* sc=60 */ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51), 0xFF, 0x00,
+/* sc=61 */ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53), 0xFF, 0x00,
+/* sc=62 */ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55), 0xFF, 0x00,
+/* sc=63 */ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57), 0xFF, 0x00,
+/* sc=64 */ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58), 0xFF, 0x00,
+/* sc=65 */ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59), 0xFF, 0x00,
+/* sc=66 */ F(60), F(60), F(60), F(60), F(60), F(60), F(60), F(60), 0xFF, 0x00,
+/* sc=67 */ F(54), F(54), F(54), F(54), F(54), F(54), RBT, F(54), 0xFF, 0x00,
+/* sc=68 */ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, 0xFF, 0x00,
+};
+
+#endif
+
+fkeytab_t fkey_tab[60] = {
+/* 00-03 */ {"\033[M", 3}, {"\033[N", 3}, {"\033[O", 3}, {"\033[P", 3},
+/* 04-07 */ {"\033[Q", 3}, {"\033[R", 3}, {"\033[S", 3}, {"\033[T", 3},
+/* 08-0B */ {"\033[U", 3}, {"\033[V", 3}, {"\033[W", 3}, {"\033[X", 3},
+/* 0C-0F */ {"\033[W", 3}, {"\033[X", 3}, {"\033[Y", 3}, {"\033[Z", 3},
+/* 10-13 */ {"\033[a", 3}, {"\033[b", 3}, {"\033[c", 3}, {"\033[d", 3},
+/* 14-17 */ {"\033[e", 3}, {"\033[f", 3}, {"\033[g", 3}, {"\033[h", 3},
+/* 18-1B */ {"\033[g", 3}, {"\033[h", 3}, {"\033[i", 3}, {"\033[j", 3},
+/* 1C-1F */ {"\033[k", 3}, {"\033[l", 3}, {"\033[m", 3}, {"\033[n", 3},
+/* 20-23 */ {"\033[o", 3}, {"\033[p", 3}, {"\033[q", 3}, {"\033[r", 3},
+/* 24-27 */ {"\033[g", 3}, {"\033[h", 3}, {"\033[i", 3}, {"\033[j", 3},
+/* 28-2B */ {"\033[k", 3}, {"\033[l", 3}, {"\033[m", 3}, {"\033[n", 3},
+/* 2C-2F */ {"\033[o", 3}, {"\033[p", 3}, {"\033[q", 3}, {"\033[r", 3},
+/* 30-33 */ {"\033[H", 3}, {"\033[A", 3}, {"\033[I", 3}, {"-" , 1},
+/* 34-37 */ {"\033[D", 3}, {"\177" , 1}, {"\033[C", 3}, {"+" , 1},
+/* 38-3B */ {"\033[F", 3}, {"\033[B", 3}, {"\033[G", 3}, {"\033[L", 3}
+};
diff --git a/sys/isa/rtc.h b/sys/isa/rtc.h
new file mode 100644
index 0000000..ba008b6
--- /dev/null
+++ b/sys/isa/rtc.h
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)rtc.h 7.1 (Berkeley) 5/12/91
+ * $Id: rtc.h,v 1.3 1993/11/07 17:44:34 wollman Exp $
+ */
+
+#ifndef _I386_ISA_RTC_H_
+#define _I386_ISA_RTC_H_ 1
+
+/*
+ * RTC Register locations
+ */
+
+#define RTC_SEC 0x00 /* seconds */
+#define RTC_SECALRM 0x01 /* seconds alarm */
+#define RTC_MIN 0x02 /* minutes */
+#define RTC_MINALRM 0x03 /* minutes alarm */
+#define RTC_HRS 0x04 /* hours */
+#define RTC_HRSALRM 0x05 /* hours alarm */
+#define RTC_WDAY 0x06 /* week day */
+#define RTC_DAY 0x07 /* day of month */
+#define RTC_MONTH 0x08 /* month of year */
+#define RTC_YEAR 0x09 /* month of year */
+#define RTC_STATUSA 0x0a /* status register A */
+#define RTCSA_TUP 0x80 /* time update, don't look now */
+
+#define RTC_STATUSB 0x0b /* status register B */
+
+#define RTC_INTR 0x0c /* status register C (R) interrupt source */
+#define RTCIR_UPDATE 0x10 /* update intr */
+#define RTCIR_ALARM 0x20 /* alarm intr */
+#define RTCIR_PERIOD 0x40 /* periodic intr */
+#define RTCIR_INT 0x80 /* interrupt output signal */
+
+#define RTC_STATUSD 0x0d /* status register D (R) Lost Power */
+#define RTCSD_PWR 0x80 /* clock lost power */
+
+#define RTC_DIAG 0x0e /* status register E - bios diagnostic */
+#define RTCDG_BITS "\020\010clock_battery\007ROM_cksum\006config_unit\005memory_size\004fixed_disk\003invalid_time"
+
+#define RTC_RESET 0x0f /* status register F - reset code byte */
+#define RTCRS_RST 0x00 /* normal reset */
+#define RTCRS_LOAD 0x04 /* load system */
+
+#define RTC_FDISKETTE 0x10 /* diskette drive type in upper/lower nibble */
+#define RTCFDT_NONE 0 /* none present */
+#define RTCFDT_360K 0x10 /* 360K */
+#define RTCFDT_12M 0x20 /* 1.2M */
+#define RTCFDT_720K 0x30 /* 720K */
+#define RTCFDT_144M 0x40 /* 1.44M */
+
+#define RTC_BASELO 0x15 /* low byte of basemem size */
+#define RTC_BASEHI 0x16 /* high byte of basemem size */
+#define RTC_EXTLO 0x17 /* low byte of extended mem size */
+#define RTC_EXTHI 0x18 /* low byte of extended mem size */
+
+#define RTC_CENTURY 0x32 /* current century - please increment in Dec99*/
+#endif /* _I386_ISA_RTC_H_ */
diff --git a/sys/isa/sio.c b/sys/isa/sio.c
new file mode 100644
index 0000000..ad09f7a3
--- /dev/null
+++ b/sys/isa/sio.c
@@ -0,0 +1,1919 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)com.c 7.5 (Berkeley) 5/16/91
+ * $Id: sio.c,v 1.44 1994/04/03 12:25:57 ache Exp $
+ */
+
+#include "sio.h"
+#if NSIO > 0
+/*
+ * Serial driver, based on 386BSD-0.1 com driver.
+ * Mostly rewritten to use pseudo-DMA.
+ * Works for National Semiconductor NS8250-NS16550AF UARTs.
+ * COM driver, based on HP dca driver.
+ */
+#include "param.h"
+#include "systm.h"
+#include "ioctl.h"
+#include "tty.h"
+#include "proc.h"
+#include "user.h"
+#include "conf.h"
+#include "file.h"
+#include "uio.h"
+#include "kernel.h"
+#include "syslog.h"
+
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/comreg.h"
+#include "i386/isa/ic/ns16550.h"
+
+#define FAKE_DCD(unit) ((unit) == comconsole)
+#define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
+#define RB_I_HIGH_WATER (RBSZ - 2 * RS_IBUFSIZE)
+#define RB_I_LOW_WATER ((RBSZ - 2 * RS_IBUFSIZE) * 7 / 8)
+#define RS_IBUFSIZE 256
+#define TTY_BI TTY_FE /* XXX */
+#define TTY_OE TTY_PE /* XXX */
+
+#ifdef COM_BIDIR
+#define CALLOUT(x) (minor(x) & COM_CALLOUT_MASK)
+#define COM_CALLOUT_MASK 0x80
+#define COM_MINOR_MAGIC_MASK 0x80
+#else /* COM_BIDIR */
+#define COM_MINOR_MAGIC_MASK 0
+#endif /* COM_BIDIR */
+
+#define UNIT(x) (minor(x) & ~COM_MINOR_MAGIC_MASK)
+
+#ifdef COM_MULTIPORT
+/* checks in flags for multiport and which is multiport "master chip"
+ * for a given card
+ */
+#define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
+#define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
+#define COM_NOMASTER(dev) ((dev)->id_flags & 0x04)
+#endif /* COM_MULTIPORT */
+
+#define COM_NOFIFO(dev) ((dev)->id_flags & 0x02)
+
+#ifndef FIFO_TRIGGER
+/*
+ * This driver is fast enough to work with any value and for high values
+ * to be only slightly more efficient. Low values may be better because
+ * they give lower latency.
+ * TODO: always use low values for low speeds. Mouse movements are jerky
+ * if more than one packet arrives at once. The low speeds used for
+ * serial mice help avoid this, but not if (large) fifos are enabled.
+ */
+#define FIFO_TRIGGER FIFO_TRIGGER_14
+#endif
+
+#define com_scr 7 /* scratch register for 16450-16550 (R/W) */
+
+#ifndef setsofttty
+#define OLD_INTERRUPT_HANDLING /* XXX FreeBSD-1.1 and earlier */
+#define setsofttty() (ipending |= 1 << 4) /* XXX requires owning IRQ4 */
+extern u_int ipending; /* XXX */
+void softsio1 __P((void));
+#endif
+
+/*
+ * Input buffer watermarks.
+ * The external device is asked to stop sending when the buffer exactly reaches
+ * high water, or when the high level requests it.
+ * The high level is notified immediately (rather than at a later clock tick)
+ * when this watermark is reached.
+ * The buffer size is chosen so the watermark should almost never be reached.
+ * The low watermark is invisibly 0 since the buffer is always emptied all at
+ * once.
+ */
+#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
+
+/*
+ * com state bits.
+ * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
+ * than the other bits so that they can be tested as a group without masking
+ * off the low bits.
+ *
+ * The following com and tty flags correspond closely:
+ * TS_BUSY = CS_BUSY (maintained by comstart() and comflush())
+ * CS_TTGO = ~TS_TTSTOP (maintained by comstart() and siostop())
+ * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam())
+ * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam())
+ * TS_FLUSH is not used.
+ * Bug: I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
+ */
+#define CS_BUSY 0x80 /* output in progress */
+#define CS_TTGO 0x40 /* output not stopped by XOFF */
+#define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */
+#define CS_CHECKMSR 1 /* check of MSR scheduled */
+#define CS_CTS_OFLOW 2 /* use CTS output flow control */
+#define CS_ODONE 4 /* output completed */
+#define CS_RTS_IFLOW 8 /* use RTS input flow control */
+
+static char *error_desc[] = {
+#define CE_OVERRUN 0
+ "silo overflow",
+#define CE_INTERRUPT_BUF_OVERFLOW 1
+ "interrupt-level buffer overflow",
+#define CE_TTY_BUF_OVERFLOW 2
+ "tty-level buffer overflow",
+};
+
+#define CE_NTYPES 3
+#define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum])
+
+/* types. XXX - should be elsewhere */
+typedef u_int Port_t; /* hardware port */
+typedef u_char bool_t; /* boolean */
+
+/* com device structure */
+struct com_s {
+ u_char state; /* miscellaneous flag bits */
+ u_char cfcr_image; /* copy of value written to CFCR */
+ bool_t hasfifo; /* nonzero for 16550 UARTs */
+ u_char mcr_image; /* copy of value written to MCR */
+#ifdef COM_BIDIR
+ bool_t bidir; /* is this unit bidirectional? */
+ bool_t active; /* is the port active _at all_? */
+ bool_t active_in; /* is the incoming port in use? */
+ bool_t active_out; /* is the outgoing port in use? */
+#endif /* COM_BIDIR */
+#ifdef COM_MULTIPORT
+ bool_t multiport; /* is this unit part of a multiport device? */
+#endif /* COM_MULTIPORT */
+ int dtr_wait; /* time to hold DTR down on close (* 1/HZ) */
+ u_int tx_fifo_size;
+
+ /*
+ * The high level of the driver never reads status registers directly
+ * because there would be too many side effects to handle conveniently.
+ * Instead, it reads copies of the registers stored here by the
+ * interrupt handler.
+ */
+ u_char last_modem_status; /* last MSR read by intr handler */
+ u_char prev_modem_status; /* last MSR handled by high level */
+
+ u_char *ibuf; /* start of input buffer */
+ u_char *ibufend; /* end of input buffer */
+ u_char *ihighwater; /* threshold in input buffer */
+ u_char *iptr; /* next free spot in input buffer */
+
+ u_char *obufend; /* end of output buffer */
+ int ocount; /* original count for current output */
+ u_char *optr; /* next char to output */
+
+ Port_t data_port; /* i/o ports */
+ Port_t int_id_port;
+ Port_t iobase;
+ Port_t modem_ctl_port;
+ Port_t line_status_port;
+ Port_t modem_status_port;
+
+ struct tty *tp; /* cross reference */
+
+#ifdef TIOCTIMESTAMP
+ bool_t do_timestamp;
+ struct timeval timestamp;
+#endif
+
+ u_long bytes_in; /* statistics */
+ u_long bytes_out;
+ u_int delta_error_counts[CE_NTYPES];
+ u_int error_counts[CE_NTYPES];
+
+ /*
+ * Ping-pong input buffers. The extra factor of 2 in the sizes is
+ * to allow for an error byte for each input byte.
+ */
+#define CE_INPUT_OFFSET RS_IBUFSIZE
+ u_char ibuf1[2 * RS_IBUFSIZE];
+ u_char ibuf2[2 * RS_IBUFSIZE];
+};
+
+/*
+ * The public functions in the com module ought to be declared in a com-driver
+ * system header.
+ */
+#define Dev_t int /* promoted dev_t */
+
+/* Interrupt handling entry points. */
+void siointr __P((int unit));
+void siopoll __P((void));
+
+/* Device switch entry points. */
+int sioopen __P((Dev_t dev, int oflags, int devtype,
+ struct proc *p));
+int sioclose __P((Dev_t dev, int fflag, int devtype,
+ struct proc *p));
+int sioread __P((Dev_t dev, struct uio *uio, int ioflag));
+int siowrite __P((Dev_t dev, struct uio *uio, int ioflag));
+int sioioctl __P((Dev_t dev, int cmd, caddr_t data,
+ int fflag, struct proc *p));
+void siostop __P((struct tty *tp, int rw));
+#define sioreset noreset
+int sioselect __P((Dev_t dev, int rw, struct proc *p));
+#define siommap nommap
+#define siostrategy nostrategy
+
+/* Console device entry points. */
+int siocngetc __P((Dev_t dev));
+struct consdev;
+void siocninit __P((struct consdev *cp));
+void siocnprobe __P((struct consdev *cp));
+void siocnputc __P((Dev_t dev, int c));
+
+static int sioattach __P((struct isa_device *dev));
+static void comflush __P((struct com_s *com));
+static void comhardclose __P((struct com_s *com));
+static void siointr1 __P((struct com_s *com));
+static void commctl __P((struct com_s *com, int bits, int how));
+static int comparam __P((struct tty *tp, struct termios *t));
+static int sioprobe __P((struct isa_device *dev));
+static void comstart __P((struct tty *tp));
+static void comwakeup __P((caddr_t chan, int ticks));
+static int tiocm_xxx2mcr __P((int tiocm_xxx));
+
+/* table and macro for fast conversion from a unit number to its com struct */
+static struct com_s *p_com_addr[NSIO];
+#define com_addr(unit) (p_com_addr[unit])
+
+static struct com_s com_structs[NSIO];
+
+#ifdef TIOCTIMESTAMP
+static struct timeval intr_timestamp;
+#endif
+
+struct isa_driver siodriver = {
+ sioprobe, sioattach, "sio"
+};
+
+#ifdef COMCONSOLE
+static int comconsole = COMCONSOLE;
+#else
+static int comconsole = -1;
+#endif
+static speed_t comdefaultrate = TTYDEF_SPEED;
+static u_int com_events; /* input chars + weighted output completions */
+static int commajor;
+#ifdef DONT_MALLOC_TTYS
+#define TB_OUT(tp) (&(tp)->t_out)
+#define TB_RAW(tp) (&(tp)->t_raw)
+struct tty sio_tty[NSIO];
+#else
+#define TB_OUT(tp) ((tp)->t_out)
+#define TB_RAW(tp) ((tp)->t_raw)
+struct tty *sio_tty[NSIO];
+#endif
+extern struct tty *constty;
+extern int tk_nin; /* XXX */
+extern int tk_rawcc; /* XXX */
+
+#ifdef KGDB
+#include "machine/remote-sl.h"
+
+extern int kgdb_dev;
+extern int kgdb_rate;
+extern int kgdb_debug_init;
+#endif
+
+static struct speedtab comspeedtab[] = {
+ 0, 0,
+ 50, COMBRD(50),
+ 75, COMBRD(75),
+ 110, COMBRD(110),
+ 134, COMBRD(134),
+ 150, COMBRD(150),
+ 200, COMBRD(200),
+ 300, COMBRD(300),
+ 600, COMBRD(600),
+ 1200, COMBRD(1200),
+ 1800, COMBRD(1800),
+ 2400, COMBRD(2400),
+ 4800, COMBRD(4800),
+ 9600, COMBRD(9600),
+ 19200, COMBRD(19200),
+ 38400, COMBRD(38400),
+ 57600, COMBRD(57600),
+ 115200, COMBRD(115200),
+ -1, -1
+};
+
+/* XXX - configure this list */
+static Port_t likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, };
+
+static int
+sioprobe(dev)
+ struct isa_device *dev;
+{
+ static bool_t already_init;
+ Port_t *com_ptr;
+ Port_t iobase;
+ int result;
+
+ if (!already_init) {
+ /*
+ * Turn off MCR_IENABLE for all likely serial ports. An unused
+ * port with its MCR_IENABLE gate open will inhibit interrupts
+ * from any used port that shares the interrupt vector.
+ */
+ for (com_ptr = likely_com_ports;
+ com_ptr < &likely_com_ports[sizeof likely_com_ports
+ / sizeof likely_com_ports[0]];
+ ++com_ptr)
+ outb(*com_ptr + com_mcr, 0);
+ already_init = TRUE;
+ }
+ iobase = dev->id_iobase;
+ result = IO_COMSIZE;
+
+ /*
+ * We don't want to get actual interrupts, just masked ones.
+ * Interrupts from this line should already be masked in the ICU,
+ * but mask them in the processor as well in case there are some
+ * (misconfigured) shared interrupts.
+ */
+ disable_intr();
+
+ /*
+ * Initialize the speed so that any junk in the THR or output fifo will
+ * be transmitted in a known time. (There may be lots of junk after a
+ * soft reboot, and output interrupts don't work right after a master
+ * reset, at least for 16550s. (The speed is undefined after MR, but
+ * MR empties the THR and the TSR so it's not clear why this matters)).
+ * Enable output interrupts (only) and check the following:
+ * o the CFCR, IER and MCR in UART hold the values written to them
+ * (the values happen to be all distinct - this is good for
+ * avoiding false positive tests from bus echoes).
+ * o an output interrupt is generated and its vector is correct.
+ * o the interrupt goes away when the IIR in the UART is read.
+ */
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ outb(iobase + com_dlbl, COMBRD(9600) & 0xff);
+ outb(iobase + com_dlbh, (u_int) COMBRD(9600) >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS); /* ensure IER is addressed */
+ outb(iobase + com_mcr, MCR_IENABLE); /* open gate early */
+ outb(iobase + com_ier, 0); /* ensure edge on next intr */
+ outb(iobase + com_ier, IER_ETXRDY); /* generate interrupt */
+ DELAY((16 + 1) * 9600 / 10); /* enough to drain 16 bytes */
+ if ( inb(iobase + com_cfcr) != CFCR_8BITS
+ || inb(iobase + com_ier) != IER_ETXRDY
+ || inb(iobase + com_mcr) != MCR_IENABLE
+#ifndef COM_MULTIPORT /* XXX - need to do more to enable interrupts */
+ || !isa_irq_pending(dev)
+#endif
+ || (inb(iobase + com_iir) & IIR_IMASK) != IIR_TXRDY
+ || isa_irq_pending(dev)
+ || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
+ result = 0;
+
+ /*
+ * Turn off all device interrupts and check that they go off properly.
+ * Leave MCR_IENABLE set. It gates the OUT2 output of the UART to
+ * the ICU input. Closing the gate would give a floating ICU input
+ * (unless there is another device driving at) and spurious interrupts.
+ * (On the system that this was first tested on, the input floats high
+ * and gives a (masked) interrupt as soon as the gate is closed.)
+ */
+ outb(iobase + com_ier, 0);
+ outb(iobase + com_mcr, MCR_IENABLE); /* dummy to avoid bus echo */
+ if ( inb(iobase + com_ier) != 0
+ || isa_irq_pending(dev)
+ || (inb(iobase + com_iir) & IIR_IMASK) != IIR_NOPEND)
+ result = 0;
+ if (result == 0)
+ outb(iobase + com_mcr, 0);
+
+ enable_intr();
+ return (result);
+}
+
+static int
+sioattach(isdp)
+ struct isa_device *isdp;
+{
+ struct com_s *com;
+ static bool_t comwakeup_started = FALSE;
+ Port_t iobase;
+ int s;
+ int unit;
+
+ iobase = isdp->id_iobase;
+ unit = isdp->id_unit;
+ s = spltty();
+
+ /*
+ * sioprobe() has initialized the device registers as follows:
+ * o cfcr = CFCR_8BITS.
+ * It is most important that CFCR_DLAB is off, so that the
+ * data port is not hidden when we enable interrupts.
+ * o ier = 0.
+ * Interrupts are only enabled when the line is open.
+ * o mcr = MCR_IENABLE.
+ * Keeping MCR_DTR and MCR_RTS off might stop the external
+ * device from sending before we are ready.
+ */
+
+ com = &com_structs[unit]; /* XXX malloc it */
+ com->cfcr_image = CFCR_8BITS;
+ com->mcr_image = MCR_IENABLE;
+ com->dtr_wait = 3 * hz;
+ com->tx_fifo_size = 1;
+ com->iptr = com->ibuf = com->ibuf1;
+ com->ibufend = com->ibuf1 + RS_IBUFSIZE;
+ com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
+ com->iobase = iobase;
+ com->data_port = iobase + com_data;
+ com->int_id_port = iobase + com_iir;
+ com->modem_ctl_port = iobase + com_mcr;
+ com->line_status_port = iobase + com_lsr;
+ com->modem_status_port = iobase + com_msr;
+#ifdef DONT_MALLOC_TTYS
+ com->tp = &sio_tty[unit];
+#endif
+
+ /* attempt to determine UART type */
+ printf("sio%d: type", unit);
+#ifdef COM_MULTIPORT
+ if (!COM_ISMULTIPORT(isdp))
+#endif
+ {
+ u_char scr;
+ u_char scr1;
+ u_char scr2;
+
+ scr = inb(iobase + com_scr);
+ outb(iobase + com_scr, 0xa5);
+ scr1 = inb(iobase + com_scr);
+ outb(iobase + com_scr, 0x5a);
+ scr2 = inb(iobase + com_scr);
+ outb(iobase + com_scr, scr);
+ if (scr1 != 0xa5 || scr2 != 0x5a) {
+ printf(" 8250");
+ goto determined_type;
+ }
+ }
+ outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14);
+ DELAY(100);
+ switch (inb(com->int_id_port) & IIR_FIFO_MASK) {
+ case FIFO_TRIGGER_1:
+ printf(" 16450");
+ break;
+ case FIFO_TRIGGER_4:
+ printf(" 16450?");
+ break;
+ case FIFO_TRIGGER_8:
+ printf(" 16550?");
+ break;
+ case FIFO_TRIGGER_14:
+ printf(" 16550A");
+ if (COM_NOFIFO(isdp))
+ printf(" fifo disabled");
+ else {
+ com->hasfifo = TRUE;
+ com->tx_fifo_size = 16;
+ }
+ break;
+ }
+ outb(iobase + com_fifo, 0);
+determined_type: ;
+
+#ifdef COM_MULTIPORT
+ if (COM_ISMULTIPORT(isdp)) {
+ com->multiport = TRUE;
+ printf(" (multiport)");
+
+ /* Note: some cards have no master port (e.g., BocaBoards) */
+ if (!COM_NOMASTER(isdp)) {
+ struct isa_device *masterdev;
+
+ /* set the master's common-interrupt-enable reg.,
+ * as appropriate. YYY See your manual
+ */
+ /* enable only common interrupt for port */
+ outb(com->modem_ctl_port, com->mcr_image = 0);
+
+ masterdev = find_isadev(isa_devtab_tty, &siodriver,
+ COM_MPMASTER(isdp));
+ outb(masterdev->id_iobase + com_scr, 0x80);
+ }
+
+ } else
+ com->multiport = FALSE;
+#endif /* COM_MULTIPORT */
+ printf("\n");
+
+#ifdef KGDB
+ if (kgdb_dev == makedev(commajor, unit)) {
+ if (comconsole == unit)
+ kgdb_dev = -1; /* can't debug over console port */
+ else {
+ int divisor;
+
+ /*
+ * XXX now unfinished and broken. Need to do
+ * something more like a full open(). There's no
+ * suitable interrupt handler so don't enable device
+ * interrupts. Watch out for null tp's.
+ */
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ divisor = ttspeedtab(kgdb_rate, comspeedtab);
+ outb(iobase + com_dlbl, divisor & 0xFF);
+ outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS);
+ outb(com->modem_status_port,
+ com->mcr_image |= MCR_DTR | MCR_RTS);
+
+ if (kgdb_debug_init) {
+ /*
+ * Print prefix of device name,
+ * let kgdb_connect print the rest.
+ */
+ printf("sio%d: ", unit);
+ kgdb_connect(1);
+ } else
+ printf("sio%d: kgdb enabled\n", unit);
+ }
+ }
+#endif
+
+ com_addr(unit) = com;
+ splx(s);
+ if (!comwakeup_started) {
+ comwakeup((caddr_t) NULL, 0);
+ comwakeup_started = TRUE;
+ }
+ return (1);
+}
+
+/* ARGSUSED */
+int
+sioopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+#ifdef COM_BIDIR
+ bool_t callout;
+#endif /* COM_BIDIR */
+ struct com_s *com;
+ int error = 0;
+ bool_t got_status = FALSE;
+ Port_t iobase;
+ int s;
+ struct tty *tp;
+ int unit;
+
+ unit = UNIT(dev);
+ if ((u_int) unit >= NSIO || (com = com_addr(unit)) == NULL)
+ return (ENXIO);
+#ifdef COM_BIDIR
+ /* if it's a callout device, and bidir not possible on that dev, die */
+ callout = CALLOUT(dev);
+ if (callout && !(com->bidir))
+ return (ENXIO);
+#endif /* COM_BIDIR */
+
+#ifdef DONT_MALLOC_TTYS
+ tp = com->tp;
+#else
+ sio_tty[unit] = ttymalloc(sio_tty[unit]);
+ tp = com->tp = sio_tty[unit];
+#endif
+ s = spltty();
+
+#ifdef COM_BIDIR
+
+bidir_open_top:
+ got_status = FALSE;
+ /* if it's bidirectional, we've gotta deal with it... */
+ if (com->bidir) {
+ if (callout) {
+ if (com->active_in) {
+ /* it's busy. die */
+ splx(s);
+ return (EBUSY);
+ } else {
+ /* it's ours. lock it down, and set it up */
+ com->active_out = TRUE;
+ }
+ } else {
+ if (com->active_out) {
+ /* it's busy, outgoing. wait, if possible */
+ if (flag & O_NONBLOCK) {
+ /* can't wait; bail */
+ splx(s);
+ return (EBUSY);
+ } else {
+ /* wait for it... */
+ error = tsleep((caddr_t)&com->active_out,
+ TTIPRI|PCATCH,
+ "siooth",
+ 0);
+ /* if there was an error, take off. */
+ if (error != 0) {
+ splx(s);
+ return (error);
+ }
+ /* else take it from the top */
+ goto bidir_open_top;
+ }
+ }
+ disable_intr();
+ com->prev_modem_status =
+ com->last_modem_status = inb(com->modem_status_port);
+ enable_intr();
+ got_status = TRUE;
+ if (com->prev_modem_status & MSR_DCD
+ || FAKE_DCD(unit)) {
+ /* there's a carrier on the line; we win */
+ com->active_in = TRUE;
+ } else {
+ /* there is no carrier on the line */
+ if (flag & O_NONBLOCK) {
+ /* can't wait; let it open */
+ com->active_in = TRUE;
+ } else {
+ /* put DTR & RTS up */
+ /* XXX - bring up RTS earlier? */
+ commctl(com, MCR_DTR | MCR_RTS, DMSET);
+ outb(com->iobase + com_ier, IER_EMSC);
+
+ /* wait for it... */
+ error = tsleep((caddr_t)&com->active_in,
+ TTIPRI|PCATCH,
+ "siodcd",
+ 0);
+
+ /* if not active, turn intrs and DTR off */
+ if (!com->active) {
+ outb(com->iobase + com_ier, 0);
+ commctl(com, MCR_DTR, DMBIC);
+ }
+
+ /* if there was an error, take off. */
+ if (error != 0) {
+ splx(s);
+ return (error);
+ }
+ /* else take it from the top */
+ goto bidir_open_top;
+ }
+ }
+ }
+ }
+
+ com->active = TRUE;
+#endif /* COM_BIDIR */
+
+ tp->t_oproc = comstart;
+ tp->t_param = comparam;
+ tp->t_dev = dev;
+ if (!(tp->t_state & TS_ISOPEN)) {
+ tp->t_state |= TS_WOPEN;
+ ttychars(tp);
+ if (tp->t_ispeed == 0) {
+ /*
+ * We don't use all the flags from <sys/ttydefaults.h>
+ * since those are only relevant for logins. It's
+ * important to have echo off initially so that the
+ * line doesn't start blathering before the echo flag
+ * can be turned off.
+ */
+ tp->t_iflag = 0;
+ tp->t_oflag = 0;
+ tp->t_cflag = CREAD | CS8;
+#ifdef COM_BIDIR
+ if (com->bidir && !callout)
+ tp->t_cflag |= HUPCL;
+#endif
+ tp->t_lflag = 0;
+ tp->t_ispeed = tp->t_ospeed = comdefaultrate;
+ if (unit == comconsole) {
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ }
+ }
+
+ /*
+ * XXX the full state after a first open() needs to be
+ * programmable and separate for callin and callout.
+ */
+#ifdef COM_BIDIR
+ if (com->bidir) {
+ if (callout)
+ tp->t_cflag |= CLOCAL;
+ else
+ tp->t_cflag &= ~CLOCAL;
+ }
+#endif
+
+ commctl(com, MCR_DTR | MCR_RTS, DMSET);
+ error = comparam(tp, &tp->t_termios);
+ if (error != 0)
+ goto out;
+ ttsetwater(tp);
+ iobase = com->iobase;
+ if (com->hasfifo) {
+ /* (re)enable and drain FIFO */
+ outb(iobase + com_fifo, FIFO_ENABLE | FIFO_TRIGGER
+ | FIFO_RCV_RST | FIFO_XMT_RST);
+ DELAY(100);
+ }
+ disable_intr();
+ (void) inb(com->line_status_port);
+ (void) inb(com->data_port);
+ if (!got_status)
+ com->prev_modem_status =
+ com->last_modem_status = inb(com->modem_status_port);
+ outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
+ | IER_EMSC);
+ enable_intr();
+ if (com->prev_modem_status & MSR_DCD || FAKE_DCD(unit))
+ tp->t_state |= TS_CARR_ON;
+ } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
+ splx(s);
+ return (EBUSY);
+ }
+ while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL)
+#ifdef COM_BIDIR
+ /* We went through a lot of trouble to open it,
+ * but it's certain we have a carrier now, so
+ * don't spend any time on it now.
+ */
+ && !(com->bidir)
+#endif /* COM_BIDIR */
+ && !(tp->t_state & TS_CARR_ON)) {
+ tp->t_state |= TS_WOPEN;
+ error = ttysleep(tp, (caddr_t)TB_RAW(tp), TTIPRI | PCATCH,
+ ttopen, 0);
+ if (error != 0)
+ break;
+ }
+out:
+ if (error == 0)
+ error = (*linesw[tp->t_line].l_open)(dev, tp, 0);
+ splx(s);
+
+#ifdef COM_BIDIR
+ /* wakeup sleepers */
+ wakeup((caddr_t) &com->active_in);
+#endif /* COM_BIDIR */
+
+ /*
+ * XXX - the next step was once not done, so interrupts, DTR and RTS
+ * remained hot if the process was killed while it was sleeping
+ * waiting for carrier. Now there is the opposite problem. If several
+ * processes are sleeping waiting for carrier on the same line and one
+ * is killed, interrupts are turned off so the other processes will
+ * never see the carrier rise.
+ */
+ if (error != 0 && !(tp->t_state & TS_ISOPEN))
+ comhardclose(com);
+ tp->t_state &= ~TS_WOPEN;
+
+ return (error);
+}
+
+/*ARGSUSED*/
+int
+sioclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct com_s *com;
+ int s;
+ struct tty *tp;
+
+ com = com_addr(UNIT(dev));
+ tp = com->tp;
+ s = spltty();
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ siostop(tp, FREAD | FWRITE);
+ comhardclose(com);
+ ttyclose(tp);
+ splx(s);
+ return (0);
+}
+
+static void
+comhardclose(com)
+ struct com_s *com;
+{
+ Port_t iobase;
+ int s;
+ struct tty *tp;
+ int unit;
+
+ unit = com - &com_structs[0];
+ iobase = com->iobase;
+ s = spltty();
+#ifdef TIOCTIMESTAMP
+ com->do_timestamp = 0;
+#endif
+ outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
+#ifdef KGDB
+ /* do not disable interrupts or hang up if debugging */
+ if (kgdb_dev != makedev(commajor, unit))
+#endif
+ {
+ outb(iobase + com_ier, 0);
+ tp = com->tp;
+ if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN
+#ifdef COM_BIDIR
+ /*
+ * XXX we will miss any carrier drop between here and the
+ * next open. Perhaps we should watch DCD even when the
+ * port is closed; it is not sufficient to check it at
+ * the next open because it might go up and down while
+ * we're not watching. And we shouldn't look at DCD if
+ * CLOCAL is set (here or for the dialin device ...).
+ * When the termios state is reinitialized for initial
+ * opens, the correct CLOCAL bit will be
+ * ((the bit now) & (the initial bit)).
+ */
+ || com->active_in
+ && !(com->prev_modem_status & MSR_DCD) && !FAKE_DCD(unit)
+#endif
+ || !(tp->t_state & TS_ISOPEN)) {
+ commctl(com, MCR_RTS, DMSET);
+ if (com->dtr_wait != 0)
+ /*
+ * Uninterruptible sleep since we want to
+ * wait a fixed time.
+ * XXX - delay in open() (if necessary),
+ * not here (always).
+ */
+ tsleep((caddr_t)&com->dtr_wait, TTIPRI,
+ "sioclose", com->dtr_wait);
+ }
+ }
+
+#ifdef COM_BIDIR
+ com->active = com->active_in = com->active_out = FALSE;
+
+ /* wakeup sleepers who are waiting for out to finish */
+ wakeup((caddr_t) &com->active_out);
+#endif /* COM_BIDIR */
+
+ splx(s);
+}
+
+int
+sioread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct tty *tp = com_addr(UNIT(dev))->tp;
+
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+int
+siowrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ int unit = UNIT(dev);
+ struct tty *tp = com_addr(unit)->tp;
+
+ /*
+ * (XXX) We disallow virtual consoles if the physical console is
+ * a serial port. This is in case there is a display attached that
+ * is not the console. In that situation we don't need/want the X
+ * server taking over the console.
+ */
+ if (constty && unit == comconsole)
+ constty = NULL;
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+#ifdef TIOCTIMESTAMP
+/* Interrupt routine for timekeeping purposes */
+void
+siointrts(unit)
+ int unit;
+{
+ microtime(&intr_timestamp);
+ siointr(unit);
+}
+#endif
+
+void
+siointr(unit)
+ int unit;
+{
+#ifndef COM_MULTIPORT
+ siointr1(com_addr(unit));
+#else /* COM_MULTIPORT */
+ bool_t possibly_more_intrs;
+ struct com_s *com;
+
+ /*
+ * Loop until there is no activity on any port. This is necessary
+ * to get an interrupt edge more than to avoid another interrupt.
+ * If the IRQ signal is just an OR of the IRQ signals from several
+ * devices, then the edge from one may be lost because another is
+ * on.
+ */
+ do {
+ possibly_more_intrs = FALSE;
+ for (unit = 0; unit < NSIO; ++unit) {
+ com = com_addr(unit);
+ if (com != NULL
+ && (inb(com->int_id_port) & IIR_IMASK)
+ != IIR_NOPEND) {
+ siointr1(com);
+ possibly_more_intrs = TRUE;
+ }
+ }
+ } while (possibly_more_intrs);
+#endif /* COM_MULTIPORT */
+}
+
+static void
+siointr1(com)
+ struct com_s *com;
+{
+ u_char line_status;
+ u_char modem_status;
+ u_char *ioptr;
+ u_char recv_data;
+
+#ifdef TIOCTIMESTAMP
+ if (com->do_timestamp)
+ /* XXX a little bloat here... */
+ com->timestamp = intr_timestamp;
+#endif
+ while (TRUE) {
+ line_status = inb(com->line_status_port);
+
+ /* input event? (check first to help avoid overruns) */
+ while (line_status & LSR_RCV_MASK) {
+ /* break/unnattached error bits or real input? */
+ if (!(line_status & LSR_RXRDY))
+ recv_data = 0;
+ else
+ recv_data = inb(com->data_port);
+ ++com->bytes_in;
+ /* XXX reduce SLIP input latency */
+#define FRAME_END 0xc0
+ if (recv_data == FRAME_END)
+ setsofttty();
+#ifdef KGDB
+ /* trap into kgdb? (XXX - needs testing and optim) */
+ if (recv_data == FRAME_END
+ && !(com->tp->t_state & TS_ISOPEN)
+ && kgdb_dev == makedev(commajor, unit)) {
+ kgdb_connect(0);
+ continue;
+ }
+#endif /* KGDB */
+ ioptr = com->iptr;
+ if (ioptr >= com->ibufend)
+ CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
+ else {
+ ++com_events;
+#if 0 /* for testing input latency vs efficiency */
+if (com->iptr - com->ibuf == 8)
+ setsofttty();
+#endif
+ ioptr[0] = recv_data;
+ ioptr[CE_INPUT_OFFSET] = line_status;
+ com->iptr = ++ioptr;
+ if (ioptr == com->ihighwater
+ && com->state & CS_RTS_IFLOW)
+ outb(com->modem_ctl_port,
+ com->mcr_image &= ~MCR_RTS);
+ /* XXX - move this out of isr */
+ if (line_status & LSR_OE)
+ CE_RECORD(com, CE_OVERRUN);
+ }
+
+ /*
+ * "& 0x7F" is to avoid the gcc-1.40 generating a slow
+ * jump from the top of the loop to here
+ */
+ line_status = inb(com->line_status_port) & 0x7F;
+ }
+
+ /* modem status change? (always check before doing output) */
+ modem_status = inb(com->modem_status_port);
+ if (modem_status != com->last_modem_status) {
+ /*
+ * Schedule high level to handle DCD changes. Note
+ * that we don't use the delta bits anywhere. Some
+ * UARTs mess them up, and it's easy to remember the
+ * previous bits and calculate the delta.
+ */
+ com->last_modem_status = modem_status;
+ if (!(com->state & CS_CHECKMSR)) {
+ com_events += LOTS_OF_EVENTS;
+ com->state |= CS_CHECKMSR;
+ setsofttty();
+ }
+
+ /* handle CTS change immediately for crisp flow ctl */
+ if (com->state & CS_CTS_OFLOW) {
+ if (modem_status & MSR_CTS)
+ com->state |= CS_ODEVREADY;
+ else
+ com->state &= ~CS_ODEVREADY;
+ }
+ }
+
+ /* output queued and everything ready? */
+ if (line_status & LSR_TXRDY
+ && com->state >= (CS_ODEVREADY | CS_BUSY | CS_TTGO)) {
+ ioptr = com->optr;
+ if (com->tx_fifo_size > 1) {
+ u_int ocount;
+
+ ocount = com->obufend - ioptr;
+ if (ocount > com->tx_fifo_size)
+ ocount = com->tx_fifo_size;
+ com->bytes_out += ocount;
+ do
+ outb(com->data_port, *ioptr++);
+ while (--ocount != 0);
+ } else {
+ outb(com->data_port, *ioptr++);
+ ++com->bytes_out;
+ }
+ com->optr = ioptr;
+ if (ioptr >= com->obufend) {
+ /* output just completed */
+ com_events += LOTS_OF_EVENTS;
+ com->state ^= (CS_ODONE | CS_BUSY);
+ setsofttty(); /* handle at high level ASAP */
+ }
+ }
+
+ /* finished? */
+#ifndef COM_MULTIPORT
+ if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
+#endif /* COM_MULTIPORT */
+ return;
+ }
+}
+
+static int
+tiocm_xxx2mcr(tiocm_xxx)
+ int tiocm_xxx;
+{
+ int mcr;
+
+ mcr = 0;
+ if (tiocm_xxx & TIOCM_DTR)
+ mcr |= MCR_DTR;
+ if (tiocm_xxx & TIOCM_RTS)
+ mcr |= MCR_RTS;
+ return (mcr);
+}
+
+int
+sioioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct com_s *com;
+ int error;
+ Port_t iobase;
+ int mcr;
+ int msr;
+ int s;
+ int tiocm_xxx;
+ struct tty *tp;
+
+ com = com_addr(UNIT(dev));
+ tp = com->tp;
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
+ if (error >= 0)
+ return (error);
+ error = ttioctl(tp, cmd, data, flag);
+
+#ifdef COM_BIDIR
+ /* XXX: plug security hole while sticky bits not yet implemented */
+ if (com->bidir && com->active_in && p->p_ucred->cr_uid != 0)
+ tp->t_cflag &= ~CLOCAL;
+#endif
+
+ if (error >= 0)
+ return (error);
+
+ iobase = com->iobase;
+ s = spltty();
+ switch (cmd) {
+ case TIOCSBRK:
+ outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
+ break;
+ case TIOCCBRK:
+ outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
+ break;
+ case TIOCSDTR:
+ commctl(com, MCR_DTR, DMBIS);
+ break;
+ case TIOCCDTR:
+ commctl(com, MCR_DTR, DMBIC);
+ break;
+ case TIOCMSET:
+ commctl(com, tiocm_xxx2mcr(*(int *)data), DMSET);
+ break;
+ case TIOCMBIS:
+ commctl(com, tiocm_xxx2mcr(*(int *)data), DMBIS);
+ break;
+ case TIOCMBIC:
+ commctl(com, tiocm_xxx2mcr(*(int *)data), DMBIC);
+ break;
+ case TIOCMGET:
+ tiocm_xxx = TIOCM_LE; /* XXX - always enabled while open */
+ mcr = com->mcr_image;
+ if (mcr & MCR_DTR)
+ tiocm_xxx |= TIOCM_DTR;
+ if (mcr & MCR_RTS)
+ tiocm_xxx |= TIOCM_RTS;
+ msr = com->prev_modem_status;
+ if (msr & MSR_CTS)
+ tiocm_xxx |= TIOCM_CTS;
+ if (msr & MSR_DCD)
+ tiocm_xxx |= TIOCM_CD;
+ if (msr & MSR_DSR)
+ tiocm_xxx |= TIOCM_DSR;
+ /*
+ * XXX - MSR_RI is naturally volatile, and we make MSR_TERI
+ * more volatile by reading the modem status a lot. Perhaps
+ * we should latch both bits until the status is read here.
+ */
+ if (msr & (MSR_RI | MSR_TERI))
+ tiocm_xxx |= TIOCM_RI;
+ *(int *)data = tiocm_xxx;
+ break;
+#ifdef COM_BIDIR
+ case TIOCMSBIDIR:
+ /* must be root to set bidir. capability */
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0) {
+ splx(s);
+ return(EPERM);
+ }
+
+ /* if it's the console, can't do it (XXX why?) */
+ if (UNIT(dev) == comconsole) {
+ splx(s);
+ return(ENOTTY);
+ }
+
+#if 0
+ /* XXX - can't do the next, for obvious reasons...
+ * but there are problems to be looked at...
+ */
+ /* if the port is active, don't do it */
+ if (com->active) {
+ splx(s);
+ return(EBUSY);
+ }
+#endif
+
+ com->bidir = *(int *)data;
+ break;
+ case TIOCMGBIDIR:
+ *(int *)data = com->bidir;
+ break;
+#endif /* COM_BIDIR */
+ case TIOCMSDTRWAIT:
+ /* must be root since the wait applies to following logins */
+ error = suser(p->p_ucred, &p->p_acflag);
+ if (error != 0) {
+ splx(s);
+ return(EPERM);
+ }
+
+ /* if it's the console, can't do it (XXX why?) */
+ if (UNIT(dev) == comconsole) {
+ splx(s);
+ return(ENOTTY);
+ }
+ com->dtr_wait = *(int *)data;
+ break;
+ case TIOCMGDTRWAIT:
+ *(int *)data = com->dtr_wait;
+ break;
+#ifdef TIOCTIMESTAMP
+ case TIOCTIMESTAMP:
+ com->do_timestamp = TRUE;
+ *(struct timeval *)data = com->timestamp;
+ break;
+#endif
+ default:
+ splx(s);
+ return (ENOTTY);
+ }
+ splx(s);
+ return (0);
+}
+
+/* cancel pending output */
+static void
+comflush(com)
+ struct com_s *com;
+{
+ struct ringb *rbp;
+
+ disable_intr();
+ if (com->state & CS_ODONE)
+ com_events -= LOTS_OF_EVENTS;
+ com->state &= ~(CS_ODONE | CS_BUSY);
+ enable_intr();
+ rbp = TB_OUT(com->tp);
+ rbp->rb_hd += com->ocount;
+ rbp->rb_hd = RB_ROLLOVER(rbp, rbp->rb_hd);
+ com->ocount = 0;
+ com->tp->t_state &= ~TS_BUSY;
+}
+
+void
+siopoll()
+{
+#ifdef OLD_INTERRUPT_HANDLING
+ static bool_t awake = FALSE;
+ int s;
+#endif
+ int unit;
+
+ if (com_events == 0)
+ return;
+
+#ifdef OLD_INTERRUPT_HANDLING
+ disable_intr();
+ if (awake) {
+ enable_intr();
+ return;
+ }
+ awake = TRUE;
+ enable_intr();
+ s = spltty();
+#endif
+
+repeat:
+ for (unit = 0; unit < NSIO; ++unit) {
+ u_char *buf;
+ struct com_s *com;
+ u_char *ibuf;
+ int incc;
+ struct tty *tp;
+
+ com = com_addr(unit);
+ if (com == NULL)
+ continue;
+ tp = com->tp;
+#ifdef DONT_MALLOC_TTYS
+ if (tp == NULL)
+ continue;
+#endif
+
+ /* switch the role of the low-level input buffers */
+ if (com->iptr == (ibuf = com->ibuf)) {
+ buf = NULL; /* not used, but compiler can't tell */
+ incc = 0;
+ } else {
+ buf = ibuf;
+ disable_intr();
+ incc = com->iptr - buf;
+ com_events -= incc;
+ if (ibuf == com->ibuf1)
+ ibuf = com->ibuf2;
+ else
+ ibuf = com->ibuf1;
+ com->ibufend = ibuf + RS_IBUFSIZE;
+ com->ihighwater = ibuf + RS_IHIGHWATER;
+ com->iptr = ibuf;
+
+ /*
+ * There is now room for another low-level buffer full
+ * of input, so enable RTS if it is now disabled and
+ * there is room in the high-level buffer.
+ */
+ /*
+ * XXX this used not to look at CS_RTS_IFLOW. The
+ * change is to allow full control of MCR_RTS via
+ * ioctls after turning CS_RTS_IFLOW off. Check
+ * for races. We shouldn't allow the ioctls while
+ * CS_RTS_IFLOW is on.
+ */
+ if ((com->state & CS_RTS_IFLOW)
+ && !(com->mcr_image & MCR_RTS)
+ && !(tp->t_state & TS_RTS_IFLOW))
+ outb(com->modem_ctl_port,
+ com->mcr_image |= MCR_RTS);
+ enable_intr();
+ com->ibuf = ibuf;
+ }
+
+ if (com->state & CS_CHECKMSR) {
+ u_char delta_modem_status;
+
+ disable_intr();
+ delta_modem_status = com->last_modem_status
+ ^ com->prev_modem_status;
+ com->prev_modem_status = com->last_modem_status;
+ com_events -= LOTS_OF_EVENTS;
+ com->state &= ~CS_CHECKMSR;
+ enable_intr();
+ if (delta_modem_status & MSR_DCD && !FAKE_DCD(unit)) {
+ if (com->prev_modem_status & MSR_DCD) {
+ (*linesw[tp->t_line].l_modem)(tp, 1);
+#ifdef COM_BIDIR
+ wakeup((caddr_t) &com->active_in);
+#endif /* COM_BIDIR */
+ } else
+ (*linesw[tp->t_line].l_modem)(tp, 0);
+ }
+ }
+
+ /* XXX */
+ if (TRUE) {
+ u_int delta;
+ int errnum;
+ u_long total;
+
+ for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
+ disable_intr();
+ delta = com->delta_error_counts[errnum];
+ com->delta_error_counts[errnum] = 0;
+ enable_intr();
+ if (delta != 0) {
+ total =
+ com->error_counts[errnum] += delta;
+ log(LOG_WARNING,
+ "sio%d: %u more %s%s (total %lu)\n",
+ unit, delta, error_desc[errnum],
+ delta == 1 ? "" : "s", total);
+ }
+ }
+ }
+ if (com->state & CS_ODONE) {
+ comflush(com);
+ /* XXX - why isn't the table used for t_line == 0? */
+ if (tp->t_line != 0)
+ (*linesw[tp->t_line].l_start)(tp);
+ else
+ comstart(tp);
+ }
+ if (incc <= 0 || !(tp->t_state & TS_ISOPEN))
+ continue;
+ if (com->state & CS_RTS_IFLOW
+ && RB_LEN(TB_RAW(tp)) + incc >= RB_I_HIGH_WATER
+ && !(tp->t_state & TS_RTS_IFLOW)
+ /*
+ * XXX - need RTS flow control for all line disciplines.
+ * Only have it in standard one now.
+ */
+ && linesw[tp->t_line].l_rint == ttyinput) {
+ tp->t_state |= TS_RTS_IFLOW;
+ ttstart(tp);
+ }
+ /*
+ * Avoid the grotesquely inefficient lineswitch routine
+ * (ttyinput) in "raw" mode. It usually takes about 450
+ * instructions (that's without canonical processing or echo!).
+ * slinput is reasonably fast (usually 40 instructions plus
+ * call overhead).
+ */
+ if (!(tp->t_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP
+ | IXOFF | IXON))
+ && !(tp->t_lflag & (ECHO | ECHONL | ICANON | IEXTEN | ISIG
+ | PENDIN))
+ && !(tp->t_state & (TS_CNTTB | TS_LNCH))
+ && linesw[tp->t_line].l_rint == ttyinput) {
+ tk_nin += incc;
+ tk_rawcc += incc;
+ tp->t_rawcc += incc;
+ com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
+ += incc - rb_write(TB_RAW(tp), (char *) buf,
+ incc);
+ ttwakeup(tp);
+ if (tp->t_state & TS_TTSTOP
+ && (tp->t_iflag & IXANY
+ || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
+ tp->t_state &= ~TS_TTSTOP;
+ tp->t_lflag &= ~FLUSHO;
+ ttstart(tp);
+ }
+ } else {
+ do {
+ u_char line_status;
+ int recv_data;
+
+ line_status = (u_char) buf[CE_INPUT_OFFSET];
+ recv_data = (u_char) *buf++;
+ if (line_status
+ & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
+ if (line_status & LSR_BI)
+ recv_data |= TTY_BI;
+ if (line_status & LSR_FE)
+ recv_data |= TTY_FE;
+ if (line_status & LSR_OE)
+ recv_data |= TTY_OE;
+ if (line_status & LSR_PE)
+ recv_data |= TTY_PE;
+ }
+ (*linesw[tp->t_line].l_rint)(recv_data, tp);
+ } while (--incc > 0);
+ }
+ if (com_events == 0)
+ break;
+ }
+ if (com_events >= LOTS_OF_EVENTS)
+ goto repeat;
+
+#ifdef OLD_INTERRUPT_HANDLING
+ splx(s);
+ awake = FALSE;
+#endif
+}
+
+static int
+comparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ u_int cfcr;
+ int cflag;
+ struct com_s *com;
+ int divisor;
+ int error;
+ Port_t iobase;
+ int s;
+ int unit;
+
+ /* check requested parameters */
+ divisor = ttspeedtab(t->c_ospeed, comspeedtab);
+ if (t->c_ispeed == 0)
+ t->c_ispeed = t->c_ospeed;
+ if (divisor < 0 || t->c_ispeed != t->c_ospeed)
+ return (EINVAL);
+
+ /* parameters are OK, convert them to the com struct and the device */
+ unit = UNIT(tp->t_dev);
+ com = com_addr(unit);
+ iobase = com->iobase;
+ s = spltty();
+ if (divisor == 0)
+ commctl(com, MCR_DTR, DMBIC); /* hang up line */
+ else
+ commctl(com, MCR_DTR, DMBIS);
+ cflag = t->c_cflag;
+ switch (cflag & CSIZE) {
+ case CS5:
+ cfcr = CFCR_5BITS;
+ break;
+ case CS6:
+ cfcr = CFCR_6BITS;
+ break;
+ case CS7:
+ cfcr = CFCR_7BITS;
+ break;
+ default:
+ cfcr = CFCR_8BITS;
+ break;
+ }
+ if (cflag & PARENB) {
+ cfcr |= CFCR_PENAB;
+ if (!(cflag & PARODD))
+ cfcr |= CFCR_PEVEN;
+ }
+ if (cflag & CSTOPB)
+ cfcr |= CFCR_STOPB;
+
+ /*
+ * Some UARTs lock up if the divisor latch registers are selected
+ * while the UART is doing output (they refuse to transmit anything
+ * more until given a hard reset). Fix this by stopping filling
+ * the device buffers and waiting for them to drain. Reading the
+ * line status port outside of siointr1() might lose some receiver
+ * error bits, but that is acceptable here.
+ */
+ disable_intr();
+retry:
+ com->state &= ~CS_TTGO;
+ enable_intr();
+ while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
+ != (LSR_TSRE | LSR_TXRDY)) {
+ error = ttysleep(tp, (caddr_t)TB_RAW(tp), TTIPRI | PCATCH,
+ "sioparam", 1);
+ if (error != 0 && error != EAGAIN) {
+ if (!(tp->t_state & TS_TTSTOP)) {
+ disable_intr();
+ com->state |= CS_TTGO;
+ enable_intr();
+ }
+ splx(s);
+ return (error);
+ }
+ }
+
+ disable_intr(); /* very important while com_data is hidden */
+
+ /*
+ * XXX - clearing CS_TTGO is not sufficient to stop further output,
+ * because siopoll() calls comstart() which usually sets it again
+ * because TS_TTSTOP is clear. Setting TS_TTSTOP would not be
+ * sufficient, for similar reasons.
+ */
+ if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
+ != (LSR_TSRE | LSR_TXRDY))
+ goto retry;
+
+ if (divisor != 0) {
+ outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
+ outb(iobase + com_dlbl, divisor & 0xFF);
+ outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ }
+ outb(iobase + com_cfcr, com->cfcr_image = cfcr);
+ if (!(tp->t_state & TS_TTSTOP))
+ com->state |= CS_TTGO;
+ if (cflag & CRTS_IFLOW)
+ com->state |= CS_RTS_IFLOW; /* XXX - secondary changes? */
+ else
+ com->state &= ~CS_RTS_IFLOW;
+
+ /*
+ * Set up state to handle output flow control.
+ * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
+ * Now has 16+ msec latency, while CTS flow has 50- usec latency.
+ */
+ com->state &= ~CS_CTS_OFLOW;
+ com->state |= CS_ODEVREADY;
+ if (cflag & CCTS_OFLOW) {
+ com->state |= CS_CTS_OFLOW;
+ if (!(com->last_modem_status & MSR_CTS))
+ com->state &= ~CS_ODEVREADY;
+ }
+
+ /*
+ * Recover from fiddling with CS_TTGO. We used to call siointr1()
+ * unconditionally, but that defeated the careful discarding of
+ * stale input in sioopen().
+ *
+ * XXX sioopen() is not careful waiting for carrier for the callout
+ * case.
+ */
+ if (com->state >= (CS_BUSY | CS_TTGO))
+ siointr1(com);
+
+ enable_intr();
+ splx(s);
+ return (0);
+}
+
+static void
+comstart(tp)
+ struct tty *tp;
+{
+ struct com_s *com;
+ int s;
+ int unit;
+
+ unit = UNIT(tp->t_dev);
+ com = com_addr(unit);
+ s = spltty();
+ disable_intr();
+ if (tp->t_state & TS_TTSTOP)
+ com->state &= ~CS_TTGO;
+ else
+ com->state |= CS_TTGO;
+ if (tp->t_state & TS_RTS_IFLOW) {
+ if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
+ outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
+ } else {
+ /*
+ * XXX don't raise MCR_RTS if CTS_RTS_IFLOW is off. Set it
+ * appropriately in comparam() if RTS-flow is being changed.
+ * Check for races.
+ */
+ if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater)
+ outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
+ }
+ enable_intr();
+ if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
+ goto out;
+ if (RB_LEN(TB_OUT(tp)) <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)TB_OUT(tp));
+ }
+ if (tp->t_wsel) {
+ selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
+ tp->t_wsel = 0;
+ tp->t_state &= ~TS_WCOLL;
+ }
+ }
+ if (com->ocount != 0) {
+ disable_intr();
+ siointr1(com);
+ enable_intr();
+ } else if (RB_LEN(TB_OUT(tp)) != 0) {
+ tp->t_state |= TS_BUSY;
+ com->ocount = RB_CONTIGGET(TB_OUT(tp));
+ disable_intr();
+ com->obufend = (com->optr = (u_char *)TB_OUT(tp)->rb_hd)
+ + com->ocount;
+ com->state |= CS_BUSY;
+ siointr1(com); /* fake interrupt to start output */
+ enable_intr();
+ }
+out:
+ splx(s);
+}
+
+void
+siostop(tp, rw)
+ struct tty *tp;
+ int rw;
+{
+ struct com_s *com;
+
+ com = com_addr(UNIT(tp->t_dev));
+ if (rw & FWRITE)
+ comflush(com);
+ disable_intr();
+ if (rw & FREAD) {
+ com_events -= (com->iptr - com->ibuf);
+ com->iptr = com->ibuf;
+ }
+ if (tp->t_state & TS_TTSTOP)
+ com->state &= ~CS_TTGO;
+ else
+ com->state |= CS_TTGO;
+ enable_intr();
+}
+
+int
+sioselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ return (ttselect(dev & ~COM_MINOR_MAGIC_MASK, rw, p));
+}
+
+static void
+commctl(com, bits, how)
+ struct com_s *com;
+ int bits;
+ int how;
+{
+ disable_intr();
+ switch (how) {
+ case DMSET:
+ outb(com->modem_ctl_port,
+ com->mcr_image = bits | (com->mcr_image & MCR_IENABLE));
+ break;
+ case DMBIS:
+ outb(com->modem_ctl_port, com->mcr_image |= bits);
+ break;
+ case DMBIC:
+ outb(com->modem_ctl_port, com->mcr_image &= ~bits);
+ break;
+ }
+ enable_intr();
+}
+
+static void
+comwakeup(chan, ticks)
+ caddr_t chan;
+ int ticks;
+{
+ int unit;
+
+ timeout(comwakeup, (caddr_t) NULL, hz / 100);
+
+ if (com_events != 0) {
+#ifndef OLD_INTERRUPT_HANDLING
+ int s = splsofttty();
+#endif
+ siopoll();
+#ifndef OLD_INTERRUPT_HANDLING
+ splx(s);
+#endif
+ }
+
+ /* recover from lost output interrupts */
+ for (unit = 0; unit < NSIO; ++unit) {
+ struct com_s *com;
+
+ com = com_addr(unit);
+ if (com != NULL && com->state >= (CS_BUSY | CS_TTGO)) {
+ disable_intr();
+ siointr1(com);
+ enable_intr();
+ }
+ }
+}
+
+#ifdef OLD_INTERRUPT_HANDLING
+void
+softsio1()
+{
+ siopoll();
+}
+#endif
+
+/*
+ * Following are all routines needed for SIO to act as console
+ */
+#include "i386/i386/cons.h"
+
+struct siocnstate {
+ u_char dlbl;
+ u_char dlbh;
+ u_char ier;
+ u_char cfcr;
+ u_char mcr;
+};
+
+static Port_t siocniobase;
+
+static void
+siocntxwait()
+{
+ int timo;
+
+ /*
+ * Wait for any pending transmission to finish. Required to avoid
+ * the UART lockup bug when the speed is changed, and for normal
+ * transmits.
+ */
+ timo = 100000;
+ while ((inb(siocniobase + com_lsr) & (LSR_TSRE | LSR_TXRDY))
+ != (LSR_TSRE | LSR_TXRDY) && --timo != 0)
+ ;
+}
+
+static void
+siocnopen(sp)
+ struct siocnstate *sp;
+{
+ int divisor;
+ Port_t iobase;
+
+ /*
+ * Save all the device control registers except the fifo register
+ * and set our default ones (cs8 -parenb speed=comdefaultrate).
+ * We can't save the fifo register since it is read-only.
+ */
+ iobase = siocniobase;
+ sp->ier = inb(iobase + com_ier);
+ outb(iobase + com_ier, 0); /* spltty() doesn't stop siointr() */
+ siocntxwait();
+ sp->cfcr = inb(iobase + com_cfcr);
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ sp->dlbl = inb(iobase + com_dlbl);
+ sp->dlbh = inb(iobase + com_dlbh);
+ divisor = ttspeedtab(comdefaultrate, comspeedtab);
+ outb(iobase + com_dlbl, divisor & 0xFF);
+ outb(iobase + com_dlbh, (u_int) divisor >> 8);
+ outb(iobase + com_cfcr, CFCR_8BITS);
+ sp->mcr = inb(iobase + com_mcr);
+ outb(iobase + com_mcr, MCR_DTR | MCR_RTS);
+}
+
+static void
+siocnclose(sp)
+ struct siocnstate *sp;
+{
+ Port_t iobase;
+
+ /*
+ * Restore the device control registers.
+ */
+ siocntxwait();
+ iobase = siocniobase;
+ outb(iobase + com_cfcr, CFCR_DLAB);
+ outb(iobase + com_dlbl, sp->dlbl);
+ outb(iobase + com_dlbh, sp->dlbh);
+ outb(iobase + com_cfcr, sp->cfcr);
+ /*
+ * XXX damp osicllations of MCR_DTR or MCR_RTS by not restoring them.
+ */
+ outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS);
+ outb(iobase + com_ier, sp->ier);
+}
+
+void
+siocnprobe(cp)
+ struct consdev *cp;
+{
+ int unit;
+
+ /* locate the major number */
+ /* XXX - should be elsewhere since KGDB uses it */
+ for (commajor = 0; commajor < nchrdev; commajor++)
+ if (cdevsw[commajor].d_open == sioopen)
+ break;
+
+ /* XXX: ick */
+ unit = UNIT(CONUNIT);
+ siocniobase = CONADDR;
+
+ /* make sure hardware exists? XXX */
+
+ /* initialize required fields */
+ cp->cn_dev = makedev(commajor, unit);
+#ifdef COMCONSOLE
+ cp->cn_pri = CN_REMOTE; /* Force a serial port console */
+#else
+ cp->cn_pri = CN_NORMAL;
+#endif
+}
+
+void
+siocninit(cp)
+ struct consdev *cp;
+{
+ /*
+ * XXX can delete more comconsole stuff now that i/o routines are
+ * fairly reentrant.
+ */
+ comconsole = UNIT(cp->cn_dev);
+}
+
+int
+siocngetc(dev)
+ dev_t dev;
+{
+ int c;
+ Port_t iobase;
+ int s;
+ struct siocnstate sp;
+
+ iobase = siocniobase;
+ s = spltty();
+ siocnopen(&sp);
+ while (!(inb(iobase + com_lsr) & LSR_RXRDY))
+ ;
+ c = inb(iobase + com_data);
+ siocnclose(&sp);
+ splx(s);
+ return (c);
+}
+
+void
+siocnputc(dev, c)
+ dev_t dev;
+ int c;
+{
+ int s;
+ struct siocnstate sp;
+
+ s = spltty();
+ siocnopen(&sp);
+ siocntxwait();
+ outb(siocniobase + com_data, c);
+ siocnclose(&sp);
+ splx(s);
+}
+
+#endif /* NSIO > 0 */
diff --git a/sys/isa/sioreg.h b/sys/isa/sioreg.h
new file mode 100644
index 0000000..4b0f1b6
--- /dev/null
+++ b/sys/isa/sioreg.h
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)comreg.h 7.2 (Berkeley) 5/9/91
+ * $Id$
+ */
+
+
+/* 16 bit baud rate divisor (lower byte in dca_data, upper in dca_ier) */
+#define COMBRD(x) (1843200 / (16*(x)))
+
+/* interrupt enable register */
+#define IER_ERXRDY 0x1
+#define IER_ETXRDY 0x2
+#define IER_ERLS 0x4
+#define IER_EMSC 0x8
+
+/* interrupt identification register */
+#define IIR_IMASK 0xf
+#define IIR_RXTOUT 0xc
+#define IIR_RLS 0x6
+#define IIR_RXRDY 0x4
+#define IIR_TXRDY 0x2
+#define IIR_NOPEND 0x1
+#define IIR_MLSC 0x0
+#define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */
+
+/* fifo control register */
+#define FIFO_ENABLE 0x01
+#define FIFO_RCV_RST 0x02
+#define FIFO_XMT_RST 0x04
+#define FIFO_DMA_MODE 0x08
+#define FIFO_TRIGGER_1 0x00
+#define FIFO_TRIGGER_4 0x40
+#define FIFO_TRIGGER_8 0x80
+#define FIFO_TRIGGER_14 0xc0
+
+/* character format control register */
+#define CFCR_DLAB 0x80
+#define CFCR_SBREAK 0x40
+#define CFCR_PZERO 0x30
+#define CFCR_PONE 0x20
+#define CFCR_PEVEN 0x10
+#define CFCR_PODD 0x00
+#define CFCR_PENAB 0x08
+#define CFCR_STOPB 0x04
+#define CFCR_8BITS 0x03
+#define CFCR_7BITS 0x02
+#define CFCR_6BITS 0x01
+#define CFCR_5BITS 0x00
+
+/* modem control register */
+#define MCR_LOOPBACK 0x10
+#define MCR_IENABLE 0x08
+#define MCR_DRS 0x04
+#define MCR_RTS 0x02
+#define MCR_DTR 0x01
+
+/* line status register */
+#define LSR_RCV_FIFO 0x80
+#define LSR_TSRE 0x40
+#define LSR_TXRDY 0x20
+#define LSR_BI 0x10
+#define LSR_FE 0x08
+#define LSR_PE 0x04
+#define LSR_OE 0x02
+#define LSR_RXRDY 0x01
+#define LSR_RCV_MASK 0x1f
+
+/* modem status register */
+#define MSR_DCD 0x80
+#define MSR_RI 0x40
+#define MSR_DSR 0x20
+#define MSR_CTS 0x10
+#define MSR_DDCD 0x08
+#define MSR_TERI 0x04
+#define MSR_DDSR 0x02
+#define MSR_DCTS 0x01
+
+/*
+ * WARNING: Serial console is assumed to be at COM1 address
+ * and CONUNIT must be 0.
+ */
+#define CONADDR (0x3f8)
+#define CONUNIT (0)
diff --git a/sys/isa/syscons.c b/sys/isa/syscons.c
new file mode 100644
index 0000000..8757295
--- /dev/null
+++ b/sys/isa/syscons.c
@@ -0,0 +1,2659 @@
+/*-
+ * Copyright (c) 1992-1994 Søren Schmidt
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz and Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from:@(#)syscons.c 1.3 940129
+ * $Id: syscons.c,v 1.44 1994/04/21 14:22:26 sos Exp $
+ *
+ */
+
+#if !defined(__FreeBSD__)
+#define FAT_CURSOR
+#endif
+
+#include "param.h"
+#include "conf.h"
+#include "ioctl.h"
+#include "proc.h"
+#include "user.h"
+#include "tty.h"
+#include "uio.h"
+#include "callout.h"
+#include "systm.h"
+#include "kernel.h"
+#include "syslog.h"
+#include "errno.h"
+#include "malloc.h"
+#include "i386/isa/isa.h"
+#include "i386/isa/isa_device.h"
+#include "i386/isa/timerreg.h"
+#include "i386/i386/cons.h"
+#include "machine/console.h"
+#include "machine/psl.h"
+#include "machine/frame.h"
+#include "machine/pc/display.h"
+#include "iso8859.font"
+#include "kbdtables.h"
+#include "sc.h"
+
+#if NSC > 0
+
+#if !defined(NCONS)
+#define NCONS 12
+#endif
+
+/* status flags */
+#define LOCK_KEY_MASK 0x0000F
+#define LED_MASK 0x00007
+#define UNKNOWN_MODE 0x00010
+#define KBD_RAW_MODE 0x00020
+#define SWITCH_WAIT_REL 0x00040
+#define SWITCH_WAIT_ACQ 0x00080
+
+/* video hardware memory addresses */
+#define VIDEOMEM 0x000A0000
+
+/* misc defines */
+#define MAX_ESC_PAR 3
+#define TEXT80x25 1
+#define TEXT80x50 2
+#define COL 80
+#define ROW 25
+#define BELL_DURATION 5
+#define BELL_PITCH 800
+#define TIMER_FREQ 1193182 /* should be in isa.h */
+#define PCBURST 128
+
+/* defines related to hardware addresses */
+#define MONO_BASE 0x3B4 /* crt controller base mono */
+#define COLOR_BASE 0x3D4 /* crt controller base color */
+#define ATC IO_VGA+0x00 /* attribute controller */
+#define TSIDX IO_VGA+0x04 /* timing sequencer idx */
+#define TSREG IO_VGA+0x05 /* timing sequencer data */
+#define PIXMASK IO_VGA+0x06 /* pixel write mask */
+#define PALRADR IO_VGA+0x07 /* palette read address */
+#define PALWADR IO_VGA+0x08 /* palette write address */
+#define PALDATA IO_VGA+0x09 /* palette data register */
+#define GDCIDX IO_VGA+0x0E /* graph data controller idx */
+#define GDCREG IO_VGA+0x0F /* graph data controller data */
+
+/* special characters */
+#define cntlc 0x03
+#define cntld 0x04
+#define bs 0x08
+#define lf 0x0a
+#define cr 0x0d
+#define del 0x7f
+
+typedef struct term_stat {
+ int esc; /* processing escape sequence */
+ int num_param; /* # of parameters to ESC */
+ int last_param; /* last parameter # */
+ int param[MAX_ESC_PAR]; /* contains ESC parameters */
+ int cur_attr; /* current attributes */
+ int std_attr; /* normal attributes */
+ int rev_attr; /* reverse attributes */
+} term_stat;
+
+typedef struct scr_stat {
+ u_short *crt_base; /* address of screen memory */
+ u_short *scr_buf; /* buffer when off screen */
+ u_short *crtat; /* cursor address */
+ int xpos; /* current X position */
+ int ypos; /* current Y position */
+ int xsize; /* X size */
+ int ysize; /* Y size */
+ term_stat term; /* terminal emulation stuff */
+ char cursor_start; /* cursor start line # */
+ char cursor_end; /* cursor end line # */
+ u_char border; /* border color */
+ u_short bell_duration;
+ u_short bell_pitch;
+ u_short status; /* status (bitfield) */
+ u_short mode; /* mode */
+ pid_t pid; /* pid of controlling proc */
+ struct proc *proc; /* proc* of controlling proc */
+ struct vt_mode smode; /* switch mode */
+} scr_stat;
+
+typedef struct default_attr {
+ int std_attr; /* normal attributes */
+ int rev_attr; /* reverse attributes */
+} default_attr;
+
+static default_attr user_default = {
+ (FG_LIGHTGREY | BG_BLACK) << 8,
+ (FG_BLACK | BG_LIGHTGREY) << 8
+};
+
+static default_attr kernel_default = {
+ (FG_WHITE | BG_BLACK) << 8,
+ (FG_BLACK | BG_LIGHTGREY) << 8
+};
+
+#define CONSOLE_BUFFER_SIZE 1024
+int console_buffer_count;
+char console_buffer[CONSOLE_BUFFER_SIZE];
+
+static scr_stat console[NCONS];
+static scr_stat *cur_console = &console[0];
+static scr_stat *new_scp, *old_scp;
+static term_stat kernel_console;
+static default_attr *current_default;
+static int switch_in_progress = 0;
+static u_short *crtat = 0;
+static u_int crtc_addr = MONO_BASE;
+static char crtc_vga = 0;
+static u_char shfts = 0, ctls = 0, alts = 0, agrs = 0, metas = 0;
+static u_char nlkcnt = 0, clkcnt = 0, slkcnt = 0, alkcnt = 0;
+static char palette[3*256];
+static const u_int n_fkey_tab = sizeof(fkey_tab) / sizeof(*fkey_tab);
+static int cur_cursor_pos = -1;
+static char in_putc = 0;
+static char polling = 0;
+static int delayed_next_scr;
+static char saved_console = -1; /* saved console number */
+static long scrn_blank_time = 0; /* screen saver timout value */
+static int scrn_blanked = 0; /* screen saver active flag */
+static int scrn_saver = 0; /* screen saver routine */
+static long scrn_time_stamp;
+static u_char scr_map[256];
+extern int hz;
+extern struct timeval time;
+
+/* function prototypes */
+int pcprobe(struct isa_device *dev);
+int pcattach(struct isa_device *dev);
+int pcopen(dev_t dev, int flag, int mode, struct proc *p);
+int pcclose(dev_t dev, int flag, int mode, struct proc *p);
+int pcread(dev_t dev, struct uio *uio, int flag);
+int pcwrite(dev_t dev, struct uio *uio, int flag);
+int pcparam(struct tty *tp, struct termios *t);
+int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p);
+void pcxint(dev_t dev);
+void pcstart(struct tty *tp);
+void pccnprobe(struct consdev *cp);
+void pccninit(struct consdev *cp);
+void pccnputc(dev_t dev, char c);
+int pccngetc(dev_t dev);
+void scintr(int unit);
+int pcmmap(dev_t dev, int offset, int nprot);
+u_int sgetc(int noblock);
+int getchar(void);
+static void scinit(void);
+static void scput(u_char c);
+static u_int scgetc(int noblock);
+static struct tty *get_tty_ptr(dev_t dev);
+static scr_stat *get_scr_stat(dev_t dev);
+static int get_scr_num();
+static void cursor_shape(int start, int end);
+static void get_cursor_shape(int *start, int *end);
+static void cursor_pos(int force);
+static void clear_screen(scr_stat *scp);
+static int switch_scr(u_int next_scr);
+static void exchange_scr(void);
+static void move_crsr(scr_stat *scp, int x, int y);
+static void move_up(u_short *s, u_short *d, u_int len);
+static void move_down(u_short *s, u_short *d, u_int len);
+static void scan_esc(scr_stat *scp, u_char c);
+static void ansi_put(scr_stat *scp, u_char c);
+static u_char *get_fstr(u_int c, u_int *len);
+static void update_leds(int which);
+static void kbd_wait(void);
+static void kbd_cmd(u_char command);
+static void kbd_cmd2(u_char command, u_char arg);
+static int kbd_reply(void);
+static void set_mode(scr_stat *scp);
+static void set_border(int color);
+static void load_font(int segment, int size, char* font);
+static void save_palette(void);
+static void load_palette(void);
+static void change_winsize(struct tty *tp, int x, int y);
+
+
+/* available screen savers */
+
+static void none_saver(int test);
+static void blank_saver(int test);
+static void fade_saver(int test);
+static void star_saver(int test);
+static void snake_saver(int test);
+
+static const struct {
+ char *name;
+ void (*routine)();
+} screen_savers[] = {
+ { "none", none_saver }, /* 0 */
+ { "blank", blank_saver }, /* 1 */
+ { "fade", fade_saver }, /* 2 */
+ { "star", star_saver }, /* 3 */
+ { "snake", snake_saver }, /* 4 */
+};
+#define SCRN_SAVER(arg) (*screen_savers[scrn_saver].routine)(arg)
+#define NUM_SCRN_SAVERS (sizeof(screen_savers) / sizeof(screen_savers[0]))
+
+/* OS specific stuff */
+
+#if defined(NetBSD)
+#define VIRTUAL_TTY(x) pc_tty[x] ? (pc_tty[x]) : (pc_tty[x] = ttymalloc())
+#define CONSOLE_TTY pc_tty[NCONS] ? (pc_tty[NCONS]) : (pc_tty[NCONS] = ttymalloc())
+#define frametype struct trapframe
+#define eflags tf_eflags
+extern u_short *Crtat;
+struct tty *pc_tty[NCONS+1];
+int ttrstrt();
+#endif
+
+#if defined(__FreeBSD__)
+#define VIRTUAL_TTY(x) (pccons[x] = ttymalloc(pccons[x]))
+#define CONSOLE_TTY (pccons[NCONS] = ttymalloc(pccons[NCONS]))
+#define frametype struct trapframe
+#define eflags tf_eflags
+#define timeout_t timeout_func_t
+#define MONO_BUF (KERNBASE+0xB0000)
+#define CGA_BUF (KERNBASE+0xB8000)
+struct tty *pccons[NCONS+1];
+#endif
+
+#if defined(__386BSD__) && !defined(__FreeBSD__)
+#define VIRTUAL_TTY(x) &pccons[x]
+#define CONSOLE_TTY &pccons[NCONS]
+#define frametype struct syscframe
+#define eflags sf_eflags
+#define timeout_t caddr_t
+#define MONO_BUF (0xFE0B0000)
+#define CGA_BUF (0xFE0B8000)
+struct tty pccons[NCONS+1];
+#endif
+
+#if defined(__386BSD__) || defined(__FreeBSD__)
+u_short *Crtat = (u_short *)MONO_BUF;
+void consinit(void) {scinit();}
+#include "ddb.h"
+#if NDDB > 0
+#define DDB 1
+#endif
+#endif
+
+struct isa_driver scdriver = {
+ pcprobe, pcattach, "sc",
+};
+
+
+int pcprobe(struct isa_device *dev)
+{
+ /* Enable interrupts and keyboard controller */
+ kbd_wait();
+ outb(KB_STAT, KB_WRITE);
+ kbd_cmd(0x4D);
+
+ /* Start keyboard stuff RESET */
+ for (;;) {
+ kbd_cmd(KB_RESET);
+ if (kbd_reply() == KB_ACK && /* command accepted */
+ kbd_reply() == 0xaa) /* self test passed */
+ break;
+ printf("Keyboard reset failed\n");
+ }
+ return (IO_KBDSIZE);
+}
+
+
+int pcattach(struct isa_device *dev)
+{
+ scr_stat *scp;
+ int start = -1, end = -1, i;
+
+ printf("sc%d: ", dev->id_unit);
+ if (crtc_vga)
+ if (crtc_addr == MONO_BASE)
+ printf("VGA mono");
+ else
+ printf("VGA color");
+ else
+ if (crtc_addr == MONO_BASE)
+ printf("MDA/hercules");
+ else
+ printf("CGA/EGA");
+
+ if (NCONS > 1)
+ printf(" <%d virtual consoles>\n", NCONS);
+ else
+ printf("\n");
+#if defined(FAT_CURSOR)
+ start = 0;
+ end = 18;
+ if (crtc_vga) {
+#else
+ if (crtc_vga) {
+ get_cursor_shape(&start, &end);
+#endif
+ save_palette();
+ load_font(0, 16, font_8x16);
+ load_font(1, 8, font_8x8);
+ load_font(2, 14, font_8x14);
+ }
+ current_default = &user_default;
+ for (i = 0; i < NCONS; i++) {
+ scp = &console[i];
+ scp->scr_buf = (u_short *)malloc(COL * ROW * 2, M_DEVBUF, M_NOWAIT);
+ scp->mode = TEXT80x25;
+ scp->term.esc = 0;
+ scp->term.std_attr = current_default->std_attr;
+ scp->term.rev_attr = current_default->rev_attr;
+ scp->term.cur_attr = scp->term.std_attr;
+ scp->border = BG_BLACK;
+ scp->cursor_start = start;
+ scp->cursor_end = end;
+ scp->xsize = COL;
+ scp->ysize = ROW;
+ scp->bell_pitch = BELL_PITCH;
+ scp->bell_duration = BELL_DURATION;
+ scp->status = 0;
+ scp->pid = 0;
+ scp->proc = NULL;
+ scp->smode.mode = VT_AUTO;
+ if (i > 0) {
+ scp->crt_base = scp->crtat = scp->scr_buf;
+ fillw(scp->term.cur_attr|scr_map[0x20], scp->scr_buf, COL*ROW);
+ }
+ }
+ /* get cursor going */
+#if defined(FAT_CURSOR)
+ cursor_shape(console[0].cursor_start,
+ console[0].cursor_end);
+#endif
+ cursor_pos(1);
+ return 0;
+}
+
+
+static struct tty *get_tty_ptr(dev_t dev)
+{
+ int unit = minor(dev);
+
+ if (unit > NCONS)
+ return(NULL);
+ if (unit == NCONS)
+ return(CONSOLE_TTY);
+ return(VIRTUAL_TTY(unit));
+}
+
+
+static scr_stat *get_scr_stat(dev_t dev)
+{
+ int unit = minor(dev);
+
+ if (unit > NCONS)
+ return(NULL);
+ if (unit == NCONS)
+ return(&console[0]);
+ return(&console[unit]);
+}
+
+
+static int get_scr_num()
+{
+ int i = 0;
+
+ while ((i < NCONS) && (cur_console != &console[i])) i++;
+ return i < NCONS ? i : 0;
+}
+
+int pcopen(dev_t dev, int flag, int mode, struct proc *p)
+{
+ struct tty *tp = get_tty_ptr(dev);
+
+ if (!tp)
+ return(ENXIO);
+
+ tp->t_oproc = pcstart;
+ tp->t_param = pcparam;
+ tp->t_dev = dev;
+ if (!(tp->t_state & TS_ISOPEN)) {
+ tp->t_state |= TS_WOPEN;
+ ttychars(tp);
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_cflag = TTYDEF_CFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
+ pcparam(tp, &tp->t_termios);
+ ttsetwater(tp);
+ } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
+ return(EBUSY);
+ tp->t_state |= TS_CARR_ON;
+ tp->t_cflag |= CLOCAL;
+#if defined(__FreeBSD__)
+ return((*linesw[tp->t_line].l_open)(dev, tp, 0));
+#else
+ return((*linesw[tp->t_line].l_open)(dev, tp));
+#endif
+}
+
+
+int pcclose(dev_t dev, int flag, int mode, struct proc *p)
+{
+ struct tty *tp = get_tty_ptr(dev);
+ struct scr_stat *scp;
+
+ if (!tp)
+ return(ENXIO);
+ if (minor(dev) < NCONS) {
+ scp = get_scr_stat(tp->t_dev);
+ if (scp->status & SWITCH_WAIT_ACQ)
+ wakeup((caddr_t)&scp->smode);
+ scp->pid = 0;
+ scp->proc = NULL;
+ scp->smode.mode = VT_AUTO;
+ }
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ ttyclose(tp);
+ return(0);
+}
+
+
+int pcread(dev_t dev, struct uio *uio, int flag)
+{
+ struct tty *tp = get_tty_ptr(dev);
+
+ if (!tp)
+ return(ENXIO);
+ return((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+
+int pcwrite(dev_t dev, struct uio *uio, int flag)
+{
+ struct tty *tp = get_tty_ptr(dev);
+
+ if (!tp)
+ return(ENXIO);
+ return((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+
+/*
+ * Got a console interrupt, keyboard action !
+ * Catch the character, and see who it goes to.
+ */
+void scintr(int unit)
+{
+ static struct tty *cur_tty;
+ int c, len;
+ u_char *cp;
+
+ /* make screensaver happy */
+ scrn_time_stamp = time.tv_sec;
+ if (scrn_blanked)
+ SCRN_SAVER(0);
+
+ c = scgetc(1);
+
+ cur_tty = VIRTUAL_TTY(get_scr_num());
+ if (!(cur_tty->t_state & TS_ISOPEN))
+ cur_tty = CONSOLE_TTY;
+
+ if (!(cur_tty->t_state & TS_ISOPEN) || polling)
+ return;
+
+ switch (c & 0xff00) {
+ case 0x0000: /* normal key */
+ (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
+ break;
+ case NOKEY: /* nothing there */
+ break;
+ case FKEY: /* function key, return string */
+ if (cp = get_fstr((u_int)c, (u_int *)&len)) {
+ while (len-- > 0)
+ (*linesw[cur_tty->t_line].l_rint)
+ (*cp++ & 0xFF, cur_tty);
+ }
+ break;
+ case MKEY: /* meta is active, prepend ESC */
+ (*linesw[cur_tty->t_line].l_rint)(0x1b, cur_tty);
+ (*linesw[cur_tty->t_line].l_rint)(c & 0xFF, cur_tty);
+ break;
+ }
+}
+
+
+/*
+ * Set line parameters
+ */
+int pcparam(struct tty *tp, struct termios *t)
+{
+ int cflag = t->c_cflag;
+
+ /* and copy to tty */
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
+ tp->t_cflag = cflag;
+ return 0;
+}
+
+
+int pcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
+{
+ int i, error;
+ struct tty *tp;
+ frametype *fp;
+ scr_stat *scp;
+
+ tp = get_tty_ptr(dev);
+ if (!tp)
+ return ENXIO;
+ scp = get_scr_stat(tp->t_dev);
+
+ switch (cmd) { /* process console hardware related ioctl's */
+
+ case CONS_BLANKTIME: /* set screen saver timeout (0 = no saver) */
+ scrn_blank_time = *(int*)data;
+ return 0;
+ case CONS_SSAVER: /* set screen saver */
+ {
+ register ssaver_t *sav = (ssaver_t *)data;
+ if (sav->num < 0 || sav->num >= NUM_SCRN_SAVERS)
+ return EIO;
+ SCRN_SAVER(0);
+ scrn_saver = sav->num;
+ scrn_blank_time = sav->time;
+ return 0;
+ }
+ case CONS_GSAVER: /* get screen saver info */
+ {
+ register ssaver_t *sav = (ssaver_t *)data;
+ if (sav->num < 0)
+ sav->num = scrn_saver;
+ else if (sav->num >= NUM_SCRN_SAVERS)
+ return EIO;
+ sav->time = scrn_blank_time;
+ strcpy(sav->name, screen_savers[sav->num].name);
+ return 0;
+ }
+ case CONS_80x25TEXT: /* set 80x25 text mode */
+ if (!crtc_vga)
+ return ENXIO;
+ scp->mode = TEXT80x25;
+ scp->ysize = 25;
+ free(scp->scr_buf, M_DEVBUF);
+ scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*2,
+ M_DEVBUF, M_NOWAIT);
+ if (scp != cur_console)
+ scp->crt_base = scp->scr_buf;
+ set_mode(scp);
+ clear_screen(scp);
+ change_winsize(tp, scp->xsize, scp->ysize);
+ return 0;
+
+ case CONS_80x50TEXT: /* set 80x50 text mode */
+ if (!crtc_vga)
+ return ENXIO;
+ scp->mode = TEXT80x50;
+ scp->ysize = 50;
+ free(scp->scr_buf, M_DEVBUF);
+ scp->scr_buf = (u_short *)malloc(scp->xsize*scp->ysize*2,
+ M_DEVBUF, M_NOWAIT);
+ if (scp != cur_console)
+ scp->crt_base = scp->scr_buf;
+ set_mode(scp);
+ clear_screen(scp);
+ change_winsize(tp, scp->xsize, scp->ysize);
+ return 0;
+
+ case CONS_GETVERS: /* get version number */
+ *(int*)data = 0x103; /* version 1.3 */
+ return 0;
+
+ case CONS_GETINFO: /* get current (virtual) console info */
+ {
+ vid_info_t *ptr = (vid_info_t*)data;
+ if (ptr->size == sizeof(struct vid_info)) {
+ ptr->m_num = get_scr_num();
+ ptr->mv_col = scp->xpos;
+ ptr->mv_row = scp->ypos;
+ ptr->mv_csz = scp->xsize;
+ ptr->mv_rsz = scp->ysize;
+ ptr->mv_norm.fore = (scp->term.std_attr & 0x0f00)>>8;
+ ptr->mv_norm.back = (scp->term.std_attr & 0xf000)>>12;
+ ptr->mv_rev.fore = (scp->term.rev_attr & 0x0f00)>>8;
+ ptr->mv_rev.back = (scp->term.rev_attr & 0xf000)>>12;
+ ptr->mv_grfc.fore = 0; /* not supported */
+ ptr->mv_grfc.back = 0; /* not supported */
+ ptr->mv_ovscan = scp->border;
+ ptr->mk_keylock = scp->status & LOCK_KEY_MASK;
+ return 0;
+ }
+ return EINVAL;
+ }
+
+ case VT_SETMODE: /* set screen switcher mode */
+ bcopy(data, &scp->smode, sizeof(struct vt_mode));
+ if (scp->smode.mode == VT_PROCESS) {
+ scp->proc = p;
+ scp->pid = scp->proc->p_pid;
+ }
+ return 0;
+
+ case VT_GETMODE: /* get screen switcher mode */
+ bcopy(&scp->smode, data, sizeof(struct vt_mode));
+ return 0;
+
+ case VT_RELDISP: /* screen switcher ioctl */
+ switch(*data) {
+ case VT_FALSE: /* user refuses to release screen, abort */
+ if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
+ old_scp->status &= ~SWITCH_WAIT_REL;
+ switch_in_progress = 0;
+ return 0;
+ }
+ return EINVAL;
+
+ case VT_TRUE: /* user has released screen, go on */
+ if (scp == old_scp && (scp->status & SWITCH_WAIT_REL)) {
+ scp->status &= ~SWITCH_WAIT_REL;
+ exchange_scr();
+ if (new_scp->smode.mode == VT_PROCESS) {
+ new_scp->status |= SWITCH_WAIT_ACQ;
+ psignal(new_scp->proc,
+ new_scp->smode.acqsig);
+ }
+ else
+ switch_in_progress = 0;
+ return 0;
+ }
+ return EINVAL;
+
+ case VT_ACKACQ: /* acquire acknowledged, switch completed */
+ if (scp == new_scp && (scp->status & SWITCH_WAIT_ACQ)) {
+ scp->status &= ~SWITCH_WAIT_ACQ;
+ switch_in_progress = 0;
+ return 0;
+ }
+ return EINVAL;
+
+ default:
+ return EINVAL;
+ }
+ /* NOT REACHED */
+
+ case VT_OPENQRY: /* return free virtual console */
+ for (i = 0; i < NCONS; i++) {
+ tp = VIRTUAL_TTY(i);
+ if (!(tp->t_state & TS_ISOPEN)) {
+ *data = i + 1;
+ return 0;
+ }
+ }
+ return EINVAL;
+
+ case VT_ACTIVATE: /* switch to screen *data */
+ return switch_scr((*data) - 1);
+
+ case VT_WAITACTIVE: /* wait for switch to occur */
+ if (*data > NCONS)
+ return EINVAL;
+ if (minor(dev) == (*data) - 1)
+ return 0;
+ if (*data == 0) {
+ if (scp == cur_console)
+ return 0;
+ while ((error=tsleep((caddr_t)&scp->smode,
+ PZERO|PCATCH, "waitvt", 0)) == ERESTART) ;
+ }
+ else
+ while ((error=tsleep(
+ (caddr_t)&console[*(data-1)].smode,
+ PZERO|PCATCH, "waitvt", 0)) == ERESTART) ;
+ return error;
+
+ case VT_GETACTIVE:
+ *data = get_scr_num()+1;
+ return 0;
+
+ case KDENABIO: /* allow io operations */
+ fp = (frametype *)p->p_regs;
+ fp->eflags |= PSL_IOPL;
+ return 0;
+
+ case KDDISABIO: /* disallow io operations (default) */
+ fp = (frametype *)p->p_regs;
+ fp->eflags &= ~PSL_IOPL;
+ return 0;
+
+ case KDSETMODE: /* set current mode of this (virtual) console */
+ switch (*data) {
+ case KD_TEXT: /* switch to TEXT (known) mode */
+ /* restore fonts & palette ! */
+ if (crtc_vga) {
+ load_font(0, 16, font_8x16);
+ load_font(1, 8, font_8x8);
+ load_font(2, 14, font_8x14);
+ load_palette();
+ }
+ /* FALL THROUGH */
+
+ case KD_TEXT1: /* switch to TEXT (known) mode */
+ /* no restore fonts & palette */
+ scp->status &= ~UNKNOWN_MODE;
+ set_mode(scp);
+ clear_screen(scp);
+ return 0;
+
+ case KD_GRAPHICS:/* switch to GRAPHICS (unknown) mode */
+ scp->status |= UNKNOWN_MODE;
+ return 0;
+ default:
+ return EINVAL;
+ }
+ /* NOT REACHED */
+
+ case KDGETMODE: /* get current mode of this (virtual) console */
+ *data = (scp->status & UNKNOWN_MODE) ? KD_GRAPHICS : KD_TEXT;
+ return 0;
+
+ case KDSBORDER: /* set border color of this (virtual) console */
+ if (!crtc_vga)
+ return ENXIO;
+ scp->border = *data;
+ if (scp == cur_console)
+ set_border(scp->border);
+ return 0;
+
+ case KDSKBSTATE: /* set keyboard state (locks) */
+ if (*data >= 0 && *data <= LOCK_KEY_MASK) {
+ scp->status &= ~LOCK_KEY_MASK;
+ scp->status |= *data;
+ if (scp == cur_console)
+ update_leds(scp->status);
+ return 0;
+ }
+ return EINVAL;
+
+ case KDGKBSTATE: /* get keyboard state (locks) */
+ *data = scp->status & LOCK_KEY_MASK;
+ return 0;
+
+ case KDSETRAD: /* set keyboard repeat & delay rates */
+ if (*data & 0x80)
+ return EINVAL;
+ kbd_cmd2(KB_SETRAD, *data);
+ return 0;
+
+ case KDSKBMODE: /* set keyboard mode */
+ switch (*data) {
+ case K_RAW: /* switch to RAW scancode mode */
+ scp->status |= KBD_RAW_MODE;
+ return 0;
+
+ case K_XLATE: /* switch to XLT ascii mode */
+ if (scp == cur_console && scp->status == KBD_RAW_MODE)
+ shfts = ctls = alts = agrs = metas = 0;
+ scp->status &= ~KBD_RAW_MODE;
+ return 0;
+ default:
+ return EINVAL;
+ }
+ /* NOT REACHED */
+
+ case KDGKBMODE: /* get keyboard mode */
+ *data = (scp->status & KBD_RAW_MODE) ? K_RAW : K_XLATE;
+ return 0;
+
+ case KDMKTONE: /* sound the bell */
+ if (scp == cur_console)
+ sysbeep(scp->bell_pitch, scp->bell_duration);
+ return 0;
+
+ case KIOCSOUND: /* make tone (*data) hz */
+ if (scp == cur_console) {
+ if (*(int*)data) {
+ int pitch = TIMER_FREQ/(*(int*)data);
+ /* set command for counter 2, 2 byte write */
+ if (acquire_timer2(TIMER_16BIT|TIMER_SQWAVE)) {
+ return EBUSY;
+ }
+ /* set pitch */
+ outb(TIMER_CNTR2, pitch);
+ outb(TIMER_CNTR2, (pitch>>8));
+ /* enable counter 2 output to speaker */
+ outb(IO_PPI, inb(IO_PPI) | 3);
+ }
+ else {
+ /* disable counter 2 output to speaker */
+ outb(IO_PPI, inb(IO_PPI) & 0xFC);
+ release_timer2();
+ }
+ }
+ return 0;
+
+ case KDGKBTYPE: /* get keyboard type */
+ *data = 0; /* type not known (yet) */
+ return 0;
+
+ case KDSETLED: /* set keyboard LED status */
+ if (*data >= 0 && *data <= LED_MASK) {
+ scp->status &= ~LED_MASK;
+ scp->status |= *data;
+ if (scp == cur_console)
+ update_leds(scp->status);
+ return 0;
+ }
+ return EINVAL;
+
+ case KDGETLED: /* get keyboard LED status */
+ *data = scp->status & LED_MASK;
+ return 0;
+
+ case GETFKEY: /* get functionkey string */
+ if (*(u_short*)data < n_fkey_tab) {
+ fkeyarg_t *ptr = (fkeyarg_t*)data;
+ bcopy(&fkey_tab[ptr->keynum].str,
+ ptr->keydef,
+ fkey_tab[ptr->keynum].len);
+ ptr->flen = fkey_tab[ptr->keynum].len;
+ return 0;
+ }
+ else
+ return EINVAL;
+
+ case SETFKEY: /* set functionkey string */
+ if (*(u_short*)data < n_fkey_tab) {
+ fkeyarg_t *ptr = (fkeyarg_t*)data;
+ bcopy(ptr->keydef,
+ &fkey_tab[ptr->keynum].str,
+ min(ptr->flen, MAXFK));
+ fkey_tab[ptr->keynum].len = min(ptr->flen, MAXFK);
+ return 0;
+ }
+ else
+ return EINVAL;
+
+ case GIO_SCRNMAP: /* get output translation table */
+ bcopy(&scr_map, data, sizeof(scr_map));
+ return 0;
+
+ case PIO_SCRNMAP: /* set output translation table */
+ bcopy(data, &scr_map, sizeof(scr_map));
+ return 0;
+
+ case GIO_KEYMAP: /* get keyboard translation table */
+ bcopy(&key_map, data, sizeof(key_map));
+ return 0;
+
+ case PIO_KEYMAP: /* set keyboard translation table */
+ bcopy(data, &key_map, sizeof(key_map));
+ return 0;
+
+ case PIO_FONT8x8: /* set 8x8 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(data, &font_8x8, sizeof(font_8x8));
+ load_font(1, 8, font_8x8);
+ return 0;
+
+ case GIO_FONT8x8: /* get 8x8 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(&font_8x8, data, sizeof(font_8x8));
+ return 0;
+
+ case PIO_FONT8x14: /* set 8x14 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(data, &font_8x14, sizeof(font_8x14));
+ load_font(2, 14, font_8x14);
+ return 0;
+
+ case GIO_FONT8x14: /* get 8x14 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(&font_8x14, data, sizeof(font_8x14));
+ return 0;
+
+ case PIO_FONT8x16: /* set 8x16 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(data, &font_8x16, sizeof(font_8x16));
+ load_font(0, 16, font_8x16);
+ return 0;
+
+ case GIO_FONT8x16: /* get 8x16 dot font */
+ if (!crtc_vga)
+ return ENXIO;
+ bcopy(&font_8x16, data, sizeof(font_8x16));
+ return 0;
+
+ case CONSOLE_X_MODE_ON: /* just to be compatible */
+ if (saved_console < 0) {
+ saved_console = get_scr_num();
+ switch_scr(minor(dev));
+ fp = (frametype *)p->p_regs;
+ fp->eflags |= PSL_IOPL;
+ scp->status |= UNKNOWN_MODE;
+ scp->status |= KBD_RAW_MODE;
+ return 0;
+ }
+ return EAGAIN;
+
+ case CONSOLE_X_MODE_OFF:/* just to be compatible */
+ fp = (frametype *)p->p_regs;
+ fp->eflags &= ~PSL_IOPL;
+ if (crtc_vga) {
+ load_font(0, 16, font_8x16);
+ load_font(1, 8, font_8x8);
+ load_font(2, 14, font_8x14);
+ load_palette();
+ }
+ scp->status &= ~UNKNOWN_MODE;
+ set_mode(scp);
+ clear_screen(scp);
+ scp->status &= ~KBD_RAW_MODE;
+ switch_scr(saved_console);
+ saved_console = -1;
+ return 0;
+
+ case CONSOLE_X_BELL: /* more compatibility */
+ /*
+ * if set, data is a pointer to a length 2 array of
+ * integers. data[0] is the pitch in Hz and data[1]
+ * is the duration in msec.
+ */
+ if (data)
+ sysbeep(TIMER_FREQ/((int*)data)[0],
+ ((int*)data)[1]*hz/3000);
+ else
+ sysbeep(scp->bell_pitch, scp->bell_duration);
+ return 0;
+
+ default:
+ break;
+ }
+
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
+ if (error >= 0)
+ return(error);
+ error = ttioctl(tp, cmd, data, flag);
+ if (error >= 0)
+ return(error);
+ return(ENOTTY);
+}
+
+
+void pcxint(dev_t dev)
+{
+ struct tty *tp = get_tty_ptr(dev);
+
+ if (!tp)
+ return;
+ tp->t_state &= ~TS_BUSY;
+ if (tp->t_line)
+ (*linesw[tp->t_line].l_start)(tp);
+ else
+ pcstart(tp);
+}
+
+
+void pcstart(struct tty *tp)
+{
+#if defined(NetBSD)
+ struct clist *rbp;
+ int i, s, len;
+ u_char buf[PCBURST];
+ scr_stat *scp = get_scr_stat(tp->t_dev);
+
+ if (scp->status & SLKED)
+ return;
+ s = spltty();
+ if (!(tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))) {
+ tp->t_state |= TS_BUSY;
+ splx(s);
+ rbp = &tp->t_outq;
+ len = q_to_b(rbp, buf, PCBURST);
+ for (i=0; i<len; i++)
+ if (buf[i]) ansi_put(scp, buf[i]);
+ s = spltty();
+ tp->t_state &= ~TS_BUSY;
+ if (rbp->c_cc) {
+ tp->t_state |= TS_TIMEOUT;
+ timeout((timeout_t)ttrstrt, (caddr_t)tp, 1);
+ }
+ if (rbp->c_cc <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)rbp);
+ }
+ selwakeup(&tp->t_wsel);
+ }
+ }
+ splx(s);
+
+#else /* __FreeBSD__ & __386BSD__ */
+
+ int c, s, len, i;
+ scr_stat *scp = get_scr_stat(tp->t_dev);
+ u_char buf[PCBURST];
+
+ if (scp->status & SLKED)
+ return;
+ s = spltty();
+ if (!(tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))) {
+ for (;;) {
+ if (RB_LEN(tp->t_out) <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup((caddr_t)tp->t_out);
+ }
+ if (tp->t_wsel) {
+ selwakeup(tp->t_wsel,
+ tp->t_state & TS_WCOLL);
+ tp->t_wsel = 0;
+ tp->t_state &= ~TS_WCOLL;
+ }
+ }
+ if (RB_LEN(tp->t_out) == 0)
+ break;
+ if (scp->status & SLKED)
+ break;
+ len = 0;
+ while( len < PCBURST) {
+ buf[len++] = getc(tp->t_out);
+ if( RB_LEN(tp->t_out) == 0)
+ break;
+ }
+ tp->t_state |= TS_BUSY;
+ splx(s);
+ for(i=0;i<len;i++)
+ ansi_put(scp, buf[i]);
+ s = spltty();
+ tp->t_state &= ~TS_BUSY;
+ }
+ tp->t_state |= TS_BUSY;
+ if( in_putc == 0) {
+ int i;
+ for(i=0;i<console_buffer_count;i++) {
+ scput(console_buffer[i]);
+ }
+ console_buffer_count = 0;
+ }
+ tp->t_state &= ~TS_BUSY;
+ }
+ splx(s);
+#endif
+}
+
+
+void pccnprobe(struct consdev *cp)
+{
+ int maj;
+
+ /* locate the major number */
+ for (maj = 0; maj < nchrdev; maj++)
+ if ((void*)cdevsw[maj].d_open == (void*)pcopen)
+ break;
+
+ /* initialize required fields */
+ cp->cn_dev = makedev(maj, NCONS);
+ cp->cn_pri = CN_INTERNAL;
+#if defined(__386BSD__) && !defined(__FreeBSD__)
+ cp->cn_tp = CONSOLE_TTY;
+#endif
+}
+
+
+void pccninit(struct consdev *cp)
+{
+ scinit();
+}
+
+
+void pccnputc(dev_t dev, char c)
+{
+ if (c == '\n')
+ scput('\r');
+ scput(c);
+ if (cur_console == &console[0]) {
+ int pos = cur_console->crtat - cur_console->crt_base;
+ if (pos != cur_cursor_pos) {
+ cur_cursor_pos = pos;
+ outb(crtc_addr,14);
+ outb(crtc_addr+1,pos >> 8);
+ outb(crtc_addr,15);
+ outb(crtc_addr+1,pos&0xff);
+ }
+ }
+}
+
+
+int pccngetc(dev_t dev)
+{
+ int s = spltty(); /* block scintr while we poll */
+ int c = scgetc(0);
+ splx(s);
+ if (c == '\r') c = '\n';
+ return(c);
+}
+
+static void none_saver(int test)
+{
+}
+
+static void fade_saver(int test)
+{
+ static int count = 0;
+ int i;
+
+ if (test) {
+ scrn_blanked = 1;
+ if (count < 64) {
+ outb(PIXMASK, 0xFF); /* no pixelmask */
+ outb(PALWADR, 0x00);
+ outb(PALDATA, 0);
+ outb(PALDATA, 0);
+ outb(PALDATA, 0);
+ for (i = 3; i < 768; i++) {
+ if (palette[i] - count > 15)
+ outb(PALDATA, palette[i]-count);
+ else
+ outb(PALDATA, 15);
+ }
+ inb(crtc_addr+6); /* reset flip/flop */
+ outb(ATC, 0x20); /* enable palette */
+ count++;
+ }
+ }
+ else {
+ count = scrn_blanked = 0;
+ load_palette();
+ }
+}
+
+static void blank_saver(int test)
+{
+ u_char val;
+ if (test) {
+ scrn_blanked = 1;
+ outb(TSIDX, 0x01); val = inb(TSREG);
+ outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
+ }
+ else {
+ scrn_blanked = 0;
+ outb(TSIDX, 0x01); val = inb(TSREG);
+ outb(TSIDX, 0x01); outb(TSREG, val & 0xDF);
+ }
+}
+
+static u_long rand_next = 1;
+
+static int rand()
+{
+ return ((rand_next = rand_next * 1103515245 + 12345) & 0x7FFFFFFF);
+}
+
+/*
+ * Alternate saver that got its inspiration from a well known utility
+ * package for an unfamous OS.
+ */
+
+#define NUM_STARS 50
+
+static void star_saver(int test)
+{
+ scr_stat *scp = cur_console;
+ int cell, i;
+ char pattern[] = {"...........++++*** "};
+ char colors[] = {FG_DARKGREY, FG_LIGHTGREY,
+ FG_WHITE, FG_LIGHTCYAN};
+ static u_short stars[NUM_STARS][2];
+
+ if (test) {
+ if (!scrn_blanked) {
+ bcopy(Crtat, scp->scr_buf,
+ scp->xsize * scp->ysize * 2);
+ fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20], Crtat,
+ scp->xsize * scp->ysize);
+ set_border(0);
+ i = scp->ysize * scp->xsize + 5;
+ outb(crtc_addr, 14);
+ outb(crtc_addr+1, i >> 8);
+ outb(crtc_addr, 15);
+ outb(crtc_addr+1, i & 0xff);
+ scrn_blanked = 1;
+ for(i=0; i<NUM_STARS; i++) {
+ stars[i][0] =
+ rand() % (scp->xsize*scp->ysize);
+ stars[i][1] = 0;
+ }
+ }
+ cell = rand() % NUM_STARS;
+ *((u_short*)(Crtat + stars[cell][0])) =
+ scr_map[pattern[stars[cell][1]]] |
+ colors[rand()%sizeof(colors)] << 8;
+ if ((stars[cell][1]+=(rand()%4)) >= sizeof(pattern)-1) {
+ stars[cell][0] = rand() % (scp->xsize*scp->ysize);
+ stars[cell][1] = 0;
+ }
+ }
+ else {
+ if (scrn_blanked) {
+ bcopy(scp->scr_buf, Crtat, scp->xsize*scp->ysize*2);
+ cur_cursor_pos = -1;
+ set_border(scp->border);
+ scrn_blanked = 0;
+ }
+ }
+}
+
+
+static void snake_saver(int test)
+{
+ const char saves[] = {"FreeBSD"};
+ static u_char *savs[sizeof(saves)-1];
+ static int dirx, diry;
+ int f;
+ scr_stat *scp = cur_console;
+
+ if (test) {
+ if (!scrn_blanked) {
+ bcopy(Crtat, scp->scr_buf,
+ scp->xsize * scp->ysize * 2);
+ fillw((FG_LIGHTGREY|BG_BLACK)<<8 | scr_map[0x20],
+ Crtat, scp->xsize * scp->ysize);
+ set_border(0);
+ dirx = (scp->xpos ? 1 : -1);
+ diry = (scp->ypos ?
+ scp->xsize : -scp->xsize);
+ for (f=0; f< sizeof(saves)-1; f++)
+ savs[f] = (u_char *)Crtat + 2 *
+ (scp->xpos+scp->ypos*scp->xsize);
+ *(savs[0]) = scr_map[*saves];
+ f = scp->ysize * scp->xsize + 5;
+ outb(crtc_addr, 14);
+ outb(crtc_addr+1, f >> 8);
+ outb(crtc_addr, 15);
+ outb(crtc_addr+1, f & 0xff);
+ scrn_blanked = 1;
+ }
+ if (scrn_blanked++ < 4)
+ return;
+ scrn_blanked = 1;
+ *(savs[sizeof(saves)-2]) = scr_map[0x20];
+ for (f=sizeof(saves)-2; f > 0; f--)
+ savs[f] = savs[f-1];
+ f = (savs[0] - (u_char *)Crtat) / 2;
+ if ((f % scp->xsize) == 0 ||
+ (f % scp->xsize) == scp->xsize - 1 ||
+ (rand() % 50) == 0)
+ dirx = -dirx;
+ if ((f / scp->xsize) == 0 ||
+ (f / scp->xsize) == scp->ysize - 1 ||
+ (rand() % 20) == 0)
+ diry = -diry;
+ savs[0] += 2*dirx + 2*diry;
+ for (f=sizeof(saves)-2; f>=0; f--)
+ *(savs[f]) = scr_map[saves[f]];
+ }
+ else {
+ if (scrn_blanked) {
+ bcopy(scp->scr_buf, Crtat,
+ scp->xsize * scp->ysize * 2);
+ cur_cursor_pos = -1;
+ set_border(scp->border);
+ scrn_blanked = 0;
+ }
+ }
+}
+
+static void cursor_shape(int start, int end)
+{
+ outb(crtc_addr, 10);
+ outb(crtc_addr+1, start & 0xFF);
+ outb(crtc_addr, 11);
+ outb(crtc_addr+1, end & 0xFF);
+}
+
+
+#if !defined(FAT_CURSOR)
+static void get_cursor_shape(int *start, int *end)
+{
+ outb(crtc_addr, 10);
+ *start = inb(crtc_addr+1) & 0x1F;
+ outb(crtc_addr, 11);
+ *end = inb(crtc_addr+1) & 0x1F;
+}
+#endif
+
+
+static void cursor_pos(int force)
+{
+ int pos;
+
+ if (cur_console->status & UNKNOWN_MODE)
+ return;
+ if (scrn_blank_time && (time.tv_sec > scrn_time_stamp+scrn_blank_time))
+ SCRN_SAVER(1);
+ pos = cur_console->crtat - cur_console->crt_base;
+ if (force || (!scrn_blanked && pos != cur_cursor_pos)) {
+ cur_cursor_pos = pos;
+ outb(crtc_addr, 14);
+ outb(crtc_addr+1, pos>>8);
+ outb(crtc_addr, 15);
+ outb(crtc_addr+1, pos&0xff);
+ }
+ timeout((timeout_t)cursor_pos, 0, hz/20);
+}
+
+
+static void clear_screen(scr_stat *scp)
+{
+ move_crsr(scp, 0, 0);
+ fillw(scp->term.cur_attr | scr_map[0x20], scp->crt_base,
+ scp->xsize * scp->ysize);
+}
+
+
+static int switch_scr(u_int next_scr)
+{
+ if (in_putc) { /* delay switch if in putc */
+ delayed_next_scr = next_scr+1;
+ return 0;
+ }
+ if (switch_in_progress &&
+ (cur_console->proc != pfind(cur_console->pid)))
+ switch_in_progress = 0;
+
+ if (next_scr >= NCONS || switch_in_progress) {
+ sysbeep(BELL_PITCH, BELL_DURATION);
+ return EINVAL;
+ }
+
+ /* is the wanted virtual console open ? */
+ if (next_scr) {
+ struct tty *tp = VIRTUAL_TTY(next_scr);
+ if (!(tp->t_state & TS_ISOPEN)) {
+ sysbeep(BELL_PITCH, BELL_DURATION);
+ return EINVAL;
+ }
+ }
+
+ switch_in_progress = 1;
+ old_scp = cur_console;
+ new_scp = &console[next_scr];
+ wakeup((caddr_t)&new_scp->smode);
+ if (new_scp == old_scp) {
+ switch_in_progress = 0;
+ return 0;
+ }
+
+ /* has controlling process died? */
+ if (old_scp->proc && (old_scp->proc != pfind(old_scp->pid)))
+ old_scp->smode.mode = VT_AUTO;
+ if (new_scp->proc && (new_scp->proc != pfind(new_scp->pid)))
+ new_scp->smode.mode = VT_AUTO;
+
+ /* check the modes and switch approbiatly */
+ if (old_scp->smode.mode == VT_PROCESS) {
+ old_scp->status |= SWITCH_WAIT_REL;
+ psignal(old_scp->proc, old_scp->smode.relsig);
+ }
+ else {
+ exchange_scr();
+ if (new_scp->smode.mode == VT_PROCESS) {
+ new_scp->status |= SWITCH_WAIT_ACQ;
+ psignal(new_scp->proc, new_scp->smode.acqsig);
+ }
+ else
+ switch_in_progress = 0;
+ }
+ return 0;
+}
+
+
+static void exchange_scr(void)
+{
+ struct tty *tp;
+
+ bcopy(Crtat, old_scp->scr_buf, old_scp->xsize * old_scp->ysize * 2);
+ old_scp->crt_base = old_scp->scr_buf;
+ move_crsr(old_scp, old_scp->xpos, old_scp->ypos);
+ cur_console = new_scp;
+ set_mode(new_scp);
+ new_scp->crt_base = Crtat;
+ move_crsr(new_scp, new_scp->xpos, new_scp->ypos);
+ bcopy(new_scp->scr_buf, Crtat, new_scp->xsize * new_scp->ysize * 2);
+ update_leds(new_scp->status);
+ if ((old_scp->status & UNKNOWN_MODE) && crtc_vga) {
+ load_font(0, 16, font_8x16);
+ load_font(1, 8, font_8x8);
+ load_font(2, 14, font_8x14);
+ load_palette();
+ }
+ if (old_scp->status & KBD_RAW_MODE || new_scp->status & KBD_RAW_MODE)
+ shfts = ctls = alts = agrs = metas = 0;
+ delayed_next_scr = 0;
+}
+
+
+static void move_crsr(scr_stat *scp, int x, int y)
+{
+ if (x < 0 || y < 0 || x >= scp->xsize || y >= scp->ysize)
+ return;
+ scp->xpos = x;
+ scp->ypos = y;
+ scp->crtat = scp->crt_base + scp->ypos * scp->xsize + scp->xpos;
+}
+
+static void move_up(u_short *s, u_short *d, u_int len)
+{
+ s += len;
+ d += len;
+ while (len-- > 0)
+ *--d = *--s;
+}
+
+static void move_down(u_short *s, u_short *d, u_int len)
+{
+ while (len-- > 0)
+ *d++ = *s++;
+}
+
+static void scan_esc(scr_stat *scp, u_char c)
+{
+ static u_char ansi_col[16] =
+ {0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15};
+ int i, n;
+ u_short *src, *dst, count;
+
+ if (scp->term.esc == 1) {
+ switch (c) {
+
+ case '[': /* Start ESC [ sequence */
+ scp->term.esc = 2;
+ scp->term.last_param = -1;
+ for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
+ scp->term.param[i] = 1;
+ scp->term.num_param = 0;
+ return;
+
+ case 'M': /* Move cursor up 1 line, scroll if at top */
+ if (scp->ypos > 0)
+ move_crsr(scp, scp->xpos, scp->ypos - 1);
+ else {
+ move_up(scp->crt_base,
+ scp->crt_base + scp->xsize,
+ (scp->ysize - 1) * scp->xsize);
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base, scp->xsize);
+ }
+ break;
+#if notyet
+ case 'Q':
+ scp->term.esc = 4;
+ break;
+#endif
+ case 'c': /* Clear screen & home */
+ clear_screen(scp);
+ break;
+ }
+ }
+ else if (scp->term.esc == 2) {
+ if (c >= '0' && c <= '9') {
+ if (scp->term.num_param < MAX_ESC_PAR) {
+ if (scp->term.last_param != scp->term.num_param) {
+ scp->term.last_param = scp->term.num_param;
+ scp->term.param[scp->term.num_param] = 0;
+ }
+ else
+ scp->term.param[scp->term.num_param] *= 10;
+ scp->term.param[scp->term.num_param] += c - '0';
+ return;
+ }
+ }
+ scp->term.num_param = scp->term.last_param + 1;
+ switch (c) {
+
+ case ';':
+ if (scp->term.num_param < MAX_ESC_PAR)
+ return;
+ break;
+
+ case '=':
+ scp->term.esc = 3;
+ scp->term.last_param = -1;
+ for (i = scp->term.num_param; i < MAX_ESC_PAR; i++)
+ scp->term.param[i] = 1;
+ scp->term.num_param = 0;
+ return;
+
+ case 'A': /* up n rows */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos, scp->ypos - n);
+ break;
+
+ case 'B': /* down n rows */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos, scp->ypos + n);
+ break;
+
+ case 'C': /* right n columns */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos + n, scp->ypos);
+ break;
+
+ case 'D': /* left n columns */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos - n, scp->ypos);
+ break;
+
+ case 'E': /* cursor to start of line n lines down */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, 0, scp->ypos + n);
+ break;
+
+ case 'F': /* cursor to start of line n lines up */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, 0, scp->ypos - n);
+ break;
+
+ case 'f': /* System V consoles .. */
+ case 'H': /* Cursor move */
+ if (scp->term.num_param == 0)
+ move_crsr(scp, 0, 0);
+ else if (scp->term.num_param == 2)
+ move_crsr(scp, scp->term.param[1] - 1,
+ scp->term.param[0] - 1);
+ break;
+
+ case 'J': /* Clear all or part of display */
+ if (scp->term.num_param == 0)
+ n = 0;
+ else
+ n = scp->term.param[0];
+ switch (n) {
+ case 0: /* clear form cursor to end of display */
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crtat, scp->crt_base +
+ scp->xsize * scp->ysize -
+ scp->crtat);
+ break;
+ case 1: /* clear from beginning of display to cursor */
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base,
+ scp->crtat - scp->crt_base);
+ break;
+ case 2: /* clear entire display */
+ clear_screen(scp);
+ break;
+ }
+ break;
+
+ case 'K': /* Clear all or part of line */
+ if (scp->term.num_param == 0)
+ n = 0;
+ else
+ n = scp->term.param[0];
+ switch (n) {
+ case 0: /* clear form cursor to end of line */
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crtat, scp->xsize - scp->xpos);
+ break;
+ case 1: /* clear from beginning of line to cursor */
+ fillw(scp->term.cur_attr|scr_map[0x20],
+ scp->crtat - (scp->xsize - scp->xpos),
+ (scp->xsize - scp->xpos) + 1);
+ break;
+ case 2: /* clear entire line */
+ fillw(scp->term.cur_attr|scr_map[0x20],
+ scp->crtat - (scp->xsize - scp->xpos),
+ scp->xsize);
+ break;
+ }
+ break;
+
+ case 'L': /* Insert n lines */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->ysize - scp->ypos)
+ n = scp->ysize - scp->ypos;
+ src = scp->crt_base + scp->ypos * scp->xsize;
+ dst = src + n * scp->xsize;
+ count = scp->ysize - (scp->ypos + n);
+ move_up(src, dst, count * scp->xsize);
+ fillw(scp->term.cur_attr | scr_map[0x20], src,
+ n * scp->xsize);
+ break;
+
+ case 'M': /* Delete n lines */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->ysize - scp->ypos)
+ n = scp->ysize - scp->ypos;
+ dst = scp->crt_base + scp->ypos * scp->xsize;
+ src = dst + n * scp->xsize;
+ count = scp->ysize - (scp->ypos + n);
+ move_down(src, dst, count * scp->xsize);
+ src = dst + count * scp->xsize;
+ fillw(scp->term.cur_attr | scr_map[0x20], src,
+ n * scp->xsize);
+ break;
+
+ case 'P': /* Delete n chars */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->xsize - scp->xpos)
+ n = scp->xsize - scp->xpos;
+ dst = scp->crtat;
+ src = dst + n;
+ count = scp->xsize - (scp->xpos + n);
+ move_down(src, dst, count);
+ src = dst + count;
+ fillw(scp->term.cur_attr | scr_map[0x20], src, n);
+ break;
+
+ case '@': /* Insert n chars */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->xsize - scp->xpos)
+ n = scp->xsize - scp->xpos;
+ src = scp->crtat;
+ dst = src + n;
+ count = scp->xsize - (scp->xpos + n);
+ move_up(src, dst, count);
+ fillw(scp->term.cur_attr | scr_map[0x20], src, n);
+ break;
+
+ case 'S': /* scroll up n lines */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->ypos)
+ n = scp->ypos;
+ bcopy(scp->crt_base + (scp->xsize * n),
+ scp->crt_base,
+ scp->xsize * (scp->ysize - n) *
+ sizeof(u_short));
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base + scp->xsize *
+ (scp->ysize - 1),
+ scp->xsize);
+ break;
+
+ case 'T': /* scroll down n lines */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->ysize - scp->ypos)
+ n = scp->ysize - scp->ypos;
+ bcopy(scp->crt_base,
+ scp->crt_base + (scp->xsize * n),
+ scp->xsize * (scp->ysize - n) *
+ sizeof(u_short));
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base, scp->xsize);
+ break;
+
+ case 'X': /* delete n characters in line */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if (n > scp->xsize - scp->xpos)
+ n = scp->xsize - scp->xpos;
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base + scp->xpos +
+ ((scp->xsize*scp->ypos) * sizeof(u_short)), n);
+ break;
+
+ case 'Z': /* move n tabs backwards */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ if ((i = scp->xpos & 0xf8) == scp->xpos)
+ i -= 8*n;
+ else
+ i -= 8*(n-1);
+ if (i < 0)
+ i = 0;
+ move_crsr(scp, i, scp->ypos);
+ break;
+
+ case '`': /* move cursor to column n */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, n, scp->ypos);
+ break;
+
+ case 'a': /* move cursor n columns to the right */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos + n, scp->ypos);
+ break;
+
+ case 'd': /* move cursor to row n */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos, n);
+ break;
+
+ case 'e': /* move cursor n rows down */
+ n = scp->term.param[0]; if (n < 1) n = 1;
+ move_crsr(scp, scp->xpos, scp->ypos + n);
+ break;
+
+ case 'm': /* change attribute */
+ if (scp->term.num_param == 0)
+ n = 0;
+ else
+ n = scp->term.param[0];
+ switch (n) {
+ case 0: /* back to normal */
+ scp->term.cur_attr = scp->term.std_attr;
+ break;
+ case 1: /* highlight (bold) */
+ scp->term.cur_attr &= 0xFF00;
+ scp->term.cur_attr |= 0x0800;
+ break;
+ case 4: /* highlight (underline) */
+ scp->term.cur_attr &= 0x0F00;
+ scp->term.cur_attr |= 0x0800;
+ break;
+ case 5: /* blink */
+ scp->term.cur_attr &= 0xFF00;
+ scp->term.cur_attr |= 0x8000;
+ break;
+ case 7: /* reverse video */
+ scp->term.cur_attr = scp->term.rev_attr;
+ break;
+ case 30: case 31: case 32: case 33: /* set fg color */
+ case 34: case 35: case 36: case 37:
+ scp->term.cur_attr = (scp->term.cur_attr & 0xF0FF)
+ | (ansi_col[(n - 30) & 7] << 8);
+ break;
+ case 40: case 41: case 42: case 43: /* set bg color */
+ case 44: case 45: case 46: case 47:
+ scp->term.cur_attr = (scp->term.cur_attr & 0x0FFF)
+ | (ansi_col[(n - 40) & 7] << 12);
+ break;
+ }
+ break;
+
+ case 'x':
+ if (scp->term.num_param == 0)
+ n = 0;
+ else
+ n = scp->term.param[0];
+ switch (n) {
+ case 0: /* reset attributes */
+ scp->term.cur_attr = scp->term.std_attr =
+ current_default->std_attr;
+ scp->term.rev_attr = current_default->rev_attr;
+ break;
+ case 1: /* set ansi background */
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.std_attr & 0x0F00) |
+ (ansi_col[(scp->term.param[1])&0x0F]<<12);
+ break;
+ case 2: /* set ansi foreground */
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.std_attr & 0xF000) |
+ (ansi_col[(scp->term.param[1])&0x0F]<<8);
+ break;
+ case 3: /* set ansi attribute directly */
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.param[1]&0xFF)<<8;
+ break;
+ case 5: /* set ansi reverse video background */
+ scp->term.rev_attr =
+ (scp->term.rev_attr & 0x0F00) |
+ (ansi_col[(scp->term.param[1])&0x0F]<<12);
+ break;
+ case 6: /* set ansi reverse video foreground */
+ scp->term.rev_attr =
+ (scp->term.rev_attr & 0xF000) |
+ (ansi_col[(scp->term.param[1])&0x0F]<<8);
+ break;
+ case 7: /* set ansi reverse video directly */
+ scp->term.rev_attr = (scp->term.param[1]&0xFF)<<8;
+ break;
+ }
+ break;
+
+ case 'z': /* switch to (virtual) console n */
+ if (scp->term.num_param == 1)
+ switch_scr(scp->term.param[0]);
+ break;
+ }
+ }
+ else if (scp->term.esc == 3) {
+ if (c >= '0' && c <= '9') {
+ if (scp->term.num_param < MAX_ESC_PAR) {
+ if (scp->term.last_param != scp->term.num_param) {
+ scp->term.last_param = scp->term.num_param;
+ scp->term.param[scp->term.num_param] = 0;
+ }
+ else
+ scp->term.param[scp->term.num_param] *= 10;
+ scp->term.param[scp->term.num_param] += c - '0';
+ return;
+ }
+ }
+ scp->term.num_param = scp->term.last_param + 1;
+ switch (c) {
+
+ case ';':
+ if (scp->term.num_param < MAX_ESC_PAR)
+ return;
+ break;
+
+ case 'A': /* set display border color */
+ if (scp->term.num_param == 1)
+ scp->border=scp->term.param[0] & 0xff;
+ if (scp == cur_console)
+ set_border(scp->border);
+ break;
+
+ case 'B': /* set bell pitch and duration */
+ if (scp->term.num_param == 2) {
+ scp->bell_pitch = scp->term.param[0];
+ scp->bell_duration = scp->term.param[1]*10;
+ }
+ break;
+
+ case 'C': /* set cursor shape (start & end line) */
+ if (scp->term.num_param == 2) {
+ scp->cursor_start = scp->term.param[0] & 0x1F;
+ scp->cursor_end = scp->term.param[1] & 0x1F;
+ if (scp == cur_console)
+ cursor_shape(scp->cursor_start,
+ scp->cursor_end);
+ }
+ break;
+
+ case 'F': /* set ansi foreground */
+ if (scp->term.num_param == 1)
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.std_attr & 0xF000)
+ | ((scp->term.param[0] & 0x0F) << 8);
+ break;
+
+ case 'G': /* set ansi background */
+ if (scp->term.num_param == 1)
+ scp->term.cur_attr = scp->term.std_attr =
+ (scp->term.std_attr & 0x0F00)
+ | ((scp->term.param[0] & 0x0F) << 12);
+ break;
+
+ case 'H': /* set ansi reverse video foreground */
+ if (scp->term.num_param == 1)
+ scp->term.rev_attr =
+ (scp->term.rev_attr & 0xF000)
+ | ((scp->term.param[0] & 0x0F) << 8);
+ break;
+
+ case 'I': /* set ansi reverse video background */
+ if (scp->term.num_param == 1)
+ scp->term.rev_attr =
+ (scp->term.rev_attr & 0x0F00)
+ | ((scp->term.param[0] & 0x0F) << 12);
+ break;
+ }
+ }
+ scp->term.esc = 0;
+}
+
+
+static void ansi_put(scr_stat *scp, u_char c)
+{
+ if (scp->status & UNKNOWN_MODE)
+ return;
+
+ /* make screensaver happy */
+ if (scp == cur_console) {
+ scrn_time_stamp = time.tv_sec;
+ if (scrn_blanked)
+ SCRN_SAVER(0);
+ }
+ in_putc++;
+ if (scp->term.esc)
+ scan_esc(scp, c);
+ else switch(c) {
+ case 0x1B: /* start escape sequence */
+ scp->term.esc = 1;
+ scp->term.num_param = 0;
+ break;
+ case 0x07:
+ if (scp == cur_console)
+ sysbeep(scp->bell_pitch, scp->bell_duration);
+ break;
+ case '\t': /* non-destructive tab */
+ scp->crtat += (8 - scp->xpos % 8);
+ scp->xpos += (8 - scp->xpos % 8);
+ break;
+ case '\b': /* non-destructive backspace */
+ if (scp->crtat > scp->crt_base) {
+ scp->crtat--;
+ if (scp->xpos > 0)
+ scp->xpos--;
+ else {
+ scp->xpos += scp->xsize - 1;
+ scp->ypos--;
+ }
+ }
+ break;
+ case '\r': /* return to pos 0 */
+ move_crsr(scp, 0, scp->ypos);
+ break;
+ case '\n': /* newline, same pos */
+ scp->crtat += scp->xsize;
+ scp->ypos++;
+ break;
+ case '\f': /* form feed, clears screen */
+ clear_screen(scp);
+ break;
+ default:
+ /* Print only printables */
+ *scp->crtat = (scp->term.cur_attr | scr_map[c]);
+ scp->crtat++;
+ if (++scp->xpos >= scp->xsize) {
+ scp->xpos = 0;
+ scp->ypos++;
+ }
+ break;
+ }
+ if (scp->crtat >= scp->crt_base + scp->ysize * scp->xsize) {
+ bcopy(scp->crt_base + scp->xsize, scp->crt_base,
+ scp->xsize * (scp->ysize - 1) * sizeof(u_short));
+ fillw(scp->term.cur_attr | scr_map[0x20],
+ scp->crt_base + scp->xsize * (scp->ysize - 1),
+ scp->xsize);
+ scp->crtat -= scp->xsize;
+ scp->ypos--;
+ }
+ in_putc--;
+ if (delayed_next_scr)
+ switch_scr(delayed_next_scr - 1);
+}
+
+static void scinit(void)
+{
+ u_short volatile *cp = Crtat + (CGA_BUF-MONO_BUF)/sizeof(u_short), was;
+ unsigned cursorat;
+ int i;
+
+ /*
+ * catch that once in a blue moon occurence when scinit is called
+ * TWICE, adding the CGA_BUF offset again -> poooff
+ */
+ if (crtat != 0)
+ return;
+ /*
+ * Crtat initialized to point to MONO buffer, if not present change
+ * to CGA_BUF offset. ONLY ADD the difference since locore.s adds
+ * in the remapped offset at the "right" time
+ */
+ was = *cp;
+ *cp = (u_short) 0xA55A;
+ if (*cp != 0xA55A) {
+ crtc_addr = MONO_BASE;
+ } else {
+ *cp = was;
+ crtc_addr = COLOR_BASE;
+ Crtat = Crtat + (CGA_BUF-MONO_BUF)/sizeof(u_short);
+ }
+
+ /* Extract cursor location */
+ outb(crtc_addr,14);
+ cursorat = inb(crtc_addr+1)<<8 ;
+ outb(crtc_addr,15);
+ cursorat |= inb(crtc_addr+1);
+ crtat = Crtat + cursorat;
+
+ /* is this a VGA or higher ? */
+ outb(crtc_addr, 7);
+ if (inb(crtc_addr) == 7)
+ crtc_vga = 1;
+
+ current_default = &user_default;
+ console[0].crtat = crtat;
+ console[0].crt_base = Crtat;
+ console[0].term.esc = 0;
+ console[0].term.std_attr = current_default->std_attr;
+ console[0].term.rev_attr = current_default->rev_attr;
+ console[0].term.cur_attr = current_default->std_attr;
+ console[0].xpos = cursorat % COL;
+ console[0].ypos = cursorat / COL;
+ console[0].border = BG_BLACK;;
+ console[0].xsize = COL;
+ console[0].ysize = ROW;
+ console[0].status = 0;
+ console[0].pid = 0;
+ console[0].proc = NULL;
+ console[0].smode.mode = VT_AUTO;
+ console[0].bell_pitch = BELL_PITCH;
+ console[0].bell_duration = BELL_DURATION;
+ kernel_console.esc = 0;
+ kernel_console.std_attr = kernel_default.std_attr;
+ kernel_console.rev_attr = kernel_default.rev_attr;
+ kernel_console.cur_attr = kernel_default.std_attr;
+ /* initialize mapscrn array to a one to one map */
+ for (i=0; i<sizeof(scr_map); i++)
+ scr_map[i] = i;
+ clear_screen(&console[0]);
+}
+
+
+static void scput(u_char c)
+{
+ scr_stat *scp = &console[0];
+ term_stat save;
+
+ if (crtat == 0)
+ scinit();
+ if( in_putc == 0) {
+ ++in_putc;
+ save = scp->term;
+ scp->term = kernel_console;
+ current_default = &kernel_default;
+ ansi_put(scp, c);
+ kernel_console = scp->term;
+ current_default = &user_default;
+ scp->term = save;
+ --in_putc;
+ } else {
+ if( console_buffer_count < CONSOLE_BUFFER_SIZE)
+ console_buffer[console_buffer_count++] = c;
+ }
+}
+
+
+static u_char *get_fstr(u_int c, u_int *len)
+{
+ u_int i;
+
+ if (!(c & FKEY))
+ return(NULL);
+ i = (c & 0xFF) - F_FN;
+ if (i > n_fkey_tab)
+ return(NULL);
+ *len = fkey_tab[i].len;
+ return(fkey_tab[i].str);
+}
+
+
+static void update_leds(int which)
+{
+ static u_char xlate_leds[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+
+ /* replace CAPS led with ALTGR led for ALTGR keyboards */
+ if (key_map.n_keys > ALTGR_OFFSET) {
+ if (which & ALKED)
+ which |= CLKED;
+ else
+ which &= ~CLKED;
+ }
+ kbd_cmd2(KB_SETLEDS, xlate_leds[which & LED_MASK]);
+}
+
+
+/*
+ * scgetc(noblock) : get a character from the keyboard.
+ * If noblock = 0 wait until a key is gotten. Otherwise return NOKEY.
+ */
+u_int scgetc(int noblock)
+{
+ u_char val, code, release;
+ u_int state, action;
+ struct key_t *key;
+ static u_char esc_flag = 0, compose = 0;
+ static u_int chr = 0;
+
+next_code:
+ kbd_wait();
+ /* First see if there is something in the keyboard port */
+ if (inb(KB_STAT) & KB_BUF_FULL)
+ val = inb(KB_DATA);
+ else if (noblock)
+ return(NOKEY);
+ else
+ goto next_code;
+
+ if (cur_console->status & KBD_RAW_MODE)
+ return val;
+
+ code = val & 0x7F;
+ release = val & 0x80;
+
+ switch (esc_flag) {
+ case 0x00: /* normal scancode */
+ switch(code) {
+ case 0x38: /* left alt (compose key) */
+ if (release && compose) {
+ compose = 0;
+ if (chr > 255) {
+ sysbeep(BELL_PITCH, BELL_DURATION);
+ chr = 0;
+ }
+ }
+ else {
+ if (!compose) {
+ compose = 1;
+ chr = 0;
+ }
+ }
+ break;
+ case 0x60:
+ case 0x61:
+ esc_flag = code;
+ goto next_code;
+ }
+ break;
+ case 0x60: /* 0xE0 prefix */
+ esc_flag = 0;
+ switch (code) {
+ case 0x1c: /* right enter key */
+ code = 0x59;
+ break;
+ case 0x1d: /* right ctrl key */
+ code = 0x5a;
+ break;
+ case 0x35: /* keypad divide key */
+ code = 0x5b;
+ break;
+ case 0x37: /* print scrn key */
+ code = 0x5c;
+ break;
+ case 0x38: /* right alt key (alt gr) */
+ code = 0x5d;
+ break;
+ case 0x47: /* grey home key */
+ code = 0x5e;
+ break;
+ case 0x48: /* grey up arrow key */
+ code = 0x5f;
+ break;
+ case 0x49: /* grey page up key */
+ code = 0x60;
+ break;
+ case 0x4b: /* grey left arrow key */
+ code = 0x61;
+ break;
+ case 0x4d: /* grey right arrow key */
+ code = 0x62;
+ break;
+ case 0x4f: /* grey end key */
+ code = 0x63;
+ break;
+ case 0x50: /* grey down arrow key */
+ code = 0x64;
+ break;
+ case 0x51: /* grey page down key */
+ code = 0x65;
+ break;
+ case 0x52: /* grey insert key */
+ code = 0x66;
+ break;
+ case 0x53: /* grey delete key */
+ code = 0x67;
+ break;
+ default: /* ignore everything else */
+ goto next_code;
+ }
+ break;
+ case 0x61: /* 0xE1 prefix */
+ esc_flag = 0;
+ if (code == 0x1D)
+ esc_flag = 0x1D;
+ goto next_code;
+ /* NOT REACHED */
+ case 0x1D: /* pause / break */
+ esc_flag = 0;
+ if (code != 0x45)
+ goto next_code;
+ code = 0x68;
+ break;
+ }
+
+ if (compose) {
+ switch (code) {
+ case 0x47:
+ case 0x48: /* keypad 7,8,9 */
+ case 0x49:
+ if (!release)
+ chr = (code - 0x40) + chr*10;
+ goto next_code;
+ case 0x4b:
+ case 0x4c: /* keypad 4,5,6 */
+ case 0x4d:
+ if (!release)
+ chr = (code - 0x47) + chr*10;
+ goto next_code;
+ case 0x4f:
+ case 0x50: /* keypad 1,2,3 */
+ case 0x51:
+ if (!release)
+ chr = (code - 0x4e) + chr*10;
+ goto next_code;
+ case 0x52: /* keypad 0 */
+ if (!release)
+ chr *= 10;
+ goto next_code;
+ case 0x38: /* left alt key */
+ break;
+ default:
+ if (chr) {
+ compose = chr = 0;
+ sysbeep(BELL_PITCH, BELL_DURATION);
+ goto next_code;
+ }
+ break;
+ }
+ }
+
+ state = (shfts ? 1 : 0 ) | (2 * (ctls ? 1 : 0)) | (4 * (alts ? 1 : 0));
+ if ((!agrs && (cur_console->status & ALKED))
+ || (agrs && !(cur_console->status & ALKED)))
+ code += ALTGR_OFFSET;
+ key = &key_map.key[code];
+ if ( ((key->flgs & FLAG_LOCK_C) && (cur_console->status & CLKED))
+ || ((key->flgs & FLAG_LOCK_N) && (cur_console->status & NLKED)) )
+ state ^= 1;
+
+ /* Check for make/break */
+ action = key->map[state];
+ if (release) { /* key released */
+ if (key->spcl & 0x80) {
+ switch (action) {
+ case LSH:
+ shfts &= ~1;
+ break;
+ case RSH:
+ shfts &= ~2;
+ break;
+ case LCTR:
+ ctls &= ~1;
+ break;
+ case RCTR:
+ ctls &= ~2;
+ break;
+ case LALT:
+ alts &= ~1;
+ break;
+ case RALT:
+ alts &= ~2;
+ break;
+ case NLK:
+ nlkcnt = 0;
+ break;
+ case CLK:
+ clkcnt = 0;
+ break;
+ case SLK:
+ slkcnt = 0;
+ break;
+ case ASH:
+ agrs = 0;
+ break;
+ case ALK:
+ alkcnt = 0;
+ break;
+ case META:
+ metas = 0;
+ break;
+ }
+ }
+ if (chr && !compose) {
+ action = chr;
+ chr = 0;
+ return(action);
+ }
+ } else {
+ /* key pressed */
+ if (key->spcl & (0x80>>state)) {
+ switch (action) {
+ /* LOCKING KEYS */
+ case NLK:
+ if (!nlkcnt) {
+ nlkcnt++;
+ if (cur_console->status & NLKED)
+ cur_console->status &= ~NLKED;
+ else
+ cur_console->status |= NLKED;
+ update_leds(cur_console->status);
+ }
+ break;
+ case CLK:
+ if (!clkcnt) {
+ clkcnt++;
+ if (cur_console->status & CLKED)
+ cur_console->status &= ~CLKED;
+ else
+ cur_console->status |= CLKED;
+ update_leds(cur_console->status);
+ }
+ break;
+ case SLK:
+ if (!slkcnt) {
+ slkcnt++;
+ if (cur_console->status & SLKED) {
+ cur_console->status &= ~SLKED;
+ pcstart(VIRTUAL_TTY(get_scr_num()));
+ }
+ else
+ cur_console->status |= SLKED;
+ update_leds(cur_console->status);
+ }
+ break;
+ case ALK:
+ if (!alkcnt) {
+ alkcnt++;
+ if (cur_console->status & ALKED)
+ cur_console->status &= ~ALKED;
+ else
+ cur_console->status |= ALKED;
+ update_leds(cur_console->status);
+ }
+ break;
+
+ /* NON-LOCKING KEYS */
+ case NOP:
+ break;
+ case RBT:
+#if defined(__FreeBSD__)
+ shutdown_nice();
+#else
+ cpu_reset();
+#endif
+ break;
+ case DBG:
+#if DDB > 0 /* try to switch to console 0 */
+ if (cur_console->smode.mode == VT_AUTO &&
+ console[0].smode.mode == VT_AUTO)
+ switch_scr(0);
+ Debugger("manual escape to debugger");
+ return(NOKEY);
+#else
+ printf("No debugger in kernel\n");
+#endif
+ break;
+ case LSH:
+ shfts |= 1;
+ break;
+ case RSH:
+ shfts |= 2;
+ break;
+ case LCTR:
+ ctls |= 1;
+ break;
+ case RCTR:
+ ctls |= 2;
+ break;
+ case LALT:
+ alts |= 1;
+ break;
+ case RALT:
+ alts |= 2;
+ break;
+ case ASH:
+ agrs = 1;
+ break;
+ case META:
+ metas = 1;
+ break;
+ case NEXT:
+ switch_scr((get_scr_num()+1)%NCONS);
+ break;
+ default:
+ if (action >= F_SCR && action <= L_SCR) {
+ switch_scr(action - F_SCR);
+ break;
+ }
+ if (action >= F_FN && action <= L_FN)
+ action |= FKEY;
+ return(action);
+ }
+ }
+ else {
+ if (metas)
+ action |= MKEY;
+ return(action);
+ }
+ }
+ goto next_code;
+}
+
+
+int getchar(void)
+{
+ u_char thechar;
+ int s;
+
+ polling = 1;
+ s = splhigh();
+ scput('>');
+ thechar = (u_char) scgetc(0);
+ polling = 0;
+ splx(s);
+ switch (thechar) {
+ default:
+ if (thechar >= scr_map[0x20])
+ scput(thechar);
+ return(thechar);
+ case cr:
+ case lf:
+ scput(cr); scput(lf);
+ return(lf);
+ case bs:
+ case del:
+ scput(bs); scput(scr_map[0x20]); scput(bs);
+ return(thechar);
+ case cntld:
+ scput('^'); scput('D'); scput('\r'); scput('\n');
+ return(0);
+ }
+}
+
+
+u_int sgetc(int noblock)
+{
+ return (scgetc(noblock) & 0xff);
+}
+
+int pcmmap(dev_t dev, int offset, int nprot)
+{
+ if (offset > 0x20000)
+ return EINVAL;
+ return i386_btop((VIDEOMEM + offset));
+}
+
+
+static void kbd_wait(void)
+{
+ int i;
+
+ for (i=0; i<1000; i++) { /* up to 10 msec */
+ if ((inb(KB_STAT) & KB_READY) == 0)
+ break;
+ DELAY (10);
+ }
+}
+
+
+static void kbd_cmd(u_char command)
+{
+ kbd_wait();
+ outb(KB_DATA, command);
+}
+
+
+static void kbd_cmd2(u_char command, u_char arg)
+{
+ int r, s = spltty();
+ do {
+ kbd_cmd(command);
+ r = kbd_reply();
+ if (r == KB_ACK) {
+ kbd_cmd(arg & 0x7f);
+ r = kbd_reply();
+ }
+ } while (r != KB_ACK);
+ splx(s);
+}
+
+
+static int kbd_reply()
+{
+ int i;
+
+ kbd_wait();
+ for (i=0; i<60000; i++) { /* at least 300 msec, 600 msec enough */
+ if (inb(KB_STAT) & KB_BUF_FULL)
+ return ((u_char) inb(KB_DATA));
+ DELAY (10);
+ }
+ return(-1);
+}
+
+
+static void set_mode(scr_stat *scp)
+{
+ u_char byte;
+ int s;
+
+ if (scp != cur_console)
+ return;
+
+ /* (re)activate cursor */
+ untimeout((timeout_t)cursor_pos, 0);
+ cursor_pos(1);
+
+ /* change cursor type if set */
+ if (scp->cursor_start != -1 && scp->cursor_end != -1)
+ cursor_shape(scp->cursor_start, scp->cursor_end);
+
+ /* mode change only on VGA's */
+ if (!crtc_vga)
+ return;
+
+ /* setup video hardware for the given mode */
+ s = splhigh();
+ switch(scp->mode) {
+ case TEXT80x25:
+ outb(crtc_addr, 9); byte = inb(crtc_addr+1);
+ outb(crtc_addr, 9); outb(crtc_addr+1, byte | 0x0F);
+ outb(TSIDX, 0x03); outb(TSREG, 0x00); /* select font 0 */
+ break;
+ case TEXT80x50:
+ outb(crtc_addr, 9); byte = inb(crtc_addr+1);
+ outb(crtc_addr, 9); outb(crtc_addr+1, (byte & 0xF0) | 0x07);
+ outb(TSIDX, 0x03); outb(TSREG, 0x05); /* select font 1 */
+ break;
+ default:
+ break;
+ }
+ splx(s);
+
+ /* set border color for this (virtual) console */
+ set_border(scp->border);
+ return;
+}
+
+
+static void set_border(int color)
+{
+ inb(crtc_addr+6); /* reset flip-flop */
+ outb(ATC, 0x11); outb(ATC, color);
+ inb(crtc_addr+6); /* reset flip-flop */
+ outb(ATC, 0x20); /* enable Palette */
+}
+
+static void load_font(int segment, int size, char* font)
+{
+ int ch, line, s;
+ u_char val;
+
+ outb(TSIDX, 0x01); val = inb(TSREG); /* blank screen */
+ outb(TSIDX, 0x01); outb(TSREG, val | 0x20);
+
+ /* setup vga for loading fonts (graphics plane mode) */
+ s = splhigh();
+ inb(crtc_addr+6); /* reset flip/flop */
+ outb(ATC, 0x30); outb(ATC, 0x01);
+ outb(TSIDX, 0x02); outb(TSREG, 0x04);
+ outb(TSIDX, 0x04); outb(TSREG, 0x06);
+ outb(GDCIDX, 0x04); outb(GDCREG, 0x02);
+ outb(GDCIDX, 0x05); outb(GDCREG, 0x00);
+ outb(GDCIDX, 0x06); outb(GDCREG, 0x05); /* addr = a0000, 64kb */
+ splx(s);
+ for (ch=0; ch < 256; ch++)
+ for (line=0; line < size; line++)
+ *((char *)atdevbase+(segment*0x4000)+(ch*32)+line) =
+ font[(ch*size)+line];
+ /* setup vga for text mode again */
+ s = splhigh();
+ inb(crtc_addr+6); /* reset flip/flop */
+ outb(ATC, 0x30); outb(ATC, 0x0C);
+ outb(TSIDX, 0x02); outb(TSREG, 0x03);
+ outb(TSIDX, 0x04); outb(TSREG, 0x02);
+ outb(GDCIDX, 0x04); outb(GDCREG, 0x00);
+ outb(GDCIDX, 0x05); outb(GDCREG, 0x10);
+ if (crtc_addr == MONO_BASE) {
+ outb(GDCIDX, 0x06); outb(GDCREG, 0x0A); /* addr = b0000, 32kb */
+ }
+ else {
+ outb(GDCIDX, 0x06); outb(GDCREG, 0x0E); /* addr = b8000, 32kb */
+ }
+ splx(s);
+ outb(TSIDX, 0x01); val = inb(TSREG); /* unblank screen */
+ outb(TSIDX, 0x01); outb(TSREG, val & 0xDF);
+}
+
+
+static void load_palette(void)
+{
+ int i;
+
+ outb(PIXMASK, 0xFF); /* no pixelmask */
+ outb(PALWADR, 0x00);
+ for (i=0x00; i<0x300; i++)
+ outb(PALDATA, palette[i]);
+ inb(crtc_addr+6); /* reset flip/flop */
+ outb(ATC, 0x20); /* enable palette */
+}
+
+static void save_palette(void)
+{
+ int i;
+
+ outb(PALRADR, 0x00);
+ for (i=0x00; i<0x300; i++)
+ palette[i] = inb(PALDATA);
+ inb(crtc_addr+6); /* reset flip/flop */
+}
+
+
+static void change_winsize(struct tty *tp, int x, int y)
+{
+ if (tp->t_winsize.ws_col != x || tp->t_winsize.ws_row != y) {
+ tp->t_winsize.ws_col = x;
+ tp->t_winsize.ws_row = y;
+ pgsignal(tp->t_pgrp, SIGWINCH, 1);
+ }
+}
+
+#endif /* NSC */
diff --git a/sys/isa/timerreg.h b/sys/isa/timerreg.h
new file mode 100644
index 0000000..5742f66
--- /dev/null
+++ b/sys/isa/timerreg.h
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Header: timerreg.h,v 1.2 93/02/28 15:08:58 mccanne Exp
+ * $Id$
+ */
+
+/*
+ *
+ * Register definitions for the Intel 8253 Programmable Interval Timer.
+ *
+ * This chip has three independent 16-bit down counters that can be
+ * read on the fly. There are three mode registers and three countdown
+ * registers. The countdown registers are addressed directly, via the
+ * first three I/O ports. The three mode registers are accessed via
+ * the fourth I/O port, with two bits in the mode byte indicating the
+ * register. (Why are hardware interfaces always so braindead?).
+ *
+ * To write a value into the countdown register, the mode register
+ * is first programmed with a command indicating the which byte of
+ * the two byte register is to be modified. The three possibilities
+ * are load msb (TMR_MR_MSB), load lsb (TMR_MR_LSB), or load lsb then
+ * msb (TMR_MR_BOTH).
+ *
+ * To read the current value ("on the fly") from the countdown register,
+ * you write a "latch" command into the mode register, then read the stable
+ * value from the corresponding I/O port. For example, you write
+ * TMR_MR_LATCH into the corresponding mode register. Presumably,
+ * after doing this, a write operation to the I/O port would result
+ * in undefined behavior (but hopefully not fry the chip).
+ * Reading in this manner has no side effects.
+ *
+ * The outputs of the three timers are connected as follows:
+ *
+ * timer 0 -> irq 0
+ * timer 1 -> dma chan 0 (for dram refresh)
+ * timer 2 -> speaker (via keyboard controller)
+ *
+ * Timer 0 is used to call hardclock.
+ * Timer 2 is used to generate console beeps.
+ */
+
+/*
+ * Macros for specifying values to be written into a mode register.
+ */
+#define TIMER_CNTR0 (IO_TIMER1 + 0) /* timer 0 counter port */
+#define TIMER_CNTR1 (IO_TIMER1 + 1) /* timer 1 counter port */
+#define TIMER_CNTR2 (IO_TIMER1 + 2) /* timer 2 counter port */
+#define TIMER_MODE (IO_TIMER1 + 3) /* timer mode port */
+#define TIMER_SEL0 0x00 /* select counter 0 */
+#define TIMER_SEL1 0x40 /* select counter 1 */
+#define TIMER_SEL2 0x80 /* select counter 2 */
+#define TIMER_INTTC 0x00 /* mode 0, intr on terminal cnt */
+#define TIMER_ONESHOT 0x02 /* mode 1, one shot */
+#define TIMER_RATEGEN 0x04 /* mode 2, rate generator */
+#define TIMER_SQWAVE 0x06 /* mode 3, square wave */
+#define TIMER_SWSTROBE 0x08 /* mode 4, s/w triggered strobe */
+#define TIMER_HWSTROBE 0x0a /* mode 5, h/w triggered strobe */
+#define TIMER_LATCH 0x00 /* latch counter for reading */
+#define TIMER_LSB 0x10 /* r/w counter LSB */
+#define TIMER_MSB 0x20 /* r/w counter MSB */
+#define TIMER_16BIT 0x30 /* r/w counter 16 bits, LSB first */
+#define TIMER_BCD 0x01 /* count in BCD */
+
diff --git a/sys/kern/imgact_aout.c b/sys/kern/imgact_aout.c
new file mode 100644
index 0000000..5d69e09
--- /dev/null
+++ b/sys/kern/imgact_aout.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 1993, David Greenman
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by David Greenman
+ * 4. The name of the developer may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: imgact_aout.c,v 1.3 1993/12/30 01:39:29 davidg Exp $
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "resourcevar.h"
+#include "exec.h"
+#include "mman.h"
+#include "imgact.h"
+#include "kernel.h"
+
+#include "vm/vm.h"
+
+int
+exec_aout_imgact(iparams)
+ struct image_params *iparams;
+{
+ struct exec *a_out = (struct exec *) iparams->image_header;
+ struct vmspace *vmspace = iparams->proc->p_vmspace;
+ unsigned long vmaddr, virtual_offset, file_offset;
+ unsigned long bss_size;
+ int error, len;
+
+ /*
+ * Set file/virtual offset based on a.out variant.
+ * We do two cases: host byte order and network byte order
+ * (for NetBSD compatibility)
+ */
+ switch ((int)(a_out->a_magic & 0xffff)) {
+ case ZMAGIC:
+ virtual_offset = 0;
+ if (a_out->a_text) {
+ file_offset = NBPG;
+ } else {
+ /* Bill's "screwball mode" */
+ file_offset = 0;
+ }
+ break;
+ case QMAGIC:
+ virtual_offset = NBPG;
+ file_offset = 0;
+ break;
+ default:
+ /* NetBSD compatibility */
+ switch ((int)(ntohl(a_out->a_magic) & 0xffff)) {
+ case ZMAGIC:
+ case QMAGIC:
+ virtual_offset = NBPG;
+ file_offset = 0;
+ break;
+ default:
+ return (-1);
+ }
+ }
+
+ bss_size = roundup(a_out->a_bss, NBPG);
+
+ /*
+ * Check various fields in header for validity/bounds.
+ */
+ if (/* entry point must lay with text region */
+ a_out->a_entry < virtual_offset ||
+ a_out->a_entry >= virtual_offset + a_out->a_text ||
+
+ /* text and data size must each be page rounded */
+ a_out->a_text % NBPG ||
+ a_out->a_data % NBPG)
+ return (-1);
+
+ /* text + data can't exceed file size */
+ if (a_out->a_data + a_out->a_text > iparams->attr->va_size)
+ return (EFAULT);
+
+ /*
+ * text/data/bss must not exceed limits
+ */
+ if (/* text can't exceed maximum text size */
+ a_out->a_text > MAXTSIZ ||
+
+ /* data + bss can't exceed maximum data size */
+ a_out->a_data + bss_size > MAXDSIZ ||
+
+ /* data + bss can't exceed rlimit */
+ a_out->a_data + bss_size >
+ iparams->proc->p_rlimit[RLIMIT_DATA].rlim_cur)
+ return (ENOMEM);
+
+ /* copy in arguments and/or environment from old process */
+ error = exec_extract_strings(iparams);
+ if (error)
+ return (error);
+
+ /*
+ * Destroy old process VM and create a new one (with a new stack)
+ */
+ exec_new_vmspace(iparams);
+
+ /*
+ * Map text read/execute
+ */
+ vmaddr = virtual_offset;
+ error =
+ vm_mmap(&vmspace->vm_map, /* map */
+ &vmaddr, /* address */
+ a_out->a_text, /* size */
+ VM_PROT_READ | VM_PROT_EXECUTE, /* protection */
+ VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_WRITE, /* max protection */
+ MAP_FILE | MAP_PRIVATE | MAP_FIXED, /* flags */
+ iparams->vnodep, /* vnode */
+ file_offset); /* offset */
+ if (error)
+ return (error);
+
+ /*
+ * Map data read/write (if text is 0, assume text is in data area
+ * [Bill's screwball mode])
+ */
+ vmaddr = virtual_offset + a_out->a_text;
+ error =
+ vm_mmap(&vmspace->vm_map,
+ &vmaddr,
+ a_out->a_data,
+ VM_PROT_READ | VM_PROT_WRITE | (a_out->a_text ? 0 : VM_PROT_EXECUTE),
+ VM_PROT_ALL, MAP_FILE | MAP_PRIVATE | MAP_FIXED, iparams->vnodep,
+ file_offset + a_out->a_text);
+ if (error)
+ return (error);
+
+ /*
+ * Allocate demand-zeroed area for uninitialized data
+ * "bss" = 'block started by symbol' - named after the IBM 7090
+ * instruction of the same name.
+ */
+ vmaddr = virtual_offset + a_out->a_text + a_out->a_data;
+ error = vm_allocate(&vmspace->vm_map, &vmaddr, bss_size, FALSE);
+ if (error)
+ return (error);
+
+ /* Fill in process VM information */
+ vmspace->vm_tsize = a_out->a_text >> PAGE_SHIFT;
+ vmspace->vm_dsize = (a_out->a_data + bss_size) >> PAGE_SHIFT;
+ vmspace->vm_taddr = (caddr_t) virtual_offset;
+ vmspace->vm_daddr = (caddr_t) virtual_offset + a_out->a_text;
+
+ /* Fill in image_params */
+ iparams->interpreted = 0;
+ iparams->entry_addr = a_out->a_entry;
+
+ return (0);
+}
+
+/*
+ * Tell kern_execve.c about it, with a little help from the linker.
+ * Since `const' objects end up in the text segment, TEXT_SET is the
+ * correct directive to use.
+ */
+static const struct execsw aout_execsw = { exec_aout_imgact };
+TEXT_SET(execsw_set, aout_execsw);
+
diff --git a/sys/kern/imgact_shell.c b/sys/kern/imgact_shell.c
new file mode 100644
index 0000000..42b3297
--- /dev/null
+++ b/sys/kern/imgact_shell.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 1993, David Greenman
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by David Greenman
+ * 4. The name of the developer may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: imgact_shell.c,v 1.1 1993/12/20 16:16:46 wollman Exp $
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "resourcevar.h"
+#include "imgact.h"
+#include "kernel.h"
+#include "machine/endian.h"
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define SHELLMAGIC 0x2123 /* #! */
+#else
+#define SHELLMAGIC 0x2321
+#endif
+
+#define MAXSHELLCMDLEN 64
+
+/*
+ * Shell interpreter image activator. A interpreter name beginning
+ * at iparams->stringbase is the minimal successful exit requirement.
+ */
+int
+exec_shell_imgact(iparams)
+ struct image_params *iparams;
+{
+ const char *image_header = iparams->image_header;
+ const char *ihp, *line_endp;
+ int length;
+ char *interp;
+ char **argv;
+
+ /* a shell script? */
+ if (((short *) image_header)[0] != SHELLMAGIC)
+ return(-1);
+
+ /*
+ * Don't allow a shell script to be the shell for a shell
+ * script. :-)
+ */
+ if (iparams->interpreted)
+ return(ENOEXEC);
+
+ iparams->interpreted = 1;
+
+ /*
+ * Copy shell name and arguments from image_header into string
+ * buffer.
+ */
+
+ /*
+ * Find end of line; return if the line > MAXSHELLCMDLEN long.
+ */
+ for (ihp = &image_header[2]; *ihp != '\n'; ++ihp) {
+ if (ihp >= &image_header[MAXSHELLCMDLEN])
+ return(ENOEXEC);
+ }
+ line_endp = ihp;
+
+ /* reset for another pass */
+ ihp = &image_header[2];
+
+ /* Skip over leading spaces - until the interpreter name */
+ while ((*ihp == ' ') || (*ihp == '\t')) ihp++;
+
+ /* copy the interpreter name */
+ interp = iparams->interpreter_name;
+ while ((ihp < line_endp) && (*ihp != ' ') && (*ihp != '\t'))
+ *interp++ = *ihp++;
+ *interp = '\0';
+
+ /* Disallow a null interpreter filename */
+ if (*iparams->interpreter_name == '\0')
+ return(ENOEXEC);
+
+ /* reset for another pass */
+ ihp = &image_header[2];
+
+ /* copy the interpreter name and arguments */
+ while (ihp < line_endp) {
+ /* Skip over leading spaces */
+ while ((*ihp == ' ') || (*ihp == '\t')) ihp++;
+
+ if (ihp < line_endp) {
+ /*
+ * Copy to end of token. No need to watch stringspace
+ * because this is at the front of the string buffer
+ * and the maximum shell command length is tiny.
+ */
+ while ((ihp < line_endp) && (*ihp != ' ') && (*ihp != '\t')) {
+ *iparams->stringp++ = *ihp++;
+ iparams->stringspace--;
+ }
+
+ *iparams->stringp++ = 0;
+ iparams->stringspace--;
+
+ iparams->argc++;
+ }
+ }
+
+ /* set argv[0] to point to original file name */
+ suword(iparams->uap->argv, (int)iparams->uap->fname);
+
+ return(0);
+}
+
+/*
+ * Tell kern_execve.c about it, with a little help from the linker.
+ * Since `const' objects end up in the text segment, TEXT_SET is the
+ * correct directive to use.
+ */
+static const struct execsw shell_execsw = { exec_shell_imgact };
+TEXT_SET(execsw_set, shell_execsw);
diff --git a/sys/kern/subr_rlist.c b/sys/kern/subr_rlist.c
new file mode 100644
index 0000000..4dd156c
--- /dev/null
+++ b/sys/kern/subr_rlist.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 1992 William F. Jolitz, TeleMuse
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This software is a component of "386BSD" developed by
+ William F. Jolitz, TeleMuse.
+ * 4. Neither the name of the developer nor the name "386BSD"
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
+ * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
+ * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
+ * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
+ * NOT MAKE USE THIS WORK.
+ *
+ * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
+ * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
+ * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES
+ * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
+ * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
+ * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
+ * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
+ * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "cdefs.h"
+#include "malloc.h"
+#include "rlist.h"
+#include "vm/vm.h"
+#include "vm/vm_map.h"
+
+extern vm_map_t kernel_map;
+
+/*
+ * Resource lists.
+ */
+
+#define RLIST_MIN 128
+static int rlist_count=0;
+static struct rlist *rlfree;
+int rlist_active;
+
+static struct rlist *
+rlist_malloc()
+{
+ struct rlist *rl;
+ int i;
+ while( rlist_count < RLIST_MIN) {
+ extern vm_map_t kmem_map;
+ int s = splhigh();
+ rl = (struct rlist *)kmem_malloc(kmem_map, NBPG, 0);
+ splx(s);
+ if( !rl)
+ break;
+
+ for(i=0;i<(NBPG/(sizeof *rl));i++) {
+ rl->rl_next = rlfree;
+ rlfree = rl;
+ rlist_count++;
+ rl++;
+ }
+ }
+
+ if( (rl = rlfree) == 0 )
+ panic("Cannot get an rlist entry");
+
+ --rlist_count;
+ rlfree = rl->rl_next;
+ return rl;
+}
+
+inline static void
+rlist_mfree( struct rlist *rl)
+{
+ rl->rl_next = rlfree;
+ rlfree = rl;
+ ++rlist_count;
+}
+
+
+/*
+ * Add space to a resource list. Used to either
+ * initialize a list or return free space to it.
+ */
+void
+rlist_free (rlp, start, end)
+ register struct rlist **rlp;
+ unsigned start, end;
+{
+ struct rlist *head;
+ register struct rlist *olp = 0;
+ int s;
+
+ s = splhigh();
+ while( rlist_active)
+ tsleep((caddr_t)&rlist_active, PSWP, "rlistf", 0);
+ rlist_active = 1;
+ splx(s);
+
+ head = *rlp;
+
+loop:
+ /* if nothing here, insert (tail of list) */
+ if (*rlp == 0) {
+ *rlp = rlist_malloc();
+ (*rlp)->rl_start = start;
+ (*rlp)->rl_end = end;
+ (*rlp)->rl_next = 0;
+ rlist_active = 0;
+ wakeup((caddr_t)&rlist_active);
+ return;
+ }
+
+ /* if new region overlaps something currently present, panic */
+ if (start >= (*rlp)->rl_start && start <= (*rlp)->rl_end) {
+ printf("Frag %d:%d, ent %d:%d ", start, end,
+ (*rlp)->rl_start, (*rlp)->rl_end);
+ panic("overlapping front rlist_free: freed twice?");
+ }
+ if (end >= (*rlp)->rl_start && end <= (*rlp)->rl_end) {
+ printf("Frag %d:%d, ent %d:%d ", start, end,
+ (*rlp)->rl_start, (*rlp)->rl_end);
+ panic("overlapping tail rlist_free: freed twice?");
+ }
+
+ /* are we adjacent to this element? (in front) */
+ if (end+1 == (*rlp)->rl_start) {
+ /* coalesce */
+ (*rlp)->rl_start = start;
+ goto scan;
+ }
+
+ /* are we before this element? */
+ if (end < (*rlp)->rl_start) {
+ register struct rlist *nlp;
+
+ nlp = rlist_malloc();
+ nlp->rl_start = start;
+ nlp->rl_end = end;
+ nlp->rl_next = *rlp;
+ /*
+ * If the new element is in front of the list,
+ * adjust *rlp, else don't.
+ */
+ if( olp) {
+ olp->rl_next = nlp;
+ } else {
+ *rlp = nlp;
+ }
+ rlist_active = 0;
+ wakeup((caddr_t)&rlist_active);
+ return;
+ }
+
+ /* are we adjacent to this element? (at tail) */
+ if ((*rlp)->rl_end + 1 == start) {
+ /* coalesce */
+ (*rlp)->rl_end = end;
+ goto scan;
+ }
+
+ /* are we after this element */
+ if (start > (*rlp)->rl_end) {
+ olp = *rlp;
+ rlp = &((*rlp)->rl_next);
+ goto loop;
+ } else
+ panic("rlist_free: can't happen");
+
+scan:
+ /* can we coalesce list now that we've filled a void? */
+ {
+ register struct rlist *lp, *lpn;
+
+ for (lp = head; lp->rl_next ;) {
+ lpn = lp->rl_next;
+
+ /* coalesce ? */
+ if (lp->rl_end + 1 == lpn->rl_start) {
+ lp->rl_end = lpn->rl_end;
+ lp->rl_next = lpn->rl_next;
+ rlist_mfree(lpn);
+ } else
+ lp = lp->rl_next;
+ }
+ }
+ rlist_active = 0;
+ wakeup((caddr_t)&rlist_active);
+}
+
+/*
+ * Obtain a region of desired size from a resource list.
+ * If nothing available of that size, return 0. Otherwise,
+ * return a value of 1 and set resource start location with
+ * "*loc". (Note: loc can be zero if we don't wish the value)
+ */
+int rlist_alloc (rlp, size, loc)
+ struct rlist **rlp;
+ unsigned size, *loc;
+{
+ register struct rlist *lp;
+ int s;
+ register struct rlist *olp = 0;
+
+ s = splhigh();
+ while( rlist_active)
+ tsleep((caddr_t)&rlist_active, PSWP, "rlista", 0);
+ rlist_active = 1;
+ splx(s);
+
+ /* walk list, allocating first thing that's big enough (first fit) */
+ for (; *rlp; rlp = &((*rlp)->rl_next))
+ if(size <= (*rlp)->rl_end - (*rlp)->rl_start + 1) {
+
+ /* hand it to the caller */
+ if (loc) *loc = (*rlp)->rl_start;
+ (*rlp)->rl_start += size;
+
+ /* did we eat this element entirely? */
+ if ((*rlp)->rl_start > (*rlp)->rl_end) {
+ lp = (*rlp)->rl_next;
+ rlist_mfree(*rlp);
+ /*
+ * if the deleted element was in fromt
+ * of the list, adjust *rlp, else don't.
+ */
+ if (olp) {
+ olp->rl_next = lp;
+ } else {
+ *rlp = lp;
+ }
+ }
+
+ rlist_active = 0;
+ wakeup((caddr_t)&rlist_active);
+ return (1);
+ } else {
+ olp = *rlp;
+ }
+
+ rlist_active = 0;
+ wakeup((caddr_t)&rlist_active);
+ /* nothing in list that's big enough */
+ return (0);
+}
+
+/*
+ * Finished with this resource list, reclaim all space and
+ * mark it as being empty.
+ */
+void
+rlist_destroy (rlp)
+ struct rlist **rlp;
+{
+ struct rlist *lp, *nlp;
+
+ lp = *rlp;
+ *rlp = 0;
+ for (; lp; lp = nlp) {
+ nlp = lp->rl_next;
+ rlist_mfree(lp);
+ }
+}
diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c
new file mode 100644
index 0000000..9bb38e1
--- /dev/null
+++ b/sys/kern/subr_trap.c
@@ -0,0 +1,728 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the University of Utah, and William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)trap.c 7.4 (Berkeley) 5/13/91
+ * $Id: trap.c,v 1.22 1994/04/07 10:51:00 davidg Exp $
+ */
+
+/*
+ * 386 Trap and System call handleing
+ */
+
+#include "isa.h"
+#include "npx.h"
+#include "ddb.h"
+#include "machine/cpu.h"
+#include "machine/psl.h"
+#include "machine/reg.h"
+#include "machine/eflags.h"
+
+#include "param.h"
+#include "systm.h"
+#include "proc.h"
+#include "user.h"
+#include "acct.h"
+#include "kernel.h"
+#ifdef KTRACE
+#include "ktrace.h"
+#endif
+
+#include "vm/vm_param.h"
+#include "vm/pmap.h"
+#include "vm/vm_map.h"
+#include "vm/vm_user.h"
+#include "vm/vm_page.h"
+#include "sys/vmmeter.h"
+
+#include "machine/trap.h"
+
+#ifdef __GNUC__
+
+/*
+ * The "r" contraint could be "rm" except for fatal bugs in gas. As usual,
+ * we omit the size from the mov instruction to avoid nonfatal bugs in gas.
+ */
+#define read_gs() ({ u_short gs; __asm("mov %%gs,%0" : "=r" (gs)); gs; })
+#define write_gs(newgs) __asm("mov %0,%%gs" : : "r" ((u_short) newgs))
+
+#else /* not __GNUC__ */
+
+u_short read_gs __P((void));
+void write_gs __P((/* promoted u_short */ int gs));
+
+#endif /* __GNUC__ */
+
+extern int grow(struct proc *,int);
+
+struct sysent sysent[];
+int nsysent;
+
+#define MAX_TRAP_MSG 27
+char *trap_msg[] = {
+ "reserved addressing fault", /* 0 T_RESADFLT */
+ "privileged instruction fault", /* 1 T_PRIVINFLT */
+ "reserved operand fault", /* 2 T_RESOPFLT */
+ "breakpoint instruction fault", /* 3 T_BPTFLT */
+ "", /* 4 unused */
+ "system call trap", /* 5 T_SYSCALL */
+ "arithmetic trap", /* 6 T_ARITHTRAP */
+ "system forced exception", /* 7 T_ASTFLT */
+ "segmentation (limit) fault", /* 8 T_SEGFLT */
+ "protection fault", /* 9 T_PROTFLT */
+ "trace trap", /* 10 T_TRCTRAP */
+ "", /* 11 unused */
+ "page fault", /* 12 T_PAGEFLT */
+ "page table fault", /* 13 T_TABLEFLT */
+ "alignment fault", /* 14 T_ALIGNFLT */
+ "kernel stack pointer not valid", /* 15 T_KSPNOTVAL */
+ "bus error", /* 16 T_BUSERR */
+ "kernel debugger fault", /* 17 T_KDBTRAP */
+ "integer divide fault", /* 18 T_DIVIDE */
+ "non-maskable interrupt trap", /* 19 T_NMI */
+ "overflow trap", /* 20 T_OFLOW */
+ "FPU bounds check fault", /* 21 T_BOUND */
+ "FPU device not available", /* 22 T_DNA */
+ "double fault", /* 23 T_DOUBLEFLT */
+ "FPU operand fetch fault", /* 24 T_FPOPFLT */
+ "invalid TSS fault", /* 25 T_TSSFLT */
+ "segment not present fault", /* 26 T_SEGNPFLT */
+ "stack fault", /* 27 T_STKFLT */
+};
+
+#define pde_v(v) (PTD[((v)>>PD_SHIFT)&1023].pd_v)
+
+/*
+ * trap(frame):
+ * Exception, fault, and trap interface to BSD kernel. This
+ * common code is called from assembly language IDT gate entry
+ * routines that prepare a suitable stack frame, and restore this
+ * frame after the exception has been processed. Note that the
+ * effect is as if the arguments were passed call by reference.
+ */
+
+/*ARGSUSED*/
+void
+trap(frame)
+ struct trapframe frame;
+{
+ register int i;
+ register struct proc *p = curproc;
+ struct timeval syst;
+ int ucode, type, code, eva, fault_type;
+
+ frame.tf_eflags &= ~PSL_NT; /* clear nested trap XXX */
+ type = frame.tf_trapno;
+#if NDDB > 0
+ if (curpcb && curpcb->pcb_onfault) {
+ if (frame.tf_trapno == T_BPTFLT
+ || frame.tf_trapno == T_TRCTRAP)
+ if (kdb_trap (type, 0, &frame))
+ return;
+ }
+#endif
+
+ if (curpcb == 0 || curproc == 0)
+ goto skiptoswitch;
+ if (curpcb->pcb_onfault && frame.tf_trapno != T_PAGEFLT) {
+ extern int _udatasel;
+
+ if (read_gs() != (u_short) _udatasel)
+ /*
+ * Some user has corrupted %gs but we depend on it in
+ * copyout() etc. Fix it up and retry.
+ *
+ * (We don't preserve %fs or %gs, so users can change
+ * them to either _ucodesel, _udatasel or a not-present
+ * selector, possibly ORed with 0 to 3, making them
+ * volatile for other users. Not preserving them saves
+ * time and doesn't lose functionality or open security
+ * holes.)
+ */
+ write_gs(_udatasel);
+ else
+copyfault:
+ frame.tf_eip = (int)curpcb->pcb_onfault;
+ return;
+ }
+
+ syst = p->p_stime;
+ if (ISPL(frame.tf_cs) == SEL_UPL) {
+ type |= T_USER;
+ p->p_regs = (int *)&frame;
+ }
+
+skiptoswitch:
+ ucode=0;
+ eva = rcr2();
+ code = frame.tf_err;
+
+ if ((type & ~T_USER) == T_PAGEFLT)
+ goto pfault;
+
+ switch (type) {
+ case T_SEGNPFLT|T_USER:
+ case T_STKFLT|T_USER:
+ case T_PROTFLT|T_USER: /* protection fault */
+ ucode = code + BUS_SEGM_FAULT ;
+ i = SIGBUS;
+ break;
+
+ case T_PRIVINFLT|T_USER: /* privileged instruction fault */
+ case T_RESADFLT|T_USER: /* reserved addressing fault */
+ case T_RESOPFLT|T_USER: /* reserved operand fault */
+ case T_FPOPFLT|T_USER: /* coprocessor operand fault */
+ ucode = type &~ T_USER;
+ i = SIGILL;
+ break;
+
+ case T_ASTFLT|T_USER: /* Allow process switch */
+ astoff();
+ cnt.v_soft++;
+ if ((p->p_flag & SOWEUPC) && p->p_stats->p_prof.pr_scale) {
+ addupc(frame.tf_eip, &p->p_stats->p_prof, 1);
+ p->p_flag &= ~SOWEUPC;
+ }
+ goto out;
+
+ case T_DNA|T_USER:
+#if NNPX > 0
+ /* if a transparent fault (due to context switch "late") */
+ if (npxdna()) return;
+#endif /* NNPX > 0 */
+#if defined(MATH_EMULATE) || defined(GPL_MATH_EMULATE)
+ i = math_emulate(&frame);
+ if (i == 0) return;
+#else /* MATH_EMULATE || GPL_MATH_EMULATE */
+ panic("trap: math emulation necessary!");
+#endif /* MATH_EMULATE || GPL_MATH_EMULATE */
+ ucode = FPE_FPU_NP_TRAP;
+ break;
+
+ case T_BOUND|T_USER:
+ ucode = FPE_SUBRNG_TRAP;
+ i = SIGFPE;
+ break;
+
+ case T_OFLOW|T_USER:
+ ucode = FPE_INTOVF_TRAP;
+ i = SIGFPE;
+ break;
+
+ case T_DIVIDE|T_USER:
+ ucode = FPE_INTDIV_TRAP;
+ i = SIGFPE;
+ break;
+
+ case T_ARITHTRAP|T_USER:
+ ucode = code;
+ i = SIGFPE;
+ break;
+
+ pfault:
+ case T_PAGEFLT: /* allow page faults in kernel mode */
+ case T_PAGEFLT|T_USER: /* page fault */
+ {
+ vm_offset_t va;
+ struct vmspace *vm;
+ vm_map_t map = 0;
+ int rv = 0, oldflags;
+ vm_prot_t ftype;
+ unsigned v;
+ extern vm_map_t kernel_map;
+
+ va = trunc_page((vm_offset_t)eva);
+
+ /*
+ * Don't allow user-mode faults in kernel address space
+ */
+ if ((type == (T_PAGEFLT|T_USER)) && (va >= KERNBASE)) {
+ goto nogo;
+ }
+
+ if ((p == 0) || (type == T_PAGEFLT && va >= KERNBASE)) {
+ vm = 0;
+ map = kernel_map;
+ } else {
+ vm = p->p_vmspace;
+ map = &vm->vm_map;
+ }
+
+ if (code & PGEX_W)
+ ftype = VM_PROT_READ | VM_PROT_WRITE;
+ else
+ ftype = VM_PROT_READ;
+
+ oldflags = p->p_flag;
+ if (map != kernel_map) {
+ vm_offset_t pa;
+ vm_offset_t v = (vm_offset_t) vtopte(va);
+ vm_page_t ptepg;
+
+ /*
+ * Keep swapout from messing with us during this
+ * critical time.
+ */
+ p->p_flag |= SLOCK;
+
+ /*
+ * Grow the stack if necessary
+ */
+ if ((caddr_t)va > vm->vm_maxsaddr
+ && (caddr_t)va < (caddr_t)USRSTACK) {
+ if (!grow(p, va)) {
+ rv = KERN_FAILURE;
+ p->p_flag &= ~SLOCK;
+ p->p_flag |= (oldflags & SLOCK);
+ goto nogo;
+ }
+ }
+
+ /*
+ * Check if page table is mapped, if not,
+ * fault it first
+ */
+
+ /* Fault the pte only if needed: */
+ *(volatile char *)v += 0;
+
+ ptepg = (vm_page_t) pmap_pte_vm_page(vm_map_pmap(map), v);
+ vm_page_hold(ptepg);
+
+ /* Fault in the user page: */
+ rv = vm_fault(map, va, ftype, FALSE);
+
+ vm_page_unhold(ptepg);
+
+ /*
+ * page table pages don't need to be kept if they
+ * are not held
+ */
+ if( ptepg->hold_count == 0 && ptepg->wire_count == 0) {
+ pmap_page_protect( VM_PAGE_TO_PHYS(ptepg),
+ VM_PROT_NONE);
+ if( ptepg->flags & PG_CLEAN)
+ vm_page_free(ptepg);
+ }
+
+
+ p->p_flag &= ~SLOCK;
+ p->p_flag |= (oldflags & SLOCK);
+ } else {
+ /*
+ * Since we know that kernel virtual address addresses
+ * always have pte pages mapped, we just have to fault
+ * the page.
+ */
+ rv = vm_fault(map, va, ftype, FALSE);
+ }
+
+ if (rv == KERN_SUCCESS) {
+ if (type == T_PAGEFLT)
+ return;
+ goto out;
+ }
+nogo:
+ if (type == T_PAGEFLT) {
+ if (curpcb->pcb_onfault)
+ goto copyfault;
+
+ goto we_re_toast;
+ }
+ i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV;
+
+ /* kludge to pass faulting virtual address to sendsig */
+ ucode = type &~ T_USER;
+ frame.tf_err = eva;
+
+ break;
+ }
+
+#if NDDB == 0
+ case T_TRCTRAP: /* trace trap -- someone single stepping lcall's */
+ frame.tf_eflags &= ~PSL_T;
+
+ /* Q: how do we turn it on again? */
+ return;
+#endif
+
+ case T_BPTFLT|T_USER: /* bpt instruction fault */
+ case T_TRCTRAP|T_USER: /* trace trap */
+ frame.tf_eflags &= ~PSL_T;
+ i = SIGTRAP;
+ break;
+
+#if NISA > 0
+ case T_NMI:
+ case T_NMI|T_USER:
+#if NDDB > 0
+ /* NMI can be hooked up to a pushbutton for debugging */
+ printf ("NMI ... going to debugger\n");
+ if (kdb_trap (type, 0, &frame))
+ return;
+#endif
+ /* machine/parity/power fail/"kitchen sink" faults */
+ if (isa_nmi(code) == 0) return;
+ /* FALL THROUGH */
+#endif
+ default:
+ we_re_toast:
+
+ fault_type = type & ~T_USER;
+#if NDDB > 0
+ if ((fault_type == T_BPTFLT) || (fault_type == T_TRCTRAP)) {
+ if (kdb_trap (type, 0, &frame))
+ return;
+ }
+#endif
+ if (fault_type <= MAX_TRAP_MSG)
+ printf("\n\nFatal trap %d: %s while in %s mode\n",
+ fault_type, trap_msg[fault_type],
+ ISPL(frame.tf_cs) == SEL_UPL ? "user" : "kernel");
+ if (fault_type == T_PAGEFLT) {
+ printf("fault virtual address = 0x%x\n", eva);
+ printf("fault code = %s %s, %s\n",
+ code & PGEX_U ? "user" : "supervisor",
+ code & PGEX_W ? "write" : "read",
+ code & PGEX_P ? "protection violation" : "page not present");
+ }
+ printf("instruction pointer = 0x%x\n", frame.tf_eip);
+ printf("processor eflags = ");
+ if (frame.tf_eflags & EFL_TF)
+ printf("trace/trap, ");
+ if (frame.tf_eflags & EFL_IF)
+ printf("interrupt enabled, ");
+ if (frame.tf_eflags & EFL_NT)
+ printf("nested task, ");
+ if (frame.tf_eflags & EFL_RF)
+ printf("resume, ");
+ if (frame.tf_eflags & EFL_VM)
+ printf("vm86, ");
+ printf("IOPL = %d\n", (frame.tf_eflags & EFL_IOPL) >> 12);
+ printf("current process = ");
+ if (curproc) {
+ printf("%d (%s)\n",
+ curproc->p_pid, curproc->p_comm ?
+ curproc->p_comm : "");
+ } else {
+ printf("Idle\n");
+ }
+ printf("interrupt mask = ");
+ if ((cpl & net_imask) == net_imask)
+ printf("net ");
+ if ((cpl & tty_imask) == tty_imask)
+ printf("tty ");
+ if ((cpl & bio_imask) == bio_imask)
+ printf("bio ");
+ if (cpl == 0)
+ printf("none");
+ printf("\n");
+
+#ifdef KDB
+ if (kdb_trap(&psl))
+ return;
+#endif
+#if NDDB > 0
+ if (kdb_trap (type, 0, &frame))
+ return;
+#endif
+ if (fault_type <= MAX_TRAP_MSG)
+ panic(trap_msg[fault_type]);
+ else
+ panic("unknown/reserved trap");
+
+ /* NOTREACHED */
+ }
+
+ trapsignal(p, i, ucode);
+ if ((type & T_USER) == 0)
+ return;
+
+#ifdef DIAGNOSTIC
+ fault_type = type & ~T_USER;
+ if (fault_type <= MAX_TRAP_MSG) {
+ uprintf("fatal process exception: %s",
+ trap_msg[fault_type]);
+ if ((fault_type == T_PAGEFLT) || (fault_type == T_PROTFLT))
+ uprintf(", fault VA = 0x%x", eva);
+ uprintf("\n");
+ }
+#endif
+
+out:
+ while (i = CURSIG(p))
+ psig(i);
+ p->p_pri = p->p_usrpri;
+ if (want_resched) {
+ int s;
+ /*
+ * Since we are curproc, clock will normally just change
+ * our priority without moving us from one queue to another
+ * (since the running process is not on a queue.)
+ * If that happened after we setrq ourselves but before we
+ * swtch()'ed, we might not be on the queue indicated by
+ * our priority.
+ */
+ s = splclock();
+ setrq(p);
+ p->p_stats->p_ru.ru_nivcsw++;
+ swtch();
+ splx(s);
+ while (i = CURSIG(p))
+ psig(i);
+ }
+ if (p->p_stats->p_prof.pr_scale) {
+ int ticks;
+ struct timeval *tv = &p->p_stime;
+
+ ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
+ (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
+ if (ticks) {
+#ifdef PROFTIMER
+ extern int profscale;
+ addupc(frame.tf_eip, &p->p_stats->p_prof,
+ ticks * profscale);
+#else
+ addupc(frame.tf_eip, &p->p_stats->p_prof, ticks);
+#endif
+ }
+ }
+ curpri = p->p_pri;
+}
+
+/*
+ * Compensate for 386 brain damage (missing URKR).
+ * This is a little simpler than the pagefault handler in trap() because
+ * it the page tables have already been faulted in and high addresses
+ * are thrown out early for other reasons.
+ */
+int trapwrite(addr)
+ unsigned addr;
+{
+ struct proc *p;
+ vm_offset_t va, v;
+ struct vmspace *vm;
+ int oldflags;
+ int rv;
+
+ va = trunc_page((vm_offset_t)addr);
+ /*
+ * XXX - MAX is END. Changed > to >= for temp. fix.
+ */
+ if (va >= VM_MAXUSER_ADDRESS)
+ return (1);
+
+ p = curproc;
+ vm = p->p_vmspace;
+
+ oldflags = p->p_flag;
+ p->p_flag |= SLOCK;
+
+ if ((caddr_t)va >= vm->vm_maxsaddr
+ && (caddr_t)va < (caddr_t)USRSTACK) {
+ if (!grow(p, va)) {
+ p->p_flag &= ~SLOCK;
+ p->p_flag |= (oldflags & SLOCK);
+ return (1);
+ }
+ }
+
+ v = trunc_page(vtopte(va));
+
+ /*
+ * wire the pte page
+ */
+ if (va < USRSTACK) {
+ vm_map_pageable(&vm->vm_map, v, round_page(v+1), FALSE);
+ }
+
+ /*
+ * fault the data page
+ */
+ rv = vm_fault(&vm->vm_map, va, VM_PROT_READ|VM_PROT_WRITE, FALSE);
+
+ /*
+ * unwire the pte page
+ */
+ if (va < USRSTACK) {
+ vm_map_pageable(&vm->vm_map, v, round_page(v+1), TRUE);
+ }
+
+ p->p_flag &= ~SLOCK;
+ p->p_flag |= (oldflags & SLOCK);
+
+ if (rv != KERN_SUCCESS)
+ return 1;
+
+ return (0);
+}
+
+/*
+ * syscall(frame):
+ * System call request from POSIX system call gate interface to kernel.
+ * Like trap(), argument is call by reference.
+ */
+/*ARGSUSED*/
+void
+syscall(frame)
+ volatile struct trapframe frame;
+{
+ register int *locr0 = ((int *)&frame);
+ register caddr_t params;
+ register int i;
+ register struct sysent *callp;
+ register struct proc *p = curproc;
+ struct timeval syst;
+ int error, opc;
+ int args[8], rval[2];
+ int code;
+
+#ifdef lint
+ r0 = 0; r0 = r0; r1 = 0; r1 = r1;
+#endif
+ syst = p->p_stime;
+ if (ISPL(frame.tf_cs) != SEL_UPL)
+ panic("syscall");
+
+ code = frame.tf_eax;
+ p->p_regs = (int *)&frame;
+ params = (caddr_t)frame.tf_esp + sizeof (int) ;
+
+ /*
+ * Reconstruct pc, assuming lcall $X,y is 7 bytes, as it is always.
+ */
+ opc = frame.tf_eip - 7;
+ if (code == 0) {
+ code = fuword(params);
+ params += sizeof (int);
+ }
+ if (code < 0 || code >= nsysent)
+ callp = &sysent[0];
+ else
+ callp = &sysent[code];
+
+ if ((i = callp->sy_narg * sizeof (int)) &&
+ (error = copyin(params, (caddr_t)args, (u_int)i))) {
+ frame.tf_eax = error;
+ frame.tf_eflags |= PSL_C; /* carry bit */
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSCALL))
+ ktrsyscall(p->p_tracep, code, callp->sy_narg, args);
+#endif
+ goto done;
+ }
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSCALL))
+ ktrsyscall(p->p_tracep, code, callp->sy_narg, args);
+#endif
+ rval[0] = 0;
+ rval[1] = frame.tf_edx;
+/*pg("%d. s %d\n", p->p_pid, code);*/
+ error = (*callp->sy_call)(p, args, rval);
+ if (error == ERESTART)
+ frame.tf_eip = opc;
+ else if (error != EJUSTRETURN) {
+ if (error) {
+/*pg("error %d", error);*/
+ frame.tf_eax = error;
+ frame.tf_eflags |= PSL_C; /* carry bit */
+ } else {
+ frame.tf_eax = rval[0];
+ frame.tf_edx = rval[1];
+ frame.tf_eflags &= ~PSL_C; /* carry bit */
+ }
+ }
+ /* else if (error == EJUSTRETURN) */
+ /* nothing to do */
+done:
+ /*
+ * Reinitialize proc pointer `p' as it may be different
+ * if this is a child returning from fork syscall.
+ */
+ p = curproc;
+ while (i = CURSIG(p))
+ psig(i);
+ p->p_pri = p->p_usrpri;
+ if (want_resched) {
+ int s;
+ /*
+ * Since we are curproc, clock will normally just change
+ * our priority without moving us from one queue to another
+ * (since the running process is not on a queue.)
+ * If that happened after we setrq ourselves but before we
+ * swtch()'ed, we might not be on the queue indicated by
+ * our priority.
+ */
+ s = splclock();
+ setrq(p);
+ p->p_stats->p_ru.ru_nivcsw++;
+ swtch();
+ splx(s);
+ while (i = CURSIG(p))
+ psig(i);
+ }
+ if (p->p_stats->p_prof.pr_scale) {
+ int ticks;
+ struct timeval *tv = &p->p_stime;
+
+ ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
+ (tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
+ if (ticks) {
+#ifdef PROFTIMER
+ extern int profscale;
+ addupc(frame.tf_eip, &p->p_stats->p_prof,
+ ticks * profscale);
+#else
+ addupc(frame.tf_eip, &p->p_stats->p_prof, ticks);
+#endif
+ }
+ }
+ curpri = p->p_pri;
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSRET))
+ ktrsysret(p->p_tracep, code, error, rval[0]);
+#endif
+#ifdef DIAGNOSTICx
+{ extern int _udatasel, _ucodesel;
+ if (frame.tf_ss != _udatasel)
+ printf("ss %x call %d\n", frame.tf_ss, code);
+ if ((frame.tf_cs&0xffff) != _ucodesel)
+ printf("cs %x call %d\n", frame.tf_cs, code);
+ if (frame.tf_eip > VM_MAXUSER_ADDRESS) {
+ printf("eip %x call %d\n", frame.tf_eip, code);
+ frame.tf_eip = 0;
+ }
+}
+#endif
+}
diff --git a/sys/kern/tty_cons.c b/sys/kern/tty_cons.c
new file mode 100644
index 0000000..f5fc887
--- /dev/null
+++ b/sys/kern/tty_cons.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)cons.c 7.2 (Berkeley) 5/9/91
+ * $Id: cons.c,v 1.10 1994/01/23 19:17:17 davidg Exp $
+ */
+
+
+#include "sys/param.h"
+#include "sys/proc.h"
+#include "sys/user.h"
+#include "sys/systm.h"
+#include "sys/buf.h"
+#include "sys/ioctl.h"
+#include "sys/tty.h"
+#include "sys/file.h"
+#include "sys/conf.h"
+#include "sys/vnode.h"
+#include "machine/stdarg.h"
+
+#include "machine/cons.h"
+
+/* XXX - all this could be autoconfig()ed */
+int pccnprobe(), pccninit(), pccngetc(), pccnputc();
+
+#include "sio.h"
+#if NSIO > 0
+int siocnprobe(), siocninit(), siocngetc(), siocnputc();
+#endif
+
+#include "com.h"
+#if NCOM > 0
+int comcnprobe(), comcninit(), comcngetc(), comcnputc();
+#endif
+
+struct consdev constab[] = {
+ { pccnprobe, pccninit, pccngetc, pccnputc },
+#if NSIO > 0
+ { siocnprobe, siocninit, siocngetc, siocnputc },
+#endif
+#if NCOM > 0
+ { comcnprobe, comcninit, comcngetc, comcnputc },
+#endif
+ { 0 },
+};
+/* end XXX */
+
+struct tty *constty = 0; /* virtual console output device */
+struct consdev *cn_tab; /* physical console device info */
+struct tty *cn_tty; /* XXX: console tty struct for tprintf */
+
+void
+cninit()
+{
+ register struct consdev *cp;
+
+ /*
+ * Collect information about all possible consoles
+ * and find the one with highest priority
+ */
+ for (cp = constab; cp->cn_probe; cp++) {
+ (*cp->cn_probe)(cp);
+ if (cp->cn_pri > CN_DEAD &&
+ (cn_tab == NULL || cp->cn_pri > cn_tab->cn_pri))
+ cn_tab = cp;
+ }
+ /*
+ * No console, we can handle it
+ */
+ if ((cp = cn_tab) == NULL)
+ return;
+ /*
+ * Turn on console
+ */
+ cn_tty = cp->cn_tp;
+ (*cp->cn_init)(cp);
+}
+
+int
+cnopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ struct vnode *vp = 0;
+
+ if (cn_tab == NULL)
+ return (0);
+
+ dev = cn_tab->cn_dev;
+ if ((vfinddev(dev, VCHR, &vp) == 0) && vcount(vp))
+ return (0);
+
+ return ((*cdevsw[major(dev)].d_open)(dev, flag, mode, p));
+}
+
+int
+cnclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ struct vnode *vp = 0;
+
+ if (cn_tab == NULL)
+ return (0);
+
+ dev = cn_tab->cn_dev;
+ if ((vfinddev(dev, VCHR, &vp) == 0) && vcount(vp))
+ return (0);
+
+ return ((*cdevsw[major(dev)].d_close)(dev, flag, mode, p));
+}
+
+int
+cnread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ if (cn_tab == NULL)
+ return (0);
+ dev = cn_tab->cn_dev;
+ return ((*cdevsw[major(dev)].d_read)(dev, uio, flag));
+}
+
+int
+cnwrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ if (cn_tab == NULL)
+ return (0);
+ if (constty)
+ dev = constty->t_dev;
+ else
+ dev = cn_tab->cn_dev;
+ return ((*cdevsw[major(dev)].d_write)(dev, uio, flag));
+}
+
+int
+cnioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ int error;
+
+ if (cn_tab == NULL)
+ return (0);
+ /*
+ * Superuser can always use this to wrest control of console
+ * output from the "virtual" console.
+ */
+ if (cmd == TIOCCONS && constty) {
+ error = suser(p->p_ucred, (u_short *) NULL);
+ if (error)
+ return (error);
+ constty = NULL;
+ return (0);
+ }
+ dev = cn_tab->cn_dev;
+ return ((*cdevsw[major(dev)].d_ioctl)(dev, cmd, data, flag, p));
+}
+
+/*ARGSUSED*/
+int
+cnselect(dev, rw, p)
+ dev_t dev;
+ int rw;
+ struct proc *p;
+{
+ if (cn_tab == NULL)
+ return (1);
+ return (ttselect(cn_tab->cn_dev, rw, p));
+}
+
+int
+cngetc()
+{
+ if (cn_tab == NULL)
+ return (0);
+ return ((*cn_tab->cn_getc)(cn_tab->cn_dev));
+}
+
+void
+cnputc(c)
+ register int c;
+{
+ if (cn_tab == NULL)
+ return;
+ if (c) {
+ (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
+ if (c == '\n')
+ (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
+ }
+}
+
+int
+pg(const char *p, ...) {
+ va_list args;
+ va_start(args, p);
+ printf("%r\n>", p, args);
+ return(cngetc());
+}
+
+
diff --git a/sys/powerpc/include/_limits.h b/sys/powerpc/include/_limits.h
new file mode 100644
index 0000000..5aed870
--- /dev/null
+++ b/sys/powerpc/include/_limits.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)limits.h 7.2 (Berkeley) 6/28/90
+ * $Id: limits.h,v 1.5 1994/02/26 00:56:02 ache Exp $
+ */
+
+#ifndef _MACHINE_LIMITS_H_
+#define _MACHINE_LIMITS_H_ 1
+
+#define CHAR_BIT 8 /* number of bits in a char */
+#define MB_LEN_MAX 6 /* allow 21-bit UTF2 */
+
+#define SCHAR_MIN (-0x7f-1) /* max value for a signed char */
+#define SCHAR_MAX 0x7f /* min value for a signed char */
+
+#define UCHAR_MAX 0xff /* max value for an unsigned char */
+#define CHAR_MAX 0x7f /* max value for a char */
+#define CHAR_MIN (-0x7f-1) /* min value for a char */
+
+#define USHRT_MAX 0xffff /* max value for an unsigned short */
+#define SHRT_MAX 0x7fff /* max value for a short */
+#define SHRT_MIN (-0x7fff-1) /* min value for a short */
+
+#define UINT_MAX 0xffffffff /* max value for an unsigned int */
+#define INT_MAX 0x7fffffff /* max value for an int */
+#define INT_MIN (-0x7fffffff-1) /* min value for an int */
+
+#define ULONG_MAX 0xffffffff /* max value for an unsigned long */
+#define LONG_MAX 0x7fffffff /* max value for a long */
+#define LONG_MIN (-0x7fffffff-1) /* min value for a long */
+
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+#define CLK_TCK 128 /* ticks per second */
+#define UQUAD_MAX 0xffffffffffffffffLL /* max unsigned quad */
+#define QUAD_MAX 0x7fffffffffffffffLL /* max signed quad */
+#define QUAD_MIN (-0x7fffffffffffffffLL-1) /* min signed quad */
+#endif
+
+#endif /* _MACHINE_LIMITS_H_ */
diff --git a/sys/powerpc/include/limits.h b/sys/powerpc/include/limits.h
new file mode 100644
index 0000000..5aed870
--- /dev/null
+++ b/sys/powerpc/include/limits.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)limits.h 7.2 (Berkeley) 6/28/90
+ * $Id: limits.h,v 1.5 1994/02/26 00:56:02 ache Exp $
+ */
+
+#ifndef _MACHINE_LIMITS_H_
+#define _MACHINE_LIMITS_H_ 1
+
+#define CHAR_BIT 8 /* number of bits in a char */
+#define MB_LEN_MAX 6 /* allow 21-bit UTF2 */
+
+#define SCHAR_MIN (-0x7f-1) /* max value for a signed char */
+#define SCHAR_MAX 0x7f /* min value for a signed char */
+
+#define UCHAR_MAX 0xff /* max value for an unsigned char */
+#define CHAR_MAX 0x7f /* max value for a char */
+#define CHAR_MIN (-0x7f-1) /* min value for a char */
+
+#define USHRT_MAX 0xffff /* max value for an unsigned short */
+#define SHRT_MAX 0x7fff /* max value for a short */
+#define SHRT_MIN (-0x7fff-1) /* min value for a short */
+
+#define UINT_MAX 0xffffffff /* max value for an unsigned int */
+#define INT_MAX 0x7fffffff /* max value for an int */
+#define INT_MIN (-0x7fffffff-1) /* min value for an int */
+
+#define ULONG_MAX 0xffffffff /* max value for an unsigned long */
+#define LONG_MAX 0x7fffffff /* max value for a long */
+#define LONG_MIN (-0x7fffffff-1) /* min value for a long */
+
+#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE)
+#define CLK_TCK 128 /* ticks per second */
+#define UQUAD_MAX 0xffffffffffffffffLL /* max unsigned quad */
+#define QUAD_MAX 0x7fffffffffffffffLL /* max signed quad */
+#define QUAD_MIN (-0x7fffffffffffffffLL-1) /* min signed quad */
+#endif
+
+#endif /* _MACHINE_LIMITS_H_ */
diff --git a/sys/scsi/README b/sys/scsi/README
new file mode 100644
index 0000000..b110930
--- /dev/null
+++ b/sys/scsi/README
@@ -0,0 +1,196 @@
+This release consists of the following files
+(relative to the base of the source tree )
+
+share/man/man4/scsi.4 <-useful general info
+share/man/man4/uk.4
+share/man/man4/su.4
+share/man/man4/ch.4
+share/man/man4/cd.4
+share/man/man4/sd.4
+share/man/man4/st.4 <--READ THIS IF YOU USE TAPES!
+sbin/scsi/procargs.c
+sbin/scsi/scsi.c
+sbin/scsi/scsi.1
+sbin/scsi/Makefile
+sbin/st/Makefile
+sbin/st/st.1
+sbin/st/st.c
+sys/sys/chio.h
+sys/sys/cdio.h
+sys/sys/mtio.h
+sys/sys/scsiio.h
+sys/i386/conf/EXAMPLE
+sys/i386/isa/ultra14f.c <-runs 14f and 34f
+sys/i386/isa/ultra_all.c.beta <-beta version, runs 14f,24f and 34f
+sys/i386/isa/bt742a.c
+sys/i386/isa/aha1742.c
+sys/i386/isa/aha1542.c
+sys/scsi/syspatches
+sys/scsi/syspatches/conf.c
+sys/scsi/syspatches/user_scsi.diffs
+sys/scsi/syspatches/MAKEDEV.diff
+sys/scsi/syspatches/isa.c.patch
+sys/scsi/syspatches/README
+sys/scsi/uk.c
+sys/scsi/su.c
+sys/scsi/st.c
+sys/scsi/sd.c
+sys/scsi/ch.c
+sys/scsi/cd.c
+sys/scsi/scsi_ioctl.c
+sys/scsi/scsi_base.c
+sys/scsi/scsiconf.c
+sys/scsi/scsi_tape.h
+sys/scsi/scsi_disk.h
+sys/scsi/scsi_changer.h
+sys/scsi/scsi_cd.h
+sys/scsi/scsi_all.h
+sys/scsi/scsi_debug.h
+sys/scsi/scsiconf.h
+sys/scsi/README <--this file
+
+notice sys/scsi/sg.c and sys/sys/sgio.h have been removed
+
+
+----------------------------------------------------------------
+This scsi system is designed to allow the re-use of top end drivers
+such as disk and tape drivers, with different scsi adapters.
+
+As of writing this document, There are top end drivers working for:
+----------------------------------------------------------------
+generic scsi disk
+generic scsi tape
+cd-rom (plays music under the xcplayer (?) program)
+AEG Character recognition devices *
+Calera Character recognition devices *
+Generic scsi-II scanners *
+Exabyte tape changer device.
+GENERIC SCSI DEVICES (user generated scsi commands)
+----------------------------------------------------------------
+
+
+There are also working bottom end drivers for:
+----------------------------------------------------------------
+adaptec 1542 (and 1742 in 1542 mode)
+bustec 742a (apparently works for VESA version (445S?))(and 747?)
+adaptec 174x (note NOT 27xx)
+Ultrastore 14f (works for 34f (VESA version))
+Ultrastore 24f RSN (Beta version included here)
+----------------------------------------------------------------
+
+
+################## Using the scsi system ##################
+------------minor numbers---------------
+This scsi system does not allocate minor numbers to devices depending
+on their SCSI IDs is any way. A devices minor number is dependant
+on the order in which it was found.
+e.g. the first tape found will become st0 (minor number 0)
+ the second found will become st1 (minor number 16)
+ the third will become st2 (minor 32)
+ etc.
+
+These devices could be on the same scsi bus or different scsi busses.
+That would not change their minor numbers.
+
+THE EXCEPTION TO THIS IS IN THE GENERIC SCSI DRIVER. in which case
+the following mapping applies:
+
+BB TTT LLL B= scsi bus number, T = target number, L = LUN.
+
+It is possible to run two different TYPES of scsi adapters at the
+same time and have st0 on one and st1 on another. (for example)
+
+There is a scheme supported in which scsi devices can be 'wired in' even
+if they are not present or powered on at probe time. (see scsiconf.c)
+In addition, the scsi(1) command allows the operator ask for a
+reprobe at any time. Newly found devices will be configured in. Any
+device that does not map to a known device type is attached to the
+'unknown' (uk) driver.
+
+
+--------------making devices------------
+A changed version of /dev/MAKEDEV is supplied that
+can be used to make devices sd[01234] and st[01234]
+
+e.g.
+cd /dev
+sh MAKEDEV sd0 sd1 sd2 st0 st1 cd0
+
+see st(1) and st(4) for info on tape devices.
+
+--------------file layout-------------------
+Originally I had all scsi definitions in one file: scsi.h
+I have since moved definitions of commands so that all
+definitions needed for a particular type of device are
+found together in the include file of that name.
+This approximatly follows the layout of their definition
+in the SCSI-2 spec.
+As such they are:
+
+scsi_all.h general commands for all devices --- CHAPTER 7
+scsi-disk.h commands relevant to disk --- CHAPTER 8
+scsi-tape.h commands for scsi tapes --- CHAPTER 9
+scsi-cd.h commands for cd-roms (and audio) --- CHAPTER 13
+scsi-changer.h commands medium changer devices --- CHAPTER 16
+
+---------ioctl definitions-------------
+User accessable structures (e.g. ioctl definitions) have been
+placed in sys/cdio, sys/sgio and sys/chio (based after sys/mtio for
+the ioctls for mag tapes (including st).
+General scsi ioctls are found in sys/scsiio.h.
+
+-----------cd-rom-----------------
+The cd rom driver ha been tested by a number of people and
+grefen@convex.com has completed the audio play
+functions.
+(xcdplayer was available from the 'from_ref' directory on agate)
+
+At this time it is possible audio play is broken on cdroms and I will
+be unable to fix it until I get one to test.
+***IMPORTANT***
+Cdrom audio is only suported at all for cdroms that use SCSI2 audio
+definitions.
+
+-------------media changer---------------
+Once again courtesy of grefen@convex.com (in germany)
+I have not tested this but he assures me it's ready for testing.
+If anyone has an exabyte tape changer or similar,
+contact the author for information regarding the control interface
+and program.
+
+WARNING: This has not been tested for a LONG TIME!
+
+
+---------recent changes-----------
+Removed all bitfields from machine independent sections to make
+it possible for them to be used on big-endian architectures.
+
+Removed scsi specific timeouts in favour of system timeout handling.
+
+Many structures (getting more all the time) now dynamically allocated.
+
+Addition of code in the tape driver to recognise models of drive that
+have particular problems so they can be handled specially.
+
+many bug-fixes and cleanups.
+
+---------even more recent changes:--------
+
+rewrote almost the entire thing..
+
+
+
+------Mon Oct 11 22:20:25 WST 1993------
+
+Code is now all KNF (or close to it).
+
+A new structure has been introduced..
+Called scsi_link, one of these exists for every bus/target/lun
+that has a driver attached to it.
+It has links to the adapter and to the driver, as well as status
+information of global interest. (e.g. if the device is in use).
+The use of this new structure has allowed the compaction of a
+lot of duplicated code into a single copy (now in scsi_base.c)
+and makes more simple the USER level scsi implimentation.
+
+
diff --git a/sys/scsi/cd.c b/sys/scsi/cd.c
new file mode 100644
index 0000000..0d64665
--- /dev/null
+++ b/sys/scsi/cd.c
@@ -0,0 +1,1317 @@
+/*
+ * Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems for use under the MACH(2.5) operating system.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * $Id: cd.c,v 1.17 1994/03/23 09:15:51 davidg Exp $
+ */
+
+#define SPLCD splbio
+#define ESUCCESS 0
+#include <cd.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/dkbad.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/buf.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+#include <sys/cdio.h>
+
+#include <sys/errno.h>
+#include <sys/disklabel.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsi_cd.h>
+#include <scsi/scsi_disk.h> /* rw_big and start_stop come from there */
+#include <scsi/scsiconf.h>
+
+/* static function prototypes */
+static errval cd_get_parms(int, int);
+static errval cd_get_mode(u_int32, struct cd_mode_data *, u_int32);
+static errval cd_set_mode(u_int32 unit, struct cd_mode_data *);
+static errval cd_read_toc(u_int32, u_int32, u_int32, struct cd_toc_entry *,
+ u_int32);
+
+
+int32 cdstrats, cdqueues;
+
+#include <ddb.h>
+#if NDDB > 0
+#else /* NDDB > 0 */
+#define Debugger()
+#endif /* NDDB > 0 */
+
+#define PAGESIZ 4096
+#define SECSIZE 2048 /* XXX */ /* default only */
+#define CDOUTSTANDING 2
+#define CDRETRIES 1
+
+#define UNITSHIFT 3
+#define PARTITION(z) (minor(z) & 0x07)
+#define RAW_PART 3
+#define UNIT(z) ( (minor(z) >> UNITSHIFT) )
+
+errval cdstrategy();
+
+void cdstart();
+struct scsi_device cd_switch =
+{
+ NULL, /* use default error handler */
+ cdstart, /* we have a queue, which is started by this */
+ NULL, /* we do not have an async handler */
+ NULL, /* use default 'done' routine */
+ "cd", /* we are to be refered to by this name */
+ 0, /* no device specific flags */
+ 0, 0 /* spares not used */
+};
+
+struct cd_data {
+ u_int32 flags;
+#define CDINIT 0x04 /* device has been init'd */
+ struct scsi_link *sc_link; /* address of scsi low level switch */
+ u_int32 cmdscount; /* cmds allowed outstanding by board */
+ struct cd_parms {
+ u_int32 blksize;
+ u_long disksize; /* total number sectors */
+ } params;
+ struct disklabel disklabel;
+ u_int32 partflags[MAXPARTITIONS]; /* per partition flags */
+#define CDOPEN 0x01
+ u_int32 openparts; /* one bit for each open partition */
+ u_int32 xfer_block_wait;
+ struct buf buf_queue;
+};
+
+#define CD_STOP 0
+#define CD_START 1
+#define CD_EJECT -2
+
+struct cd_driver {
+ u_int32 size;
+ struct cd_data **cd_data;
+} cd_driver;
+
+static u_int32 next_cd_unit = 0;
+
+/*
+ * The routine called by the low level scsi routine when it discovers
+ * A device suitable for this driver
+ */
+int
+cdattach(sc_link)
+ struct scsi_link *sc_link;
+{
+ u_int32 unit, i;
+ unsigned char *tbl;
+ struct cd_data *cd, **cdrealloc;
+ struct cd_parms *dp;
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("cdattach "));
+
+ /*
+ * Fill out any more info in the
+ * Link structure that we can
+ */
+ unit = next_cd_unit++;
+ sc_link->device = &cd_switch;
+ sc_link->dev_unit = unit;
+ /*
+ * allocate the resources for another drive
+ * if we have already allocate a cd_data pointer we must
+ * copy the old pointers into a new region that is
+ * larger and release the old region, aka realloc
+ */
+ /* XXX
+ * This if will always be true for now, but future code may
+ * preallocate more units to reduce overhead. This would be
+ * done by changing the malloc to be (next_cd_unit * x) and
+ * the cd_driver.size++ to be +x
+ */
+ if (unit >= cd_driver.size) {
+ cdrealloc =
+ malloc(sizeof(cd_driver.cd_data) * next_cd_unit,
+ M_DEVBUF, M_NOWAIT);
+ if (!cdrealloc) {
+ printf("cd%d: malloc failed for cdrealloc\n", unit);
+ return (0);
+ }
+ /* Make sure we have something to copy before we copy it */
+ bzero(cdrealloc, sizeof(cd_driver.cd_data) * next_cd_unit);
+ if (cd_driver.size) {
+ bcopy(cd_driver.cd_data, cdrealloc,
+ sizeof(cd_driver.cd_data) * cd_driver.size);
+ free(cd_driver.cd_data, M_DEVBUF);
+ }
+ cd_driver.cd_data = cdrealloc;
+ cd_driver.cd_data[unit] = NULL;
+ cd_driver.size++;
+ }
+ if (cd_driver.cd_data[unit]) {
+ printf("cd%d: Already has storage!\n", unit);
+ return (0);
+ }
+ /*
+ * allocate the per drive data area
+ */
+ cd = cd_driver.cd_data[unit] =
+ malloc(sizeof(struct cd_data), M_DEVBUF, M_NOWAIT);
+ if (!cd) {
+ printf("cd%d: malloc failed for cd_data\n", unit);
+ return (0);
+ }
+ bzero(cd, sizeof(struct cd_data));
+ dp = &(cd->params);
+ /*
+ * Store information needed to contact our base driver
+ */
+ cd->sc_link = sc_link;
+ /* only allow 1 outstanding command on tapes */
+ sc_link->opennings = cd->cmdscount = CDOUTSTANDING;
+
+ /*
+ * Use the subdriver to request information regarding
+ * the drive. We cannot use interrupts yet, so the
+ * request must specify this.
+ */
+ cd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK);
+ if (dp->disksize) {
+ printf("cd%d: cd present.[%d x %d byte records]\n",
+ unit,
+ cd->params.disksize,
+ cd->params.blksize);
+ } else {
+ printf("cd%d: drive empty\n", unit);
+ }
+ cd->flags |= CDINIT;
+ return (1);
+}
+
+/*
+ * open the device. Make sure the partition info is a up-to-date as can be.
+ */
+errval
+cdopen(dev)
+ dev_t dev;
+{
+ errval errcode = 0;
+ u_int32 unit, part;
+ struct cd_parms cd_parms;
+ struct cd_data *cd;
+ struct scsi_link *sc_link;
+ u_int32 heldflags;
+
+ unit = UNIT(dev);
+ part = PARTITION(dev);
+
+ /*
+ * Check the unit is legal
+ */
+ if (unit >= cd_driver.size) {
+ return (ENXIO);
+ }
+ cd = cd_driver.cd_data[unit];
+ /*
+ * Make sure the device has been initialised
+ */
+ if ((cd == NULL) || (!(cd->flags & CDINIT)))
+ return (ENXIO);
+
+ sc_link = cd->sc_link;
+ SC_DEBUG(sc_link, SDEV_DB1,
+ ("cdopen: dev=0x%x (unit %d (of %d),partition %d)\n",
+ dev, unit, cd_driver.size, part));
+ /*
+ * If it's been invalidated, and not everybody has closed it then
+ * forbid re-entry. (may have changed media)
+ */
+ if ((!(sc_link->flags & SDEV_MEDIA_LOADED))
+ && (cd->openparts))
+ return (ENXIO);
+
+ /*
+ * Check that it is still responding and ok.
+ * if the media has been changed this will result in a
+ * "unit attention" error which the error code will
+ * disregard because the SDEV_MEDIA_LOADED flag is not yet set
+ */
+ scsi_test_unit_ready(sc_link, SCSI_SILENT);
+
+ /*
+ * Next time actually take notice of error returns
+ */
+ sc_link->flags |= SDEV_OPEN; /* unit attn errors are now errors */
+ if (scsi_test_unit_ready(sc_link, SCSI_SILENT) != 0) {
+ SC_DEBUG(sc_link, SDEV_DB3, ("not ready\n"));
+ errcode = ENXIO;
+ goto bad;
+ }
+ SC_DEBUG(sc_link, SDEV_DB3, ("Device present\n"));
+ /*
+ * In case it is a funny one, tell it to start
+ * not needed for some drives
+ */
+ scsi_start_unit(sc_link, CD_START);
+ scsi_prevent(sc_link, PR_PREVENT, SCSI_SILENT);
+ SC_DEBUG(sc_link, SDEV_DB3, ("started "));
+ /*
+ * Load the physical device parameters
+ */
+ if (cd_get_parms(unit, 0)) {
+ errcode = ENXIO;
+ goto bad;
+ }
+ SC_DEBUG(sc_link, SDEV_DB3, ("Params loaded "));
+ /*
+ * Make up some partition information
+ */
+ cdgetdisklabel(unit);
+ SC_DEBUG(sc_link, SDEV_DB3, ("Disklabel fabricated "));
+ /*
+ * Check the partition is legal
+ */
+ if ((part >= cd->disklabel.d_npartitions)
+ && (part != RAW_PART)) {
+ SC_DEBUG(sc_link, SDEV_DB3, ("partition %d > %d\n", part
+ ,cd->disklabel.d_npartitions));
+ errcode = ENXIO;
+ goto bad;
+ }
+ /*
+ * Check that the partition exists
+ */
+ if ((cd->disklabel.d_partitions[part].p_fstype == FS_UNUSED)
+ && (part != RAW_PART)) {
+ SC_DEBUG(sc_link, SDEV_DB3, ("part %d type UNUSED\n", part));
+ errcode = ENXIO;
+ goto bad;
+ }
+ cd->partflags[part] |= CDOPEN;
+ cd->openparts |= (1 << part);
+ SC_DEBUG(sc_link, SDEV_DB3, ("open complete\n"));
+ sc_link->flags |= SDEV_MEDIA_LOADED;
+ return (0);
+ bad:
+
+ /*
+ * if we would have been the only open
+ * then leave things back as they were
+ */
+ if (!(cd->openparts)) {
+ sc_link->flags &= ~SDEV_OPEN;
+ scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
+ }
+ return (errcode);
+}
+
+/*
+ * close the device.. only called if we are the LAST
+ * occurence of an open device
+ */
+errval
+cdclose(dev)
+ dev_t dev;
+{
+ u_int8 unit, part;
+ u_int32 old_priority;
+ struct cd_data *cd;
+ struct scsi_link *sc_link;
+
+ unit = UNIT(dev);
+ part = PARTITION(dev);
+ cd = cd_driver.cd_data[unit];
+ sc_link = cd->sc_link;
+ SC_DEBUG(sc_link, SDEV_DB2, ("cd%d: closing part %d\n", unit, part));
+ cd->partflags[part] &= ~CDOPEN;
+ cd->openparts &= ~(1 << part);
+
+ /*
+ * If we were the last open of the entire device, release it.
+ */
+ if (!(cd->openparts)) {
+ scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
+ cd->sc_link->flags &= ~SDEV_OPEN;
+ }
+ return (0);
+}
+
+/*
+ * trim the size of the transfer if needed,
+ * called by physio
+ * basically the smaller of our max and the scsi driver's
+ * minphys (note we have no max ourselves)
+ *
+ * Trim buffer length if buffer-size is bigger than page size
+ */
+void
+cdminphys(bp)
+ struct buf *bp;
+{
+ (*(cd_driver.cd_data[UNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp);
+}
+
+/*
+ * Actually translate the requested transfer into one the physical driver can
+ * understand. The transfer is described by a buf and will include only one
+ * physical transfer.
+ */
+errval
+cdstrategy(bp)
+ struct buf *bp;
+{
+ struct buf *dp;
+ u_int32 opri;
+ u_int32 unit = UNIT((bp->b_dev));
+ struct cd_data *cd = cd_driver.cd_data[unit];
+
+ cdstrats++;
+ SC_DEBUG(cd->sc_link, SDEV_DB2, ("\ncdstrategy "));
+ SC_DEBUG(cd->sc_link, SDEV_DB1, ("cd%d: %d bytes @ blk%d\n",
+ unit, bp->b_bcount, bp->b_blkno));
+ cdminphys(bp);
+ /*
+ * If the device has been made invalid, error out
+ * maybe the media changed
+ */
+ if (!(cd->sc_link->flags & SDEV_MEDIA_LOADED)) {
+ bp->b_error = EIO;
+ goto bad;
+ }
+ /*
+ * can't ever write to a CD
+ */
+ if ((bp->b_flags & B_READ) == 0) {
+ bp->b_error = EROFS;
+ goto bad;
+ }
+ /*
+ * If it's a null transfer, return immediatly
+ */
+ if (bp->b_bcount == 0) {
+ goto done;
+ }
+ /*
+ * Decide which unit and partition we are talking about
+ */
+ if (PARTITION(bp->b_dev) != RAW_PART) {
+ /*
+ * do bounds checking, adjust transfer. if error, process.
+ * if end of partition, just return
+ */
+ if (bounds_check_with_label(bp, &cd->disklabel, 1) <= 0)
+ goto done;
+ /* otherwise, process transfer request */
+ } else {
+ bp->b_pblkno = bp->b_blkno;
+ bp->b_resid = 0;
+ }
+ opri = SPLCD();
+ dp = &cd->buf_queue;
+
+ /*
+ * Use a bounce buffer if necessary
+ */
+#ifndef NOBOUNCE
+ if (cd->sc_link->flags & SDEV_BOUNCE)
+ vm_bounce_alloc(bp);
+#endif
+
+ /*
+ * Place it in the queue of disk activities for this disk
+ */
+ disksort(dp, bp);
+
+ /*
+ * Tell the device to get going on the transfer if it's
+ * not doing anything, otherwise just wait for completion
+ */
+ cdstart(unit);
+
+ splx(opri);
+ return 0; /* XXX ??? is this the right return? */
+ bad:
+ bp->b_flags |= B_ERROR;
+ done:
+
+ /*
+ * Correctly set the buf to indicate a completed xfer
+ */
+ bp->b_resid = bp->b_bcount;
+ biodone(bp);
+ return (0);
+}
+
+/*
+ * cdstart looks to see if there is a buf waiting for the device
+ * and that the device is not already busy. If both are true,
+ * It deques the buf and creates a scsi command to perform the
+ * transfer in the buf. The transfer request will call scsi_done
+ * on completion, which will in turn call this routine again
+ * so that the next queued transfer is performed.
+ * The bufs are queued by the strategy routine (cdstrategy)
+ *
+ * This routine is also called after other non-queued requests
+ * have been made of the scsi driver, to ensure that the queue
+ * continues to be drained.
+ *
+ * must be called at the correct (highish) spl level
+ * cdstart() is called at SPLCD from cdstrategy and scsi_done
+ */
+void
+cdstart(unit)
+ u_int32 unit;
+{
+ register struct buf *bp = 0;
+ register struct buf *dp;
+ struct scsi_rw_big cmd;
+ u_int32 blkno, nblk;
+ struct partition *p;
+ struct cd_data *cd = cd_driver.cd_data[unit];
+ struct scsi_link *sc_link = cd->sc_link;
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("cdstart%d ", unit));
+ /*
+ * See if there is a buf to do and we are not already
+ * doing one
+ */
+ if (!sc_link->opennings) {
+ return; /* no room for us, unit already underway */
+ }
+ if (sc_link->flags & SDEV_WAITING) { /* is room, but a special waits */
+ return; /* give the special that's waiting a chance to run */
+ }
+ dp = &cd->buf_queue;
+ if ((bp = dp->b_actf) != NULL) { /* yes, an assign */
+ dp->b_actf = bp->av_forw;
+ } else {
+ return;
+ }
+ /*
+ * Should reject all queued entries if SDEV_MEDIA_LOADED is not true.
+ */
+ if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
+ goto bad; /* no I/O.. media changed or something */
+ }
+ /*
+ * We have a buf, now we should make a command
+ *
+ * First, translate the block to absolute and put it in terms of the
+ * logical blocksize of the device. Really a bit silly until we have
+ * real partitions, but.
+ */
+ blkno = bp->b_blkno / (cd->params.blksize / 512);
+ if (PARTITION(bp->b_dev) != RAW_PART) {
+ p = cd->disklabel.d_partitions + PARTITION(bp->b_dev);
+ blkno += p->p_offset;
+ }
+ nblk = (bp->b_bcount + (cd->params.blksize - 1)) / (cd->params.blksize);
+ /* what if something asks for 512 bytes not on a 2k boundary? *//*XXX */
+
+ /*
+ * Fill out the scsi command
+ */
+ bzero(&cmd, sizeof(cmd));
+ cmd.op_code = READ_BIG;
+ cmd.addr_3 = (blkno & 0xff000000UL) >> 24;
+ cmd.addr_2 = (blkno & 0xff0000) >> 16;
+ cmd.addr_1 = (blkno & 0xff00) >> 8;
+ cmd.addr_0 = blkno & 0xff;
+ cmd.length2 = (nblk & 0xff00) >> 8;
+ cmd.length1 = (nblk & 0xff);
+
+ /*
+ * Call the routine that chats with the adapter.
+ * Note: we cannot sleep as we may be an interrupt
+ */
+ if (scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &cmd,
+ sizeof(cmd),
+ (u_char *) bp->b_un.b_addr,
+ bp->b_bcount,
+ CDRETRIES,
+ 30000,
+ bp,
+ SCSI_NOSLEEP | ((bp->b_flags & B_READ) ?
+ SCSI_DATA_IN : SCSI_DATA_OUT))
+ != SUCCESSFULLY_QUEUED) {
+ bad:
+ printf("cd%d: oops not queued", unit);
+ bp->b_error = EIO;
+ bp->b_flags |= B_ERROR;
+ biodone(bp);
+ return;
+ }
+ cdqueues++;
+}
+
+/*
+ * Perform special action on behalf of the user.
+ * Knows about the internals of this device
+ */
+errval
+cdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
+{
+ errval error = 0;
+ u_int32 opri;
+ u_int8 unit, part;
+ register struct cd_data *cd;
+
+ /*
+ * Find the device that the user is talking about
+ */
+ unit = UNIT(dev);
+ part = PARTITION(dev);
+ cd = cd_driver.cd_data[unit];
+ SC_DEBUG(cd->sc_link, SDEV_DB2, ("cdioctl 0x%x ", cmd));
+
+ /*
+ * If the device is not valid.. abandon ship
+ */
+ if (!(cd->sc_link->flags & SDEV_MEDIA_LOADED))
+ return (EIO);
+ switch (cmd) {
+
+ case DIOCSBAD:
+ error = EINVAL;
+ break;
+
+ case DIOCGDINFO:
+ *(struct disklabel *) addr = cd->disklabel;
+ break;
+
+ case DIOCGPART:
+ ((struct partinfo *) addr)->disklab = &cd->disklabel;
+ ((struct partinfo *) addr)->part =
+ &cd->disklabel.d_partitions[PARTITION(dev)];
+ break;
+
+ /*
+ * a bit silly, but someone might want to test something on a
+ * section of cdrom.
+ */
+ case DIOCWDINFO:
+ case DIOCSDINFO:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else
+ error = setdisklabel(&cd->disklabel,
+ (struct disklabel *) addr,
+ 0,
+ 0);
+ if (error == 0)
+ break;
+
+ case DIOCWLABEL:
+ error = EBADF;
+ break;
+
+ case CDIOCPLAYTRACKS:
+ {
+ struct ioc_play_track *args
+ = (struct ioc_play_track *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
+ break;
+ data.page.audio.flags &= ~CD_PA_SOTC;
+ data.page.audio.flags |= CD_PA_IMMED;
+ if (error = cd_set_mode(unit, &data))
+ break;
+ return (cd_play_tracks(unit
+ ,args->start_track
+ ,args->start_index
+ ,args->end_track
+ ,args->end_index
+ ));
+ }
+ break;
+ case CDIOCPLAYMSF:
+ {
+ struct ioc_play_msf *args
+ = (struct ioc_play_msf *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
+ break;
+ data.page.audio.flags &= ~CD_PA_SOTC;
+ data.page.audio.flags |= CD_PA_IMMED;
+ if (error = cd_set_mode(unit, &data))
+ break;
+ return (cd_play_msf(unit
+ ,args->start_m
+ ,args->start_s
+ ,args->start_f
+ ,args->end_m
+ ,args->end_s
+ ,args->end_f
+ ));
+ }
+ break;
+ case CDIOCPLAYBLOCKS:
+ {
+ struct ioc_play_blocks *args
+ = (struct ioc_play_blocks *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
+ break;
+ data.page.audio.flags &= ~CD_PA_SOTC;
+ data.page.audio.flags |= CD_PA_IMMED;
+ if (error = cd_set_mode(unit, &data))
+ break;
+ return (cd_play(unit, args->blk, args->len));
+
+ }
+ break;
+ case CDIOCREADSUBCHANNEL:
+ {
+ struct ioc_read_subchannel *args
+ = (struct ioc_read_subchannel *) addr;
+ struct cd_sub_channel_info data;
+ u_int32 len = args->data_len;
+ if (len > sizeof(data) ||
+ len < sizeof(struct cd_sub_channel_header)) {
+ error = EINVAL;
+ break;
+ }
+ if (error = cd_read_subchannel(unit, args->address_format,
+ args->data_format, args->track, &data, len)) {
+ break;
+ }
+ len = MIN(len, ((data.header.data_len[0] << 8) + data.header.data_len[1] +
+ sizeof(struct cd_sub_channel_header)));
+ if (copyout(&data, args->data, len) != 0) {
+ error = EFAULT;
+ }
+ }
+ break;
+ case CDIOREADTOCHEADER:
+ { /* ??? useless bcopy? XXX */
+ struct ioc_toc_header th;
+ if (error = cd_read_toc(unit, 0, 0,
+ (struct cd_toc_entry *)&th,
+ sizeof th))
+ break;
+ th.len = (th.len & 0xff) << 8 + ((th.len >> 8) & 0xff);
+ bcopy(&th, addr, sizeof th);
+ }
+ break;
+ case CDIOREADTOCENTRYS:
+ {
+ struct cd_toc {
+ struct ioc_toc_header header;
+ struct cd_toc_entry entries[65];
+ } data;
+ struct ioc_read_toc_entry *te =
+ (struct ioc_read_toc_entry *) addr;
+ struct ioc_toc_header *th;
+ u_int32 len = te->data_len;
+ th = &data.header;
+
+ if (len > sizeof(data.entries) || len < sizeof(struct cd_toc_entry)) {
+ error = EINVAL;
+ break;
+ }
+ if (error = cd_read_toc(unit, te->address_format,
+ te->starting_track,
+ (struct cd_toc_entry *)&data,
+ len + sizeof(struct ioc_toc_header)))
+ break;
+ len = MIN(len, ((((th->len & 0xff) << 8) + ((th->len >> 8))) - (sizeof(th->starting_track) + sizeof(th->ending_track))));
+ if (copyout(data.entries, te->data, len) != 0) {
+ error = EFAULT;
+ }
+ }
+ break;
+ case CDIOCSETPATCH:
+ {
+ struct ioc_patch *arg = (struct ioc_patch *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
+ break;
+ data.page.audio.port[LEFT_PORT].channels = arg->patch[0];
+ data.page.audio.port[RIGHT_PORT].channels = arg->patch[1];
+ data.page.audio.port[2].channels = arg->patch[2];
+ data.page.audio.port[3].channels = arg->patch[3];
+ if (error = cd_set_mode(unit, &data))
+ break; /* eh? */
+ }
+ break;
+ case CDIOCGETVOL:
+ {
+ struct ioc_vol *arg = (struct ioc_vol *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
+ break;
+ arg->vol[LEFT_PORT] = data.page.audio.port[LEFT_PORT].volume;
+ arg->vol[RIGHT_PORT] = data.page.audio.port[RIGHT_PORT].volume;
+ arg->vol[2] = data.page.audio.port[2].volume;
+ arg->vol[3] = data.page.audio.port[3].volume;
+ }
+ break;
+ case CDIOCSETVOL:
+ {
+ struct ioc_vol *arg = (struct ioc_vol *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
+ break;
+ data.page.audio.port[LEFT_PORT].channels = CHANNEL_0;
+ data.page.audio.port[LEFT_PORT].volume = arg->vol[LEFT_PORT];
+ data.page.audio.port[RIGHT_PORT].channels = CHANNEL_1;
+ data.page.audio.port[RIGHT_PORT].volume = arg->vol[RIGHT_PORT];
+ data.page.audio.port[2].volume = arg->vol[2];
+ data.page.audio.port[3].volume = arg->vol[3];
+ if (error = cd_set_mode(unit, &data))
+ break;
+ }
+ break;
+ case CDIOCSETMONO:
+ {
+ struct ioc_vol *arg = (struct ioc_vol *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
+ break;
+ data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL | RIGHT_CHANNEL | 4 | 8;
+ data.page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL | RIGHT_CHANNEL;
+ data.page.audio.port[2].channels = 0;
+ data.page.audio.port[3].channels = 0;
+ if (error = cd_set_mode(unit, &data))
+ break;
+ }
+ break;
+ case CDIOCSETSTERIO:
+ {
+ struct ioc_vol *arg = (struct ioc_vol *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
+ break;
+ data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL;
+ data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL;
+ data.page.audio.port[2].channels = 0;
+ data.page.audio.port[3].channels = 0;
+ if (error = cd_set_mode(unit, &data))
+ break;
+ }
+ break;
+ case CDIOCSETMUTE:
+ {
+ struct ioc_vol *arg = (struct ioc_vol *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
+ break;
+ data.page.audio.port[LEFT_PORT].channels = 0;
+ data.page.audio.port[RIGHT_PORT].channels = 0;
+ data.page.audio.port[2].channels = 0;
+ data.page.audio.port[3].channels = 0;
+ if (error = cd_set_mode(unit, &data))
+ break;
+ }
+ break;
+ case CDIOCSETLEFT:
+ {
+ struct ioc_vol *arg = (struct ioc_vol *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
+ break;
+ data.page.audio.port[LEFT_PORT].channels = LEFT_CHANNEL;
+ data.page.audio.port[RIGHT_PORT].channels = LEFT_CHANNEL;
+ data.page.audio.port[2].channels = 0;
+ data.page.audio.port[3].channels = 0;
+ if (error = cd_set_mode(unit, &data))
+ break;
+ }
+ break;
+ case CDIOCSETRIGHT:
+ {
+ struct ioc_vol *arg = (struct ioc_vol *) addr;
+ struct cd_mode_data data;
+ if (error = cd_get_mode(unit, &data, AUDIO_PAGE))
+ break;
+ data.page.audio.port[LEFT_PORT].channels = RIGHT_CHANNEL;
+ data.page.audio.port[RIGHT_PORT].channels = RIGHT_CHANNEL;
+ data.page.audio.port[2].channels = 0;
+ data.page.audio.port[3].channels = 0;
+ if (error = cd_set_mode(unit, &data))
+ break;
+ }
+ break;
+ case CDIOCRESUME:
+ error = cd_pause(unit, 1);
+ break;
+ case CDIOCPAUSE:
+ error = cd_pause(unit, 0);
+ break;
+ case CDIOCSTART:
+ error = scsi_start_unit(cd->sc_link, 0);
+ break;
+ case CDIOCSTOP:
+ error = scsi_stop_unit(cd->sc_link, 0, 0);
+ break;
+ case CDIOCEJECT:
+ error = scsi_stop_unit(cd->sc_link, 1, 0);
+ break;
+ case CDIOCALLOW:
+ error = scsi_prevent(cd->sc_link, PR_ALLOW, 0);
+ break;
+ case CDIOCPREVENT:
+ error = scsi_prevent(cd->sc_link, PR_PREVENT, 0);
+ break;
+ case CDIOCSETDEBUG:
+ cd->sc_link->flags |= (SDEV_DB1 | SDEV_DB2);
+ break;
+ case CDIOCCLRDEBUG:
+ cd->sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2);
+ break;
+ case CDIOCRESET:
+ return (cd_reset(unit));
+ break;
+ default:
+ if(part == RAW_PART)
+ error = scsi_do_ioctl(cd->sc_link,cmd,addr,flag);
+ else
+ error = ENOTTY;
+ break;
+ }
+ return (error);
+}
+
+/*
+ * Load the label information on the named device
+ * Actually fabricate a disklabel
+ *
+ * EVENTUALLY take information about different
+ * data tracks from the TOC and put it in the disklabel
+ */
+errval
+cdgetdisklabel(unit)
+ u_int8 unit;
+{
+ /*unsigned int n, m; */
+ char *errstring;
+ struct cd_data *cd;
+
+ cd = cd_driver.cd_data[unit];
+
+ bzero(&cd->disklabel, sizeof(struct disklabel));
+ /*
+ * make partition 0 the whole disk
+ */
+ strncpy(cd->disklabel.d_typename, "scsi cd_rom", 16);
+ strncpy(cd->disklabel.d_packname, "ficticious", 16);
+ cd->disklabel.d_secsize = cd->params.blksize; /* as long as it's not 0 */
+ cd->disklabel.d_nsectors = 100;
+ cd->disklabel.d_ntracks = 1;
+ cd->disklabel.d_ncylinders = (cd->params.disksize / 100) + 1;
+ cd->disklabel.d_secpercyl = 100;
+ cd->disklabel.d_secperunit = cd->params.disksize;
+ cd->disklabel.d_rpm = 300;
+ cd->disklabel.d_interleave = 1;
+ cd->disklabel.d_flags = D_REMOVABLE;
+
+ /*
+ * remember that comparisons with the partition are done
+ * assuming the blocks are 512 bytes so fudge it.
+ */
+ cd->disklabel.d_npartitions = 1;
+ cd->disklabel.d_partitions[0].p_offset = 0;
+ cd->disklabel.d_partitions[0].p_size
+ = cd->params.disksize * (cd->params.blksize / 512);
+ cd->disklabel.d_partitions[0].p_fstype = 9;
+
+ cd->disklabel.d_magic = DISKMAGIC;
+ cd->disklabel.d_magic2 = DISKMAGIC;
+ cd->disklabel.d_checksum = dkcksum(&(cd->disklabel));
+
+ /*
+ * Signal to other users and routines that we now have a
+ * disklabel that represents the media (maybe)
+ */
+ return (ESUCCESS);
+}
+
+/*
+ * Find out from the device what it's capacity is
+ */
+u_int32
+cd_size(unit, flags)
+ int unit;
+ int flags;
+{
+ struct scsi_read_cd_cap_data rdcap;
+ struct scsi_read_cd_capacity scsi_cmd;
+ u_int32 size;
+ u_int32 blksize;
+ struct cd_data *cd = cd_driver.cd_data[unit];
+
+ /*
+ * make up a scsi command and ask the scsi driver to do
+ * it for you.
+ */
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = READ_CD_CAPACITY;
+
+ /*
+ * If the command works, interpret the result as a 4 byte
+ * number of blocks and a blocksize
+ */
+ if (scsi_scsi_cmd(cd->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) & rdcap,
+ sizeof(rdcap),
+ CDRETRIES,
+ 20000, /* might be a disk-changer */
+ NULL,
+ SCSI_DATA_IN | flags) != 0) {
+ printf("cd%d: could not get size\n", unit);
+ return (0);
+ } else {
+ size = rdcap.addr_0 + 1;
+ size += rdcap.addr_1 << 8;
+ size += rdcap.addr_2 << 16;
+ size += rdcap.addr_3 << 24;
+ blksize = rdcap.length_0;
+ blksize += rdcap.length_1 << 8;
+ blksize += rdcap.length_2 << 16;
+ blksize += rdcap.length_3 << 24;
+ }
+ if (blksize < 512)
+ blksize = 2048; /* some drives lie ! */
+ if (size < 100)
+ size = 400000; /* ditto */
+ SC_DEBUG(cd->sc_link, SDEV_DB3, ("cd%d: %d %d byte blocks\n"
+ ,unit, size, blksize));
+ cd->params.disksize = size;
+ cd->params.blksize = blksize;
+ return (size);
+}
+
+/*
+ * Get the requested page into the buffer given
+ */
+static errval
+cd_get_mode(unit, data, page)
+ u_int32 unit;
+ struct cd_mode_data *data;
+ u_int32 page;
+{
+ struct scsi_mode_sense scsi_cmd;
+ errval retval;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ bzero(data, sizeof(*data));
+ scsi_cmd.op_code = MODE_SENSE;
+ scsi_cmd.page = page;
+ scsi_cmd.length = sizeof(*data) & 0xff;
+ retval = scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) data,
+ sizeof(*data),
+ CDRETRIES,
+ 20000, /* should be immed */
+ NULL,
+ SCSI_DATA_IN);
+ return (retval);
+}
+
+/*
+ * Get the requested page into the buffer given
+ */
+errval
+cd_set_mode(unit, data)
+ u_int32 unit;
+ struct cd_mode_data *data;
+{
+ struct scsi_mode_select scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = MODE_SELECT;
+ scsi_cmd.byte2 |= SMS_PF;
+ scsi_cmd.length = sizeof(*data) & 0xff;
+ data->header.data_length = 0;
+ return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) data,
+ sizeof(*data),
+ CDRETRIES,
+ 20000, /* should be immed */
+ NULL,
+ SCSI_DATA_OUT));
+}
+
+/*
+ * Get scsi driver to send a "start playing" command
+ */
+errval
+cd_play(unit, blk, len)
+ u_int32 unit, blk, len;
+{
+ struct scsi_play scsi_cmd;
+ errval retval;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = PLAY;
+ scsi_cmd.blk_addr[0] = (blk >> 24) & 0xff;
+ scsi_cmd.blk_addr[1] = (blk >> 16) & 0xff;
+ scsi_cmd.blk_addr[2] = (blk >> 8) & 0xff;
+ scsi_cmd.blk_addr[3] = blk & 0xff;
+ scsi_cmd.xfer_len[0] = (len >> 8) & 0xff;
+ scsi_cmd.xfer_len[1] = len & 0xff;
+ return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ CDRETRIES,
+ 200000, /* should be immed */
+ NULL,
+ 0));
+}
+
+/*
+ * Get scsi driver to send a "start playing" command
+ */
+errval
+cd_play_big(unit, blk, len)
+ u_int32 unit, blk, len;
+{
+ struct scsi_play_big scsi_cmd;
+ errval retval;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = PLAY_BIG;
+ scsi_cmd.blk_addr[0] = (blk >> 24) & 0xff;
+ scsi_cmd.blk_addr[1] = (blk >> 16) & 0xff;
+ scsi_cmd.blk_addr[2] = (blk >> 8) & 0xff;
+ scsi_cmd.blk_addr[3] = blk & 0xff;
+ scsi_cmd.xfer_len[0] = (len >> 24) & 0xff;
+ scsi_cmd.xfer_len[1] = (len >> 16) & 0xff;
+ scsi_cmd.xfer_len[2] = (len >> 8) & 0xff;
+ scsi_cmd.xfer_len[3] = len & 0xff;
+ return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ CDRETRIES,
+ 20000, /* should be immed */
+ NULL,
+ 0));
+}
+
+/*
+ * Get scsi driver to send a "start playing" command
+ */
+errval
+cd_play_tracks(unit, strack, sindex, etrack, eindex)
+ u_int32 unit, strack, sindex, etrack, eindex;
+{
+ struct scsi_play_track scsi_cmd;
+ errval retval;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = PLAY_TRACK;
+ scsi_cmd.start_track = strack;
+ scsi_cmd.start_index = sindex;
+ scsi_cmd.end_track = etrack;
+ scsi_cmd.end_index = eindex;
+ return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ CDRETRIES,
+ 20000, /* should be immed */
+ NULL,
+ 0));
+}
+
+/*
+ * Get scsi driver to send a "play msf" command
+ */
+errval
+cd_play_msf(unit, startm, starts, startf, endm, ends, endf)
+ u_int32 unit, startm, starts, startf, endm, ends, endf;
+{
+ struct scsi_play_msf scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = PLAY_MSF;
+ scsi_cmd.start_m = startm;
+ scsi_cmd.start_s = starts;
+ scsi_cmd.start_f = startf;
+ scsi_cmd.end_m = endm;
+ scsi_cmd.end_s = ends;
+ scsi_cmd.end_f = endf;
+
+ return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ CDRETRIES,
+ 2000,
+ NULL,
+ 0));
+}
+
+/*
+ * Get scsi driver to send a "start up" command
+ */
+errval
+cd_pause(unit, go)
+ u_int32 unit, go;
+{
+ struct scsi_pause scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = PAUSE;
+ scsi_cmd.resume = go;
+
+ return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ CDRETRIES,
+ 2000,
+ NULL,
+ 0));
+}
+
+/*
+ * Get scsi driver to send a "RESET" command
+ */
+errval
+cd_reset(unit)
+ u_int32 unit;
+{
+ return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
+ 0,
+ 0,
+ 0,
+ 0,
+ CDRETRIES,
+ 2000,
+ NULL,
+ SCSI_RESET));
+}
+
+/*
+ * Read subchannel
+ */
+errval
+cd_read_subchannel(unit, mode, format, track, data, len)
+ u_int32 unit, mode, format;
+ int track;
+ struct cd_sub_channel_info *data;
+ u_int32 len;
+{
+ struct scsi_read_subchannel scsi_cmd;
+ errval error;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+
+ scsi_cmd.op_code = READ_SUBCHANNEL;
+ if (mode == CD_MSF_FORMAT)
+ scsi_cmd.byte2 |= CD_MSF;
+ scsi_cmd.byte3 = SRS_SUBQ;
+ scsi_cmd.subchan_format = format;
+ scsi_cmd.track = track;
+ scsi_cmd.data_len[0] = (len) >> 8;
+ scsi_cmd.data_len[1] = (len) & 0xff;
+ return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(struct scsi_read_subchannel),
+ (u_char *) data,
+ len,
+ CDRETRIES,
+ 5000,
+ NULL,
+ SCSI_DATA_IN));
+}
+
+/*
+ * Read table of contents
+ */
+static errval
+cd_read_toc(unit, mode, start, data, len)
+ u_int32 unit, mode, start;
+ struct cd_toc_entry *data;
+ u_int32 len;
+{
+ struct scsi_read_toc scsi_cmd;
+ errval error;
+ u_int32 ntoc;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ /*if(len!=sizeof(struct ioc_toc_header))
+ * ntoc=((len)-sizeof(struct ioc_toc_header))/sizeof(struct cd_toc_entry);
+ * else */
+ ntoc = len;
+
+ scsi_cmd.op_code = READ_TOC;
+ if (mode == CD_MSF_FORMAT)
+ scsi_cmd.byte2 |= CD_MSF;
+ scsi_cmd.from_track = start;
+ scsi_cmd.data_len[0] = (ntoc) >> 8;
+ scsi_cmd.data_len[1] = (ntoc) & 0xff;
+ return (scsi_scsi_cmd(cd_driver.cd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(struct scsi_read_toc),
+ (u_char *) data,
+ len,
+ CDRETRIES,
+ 5000,
+ NULL,
+ SCSI_DATA_IN));
+}
+
+#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 )
+
+/*
+ * Get the scsi driver to send a full inquiry to the device and use the
+ * results to fill out the disk parameter structure.
+ */
+static errval
+cd_get_parms(unit, flags)
+ int unit;
+ int flags;
+{
+ struct cd_data *cd = cd_driver.cd_data[unit];
+
+ /*
+ * First check if we have it all loaded
+ */
+ if (cd->sc_link->flags & SDEV_MEDIA_LOADED)
+ return (0);
+ /*
+ * give a number of sectors so that sec * trks * cyls
+ * is <= disk_size
+ */
+ if (cd_size(unit, flags)) {
+ cd->sc_link->flags |= SDEV_MEDIA_LOADED;
+ return (0);
+ } else {
+ return (ENXIO);
+ }
+}
+
+int
+cdsize(dev_t dev)
+{
+ return (-1);
+}
diff --git a/sys/scsi/ch.c b/sys/scsi/ch.c
new file mode 100644
index 0000000..315dab9
--- /dev/null
+++ b/sys/scsi/ch.c
@@ -0,0 +1,487 @@
+/*
+ * Written by grefen@?????
+ * Based on scsi drivers by Julian Elischer (julian@tfs.com)
+ *
+ * $Id: ch.c,v 1.7 1993/12/19 00:54:49 wollman Exp $
+ */
+
+#include <sys/types.h>
+#include <ch.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/chio.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsi_changer.h>
+#include <scsi/scsiconf.h>
+
+static errval ch_mode_sense(u_int32, u_int32);
+
+struct scsi_xfer ch_scsi_xfer[NCH];
+u_int32 ch_xfer_block_wait[NCH];
+
+#define PAGESIZ 4096
+#define STQSIZE 4
+#define CHRETRIES 2
+
+#define MODE(z) ( (minor(z) & 0x0F) )
+#define UNIT(z) ( (minor(z) >> 4) )
+
+#define ESUCCESS 0
+
+errval chattach();
+
+/*
+ * This driver is so simple it uses all the default services
+ */
+struct scsi_device ch_switch =
+{
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "ch",
+ 0,
+ 0, 0
+};
+
+struct ch_data {
+ u_int32 flags;
+ struct scsi_link *sc_link; /* all the inter level info */
+ u_int16 chmo; /* Offset of first CHM */
+ u_int16 chms; /* No. of CHM */
+ u_int16 slots; /* No. of Storage Elements */
+ u_int16 sloto; /* Offset of first SE */
+ u_int16 imexs; /* No. of Import/Export Slots */
+ u_int16 imexo; /* Offset of first IM/EX */
+ u_int16 drives; /* No. of CTS */
+ u_int16 driveo; /* Offset of first CTS */
+ u_int16 rot; /* CHM can rotate */
+ u_long op_matrix; /* possible opertaions */
+ u_int16 lsterr; /* details of lasterror */
+ u_char stor; /* posible Storage locations */
+ u_int32 initialized;
+} ch_data[NCH];
+
+#define CH_OPEN 0x01
+#define CH_KNOWN 0x02
+
+static u_int32 next_ch_unit = 0;
+
+/*
+ * The routine called by the low level scsi routine when it discovers
+ * a device suitable for this driver.
+ */
+errval
+chattach(sc_link)
+ struct scsi_link *sc_link;
+{
+ u_int32 unit, i, stat;
+ unsigned char *tbl;
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("chattach: "));
+ /*
+ * Check we have the resources for another drive
+ */
+ unit = next_ch_unit++;
+ if (unit >= NCH) {
+ printf("Too many scsi changers..(%d > %d) reconfigure kernel\n", (unit + 1), NCH);
+ return (0);
+ }
+ /*
+ * Store information needed to contact our base driver
+ */
+ ch_data[unit].sc_link = sc_link;
+ sc_link->device = &ch_switch;
+ sc_link->dev_unit = unit;
+
+ /*
+ * Use the subdriver to request information regarding
+ * the drive. We cannot use interrupts yet, so the
+ * request must specify this.
+ */
+ if ((ch_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK /*| SCSI_SILENT */ ))) {
+ printf("ch%d: scsi changer :- offline\n", unit);
+ stat = CH_OPEN;
+ } else {
+ printf("ch%d: scsi changer, %d slot(s) %d drive(s) %d arm(s) %d i/e-slot(s)\n",
+ unit, ch_data[unit].slots, ch_data[unit].drives, ch_data[unit].chms, ch_data[unit].imexs);
+ stat = CH_KNOWN;
+ }
+ ch_data[unit].initialized = 1;
+
+ return 1;
+ /* XXX ??? is this the right return val? */
+}
+
+/*
+ * open the device.
+ */
+errval
+chopen(dev)
+ dev_t dev;
+{
+ errval errcode = 0;
+ u_int32 unit, mode;
+ struct scsi_link *sc_link;
+
+ unit = UNIT(dev);
+ mode = MODE(dev);
+
+ /*
+ * Check the unit is legal
+ */
+ if (unit >= NCH) {
+ printf("ch%d: ch %d > %d\n", unit, unit, NCH);
+ errcode = ENXIO;
+ return (errcode);
+ }
+ /*
+ * Only allow one at a time
+ */
+ if (ch_data[unit].flags & CH_OPEN) {
+ printf("ch%d: already open\n", unit);
+ return EBUSY;
+ }
+ /*
+ * Make sure the device has been initialised
+ */
+ if (!ch_data[unit].initialized)
+ return (ENXIO);
+
+ sc_link = ch_data[unit].sc_link;
+
+ SC_DEBUG(sc_link, SDEV_DB1, ("chopen: dev=0x%x (unit %d (of %d))\n"
+ ,dev, unit, NCH));
+ /*
+ * Catch any unit attention errors.
+ */
+ scsi_test_unit_ready(sc_link, SCSI_SILENT);
+
+ sc_link->flags |= SDEV_OPEN;
+ /*
+ * Check that it is still responding and ok.
+ */
+ if (errcode = (scsi_test_unit_ready(sc_link, 0))) {
+ printf("ch%d: not ready\n", unit);
+ sc_link->flags &= ~SDEV_OPEN;
+ return errcode;
+ }
+ /*
+ * Make sure data is loaded
+ */
+ if (errcode = (ch_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK))) {
+ printf("ch%d: scsi changer :- offline\n", unit);
+ sc_link->flags &= ~SDEV_OPEN;
+ return (errcode);
+ }
+ ch_data[unit].flags = CH_OPEN;
+ return 0;
+}
+
+/*
+ * close the device.. only called if we are the LAST
+ * occurence of an open device
+ */
+errval
+chclose(dev)
+ dev_t dev;
+{
+ unsigned char unit, mode;
+ struct scsi_link *sc_link;
+
+ unit = UNIT(dev);
+ mode = MODE(dev);
+ sc_link = ch_data[unit].sc_link;
+
+ SC_DEBUG(sc_link, SDEV_DB1, ("Closing device"));
+ ch_data[unit].flags = 0;
+ sc_link->flags &= ~SDEV_OPEN;
+ return (0);
+}
+
+/*
+ * Perform special action on behalf of the user
+ * Knows about the internals of this device
+ */
+errval
+chioctl(dev, cmd, arg, mode)
+ dev_t dev;
+ u_int32 cmd;
+ caddr_t arg;
+ int mode;
+{
+ /* struct ch_cmd_buf *args; */
+ union scsi_cmd *scsi_cmd;
+ register i, j;
+ u_int32 opri;
+ errval errcode = 0;
+ unsigned char unit;
+ u_int32 number, flags;
+ errval ret;
+ struct scsi_link *sc_link;
+
+ /*
+ * Find the device that the user is talking about
+ */
+ flags = 0; /* give error messages, act on errors etc. */
+ unit = UNIT(dev);
+ sc_link = ch_data[unit].sc_link;
+
+ switch ((int)cmd) {
+ case CHIOOP:{
+ struct chop *ch = (struct chop *) arg;
+ SC_DEBUG(sc_link, SDEV_DB2,
+ ("[chtape_chop: %x]\n", ch->ch_op));
+
+ switch ((short) (ch->ch_op)) {
+ case CHGETPARAM:
+ ch->u.getparam.chmo = ch_data[unit].chmo;
+ ch->u.getparam.chms = ch_data[unit].chms;
+ ch->u.getparam.sloto = ch_data[unit].sloto;
+ ch->u.getparam.slots = ch_data[unit].slots;
+ ch->u.getparam.imexo = ch_data[unit].imexo;
+ ch->u.getparam.imexs = ch_data[unit].imexs;
+ ch->u.getparam.driveo = ch_data[unit].driveo;
+ ch->u.getparam.drives = ch_data[unit].drives;
+ ch->u.getparam.rot = ch_data[unit].rot;
+ ch->result = 0;
+ return 0;
+ break;
+ case CHPOSITION:
+ return ch_position(unit, &ch->result, ch->u.position.chm,
+ ch->u.position.to,
+ flags);
+ case CHMOVE:
+ return ch_move(unit, &ch->result, ch->u.position.chm,
+ ch->u.move.from, ch->u.move.to,
+ flags);
+ case CHGETELEM:
+ return ch_getelem(unit, &ch->result, ch->u.get_elem_stat.type,
+ ch->u.get_elem_stat.from, &ch->u.get_elem_stat.elem_data,
+ flags);
+ default:
+ return EINVAL;
+ }
+ }
+ default:
+ return scsi_do_ioctl(sc_link, cmd, arg, mode);
+ }
+ return (ret ? ESUCCESS : EIO);
+}
+
+errval
+ch_getelem(unit, stat, type, from, data, flags)
+ u_int32 unit, from, flags;
+ int type;
+ short *stat;
+ char *data;
+{
+ struct scsi_read_element_status scsi_cmd;
+ char elbuf[32];
+ errval ret;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = READ_ELEMENT_STATUS;
+ scsi_cmd.byte2 = type;
+ scsi_cmd.starting_element_addr[0] = (from >> 8) & 0xff;
+ scsi_cmd.starting_element_addr[1] = from & 0xff;
+ scsi_cmd.number_of_elements[1] = 1;
+ scsi_cmd.allocation_length[2] = 32;
+
+ if ((ret = scsi_scsi_cmd(ch_data[unit].sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) elbuf,
+ 32,
+ CHRETRIES,
+ 100000,
+ NULL,
+ SCSI_DATA_IN | flags) != ESUCCESS)) {
+ *stat = ch_data[unit].lsterr;
+ bcopy(elbuf + 16, data, 16);
+ return ret;
+ }
+ bcopy(elbuf + 16, data, 16); /*Just a hack sh */
+ return ret;
+}
+
+errval
+ch_move(unit, stat, chm, from, to, flags)
+ u_int32 unit, chm, from, to, flags;
+ short *stat;
+{
+ struct scsi_move_medium scsi_cmd;
+ errval ret;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = MOVE_MEDIUM;
+ scsi_cmd.transport_element_address[0] = (chm >> 8) & 0xff;
+ scsi_cmd.transport_element_address[1] = chm & 0xff;
+ scsi_cmd.source_address[0] = (from >> 8) & 0xff;
+ scsi_cmd.source_address[1] = from & 0xff;
+ scsi_cmd.destination_address[0] = (to >> 8) & 0xff;
+ scsi_cmd.destination_address[1] = to & 0xff;
+ scsi_cmd.invert = (chm & CH_INVERT) ? 1 : 0;
+ if ((ret = scsi_scsi_cmd(ch_data[unit].sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ NULL,
+ 0,
+ CHRETRIES,
+ 100000,
+ NULL,
+ flags) != ESUCCESS)) {
+ *stat = ch_data[unit].lsterr;
+ return ret;
+ }
+ return ret;
+}
+
+errval
+ch_position(unit, stat, chm, to, flags)
+ u_int32 unit, chm, to, flags;
+ short *stat;
+{
+ struct scsi_position_to_element scsi_cmd;
+ errval ret;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = POSITION_TO_ELEMENT;
+ scsi_cmd.transport_element_address[0] = (chm >> 8) & 0xff;
+ scsi_cmd.transport_element_address[1] = chm & 0xff;
+ scsi_cmd.source_address[0] = (to >> 8) & 0xff;
+ scsi_cmd.source_address[1] = to & 0xff;
+ scsi_cmd.invert = (chm & CH_INVERT) ? 1 : 0;
+ if ((ret = scsi_scsi_cmd(ch_data[unit].sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ NULL,
+ 0,
+ CHRETRIES,
+ 100000,
+ NULL,
+ flags) != ESUCCESS)) {
+ *stat = ch_data[unit].lsterr;
+ return ret;
+ }
+ return ret;
+}
+
+#ifdef __STDC__
+#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 )
+#else
+#define b2tol(a) (((unsigned)(a/**/_1) << 8) + (unsigned)a/**/_0 )
+#endif
+
+/*
+ * Get the scsi driver to send a full inquiry to the
+ * device and use the results to fill out the global
+ * parameter structure.
+ */
+static errval
+ch_mode_sense(unit, flags)
+ u_int32 unit, flags;
+{
+ struct scsi_mode_sense scsi_cmd;
+ u_char scsi_sense[128]; /* Can't use scsi_mode_sense_data because of
+ * missing block descriptor
+ */
+ u_char *b;
+ int32 i, l;
+ errval errcode;
+ struct scsi_link *sc_link = ch_data[unit].sc_link;
+
+ /*
+ * First check if we have it all loaded
+ */
+ if (sc_link->flags & SDEV_MEDIA_LOADED)
+ return 0;
+
+ /*
+ * First do a mode sense
+ */
+ /* sc_link->flags &= ~SDEV_MEDIA_LOADED; *//*XXX */
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = MODE_SENSE;
+ scsi_cmd.byte2 = SMS_DBD;
+ scsi_cmd.page = 0x3f; /* All Pages */
+ scsi_cmd.length = sizeof(scsi_sense);
+
+ /*
+ * Read in the pages
+ */
+ if (errcode = scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(struct scsi_mode_sense),
+ (u_char *) & scsi_sense,
+ sizeof (scsi_sense),
+ CHRETRIES,
+ 5000,
+ NULL,
+ flags | SCSI_DATA_IN) != 0) {
+ if (!(flags & SCSI_SILENT))
+ printf("ch%d: could not mode sense\n", unit);
+ return (errcode);
+ }
+ sc_link->flags |= SDEV_MEDIA_LOADED;
+ l = scsi_sense[0] - 3;
+ b = &scsi_sense[4];
+
+ /*
+ * To avoid alignment problems
+ */
+/* XXX - FIX THIS FOR MSB */
+#define p2copy(valp) (valp[1]+ (valp[0]<<8));valp+=2
+#define p4copy(valp) (valp[3]+ (valp[2]<<8) + (valp[1]<<16) + (valp[0]<<24));valp+=4
+#if 0
+ printf("\nmode_sense %d\n", l);
+ for (i = 0; i < l + 4; i++) {
+ printf("%x%c", scsi_sense[i], i % 8 == 7 ? '\n' : ':');
+ } printf("\n");
+#endif
+ for (i = 0; i < l;) {
+ u_int32 pc = (*b++) & 0x3f;
+ u_int32 pl = *b++;
+ u_char *bb = b;
+ switch ((int)pc) {
+ case 0x1d:
+ ch_data[unit].chmo = p2copy(bb);
+ ch_data[unit].chms = p2copy(bb);
+ ch_data[unit].sloto = p2copy(bb);
+ ch_data[unit].slots = p2copy(bb);
+ ch_data[unit].imexo = p2copy(bb);
+ ch_data[unit].imexs = p2copy(bb);
+ ch_data[unit].driveo = p2copy(bb);
+ ch_data[unit].drives = p2copy(bb);
+ break;
+ case 0x1e:
+ ch_data[unit].rot = (*b) & 1;
+ break;
+ case 0x1f:
+ ch_data[unit].stor = *b & 0xf;
+ bb += 2;
+ ch_data[unit].stor = p4copy(bb);
+ break;
+ default:
+ break;
+ }
+ b += pl;
+ i += pl + 2;
+ }
+ SC_DEBUG(sc_link, SDEV_DB2,
+ (" cht(%d-%d)slot(%d-%d)imex(%d-%d)cts(%d-%d) %s rotate\n",
+ ch_data[unit].chmo, ch_data[unit].chms,
+ ch_data[unit].sloto, ch_data[unit].slots,
+ ch_data[unit].imexo, ch_data[unit].imexs,
+ ch_data[unit].driveo, ch_data[unit].drives,
+ ch_data[unit].rot ? "can" : "can't"));
+ return (0);
+}
diff --git a/sys/scsi/scsi_all.h b/sys/scsi/scsi_all.h
new file mode 100644
index 0000000..2e7bdcf
--- /dev/null
+++ b/sys/scsi/scsi_all.h
@@ -0,0 +1,340 @@
+/*
+ * SCSI general interface description
+ */
+
+/*
+ * Largely written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * $Id: scsi_all.h,v 2.0 93/10/06 21:10:28 julian Exp Locker: julian $
+ */
+
+#ifndef _SCSI_SCSI_ALL_H
+#define _SCSI_SCSI_ALL_H 1
+/*
+ * SCSI command format
+ */
+
+/*
+ * Define dome bits that are in ALL (or a lot of) scsi commands
+ */
+#define SCSI_CTL_LINK 0x01
+#define SCSI_CTL_FLAG 0x02
+#define SCSI_CTL_VENDOR 0xC0
+#define SCSI_CMD_LUN 0xA0 /* these two should not be needed */
+#define SCSI_CMD_LUN_SHIFT 5 /* LUN in the cmd is no longer SCSI */
+
+
+struct scsi_generic
+{
+ u_char opcode;
+ u_char bytes[11];
+};
+
+struct scsi_test_unit_ready
+{
+ u_char op_code;
+ u_char byte2;
+ u_char unused[3];
+ u_char control;
+};
+
+struct scsi_send_diag
+{
+ u_char op_code;
+ u_char byte2;
+#define SSD_UOL 0x01
+#define SSD_DOL 0x02
+#define SSD_SELFTEST 0x04
+#define SSD_PF 0x10
+ u_char unused[1];
+ u_char paramlen[2];
+ u_char control;
+};
+
+struct scsi_sense
+{
+ u_char op_code;
+ u_char byte2;
+ u_char unused[2];
+ u_char length;
+ u_char control;
+};
+
+struct scsi_inquiry
+{
+ u_char op_code;
+ u_char byte2;
+ u_char unused[2];
+ u_char length;
+ u_char control;
+};
+
+struct scsi_mode_sense
+{
+ u_char op_code;
+ u_char byte2;
+#define SMS_DBD 0x08
+ u_char page;
+#define SMS_PAGE_CODE 0x3F
+#define SMS_PAGE_CTRL 0xC0
+#define SMS_PAGE_CTRL_CURRENT 0x00
+#define SMS_PAGE_CTRL_CHANGEABLE 0x40
+#define SMS_PAGE_CTRL_DEFAULT 0x80
+#define SMS_PAGE_CTRL_SAVED 0xC0
+ u_char unused;
+ u_char length;
+ u_char control;
+};
+
+struct scsi_mode_sense_big
+{
+ u_char op_code;
+ u_char byte2; /* same bits as small version */
+ u_char page; /* same bits as small version */
+ u_char unused[4];
+ u_char length[2];
+ u_char control;
+};
+
+struct scsi_mode_select
+{
+ u_char op_code;
+ u_char byte2;
+#define SMS_SP 0x01
+#define SMS_PF 0x10
+ u_char unused[2];
+ u_char length;
+ u_char control;
+};
+
+struct scsi_mode_select_big
+{
+ u_char op_code;
+ u_char byte2; /* same bits as small version */
+ u_char unused[5];
+ u_char length[2];
+ u_char control;
+};
+
+struct scsi_reserve
+{
+ u_char op_code;
+ u_char byte2;
+ u_char unused[2];
+ u_char length;
+ u_char control;
+};
+
+struct scsi_release
+{
+ u_char op_code;
+ u_char byte2;
+ u_char unused[2];
+ u_char length;
+ u_char control;
+};
+
+struct scsi_prevent
+{
+ u_char op_code;
+ u_char byte2;
+ u_char unused[2];
+ u_char how;
+ u_char control;
+};
+#define PR_PREVENT 0x01
+#define PR_ALLOW 0x00
+
+struct scsi_changedef
+{
+ u_char op_code;
+ u_char byte2;
+ u_char unused1;
+ u_char how;
+ u_char unused[4];
+ u_char datalen;
+ u_char control;
+};
+#define SC_SCSI_1 0x01
+#define SC_SCSI_2 0x03
+
+/*
+ * Opcodes
+ */
+
+#define TEST_UNIT_READY 0x00
+#define REQUEST_SENSE 0x03
+#define INQUIRY 0x12
+#define MODE_SELECT 0x15
+#define MODE_SENSE 0x1a
+#define START_STOP 0x1b
+#define RESERVE 0x16
+#define RELEASE 0x17
+#define PREVENT_ALLOW 0x1e
+#define POSITION_TO_ELEMENT 0x2b
+#define CHANGE_DEFINITION 0x40
+#define MODE_SENSE_BIG 0x54
+#define MODE_SELECT_BIG 0x55
+#define MOVE_MEDIUM 0xa5
+#define READ_ELEMENT_STATUS 0xb8
+
+
+/*
+ * sense data format
+ */
+#define T_DIRECT 0
+#define T_SEQUENTIAL 1
+#define T_PRINTER 2
+#define T_PROCESSOR 3
+#define T_WORM 4
+#define T_READONLY 5
+#define T_SCANNER 6
+#define T_OPTICAL 7
+#define T_NODEVICE 0x1F
+
+#define T_CHANGER 8
+#define T_COMM 9
+
+#define T_REMOV 1
+#define T_FIXED 0
+
+struct scsi_inquiry_data
+{
+ u_char device;
+#define SID_TYPE 0x1F
+#define SID_QUAL 0xE0
+#define SID_QUAL_LU_OK 0x00
+#define SID_QUAL_LU_OFFLINE 0x20
+#define SID_QUAL_RSVD 0x40
+#define SID_QUAL_BAD_LU 0x60
+ u_char dev_qual2;
+#define SID_QUAL2 0x7F
+#define SID_REMOVABLE 0x80
+ u_char version;
+#define SID_ANSII 0x07
+#define SID_ECMA 0x38
+#define SID_ISO 0xC0
+ u_char response_format;
+ u_char additional_length;
+ u_char unused[2];
+ u_char flags;
+#define SID_SftRe 0x01
+#define SID_CmdQue 0x02
+#define SID_Linked 0x08
+#define SID_Sync 0x10
+#define SID_WBus16 0x20
+#define SID_WBus32 0x40
+#define SID_RelAdr 0x80
+ char vendor[8];
+ char product[16];
+ char revision[4];
+ u_char extra[8];
+};
+
+
+struct scsi_sense_data
+{
+/* 1*/ u_char error_code; /* same bits as new version */
+ union
+ {
+ struct
+ {
+/* 2*/ u_char blockhi;
+/* 3*/ u_char blockmed;
+/* 4*/ u_char blocklow;
+ } unextended;
+ struct
+ {
+/* 2*/ u_char segment;
+/* 3*/ u_char flags; /* same bits as new version */
+/* 7*/ u_char info[4];
+/* 8*/ u_char extra_len;
+ /* allocate enough room to hold new stuff
+ ( by increasing 16 to 24 below) */
+/*32*/ u_char extra_bytes[24];
+ } extended;
+ }ext;
+}; /* total of 32 bytes */
+struct scsi_sense_data_new
+{
+/* 1*/ u_char error_code;
+#define SSD_ERRCODE 0x7F
+#define SSD_ERRCODE_VALID 0x80
+ union
+ {
+ struct /* this is deprecated, the standard says "DON'T"*/
+ {
+/* 2*/ u_char blockhi;
+/* 3*/ u_char blockmed;
+/* 4*/ u_char blocklow;
+ } unextended;
+ struct
+ {
+/* 2*/ u_char segment;
+/* 3*/ u_char flags;
+#define SSD_KEY 0x0F
+#define SSD_ILI 0x20
+#define SSD_EOM 0x40
+#define SSD_FILEMARK 0x80
+/* 7*/ u_char info[4];
+/* 8*/ u_char extra_len;
+/*12*/ u_char cmd_spec_info[4];
+/*13*/ u_char add_sense_code;
+/*14*/ u_char add_sense_code_qual;
+/*15*/ u_char fru;
+/*16*/ u_char sense_key_spec_1;
+#define SSD_SCS_VALID 0x80
+/*17*/ u_char sense_key_spec_2;
+/*18*/ u_char sense_key_spec_3;
+/*32*/ u_char extra_bytes[14];
+ } extended;
+ }ext;
+}; /* total of 32 bytes */
+
+struct blk_desc
+{
+ u_char density;
+ u_char nblocks[3];
+ u_char reserved;
+ u_char blklen[3];
+};
+
+struct scsi_mode_header
+{
+ u_char data_length; /* Sense data length */
+ u_char medium_type;
+ u_char dev_spec;
+ u_char blk_desc_len;
+};
+
+struct scsi_mode_header_big
+{
+ u_char data_length[2]; /* Sense data length */
+ u_char medium_type;
+ u_char dev_spec;
+ u_char unused[2];
+ u_char blk_desc_len[2];
+};
+
+
+/*
+ * Status Byte
+ */
+#define SCSI_OK 0x00
+#define SCSI_CHECK 0x02
+#define SCSI_BUSY 0x08
+#define SCSI_INTERM 0x10
+#endif /*_SCSI_SCSI_ALL_H*/
diff --git a/sys/scsi/scsi_base.c b/sys/scsi/scsi_base.c
new file mode 100644
index 0000000..02af5f2
--- /dev/null
+++ b/sys/scsi/scsi_base.c
@@ -0,0 +1,901 @@
+/*
+ * Written By Julian ELischer
+ * Copyright julian Elischer 1993.
+ * Permission is granted to use or redistribute this file in any way as long
+ * as this notice remains. Julian Elischer does not guarantee that this file
+ * is totally correct for any given task and users of this file must
+ * accept responsibility for any damage that occurs from the application of this
+ * file.
+ *
+ * Written by Julian Elischer (julian@dialix.oz.au)
+ * $Id: scsi_base.c,v 1.7 1994/04/20 07:06:54 davidg Exp $
+ */
+
+#define SPLSD splbio
+#define ESUCCESS 0
+#include <sys/types.h>
+#include <sys/param.h>
+#include <machine/param.h>
+#include <vm/vm_statistics.h>
+#include <vm/vm_param.h>
+#include <vm/lock.h>
+#include <machine/pmap.h>
+#include <machine/vmparam.h>
+#include "systm.h"
+#include <sys/buf.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+#include <sys/errno.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsi_disk.h>
+#include <scsi/scsiconf.h>
+
+static errval sc_err1(struct scsi_xfer *);
+static errval scsi_interpret_sense(struct scsi_xfer *);
+
+#ifdef NetBSD
+#ifdef DDB
+int Debugger();
+#else /* DDB */
+#define Debugger()
+#endif /* DDB */
+#else /* NetBSD */
+#include "ddb.h"
+#if NDDB > 0
+#else /* NDDB > 0 */
+#define Debugger()
+#endif /* NDDB > 0 */
+#endif
+
+void sc_print_addr __P((struct scsi_link *sc_link));
+
+struct scsi_xfer *next_free_xs;
+
+/*
+ * Get a scsi transfer structure for the caller. Charge the structure
+ * to the device that is referenced by the sc_link structure. If the
+ * sc_link structure has no 'credits' then the device already has the
+ * maximum number or outstanding operations under way. In this stage,
+ * wait on the structure so that when one is freed, we are awoken again
+ * If the SCSI_NOSLEEP flag is set, then do not wait, but rather, return
+ * a NULL pointer, signifying that no slots were available
+ * Note in the link structure, that we are waiting on it.
+ */
+
+struct scsi_xfer *
+get_xs(sc_link, flags)
+ struct scsi_link *sc_link; /* who to charge the xs to */
+ u_int32 flags; /* if this call can sleep */
+{
+ struct scsi_xfer *xs;
+ u_int32 s;
+
+ SC_DEBUG(sc_link, SDEV_DB3, ("get_xs\n"));
+ s = splbio();
+ while (!sc_link->opennings) {
+ SC_DEBUG(sc_link, SDEV_DB3, ("sleeping\n"));
+ if (flags & SCSI_NOSLEEP) {
+ splx(s);
+ return 0;
+ }
+ sc_link->flags |= SDEV_WAITING;
+ tsleep((caddr_t)sc_link, PRIBIO, "scsiget", 0);
+ }
+ sc_link->opennings--;
+ if (xs = next_free_xs) {
+ next_free_xs = xs->next;
+ splx(s);
+ } else {
+ splx(s);
+ SC_DEBUG(sc_link, SDEV_DB3, ("making\n"));
+ xs = malloc(sizeof(*xs), M_TEMP,
+ ((flags & SCSI_NOSLEEP) ? M_NOWAIT : M_WAITOK));
+ if (xs == NULL) {
+ sc_print_addr(sc_link);
+ printf("cannot allocate scsi xs\n");
+ return (NULL);
+ }
+ }
+ SC_DEBUG(sc_link, SDEV_DB3, ("returning\n"));
+ xs->sc_link = sc_link;
+ return (xs);
+}
+
+/*
+ * Given a scsi_xfer struct, and a device (referenced through sc_link)
+ * return the struct to the free pool and credit the device with it
+ * If another process is waiting for an xs, do a wakeup, let it proceed
+ */
+void
+free_xs(xs, sc_link, flags)
+ struct scsi_xfer *xs;
+ struct scsi_link *sc_link; /* who to credit for returning it */
+ u_int32 flags;
+{
+ xs->next = next_free_xs;
+ next_free_xs = xs;
+
+ SC_DEBUG(sc_link, SDEV_DB3, ("free_xs\n"));
+ /* if was 0 and someone waits, wake them up */
+ if ((!sc_link->opennings++) && (sc_link->flags & SDEV_WAITING)) {
+ sc_link->flags &= ~SDEV_WAITING;
+ wakeup((caddr_t)sc_link); /* remember, it wakes them ALL up */
+ } else {
+ if (sc_link->device->start) {
+ SC_DEBUG(sc_link, SDEV_DB2, ("calling private start()\n"));
+ (*(sc_link->device->start)) (sc_link->dev_unit);
+ }
+ }
+}
+
+/*
+ * Find out from the device what its capacity is.
+ */
+u_int32
+scsi_size(sc_link, flags)
+ struct scsi_link *sc_link;
+ u_int32 flags;
+{
+ struct scsi_read_cap_data rdcap;
+ struct scsi_read_capacity scsi_cmd;
+ u_int32 size;
+
+ /*
+ * make up a scsi command and ask the scsi driver to do
+ * it for you.
+ */
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = READ_CAPACITY;
+
+ /*
+ * If the command works, interpret the result as a 4 byte
+ * number of blocks
+ */
+ if (scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) & rdcap,
+ sizeof(rdcap),
+ 2,
+ 20000,
+ NULL,
+ flags | SCSI_DATA_IN) != 0) {
+
+ sc_print_addr(sc_link);
+ printf("could not get size\n");
+ return (0);
+ } else {
+ size = rdcap.addr_0 + 1;
+ size += rdcap.addr_1 << 8;
+ size += rdcap.addr_2 << 16;
+ size += rdcap.addr_3 << 24;
+ }
+ return (size);
+}
+
+/*
+ * Get scsi driver to send a "are you ready?" command
+ */
+errval
+scsi_test_unit_ready(sc_link, flags)
+ struct scsi_link *sc_link;
+ u_int32 flags;
+{
+ struct scsi_test_unit_ready scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = TEST_UNIT_READY;
+
+ return (scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 2,
+ 100000,
+ NULL,
+ flags));
+}
+
+/*
+ * Do a scsi operation, asking a device to run as SCSI-II if it can.
+ */
+errval
+scsi_change_def(sc_link, flags)
+ struct scsi_link *sc_link;
+ u_int32 flags;
+{
+ struct scsi_changedef scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = CHANGE_DEFINITION;
+ scsi_cmd.how = SC_SCSI_2;
+
+ return (scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 2,
+ 100000,
+ NULL,
+ flags));
+}
+
+/*
+ * Do a scsi operation asking a device what it is
+ * Use the scsi_cmd routine in the switch table.
+ */
+errval
+scsi_inquire(sc_link, inqbuf, flags)
+ struct scsi_link *sc_link;
+ struct scsi_inquiry_data *inqbuf;
+ u_int32 flags;
+{
+ struct scsi_inquiry scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = INQUIRY;
+ scsi_cmd.length = sizeof(struct scsi_inquiry_data);
+
+ return (scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) inqbuf,
+ sizeof(struct scsi_inquiry_data),
+ 2,
+ 100000,
+ NULL,
+ SCSI_DATA_IN | flags));
+}
+
+/*
+ * Prevent or allow the user to remove the media
+ */
+errval
+scsi_prevent(sc_link, type, flags)
+ struct scsi_link *sc_link;
+ u_int32 type, flags;
+{
+ struct scsi_prevent scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = PREVENT_ALLOW;
+ scsi_cmd.how = type;
+ return (scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 2,
+ 5000,
+ NULL,
+ flags));
+}
+
+/*
+ * Get scsi driver to send a "start up" command
+ */
+errval
+scsi_start_unit(sc_link, flags)
+ struct scsi_link *sc_link;
+ u_int32 flags;
+{
+ struct scsi_start_stop scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = START_STOP;
+ scsi_cmd.how = SSS_START;
+
+ return (scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 2,
+ 10000,
+ NULL,
+ flags));
+}
+
+/*
+ * Get scsi driver to send a "stop" command
+ */
+errval
+scsi_stop_unit(sc_link, eject, flags)
+ struct scsi_link *sc_link;
+ u_int32 eject;
+ u_int32 flags;
+{
+ struct scsi_start_stop scsi_cmd;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = START_STOP;
+ if (eject) {
+ scsi_cmd.how = SSS_LOEJ;
+ }
+
+ return (scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 2,
+ 10000,
+ NULL,
+ flags));
+}
+
+/*
+ * This routine is called by the scsi interrupt when the transfer is complete.
+ */
+void
+scsi_done(xs)
+ struct scsi_xfer *xs;
+{
+ struct scsi_link *sc_link = xs->sc_link;
+ struct buf *bp = xs->bp;
+ errval retval;
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("scsi_done\n"));
+#ifdef SCSIDEBUG
+ if (sc_link->flags & SDEV_DB1)
+ {
+ show_scsi_cmd(xs);
+ }
+#endif /*SCSIDEBUG */
+ /*
+ * If it's a user level request, bypass all usual completion processing,
+ * let the user work it out.. We take reponsibility for freeing the
+ * xs when the user returns. (and restarting the device's queue).
+ */
+ if (xs->flags & SCSI_USER) {
+ biodone(xs->bp);
+#ifdef NOTNOW
+ SC_DEBUG(sc_link, SDEV_DB3, ("calling user done()\n"));
+ scsi_user_done(xs); /* to take a copy of the sense etc. */
+ SC_DEBUG(sc_link, SDEV_DB3, ("returned from user done()\n "));
+#endif
+ free_xs(xs, sc_link, SCSI_NOSLEEP); /* restarts queue too */
+ SC_DEBUG(sc_link, SDEV_DB3, ("returning to adapter\n"));
+ return;
+ }
+ /*
+ * If the device has it's own done routine, call it first.
+ * If it returns a legit error value, return that, otherwise
+ * it wants us to continue with normal processing.
+ */
+
+ if (sc_link->device->done) {
+ SC_DEBUG(sc_link, SDEV_DB2, ("calling private done()\n"));
+ retval = (*sc_link->device->done) (xs);
+ if (retval == -1) {
+ free_xs(xs, sc_link, SCSI_NOSLEEP); /*XXX */
+ return; /* it did it all, finish up */
+ }
+ if (retval == -2) {
+ return; /* it did it all, finish up */
+ }
+ SC_DEBUG(sc_link, SDEV_DB3, ("continuing with generic done()\n"));
+ }
+ if ((bp = xs->bp) == NULL) {
+ /*
+ * if it's a normal upper level request, then ask
+ * the upper level code to handle error checking
+ * rather than doing it here at interrupt time
+ */
+ wakeup((caddr_t)xs);
+ return;
+ }
+ /*
+ * Go and handle errors now.
+ * If it returns -1 then we should RETRY
+ */
+ if ((retval = sc_err1(xs)) == -1) {
+ if ((*(sc_link->adapter->scsi_cmd)) (xs)
+ == SUCCESSFULLY_QUEUED) { /* don't wake the job, ok? */
+ return;
+ }
+ xs->flags |= ITSDONE;
+ }
+ free_xs(xs, sc_link, SCSI_NOSLEEP); /* does a start if needed */
+ biodone(bp);
+}
+
+/*
+ * ask the scsi driver to perform a command for us.
+ * tell it where to read/write the data, and how
+ * long the data is supposed to be. If we have a buf
+ * to associate with the transfer, we need that too.
+ */
+errval
+scsi_scsi_cmd(sc_link, scsi_cmd, cmdlen, data_addr, datalen,
+ retries, timeout, bp, flags)
+ struct scsi_link *sc_link;
+ struct scsi_generic *scsi_cmd;
+ u_int32 cmdlen;
+ u_char *data_addr;
+ u_int32 datalen;
+ u_int32 retries;
+ u_int32 timeout;
+ struct buf *bp;
+ u_int32 flags;
+{
+ struct scsi_xfer *xs;
+ errval retval;
+ u_int32 s;
+
+ if (bp) flags |= SCSI_NOSLEEP;
+ SC_DEBUG(sc_link, SDEV_DB2, ("scsi_cmd\n"));
+
+ xs = get_xs(sc_link, flags); /* should wait unless booting */
+ if (!xs) return (ENOMEM);
+ /*
+ * Fill out the scsi_xfer structure. We don't know whose context
+ * the cmd is in, so copy it.
+ */
+ bcopy(scsi_cmd, &(xs->cmdstore), cmdlen);
+ xs->flags = INUSE | flags;
+ xs->sc_link = sc_link;
+ xs->retries = retries;
+ xs->timeout = timeout;
+ xs->cmd = &xs->cmdstore;
+ xs->cmdlen = cmdlen;
+ xs->data = data_addr;
+ xs->datalen = datalen;
+ xs->resid = datalen;
+ xs->bp = bp;
+/*XXX*/ /*use constant not magic number */
+ if (datalen && ((caddr_t) data_addr < (caddr_t) KERNBASE)) {
+ if (bp) {
+ printf("Data buffered space not in kernel context\n");
+#ifdef SCSIDEBUG
+ show_scsi_cmd(xs);
+#endif /* SCSIDEBUG */
+ retval = EFAULT;
+ goto bad;
+ }
+#ifdef NOBOUNCE
+ xs->data = malloc(datalen, M_TEMP, M_WAITOK);
+#else
+ xs->data = (caddr_t) vm_bounce_kva_alloc( (datalen + PAGE_SIZE - 1)/PAGE_SIZE);
+#endif
+ /* I think waiting is ok *//*XXX */
+ switch ((int)(flags & (SCSI_DATA_IN | SCSI_DATA_OUT))) {
+ case 0:
+ printf("No direction flags, assuming both\n");
+#ifdef SCSIDEBUG
+ show_scsi_cmd(xs);
+#endif /* SCSIDEBUG */
+ case SCSI_DATA_IN | SCSI_DATA_OUT: /* weird */
+ case SCSI_DATA_OUT:
+ bcopy(data_addr, xs->data, datalen);
+ break;
+ case SCSI_DATA_IN:
+ bzero(xs->data, datalen);
+ }
+ }
+retry:
+ xs->error = XS_NOERROR;
+#ifdef PARANOID
+ if (datalen && ((caddr_t) xs->data < (caddr_t) KERNBASE)) {
+ printf("It's still wrong!\n");
+ }
+#endif /*PARANOID*/
+#ifdef SCSIDEBUG
+ if (sc_link->flags & SDEV_DB3) show_scsi_xs(xs);
+#endif /* SCSIDEBUG */
+ /*
+ * Do the transfer. If we are polling we will return:
+ * COMPLETE, Was poll, and scsi_done has been called
+ * TRY_AGAIN_LATER, Adapter short resources, try again
+ *
+ * if under full steam (interrupts) it will return:
+ * SUCCESSFULLY_QUEUED, will do a wakeup when complete
+ * TRY_AGAIN_LATER, (as for polling)
+ * After the wakeup, we must still check if it succeeded
+ *
+ * If we have a bp however, all the error proccessing
+ * and the buffer code both expect us to return straight
+ * to them, so as soon as the command is queued, return
+ */
+
+ retval = (*(sc_link->adapter->scsi_cmd)) (xs);
+
+ switch (retval) {
+ case SUCCESSFULLY_QUEUED:
+ if (bp)
+ return retval; /* will sleep (or not) elsewhere */
+ s = splbio();
+ while (!(xs->flags & ITSDONE)) {
+ tsleep((caddr_t)xs, PRIBIO + 1, "scsicmd", 0);
+ }
+ splx(s);
+ /* fall through to check success of completed command */
+ case COMPLETE: /* Polling command completed ok */
+/*XXX*/ case HAD_ERROR: /* Polling command completed with error */
+ SC_DEBUG(sc_link, SDEV_DB3, ("back in cmd()\n"));
+ if ((retval = sc_err1(xs)) == -1)
+ goto retry;
+ break;
+
+ case TRY_AGAIN_LATER: /* adapter resource shortage */
+ SC_DEBUG(sc_link, SDEV_DB3, ("will try again \n"));
+ /* should sleep 1 sec here */
+ if (xs->retries--) {
+ xs->flags &= ~ITSDONE;
+ goto retry;
+ }
+ default:
+ retval = EIO;
+ }
+ /*
+ * If we had to copy the data out of the user's context,
+ * then do the other half (copy it back or whatever)
+ * and free the memory buffer
+ */
+ if (datalen && (xs->data != data_addr)) {
+ switch ((int)(flags & (SCSI_DATA_IN | SCSI_DATA_OUT))) {
+ case 0:
+ case SCSI_DATA_IN | SCSI_DATA_OUT: /* weird */
+ case SCSI_DATA_IN:
+ bcopy(xs->data, data_addr, datalen);
+ break;
+ }
+#ifdef NOBOUNCE
+ free(xs->data, M_TEMP);
+#else
+ vm_bounce_kva_alloc_free(xs->data, (datalen + PAGE_SIZE - 1)/PAGE_SIZE, 0);
+#endif
+ }
+ /*
+ * we have finished with the xfer stuct, free it and
+ * check if anyone else needs to be started up.
+ */
+bad:
+ free_xs(xs, sc_link, flags); /* includes the 'start' op */
+ if (bp && retval) {
+ bp->b_error = retval;
+ bp->b_flags |= B_ERROR;
+ biodone(bp);
+ }
+ return (retval);
+}
+
+static errval
+sc_err1(xs)
+ struct scsi_xfer *xs;
+{
+ struct buf *bp = xs->bp;
+ errval retval;
+
+ SC_DEBUG(xs->sc_link, SDEV_DB3, ("sc_err1,err = 0x%x \n", xs->error));
+ /*
+ * If it has a buf, we might be working with
+ * a request from the buffer cache or some other
+ * piece of code that requires us to process
+ * errors at inetrrupt time. We have probably
+ * been called by scsi_done()
+ */
+ switch ((int)xs->error) {
+ case XS_NOERROR: /* nearly always hit this one */
+ retval = ESUCCESS;
+ if (bp) {
+ bp->b_error = 0;
+ bp->b_resid = 0;
+ }
+ break;
+
+ case XS_SENSE:
+ if (bp) {
+ bp->b_error = 0;
+ bp->b_resid = 0;
+ if (retval = (scsi_interpret_sense(xs))) {
+ bp->b_flags |= B_ERROR;
+ bp->b_error = retval;
+ bp->b_resid = bp->b_bcount;
+ }
+ SC_DEBUG(xs->sc_link, SDEV_DB3,
+ ("scsi_interpret_sense (bp) returned %d\n", retval));
+ } else {
+ retval = (scsi_interpret_sense(xs));
+ SC_DEBUG(xs->sc_link, SDEV_DB3,
+ ("scsi_interpret_sense (no bp) returned %d\n", retval));
+ }
+ break;
+
+ case XS_BUSY:
+ /*should somehow arange for a 1 sec delay here (how?) */
+ /* XXX tsleep(&localvar, priority, "foo", hz);
+ that's how! */
+ case XS_TIMEOUT:
+ /*
+ * If we can, resubmit it to the adapter.
+ */
+ if (xs->retries--) {
+ xs->error = XS_NOERROR;
+ xs->flags &= ~ITSDONE;
+ goto retry;
+ }
+ /* fall through */
+ case XS_DRIVER_STUFFUP:
+ if (bp) {
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ }
+ retval = EIO;
+ break;
+ default:
+ retval = EIO;
+ sc_print_addr(xs->sc_link);
+ printf("unknown error category from scsi driver\n");
+ }
+ return retval;
+retry:
+ return (-1);
+}
+
+/*
+ * Look at the returned sense and act on the error, determining
+ * the unix error number to pass back. (0 = report no error)
+ *
+ * THIS IS THE DEFAULT ERROR HANDLER
+ */
+static errval
+scsi_interpret_sense(xs)
+ struct scsi_xfer *xs;
+{
+ struct scsi_sense_data *sense;
+ struct scsi_link *sc_link = xs->sc_link;
+ u_int32 key;
+ u_int32 silent;
+ u_int32 info;
+ errval errcode;
+
+ static char *error_mes[] =
+ {"soft error (corrected)",
+ "not ready", "medium error",
+ "non-media hardware failure", "illegal request",
+ "unit attention", "readonly device",
+ "no data found", "vendor unique",
+ "copy aborted", "command aborted",
+ "search returned equal", "volume overflow",
+ "verify miscompare", "unknown error key"
+ };
+
+ /*
+ * If the flags say errs are ok, then always return ok.
+ */
+ if (xs->flags & SCSI_ERR_OK)
+ return (ESUCCESS);
+
+ sense = &(xs->sense);
+#ifdef SCSIDEBUG
+ if (sc_link->flags & SDEV_DB1) {
+ u_int32 count = 0;
+ printf("code%x valid%x ",
+ sense->error_code & SSD_ERRCODE,
+ sense->error_code & SSD_ERRCODE_VALID ? 1 : 0);
+ printf("seg%x key%x ili%x eom%x fmark%x\n",
+ sense->ext.extended.segment,
+ sense->ext.extended.flags & SSD_KEY,
+ sense->ext.extended.flags & SSD_ILI ? 1 : 0,
+ sense->ext.extended.flags & SSD_EOM ? 1 : 0,
+ sense->ext.extended.flags & SSD_FILEMARK ? 1 : 0);
+ printf("info: %x %x %x %x followed by %d extra bytes\n",
+ sense->ext.extended.info[0],
+ sense->ext.extended.info[1],
+ sense->ext.extended.info[2],
+ sense->ext.extended.info[3],
+ sense->ext.extended.extra_len);
+ printf("extra: ");
+ while (count < sense->ext.extended.extra_len) {
+ printf("%x ", sense->ext.extended.extra_bytes[count++]);
+ }
+ printf("\n");
+ }
+#endif /*SCSIDEBUG */
+ /*
+ * If the device has it's own error handler, call it first.
+ * If it returns a legit error value, return that, otherwise
+ * it wants us to continue with normal error processing.
+ */
+ if (sc_link->device->err_handler) {
+ SC_DEBUG(sc_link, SDEV_DB2, ("calling private err_handler()\n"));
+ errcode = (*sc_link->device->err_handler) (xs);
+ if (errcode != -1)
+ return errcode; /* errcode >= 0 better ? */
+ }
+ /* otherwise use the default */
+ silent = (xs->flags & SCSI_SILENT);
+ switch (sense->error_code & SSD_ERRCODE) {
+ /*
+ * If it's code 70, use the extended stuff and interpret the key
+ */
+ case 0x71: /* delayed error */
+ sc_print_addr(sc_link);
+ key = sense->ext.extended.flags & SSD_KEY;
+ printf(" DELAYED ERROR, key = 0x%x\n", key);
+ case 0x70:
+ if (sense->error_code & SSD_ERRCODE_VALID) {
+ info = ntohl(*((long *) sense->ext.extended.info));
+ } else {
+ info = 0;
+ }
+ key = sense->ext.extended.flags & SSD_KEY;
+
+ if (key && !silent) {
+ sc_print_addr(sc_link);
+ printf("%s", error_mes[key - 1]);
+ if (sense->error_code & SSD_ERRCODE_VALID) {
+ switch ((int)key) {
+ case 0x2: /* NOT READY */
+ case 0x5: /* ILLEGAL REQUEST */
+ case 0x6: /* UNIT ATTENTION */
+ case 0x7: /* DATA PROTECT */
+ break;
+ case 0x8: /* BLANK CHECK */
+ printf(", requested size: %d (decimal)",
+ info);
+ break;
+ default:
+ printf(", info = %d (decimal)", info);
+ }
+ }
+ printf("\n");
+ }
+ switch ((int)key) {
+ case 0x0: /* NO SENSE */
+ case 0x1: /* RECOVERED ERROR */
+ if (xs->resid == xs->datalen)
+ xs->resid = 0; /* not short read */
+ case 0xc: /* EQUAL */
+ return (ESUCCESS);
+ case 0x2: /* NOT READY */
+ sc_link->flags &= ~SDEV_MEDIA_LOADED;
+ return (EBUSY);
+ case 0x5: /* ILLEGAL REQUEST */
+ return (EINVAL);
+ case 0x6: /* UNIT ATTENTION */
+ sc_link->flags &= ~SDEV_MEDIA_LOADED;
+ if (sc_link->flags & SDEV_OPEN) {
+ return (EIO);
+ } else {
+ return 0;
+ }
+ case 0x7: /* DATA PROTECT */
+ return (EACCES);
+ case 0xd: /* VOLUME OVERFLOW */
+ return (ENOSPC);
+ case 0x8: /* BLANK CHECK */
+ return (ESUCCESS);
+ default:
+ return (EIO);
+ }
+ /*
+ * Not code 70, just report it
+ */
+ default:
+ if (!silent) {
+ sc_print_addr(sc_link);
+ printf("error code %d",
+ sense->error_code & SSD_ERRCODE);
+ if (sense->error_code & SSD_ERRCODE_VALID) {
+ printf(" at block no. %d (decimal)",
+ (sense->ext.unextended.blockhi << 16) +
+ (sense->ext.unextended.blockmed << 8) +
+ (sense->ext.unextended.blocklow));
+ }
+ printf("\n");
+ }
+ return (EIO);
+ }
+}
+
+/*
+ * Utility routines often used in SCSI stuff
+ */
+
+/*
+ * convert a physical address to 3 bytes,
+ * MSB at the lowest address,
+ * LSB at the highest.
+ */
+void
+lto3b(val, bytes)
+ int val;
+ u_char *bytes;
+{
+ *bytes++ = (val & 0xff0000) >> 16;
+ *bytes++ = (val & 0xff00) >> 8;
+ *bytes = val & 0xff;
+}
+
+/*
+ * The reverse of lto3b
+ */
+int
+_3btol(bytes)
+ u_char *bytes;
+{
+ u_int32 rc;
+ rc = (*bytes++ << 16);
+ rc += (*bytes++ << 8);
+ rc += *bytes;
+ return ((int) rc);
+}
+
+/*
+ * Print out the scsi_link structure's address info.
+ */
+
+void
+sc_print_addr(sc_link)
+ struct scsi_link *sc_link;
+{
+
+ printf("%s%d(%s%d:%d:%d): ", sc_link->device->name, sc_link->dev_unit,
+ sc_link->adapter->name, sc_link->adapter_unit,
+ sc_link->target, sc_link->lun);
+}
+#ifdef SCSIDEBUG
+/*
+ * Given a scsi_xfer, dump the request, in all it's glory
+ */
+void
+show_scsi_xs(xs)
+ struct scsi_xfer *xs;
+{
+ printf("xs(0x%x): ", xs);
+ printf("flg(0x%x)", xs->flags);
+ printf("sc_link(0x%x)", xs->sc_link);
+ printf("retr(0x%x)", xs->retries);
+ printf("timo(0x%x)", xs->timeout);
+ printf("cmd(0x%x)", xs->cmd);
+ printf("len(0x%x)", xs->cmdlen);
+ printf("data(0x%x)", xs->data);
+ printf("len(0x%x)", xs->datalen);
+ printf("res(0x%x)", xs->resid);
+ printf("err(0x%x)", xs->error);
+ printf("bp(0x%x)", xs->bp);
+ show_scsi_cmd(xs);
+}
+
+void
+show_scsi_cmd(struct scsi_xfer *xs)
+{
+ u_char *b = (u_char *) xs->cmd;
+ int i = 0;
+
+ sc_print_addr(xs->sc_link);
+ printf("command: ");
+
+ if (!(xs->flags & SCSI_RESET)) {
+ while (i < xs->cmdlen) {
+ if (i)
+ printf(",");
+ printf("%x", b[i++]);
+ }
+ printf("-[%d bytes]\n", xs->datalen);
+ if (xs->datalen)
+ show_mem(xs->data, min(64, xs->datalen));
+ } else {
+ printf("-RESET-\n");
+ }
+}
+
+void
+show_mem(address, num)
+ unsigned char *address;
+ u_int32 num;
+{
+ u_int32 x, y;
+ printf("------------------------------");
+ for (y = 0; y < num; y += 1) {
+ if (!(y % 16))
+ printf("\n%03d: ", y);
+ printf("%02x ", *address++);
+ }
+ printf("\n------------------------------\n");
+}
+#endif /*SCSIDEBUG */
diff --git a/sys/scsi/scsi_cd.h b/sys/scsi/scsi_cd.h
new file mode 100644
index 0000000..0a4759b
--- /dev/null
+++ b/sys/scsi/scsi_cd.h
@@ -0,0 +1,229 @@
+/*
+ * Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * $Id: scsi_cd.h,v 1.6 93/08/26 21:09:19 julian Exp Locker: julian $
+ */
+#ifndef _SCSI_SCSI_CD_H
+#define _SCSI_SCSI_CD_H 1
+
+/*
+ * Define two bits always in the same place in byte 2 (flag byte)
+ */
+#define CD_RELADDR 0x01
+#define CD_MSF 0x02
+
+/*
+ * SCSI command format
+ */
+
+struct scsi_read_capacity_cd
+{
+ u_char op_code;
+ u_char byte2;
+ u_char addr_3; /* Most Significant */
+ u_char addr_2;
+ u_char addr_1;
+ u_char addr_0; /* Least Significant */
+ u_char unused[3];
+ u_char control;
+};
+
+struct scsi_pause
+{
+ u_char op_code;
+ u_char byte2;
+ u_char unused[6];
+ u_char resume;
+ u_char control;
+};
+#define PA_PAUSE 1
+#define PA_RESUME 0
+
+struct scsi_play_msf
+{
+ u_char op_code;
+ u_char byte2;
+ u_char unused;
+ u_char start_m;
+ u_char start_s;
+ u_char start_f;
+ u_char end_m;
+ u_char end_s;
+ u_char end_f;
+ u_char control;
+};
+
+struct scsi_play_track
+{
+ u_char op_code;
+ u_char byte2;
+ u_char unused[2];
+ u_char start_track;
+ u_char start_index;
+ u_char unused1;
+ u_char end_track;
+ u_char end_index;
+ u_char control;
+};
+
+struct scsi_play
+{
+ u_char op_code;
+ u_char byte2;
+ u_char blk_addr[4];
+ u_char unused;
+ u_char xfer_len[2];
+ u_char control;
+};
+
+struct scsi_play_big
+{
+ u_char op_code;
+ u_char byte2; /* same as above */
+ u_char blk_addr[4];
+ u_char xfer_len[4];
+ u_char unused;
+ u_char control;
+};
+
+struct scsi_play_rel_big
+{
+ u_char op_code;
+ u_char byte2; /* same as above */
+ u_char blk_addr[4];
+ u_char xfer_len[4];
+ u_char track;
+ u_char control;
+};
+
+struct scsi_read_header
+{
+ u_char op_code;
+ u_char byte2;
+ u_char blk_addr[4];
+ u_char unused;
+ u_char data_len[2];
+ u_char control;
+};
+
+struct scsi_read_subchannel
+{
+ u_char op_code;
+ u_char byte2;
+ u_char byte3;
+#define SRS_SUBQ 0x40
+ u_char subchan_format;
+ u_char unused[2];
+ u_char track;
+ u_char data_len[2];
+ u_char control;
+};
+
+struct scsi_read_toc
+{
+ u_char op_code;
+ u_char byte2;
+ u_char unused[4];
+ u_char from_track;
+ u_char data_len[2];
+ u_char control;
+};
+;
+
+struct scsi_read_cd_capacity
+{
+ u_char op_code;
+ u_char byte2;
+ u_char addr_3; /* Most Significant */
+ u_char addr_2;
+ u_char addr_1;
+ u_char addr_0; /* Least Significant */
+ u_char unused[3];
+ u_char control;
+};
+
+/*
+ * Opcodes
+ */
+
+#define READ_CD_CAPACITY 0x25 /* slightly different from disk */
+#define READ_SUBCHANNEL 0x42 /* cdrom read Subchannel */
+#define READ_TOC 0x43 /* cdrom read TOC */
+#define READ_HEADER 0x44 /* cdrom read header */
+#define PLAY 0x45 /* cdrom play 'play audio' mode */
+#define PLAY_MSF 0x47 /* cdrom play Min,Sec,Frames mode */
+#define PLAY_TRACK 0x48 /* cdrom play track/index mode */
+#define PLAY_TRACK_REL 0x49 /* cdrom play track/index mode */
+#define PAUSE 0x4b /* cdrom pause in 'play audio' mode */
+#define PLAY_BIG 0xa5 /* cdrom pause in 'play audio' mode */
+#define PLAY_TRACK_REL_BIG 0xa9 /* cdrom play track/index mode */
+
+
+
+struct scsi_read_cd_cap_data
+{
+ u_char addr_3; /* Most significant */
+ u_char addr_2;
+ u_char addr_1;
+ u_char addr_0; /* Least significant */
+ u_char length_3; /* Most significant */
+ u_char length_2;
+ u_char length_1;
+ u_char length_0; /* Least significant */
+};
+
+union cd_pages
+{
+ struct audio_page
+ {
+ u_char page_code;
+#define CD_PAGE_CODE 0x3F
+#define AUDIO_PAGE 0x0e
+#define CD_PAGE_PS 0x80
+ u_char param_len;
+ u_char flags;
+#define CD_PA_SOTC 0x02
+#define CD_PA_IMMED 0x04
+ u_char unused[2];
+ u_char format_lba;
+#define CD_PA_FORMAT_LBA 0x0F
+#define CD_PA_APR_VALID 0x80
+ u_char lb_per_sec[2];
+ struct port_control
+ {
+ u_char channels;
+#define CHANNEL 0x0F
+#define CHANNEL_0 1
+#define CHANNEL_1 2
+#define CHANNEL_2 4
+#define CHANNEL_3 8
+#define LEFT_CHANNEL CHANNEL_0
+#define RIGHT_CHANNEL CHANNEL_1
+ u_char volume;
+ } port[4];
+#define LEFT_PORT 0
+#define RIGHT_PORT 1
+ }audio;
+};
+
+struct cd_mode_data
+{
+ struct scsi_mode_header header;
+ struct blk_desc blk_desc;
+ union cd_pages page;
+};
+#endif /*_SCSI_SCSI_CD_H*/
+
diff --git a/sys/scsi/scsi_changer.h b/sys/scsi/scsi_changer.h
new file mode 100644
index 0000000..85819c8
--- /dev/null
+++ b/sys/scsi/scsi_changer.h
@@ -0,0 +1,98 @@
+/*
+ * SCSI changer interface description
+ */
+
+/*
+ * Written by Stefan Grefen (grefen@goofy.zdv.uni-mainz.de soon grefen@convex.com)
+ * based on the SCSI System by written Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * $Id: scsi_changer.h,v 1.5 93/08/26 21:09:22 julian Exp Locker: julian $
+ */
+#ifndef _SCSI_SCSI_CHANGER_H
+#define _SCSI_SCSI_CHANGER_H 1
+
+/*
+ * SCSI command format
+ */
+struct scsi_read_element_status
+{
+ u_char op_code;
+ u_char byte2;
+#define SRES_ELEM_TYPE_CODE 0x0F
+#define SRES_ELEM_VOLTAG 0x10
+ u_char starting_element_addr[2];
+ u_char number_of_elements[2];
+ u_char resv1;
+ u_char allocation_length[3];
+ u_char resv2;
+ u_char control;
+};
+#define RE_ALL_ELEMENTS 0
+#define RE_MEDIUM_TRANSPORT_ELEMENT 1
+#define RE_STORAGE_ELEMENT 2
+#define RE_IMPORT_EXPORT 3
+#define RE_DATA_TRANSFER_ELEMENT 4
+
+struct scsi_move_medium
+{
+ u_char op_code;
+ u_char byte2;
+ u_char transport_element_address[2];
+ u_char source_address[2];
+ u_char destination_address[2];
+ u_char rsvd[2];
+ u_char invert;
+ u_char control;
+};
+
+struct scsi_position_to_element
+{
+ u_char op_code;
+ u_char byte2;
+ u_char transport_element_address[2];
+ u_char source_address[2];
+ u_char rsvd[2];
+ u_char invert;
+ u_char control;
+};
+
+/*
+ * Opcodes
+ */
+#define POSITION_TO_ELEMENT 0x2b
+#define MOVE_MEDIUM 0xa5
+#define READ_ELEMENT_STATUS 0xb8
+
+struct scsi_element_status_data
+{
+ u_char first_element_reported[2];
+ u_char number_of_elements_reported[2];
+ u_char rsvd;
+ u_char byte_count_of_report[3];
+};
+
+struct element_status_page
+{
+ u_char element_type_code;
+ u_char flags;
+#define ESP_AVOLTAG 0x40
+#define ESP_PVOLTAG 0x80
+ u_char element_descriptor_length[2];
+ u_char rsvd;
+ u_char byte_count_of_descriptor_data[3];
+};
+#endif /*_SCSI_SCSI_CHANGER_H*/
+
diff --git a/sys/scsi/scsi_debug.h b/sys/scsi/scsi_debug.h
new file mode 100644
index 0000000..480ff14
--- /dev/null
+++ b/sys/scsi/scsi_debug.h
@@ -0,0 +1,53 @@
+/*#define SCSIDEBUG 1*/
+/*
+ * Written by Julian Elischer (julian@tfs.com)
+ *
+ * $Id: scsi_debug.h,v 1.3 93/10/10 09:26:05 julian Exp Locker: julian $
+ */
+#ifndef _SCSI_SCSI_DEBUG_H
+#define _SCSI_SCSI_DEBUG_H 1
+
+/*
+ * These are the new debug bits. (Sat Oct 2 12:46:46 WST 1993)
+ * the following DEBUG bits are defined to exist in the flags word of
+ * the scsi_link structure.
+ */
+#define SDEV_DB1 0x10 /* scsi commands, errors, data */
+#define SDEV_DB2 0x20 /* routine flow tracking */
+#define SDEV_DB3 0x40 /* internal to routine flows */
+#define SDEV_DB4 0x80 /* level 4 debugging for this dev */
+
+/* target and LUN we want to debug */
+#define DEBUGTARG 9 /*9 = dissable*/
+#define DEBUGLUN 0
+#define DEBUGLEVEL (SDEV_DB1|SDEV_DB2)
+
+/*
+ * This is the usual debug macro for use with the above bits
+ */
+#ifdef SCSIDEBUG
+#define SC_DEBUG(sc_link,Level,Printstuff) \
+ if((sc_link)->flags & (Level)) \
+ { \
+ printf("%s%d(%s%d:%d:%d): ", \
+ sc_link->device->name, \
+ sc_link->dev_unit, \
+ sc_link->adapter->name, \
+ sc_link->adapter_unit, \
+ sc_link->target, \
+ sc_link->lun); \
+ printf Printstuff; \
+ }
+#define SC_DEBUGN(sc_link,Level,Printstuff) \
+ if((sc_link)->flags & (Level)) \
+ { \
+ printf Printstuff; \
+ }
+#else
+#define SC_DEBUG(A,B,C) /* not included */
+#define SC_DEBUGN(A,B,C) /* not included */
+#endif
+
+#endif /*_SCSI_SCSI_DEBUG_H*/
+/* END OF FILE */
+
diff --git a/sys/scsi/scsi_disk.h b/sys/scsi/scsi_disk.h
new file mode 100644
index 0000000..60d0bcc
--- /dev/null
+++ b/sys/scsi/scsi_disk.h
@@ -0,0 +1,216 @@
+/*
+ * SCSI interface description
+ */
+
+/*
+ * Some lines of this file come from a file of the name "scsi.h"
+ * distributed by OSF as part of mach2.5,
+ * so the following disclaimer has been kept.
+ *
+ * Copyright 1990 by Open Software Foundation,
+ * Grenoble, FRANCE
+ *
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of OSF or Open Software
+ * Foundation not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.
+ *
+ * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+ * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Largely written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * $Id: scsi_disk.h,v 1.4 93/08/26 21:09:23 julian Exp Locker: julian $
+ */
+
+/*
+ * SCSI command format
+ */
+
+#ifndef _SCSI_SCSI_DISK_H
+#define _SCSI_SCSI_DISK_H 1
+
+struct scsi_reassign_blocks
+{
+ u_char op_code;
+ u_char byte2;
+ u_char unused[3];
+ u_char control;
+};
+
+struct scsi_rw
+{
+ u_char op_code;
+ u_char addr_2; /* Most significant */
+#define SRW_TOPADDR 0x1F /* only 5 bits here */
+ u_char addr_1;
+ u_char addr_0; /* least significant */
+ u_char length;
+ u_char control;
+};
+
+struct scsi_rw_big
+{
+ u_char op_code;
+ u_char byte2;
+#define SRWB_RELADDR 0x01
+ u_char addr_3; /* Most significant */
+ u_char addr_2;
+ u_char addr_1;
+ u_char addr_0; /* least significant */
+ u_char reserved;;
+ u_char length2;
+ u_char length1;
+ u_char control;
+};
+
+struct scsi_read_capacity
+{
+ u_char op_code;
+ u_char byte2;
+ u_char addr_3; /* Most Significant */
+ u_char addr_2;
+ u_char addr_1;
+ u_char addr_0; /* Least Significant */
+ u_char unused[3];
+ u_char control;
+};
+
+struct scsi_start_stop
+{
+ u_char op_code;
+ u_char byte2;
+ u_char unused[2];
+ u_char how;
+#define SSS_START 0x01
+#define SSS_LOEJ 0x02
+ u_char control;
+};
+
+
+
+/*
+ * Opcodes
+ */
+
+#define REASSIGN_BLOCKS 0x07
+#define READ_COMMAND 0x08
+#define WRITE_COMMAND 0x0a
+#define MODE_SELECT 0x15
+#define MODE_SENSE 0x1a
+#define START_STOP 0x1b
+#define PREVENT_ALLOW 0x1e
+#define READ_CAPACITY 0x25
+#define READ_BIG 0x28
+#define WRITE_BIG 0x2a
+
+
+
+struct scsi_read_cap_data
+{
+ u_char addr_3; /* Most significant */
+ u_char addr_2;
+ u_char addr_1;
+ u_char addr_0; /* Least significant */
+ u_char length_3; /* Most significant */
+ u_char length_2;
+ u_char length_1;
+ u_char length_0; /* Least significant */
+};
+
+struct scsi_reassign_blocks_data
+{
+ u_char reserved[2];
+ u_char length_msb;
+ u_char length_lsb;
+ struct
+ {
+ u_char dlbaddr_3; /* defect logical block address (MSB) */
+ u_char dlbaddr_2;
+ u_char dlbaddr_1;
+ u_char dlbaddr_0; /* defect logical block address (LSB) */
+ } defect_descriptor[1];
+};
+
+union disk_pages /* this is the structure copied from osf */
+{
+ struct page_disk_format {
+ u_char pg_code; /* page code (should be 3) */
+#define DISK_PGCODE 0x3F /* only 6 bits valid */
+ u_char pg_length; /* page length (should be 0x16) */
+ u_char trk_z_1; /* tracks per zone (MSB) */
+ u_char trk_z_0; /* tracks per zone (LSB) */
+ u_char alt_sec_1; /* alternate sectors per zone (MSB) */
+ u_char alt_sec_0; /* alternate sectors per zone (LSB) */
+ u_char alt_trk_z_1; /* alternate tracks per zone (MSB) */
+ u_char alt_trk_z_0; /* alternate tracks per zone (LSB) */
+ u_char alt_trk_v_1; /* alternate tracks per volume (MSB) */
+ u_char alt_trk_v_0; /* alternate tracks per volume (LSB) */
+ u_char ph_sec_t_1; /* physical sectors per track (MSB) */
+ u_char ph_sec_t_0; /* physical sectors per track (LSB) */
+ u_char bytes_s_1; /* bytes per sector (MSB) */
+ u_char bytes_s_0; /* bytes per sector (LSB) */
+ u_char interleave_1;/* interleave (MSB) */
+ u_char interleave_0;/* interleave (LSB) */
+ u_char trk_skew_1; /* track skew factor (MSB) */
+ u_char trk_skew_0; /* track skew factor (LSB) */
+ u_char cyl_skew_1; /* cylinder skew (MSB) */
+ u_char cyl_skew_0; /* cylinder skew (LSB) */
+ u_char flags; /* various */
+#define DISK_FMT_SURF 0x10
+#define DISK_FMT_RMB 0x20
+#define DISK_FMT_HSEC 0x40
+#define DISK_FMT_SSEC 0x80
+ u_char reserved2;
+ u_char reserved3;
+ } disk_format;
+ struct page_rigid_geometry {
+ u_char pg_code; /* page code (should be 4) */
+ u_char pg_length; /* page length (should be 0x16) */
+ u_char ncyl_2; /* number of cylinders (MSB) */
+ u_char ncyl_1; /* number of cylinders */
+ u_char ncyl_0; /* number of cylinders (LSB) */
+ u_char nheads; /* number of heads */
+ u_char st_cyl_wp_2; /* starting cyl., write precomp (MSB) */
+ u_char st_cyl_wp_1; /* starting cyl., write precomp */
+ u_char st_cyl_wp_0; /* starting cyl., write precomp (LSB) */
+ u_char st_cyl_rwc_2;/* starting cyl., red. write cur (MSB)*/
+ u_char st_cyl_rwc_1;/* starting cyl., red. write cur */
+ u_char st_cyl_rwc_0;/* starting cyl., red. write cur (LSB)*/
+ u_char driv_step_1; /* drive step rate (MSB) */
+ u_char driv_step_0; /* drive step rate (LSB) */
+ u_char land_zone_2; /* landing zone cylinder (MSB) */
+ u_char land_zone_1; /* landing zone cylinder */
+ u_char land_zone_0; /* landing zone cylinder (LSB) */
+ u_char reserved1;
+ u_char reserved2;
+ u_char reserved3;
+ } rigid_geometry;
+} ;
+#endif /* _SCSI_SCSI_DISK_H*/
diff --git a/sys/scsi/scsi_generic.h b/sys/scsi/scsi_generic.h
new file mode 100644
index 0000000..44f2bd1
--- /dev/null
+++ b/sys/scsi/scsi_generic.h
@@ -0,0 +1,63 @@
+/*
+ * Contributed by HD Associates (hd@world.std.com).
+ * Copyright (c) 1992, 1993 HD Associates
+ *
+ * Berkeley style copyright. I've just snarfed it out of stdio.h:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)stdio.h 5.17 (Berkeley) 6/3/91
+ * $Id$
+ */
+
+/* generic SCSI header file. We use the same minor number format
+ * as on SGI except that the flag bits aren't available because they
+ * are used as the board index.
+ *
+ * The minor number format is:
+ * FF UUU III (FFUU UIII)
+ *
+ * Where:
+ * FF is the board index
+ * UUU are the LUN
+ * III is the SCSI ID (controller)
+ */
+
+#ifndef _SCSI_GENERIC_H_
+#define _SCSI_GENERIC_H_
+
+#define G_SCSI_FLAG(DEV) (((DEV) & 0xC0) >> 6)
+#define G_SCSI_UNIT(DEV) G_SCSI_FLAG(DEV)
+#define G_SCSI_LUN(DEV) (((DEV) & 0x38) >> 3)
+#define G_SCSI_ID(DEV) ((DEV) & 0x7)
+
+#define G_SCSI_MINOR(FLAG, LUN, ID) \
+ (((FLAG) << 6) | ((LUN) << 3) | (ID))
+
+#endif /* _SCSI_GENERIC_H_ */
diff --git a/sys/scsi/scsi_ioctl.c b/sys/scsi/scsi_ioctl.c
new file mode 100644
index 0000000..a52b3a5
--- /dev/null
+++ b/sys/scsi/scsi_ioctl.c
@@ -0,0 +1,338 @@
+/*
+ * Contributed by HD Associates (hd@world.std.com).
+ * Copyright (c) 1992, 1993 HD Associates
+ *
+ * Berkeley style copyright.
+ *
+ *
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <machine/param.h>
+#include <vm/vm_statistics.h>
+#include <vm/vm_param.h>
+#include <vm/lock.h>
+#include <machine/pmap.h>
+#include <machine/vmparam.h>
+#include "systm.h"
+#include <sys/errno.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#define b_screq b_driver1 /* a patch in buf.h */
+#define b_sc_link b_driver2 /* a patch in buf.h */
+#include <sys/proc.h>
+
+#include "scbus.h"
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#include <sys/scsiio.h>
+
+void scsierr(struct buf *, int); /* XXX ??? */
+
+/*
+ * We let the user interpret his own sense in the generic scsi world.
+ * This routine is called at interrupt time if the SCSI_USER bit was set
+ * in the flags passed to scsi_scsi_cmd(). No other completion processing
+ * takes place, even if we are running over another device driver.
+ * The lower level routines that call us here, will free the xs and restart
+ * the device's queue if such exists.
+ */
+#ifndef min
+#define min(A,B) ((A<B) ? A : B )
+#endif
+
+void scsi_user_done(xs)
+struct scsi_xfer *xs;
+{
+
+ struct buf *bp;
+ scsireq_t *screq;
+
+ bp = xs->bp;
+ if(!bp) { /* ALL user requests must have a buf */
+ sc_print_addr(xs->sc_link);
+ printf("User command with no buf\n");
+ return ;
+ }
+ screq = bp->b_screq;
+ if (!screq) { /* Is it one of ours? (the SCSI_USER bit says it is) */
+ sc_print_addr(xs->sc_link);
+ printf("User command with no request\n");
+ return ;
+ }
+
+ SC_DEBUG(xs->sc_link,SDEV_DB2,("user-done\n"));
+ screq->retsts = 0;
+ screq->status = xs->status;
+ switch((int)xs->error) {
+ case XS_NOERROR:
+ SC_DEBUG(xs->sc_link,SDEV_DB3,("no error\n"));
+ screq->datalen_used = xs->datalen - xs->resid; /* probably rubbish */
+ screq->retsts = SCCMD_OK;
+ break;
+
+ case XS_SENSE:
+ SC_DEBUG(xs->sc_link,SDEV_DB3,("have sense\n"));
+ screq->senselen_used = min(sizeof(xs->sense),SENSEBUFLEN);
+ bcopy(&xs->sense,screq->sense,screq->senselen);
+ screq->retsts = SCCMD_SENSE;
+ break;
+
+ case XS_DRIVER_STUFFUP:
+ sc_print_addr(xs->sc_link);
+ printf("host adapter code inconsistency\n");
+ screq->retsts = SCCMD_UNKNOWN;
+ break;
+
+ case XS_TIMEOUT:
+ SC_DEBUG(xs->sc_link,SDEV_DB3,("timeout\n"));
+ screq->retsts = SCCMD_TIMEOUT;
+ break;
+
+ case XS_BUSY:
+ SC_DEBUG(xs->sc_link,SDEV_DB3,("busy\n"));
+ screq->retsts = SCCMD_BUSY;
+ break;
+
+ default:
+ sc_print_addr(xs->sc_link);
+ printf("unknown error category from host adapter code\n");
+ screq->retsts = SCCMD_UNKNOWN;
+ break;
+ }
+ biodone(bp); /* we're waiting on it in scsi_strategy() */
+ return; /* it'll free the xs and restart any queue */
+}
+
+
+/* Pseudo strategy function
+ * Called by scsi_do_ioctl() via physio/physstrat if there is to
+ * be data transfered, and directly if there is no data transfer.
+ *
+ * Should I reorganize this so it returns to physio instead
+ * of sleeping in scsiio_scsi_cmd? Is there any advantage, other
+ * than avoiding the probable duplicate wakeup in iodone? [PD]
+ *
+ * No, seems ok to me... [JRE]
+ * (I don't see any duplicate wakeups)
+ *
+ * Can't be used with block devices or raw_read/raw_write directly
+ * from the cdevsw/bdevsw tables because they couldn't have added
+ * the screq structure. [JRE]
+ */
+void scsistrategy(struct buf *bp)
+{
+ errval err;
+ struct scsi_link *sc_link = bp->b_sc_link;
+ scsireq_t *screq;
+ u_int32 flags = 0;
+ int s;
+
+
+ if(!sc_link) {
+ printf("user_strat: No link pointer\n");
+ scsierr(bp,EINVAL);
+ return;
+ }
+ SC_DEBUG(sc_link,SDEV_DB2,("user_strategy\n"));
+ screq = bp->b_screq;
+ if(!screq) {
+ sc_print_addr(sc_link);
+ printf("No request block\n");
+ scsierr(bp,EINVAL);
+ return;
+ }
+
+ /* We're in trouble if physio tried to break up the
+ * transfer:
+ */
+ if (bp->b_bcount != screq->datalen) {
+ sc_print_addr(sc_link);
+ printf("physio split the request.. cannot proceed\n");
+ scsierr(bp, EIO);
+ return;
+ }
+
+ if (screq->timeout == 0) {
+ scsierr(bp, EINVAL);
+ return;
+ }
+
+ if (screq->cmdlen > sizeof(struct scsi_generic)) {
+ sc_print_addr(sc_link);
+ printf("cmdlen too big ");
+ scsierr(bp, EFAULT);
+ return;
+ }
+
+
+ if (screq->flags & SCCMD_READ)
+ flags |= SCSI_DATA_IN;
+
+ if (screq->flags & SCCMD_WRITE)
+ flags |= SCSI_DATA_OUT;
+
+ if (screq->flags & SCCMD_TARGET)
+ flags |= SCSI_TARGET;
+
+ if (screq->flags & SCCMD_ESCAPE)
+ flags |= SCSI_ESCAPE;
+ err = scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *)screq->cmd,
+ screq->cmdlen,
+ (u_char *)bp->b_un.b_addr,
+ screq->datalen,
+ 0, /* user must do the retries *//* ignored */
+ screq->timeout,
+ bp,
+ flags | SCSI_USER);
+
+
+
+ /*because there is a bp, scsi_scsi_cmd will return immediatly*/
+ if (err)
+ {
+ scsierr(bp, err);
+ return;
+ }
+ SC_DEBUG(sc_link,SDEV_DB3,("about to sleep\n"));
+ s = splbio();
+ while(!(bp->b_flags & B_DONE))
+ {
+ tsleep((caddr_t)bp, PRIBIO, "scsistrat", 0);
+ }
+ splx(s);
+ SC_DEBUG(sc_link,SDEV_DB3,("back from sleep\n"));
+ return;
+}
+
+void scsiminphys(struct buf *bp)
+{
+ /*XXX*//* call the adapter's minphys */
+}
+
+
+/*
+ * Something (e.g. another driver) has called us
+ * with an sc_link for a target/lun/adapter, and a scsi
+ * specific ioctl to perform, better try.
+ * If user-level type command, we must still be running
+ * in the context of the calling process
+ */
+errval scsi_do_ioctl(struct scsi_link *sc_link, int cmd, caddr_t addr, int f)
+{
+ errval ret = 0;
+ int phys;
+
+ SC_DEBUG(sc_link,SDEV_DB2,("scsi_do_ioctl(0x%x)\n",cmd));
+ switch(cmd)
+ {
+#ifndef NetBSD
+ case SCIOCCOMMAND:
+ {
+ /*
+ * You won't believe this, but the arg copied in
+ * from the user space, is on the kernel stack
+ * for this process, so we can't write
+ * to it at interrupt time..
+ * we need to copy it in and out!
+ * Make a static copy using malloc!
+ */
+ scsireq_t *screq2 = (scsireq_t *)addr;
+ scsireq_t *screq = (scsireq_t *)addr;
+ int rwflag = (screq->flags & SCCMD_READ) ? B_READ : B_WRITE;
+ struct buf *bp;
+ caddr_t d_addr;
+ int len;
+
+ if((unsigned int)screq < (unsigned int)KERNBASE)
+ {
+ screq = malloc(sizeof(scsireq_t),M_TEMP,M_WAITOK);
+ bcopy(screq2,screq,sizeof(scsireq_t));
+ }
+ bp = malloc(sizeof (struct buf),M_TEMP,M_WAITOK);
+ bzero(bp,sizeof(struct buf));
+ d_addr = screq->databuf;
+ bp->b_bcount = len = screq->datalen;
+ bp->b_screq = screq;
+ bp->b_sc_link = sc_link;
+ if (len) {
+ /* have data, translate it. (physio)*/
+#ifdef __NetBSD__
+#error "dev, mincntfn & uio need defining"
+ ret = physio(scsistrategy, bp, dev, rwflag,
+ mincntfn, uio);
+#else
+ ret = physio(scsistrategy,0,bp,0,rwflag,
+ d_addr,&len,curproc);
+#endif
+ } else {
+ /* if no data, no need to translate it.. */
+ bp->b_un.b_addr = 0;
+ bp->b_dev = -1; /* irrelevant info */
+ bp->b_flags = 0;
+
+ scsistrategy(bp);
+ ret = bp->b_error;
+ }
+ free(bp,M_TEMP);
+ if((unsigned int)screq2 < (unsigned int)KERNBASE)
+ {
+ bcopy(screq,screq2,sizeof(scsireq_t));
+ free(screq,M_TEMP);
+ }
+ break;
+ }
+#endif /* !NetBSD */
+ case SCIOCDEBUG:
+ {
+ int level = *((int *)addr);
+ SC_DEBUG(sc_link,SDEV_DB3,("debug set to %d\n",level));
+ sc_link->flags &= ~SDEV_DBX; /*clear debug bits */
+ if(level & 1) sc_link->flags |= SDEV_DB1;
+ if(level & 2) sc_link->flags |= SDEV_DB2;
+ if(level & 4) sc_link->flags |= SDEV_DB3;
+ if(level & 8) sc_link->flags |= SDEV_DB4;
+ ret = 0;
+ break;
+ }
+ case SCIOCREPROBE:
+ {
+ extern int scsibus;
+ struct scsi_addr *sca = (struct scsi_addr *) addr;
+
+ ret = scsi_probe_busses(sca->scbus,sca->target,sca->lun);
+ break;
+ }
+ case SCIOCRECONFIG:
+ case SCIOCDECONFIG:
+ ret = EINVAL;
+ break;
+ case SCIOCIDENTIFY:
+ {
+ struct scsi_addr *sca = (struct scsi_addr *) addr;
+ sca->scbus = sc_link->scsibus;
+ sca->target = sc_link->target;
+ sca->lun = sc_link->lun;
+ break;
+ }
+
+ default:
+ ret = ENOTTY;
+ break;
+ }
+
+ return ret;
+}
+
+void
+scsierr(bp,err)
+ struct buf *bp;
+ int err;
+{
+ bp->b_flags |= B_ERROR;
+ bp->b_error = err;
+ biodone(bp);
+ return;
+}
+
diff --git a/sys/scsi/scsi_tape.h b/sys/scsi/scsi_tape.h
new file mode 100644
index 0000000..ac417c2
--- /dev/null
+++ b/sys/scsi/scsi_tape.h
@@ -0,0 +1,204 @@
+/*
+ * SCSI tape interface description
+ */
+
+/*
+ * Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ */
+
+/*
+ * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * $Id: scsi_tape.h,v 1.8 93/08/31 21:40:16 julian Exp Locker: julian $
+ */
+#ifndef SCSI_SCSI_TAPE_H
+#define SCSI_SCSI_TAPE_H 1
+
+
+
+/*
+ * SCSI command formats
+ */
+
+
+struct scsi_rw_tape
+{
+ u_char op_code;
+ u_char byte2;
+#define SRWT_FIXED 0x01
+ u_char len[3];
+ u_char control;
+} rw_tape;
+
+struct scsi_space
+{
+ u_char op_code;
+ u_char byte2;
+#define SS_CODE 0x03
+ u_char number[3];
+ u_char control;
+} space;
+#define SP_BLKS 0
+#define SP_FILEMARKS 1
+#define SP_SEQ_FILEMARKS 2
+#define SP_EOM 3
+
+struct scsi_write_filemarks
+{
+ u_char op_code;
+ u_char byte2;
+ u_char number[3];
+ u_char control;
+} write_filemarks;
+
+struct scsi_rewind
+{
+ u_char op_code;
+ u_char byte2;
+#define SR_IMMED 0x01
+ u_char unused[3];
+ u_char control;
+} rewind;
+
+struct scsi_load
+{
+ u_char op_code;
+ u_char byte2;
+#define SL_IMMED 0x01
+ u_char unused[2];
+ u_char how;
+ u_char control;
+} load;
+#define LD_UNLOAD 0
+#define LD_LOAD 1
+#define LD_RETEN 2
+
+
+struct scsi_blk_limits
+{
+ u_char op_code;
+ u_char byte2;
+ u_char unused[3];
+ u_char control;
+} blk_limits;
+
+/*
+ * Opcodes
+ */
+
+#define REWIND 0x01
+#define READ_BLK_LIMITS 0x05
+#define READ_COMMAND_TAPE 0x08
+#define WRITE_COMMAND_TAPE 0x0a
+#define WRITE_FILEMARKS 0x10
+#define SPACE 0x11
+#define LOAD_UNLOAD 0x1b /* same as above */
+
+
+
+struct scsi_blk_limits_data
+{
+ u_char reserved;
+ u_char max_length_2; /* Most significant */
+ u_char max_length_1;
+ u_char max_length_0; /* Least significant */
+ u_char min_length_1; /* Most significant */
+ u_char min_length_0; /* Least significant */
+};
+
+/* defines for the device specific byte in the mode select/sense header */
+#define SMH_DSP_SPEED 0x0F
+#define SMH_DSP_BUFF_MODE 0x70
+#define SMH_DSP_BUFF_MODE_OFF 0x00
+#define SMH_DSP_BUFF_MODE_ON 0x10
+#define SMH_DSP_BUFF_MODE_MLTI 0x20
+#define SMH_DSP_WRITE_PROT 0x80
+
+/* A special for the CIPHER ST150S(old drive) */
+struct blk_desc_cipher
+{
+ u_char density;
+ u_char nblocks[3];
+ u_char reserved;
+ u_char blklen[3];
+ u_char other;
+#define ST150_SEC 0x01 /* soft error count */
+#define SR150_AUI 0x02 /* autoload inhibit */
+};
+
+
+
+/**********************************************************************
+ from the scsi2 spec
+ Value Tracks Density(bpi) Code Type Reference Note
+ 0x1 9 800 NRZI R X3.22-1983 2
+ 0x2 9 1600 PE R X3.39-1986 2
+ 0x3 9 6250 GCR R X3.54-1986 2
+ 0x5 4/9 8000 GCR C X3.136-1986 1
+ 0x6 9 3200 PE R X3.157-1987 2
+ 0x7 4 6400 IMFM C X3.116-1986 1
+ 0x8 4 8000 GCR CS X3.158-1986 1
+ 0x9 18 37871 GCR C X3B5/87-099 2
+ 0xA 22 6667 MFM C X3B5/86-199 1
+ 0xB 4 1600 PE C X3.56-1986 1
+ 0xC 24 12690 GCR C HI-TC1 1,5
+ 0xD 24 25380 GCR C HI-TC2 1,5
+ 0xF 15 10000 GCR C QIC-120 1,5
+ 0x10 18 10000 GCR C QIC-150 1,5
+ 0x11 26 16000 GCR C QIC-320(525?) 1,5
+ 0x12 30 51667 RLL C QIC-1350 1,5
+ 0x13 1 61000 DDS CS X3B5/88-185A 4
+ 0x14 1 43245 RLL CS X3.202-1991 4
+ 0x15 1 45434 RLL CS ECMA TC17 4
+ 0x16 48 10000 MFM C X3.193-1990 1
+ 0x17 48 42500 MFM C X3B5/91-174 1
+
+ where Code means:
+ NRZI Non Return to Zero, change on ones
+ GCR Group Code Recording
+ PE Phase Encoded
+ IMFM Inverted Modified Frequency Modulation
+ MFM Modified Frequency Modulation
+ DDS Dat Data Storage
+ RLL Run Length Encoding
+
+ where Type means:
+ R Real-to-Real
+ C Cartridge
+ CS cassette
+
+ where Notes means:
+ 1 Serial Recorded
+ 2 Parallel Recorded
+ 3 Old format know as QIC-11
+ 4 Helical Scan
+ 5 Not ANSI standard, rather industry standard.
+
+********************************************************************/
+
+#define HALFINCH_800 0x01
+#define HALFINCH_1600 0x02
+#define HALFINCH_6250 0x03
+#define QIC_11 0x04 /* from Archive 150S Theory of Op. XXX */
+#define QIC_24 0x05 /* may be bad, works for CIPHER ST150S XXX */
+#define QIC_120 0x0f
+#define QIC_150 0x10
+#define QIC_320 0x11
+#define QIC_525 0x11
+#define QIC_1320 0x12
+#define DDS 0x13
+#define DAT_1 0x13
+
+#endif /*SCSI_SCSI_TAPE_H*/
diff --git a/sys/scsi/scsiconf.c b/sys/scsi/scsiconf.c
new file mode 100644
index 0000000..9e2dfef
--- /dev/null
+++ b/sys/scsi/scsiconf.c
@@ -0,0 +1,699 @@
+/*
+ * Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems for use under the MACH(2.5) operating system.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * $Id: scsiconf.c,v 1.7 1993/11/18 05:02:58 rgrimes Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <sys/malloc.h>
+#include "st.h"
+#include "sd.h"
+#include "ch.h"
+#include "cd.h"
+#include "uk.h"
+#include "su.h"
+#ifndef NSCBUS
+#define NSCBUS 8
+#endif /* NSCBUS */
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+
+#ifdef TFS
+#include "bll.h"
+#include "cals.h"
+#include "kil.h"
+#include "scan.h"
+#else /* TFS */
+#define NBLL 0
+#define NCALS 0
+#define NKIL 0
+#define NSCAN 0
+#endif /* TFS */
+
+#if NSD > 0
+extern sdattach();
+#endif /* NSD */
+#if NST > 0
+extern stattach();
+#endif /* NST */
+#if NCH > 0
+extern chattach();
+#endif /* NCH */
+#if NCD > 0
+extern cdattach();
+#endif /* NCD */
+#if NBLL > 0
+extern bllattach();
+#endif /* NBLL */
+#if NCALS > 0
+extern calsattach();
+#endif /* NCALS */
+#if NKIL > 0
+extern kil_attach();
+#endif /* NKIL */
+#if NUK > 0
+extern ukattach();
+#endif /* NUK */
+
+/*
+ * One of these is allocated and filled in for each scsi bus.
+ * it holds pointers to allow the scsi bus to get to the driver
+ * That is running each LUN on the bus
+ * it also has a template entry which is the prototype struct
+ * supplied by the adapter driver, this is used to initialise
+ * the others, before they have the rest of the fields filled in
+ */
+struct scsibus_data *scbus_data[NSCBUS];
+
+/*
+ * The structure of pre-configured devices that might be turned
+ * off and therefore may not show up
+ */
+struct predefined {
+ u_char scsibus;
+ u_char dev;
+ u_char lu;
+ errval(*attach_rtn) ();
+ char *devname;
+ char flags;
+} pd[] =
+
+{
+#ifdef EXAMPLE_PREDEFINE
+#if NSD > 0
+ {
+ 0, 0, 0, sdattach, "sd", 0
+ }, /* define a disk at scsibus=0 dev=0 lu=0 */
+#endif /* NSD */
+#endif /* EXAMPLE_PREDEFINE */
+ {
+ 0, 9, 9
+ } /*illegal dummy end entry */
+};
+
+/*
+ * The structure of known drivers for autoconfiguration
+ */
+struct scsidevs {
+ u_int32 type;
+ boolean removable;
+ char *manufacturer;
+ char *model;
+ char *version;
+ errval(*attach_rtn) ();
+ char *devname;
+ char flags; /* 1 show my comparisons during boot(debug) */
+};
+
+#define SC_SHOWME 0x01
+#define SC_ONE_LU 0x00
+#define SC_MORE_LUS 0x02
+#if NUK > 0
+
+static struct scsidevs unknowndev = {
+ -1, 0, "standard", "any"
+ ,"any", ukattach, "uk", SC_MORE_LUS
+};
+#endif /*NUK*/
+static struct scsidevs knowndevs[] =
+{
+#if NSD > 0
+ {
+ T_DIRECT, T_FIXED, "standard", "any"
+ ,"any", sdattach, "sd", SC_ONE_LU
+ },
+ {
+ T_DIRECT, T_FIXED, "MAXTOR ", "XT-4170S "
+ ,"B5A ", sdattach, "mx1", SC_ONE_LU
+ },
+#endif /* NSD */
+#if NST > 0
+ {
+ T_SEQUENTIAL, T_REMOV, "standard", "any"
+ ,"any", stattach, "st", SC_ONE_LU
+ },
+#endif /* NST */
+#if NCALS > 0
+ {
+ T_PROCESSOR, T_FIXED, "standard", "any"
+ ,"any", calsattach, "cals", SC_MORE_LUS
+ },
+#endif /* NCALS */
+#if NCH > 0
+ {
+ T_CHANGER, T_REMOV, "standard", "any"
+ ,"any", chattach, "ch", SC_ONE_LU
+ },
+#endif /* NCH */
+#if NCD > 0
+#ifndef UKTEST /* make cdroms unrecognised to test the uk driver */
+ {
+ T_READONLY, T_REMOV, "SONY ", "CD-ROM CDU-8012 "
+ ,"3.1a", cdattach, "cd", SC_ONE_LU
+ },
+ {
+ T_READONLY, T_REMOV, "PIONEER ", "CD-ROM DRM-600 "
+ ,"any", cdattach, "cd", SC_MORE_LUS
+ },
+#endif
+#endif /* NCD */
+#if NBLL > 0
+ {
+ T_PROCESSOR, T_FIXED, "AEG ", "READER "
+ ,"V1.0", bllattach, "bll", SC_MORE_LUS
+ },
+#endif /* NBLL */
+#if NKIL > 0
+ {
+ T_SCANNER, T_FIXED, "KODAK ", "IL Scanner 900 "
+ ,"any", kil_attach, "kil", SC_ONE_LU
+ },
+#endif /* NKIL */
+
+ {
+ 0
+ }
+};
+
+/*
+ * Declarations
+ */
+struct predefined *scsi_get_predef();
+struct scsidevs *scsi_probedev();
+struct scsidevs *selectdev();
+errval scsi_probe_bus __P((int bus, int targ, int lun));
+
+struct scsi_device probe_switch =
+{
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "probe",
+ 0,
+ { 0, 0 }
+};
+
+/*
+ * controls debug level within the scsi subsystem -
+ * see scsiconf.h for values
+ */
+int32 scsibus = 0x0; /* This is the Nth scsibus we've seen */
+
+/*
+ * The routine called by the adapter boards to get all their
+ * devices configured in.
+ */
+void
+scsi_attachdevs(sc_link_proto)
+ struct scsi_link *sc_link_proto;
+{
+
+ if(scsibus >= NSCBUS) {
+ printf("too many scsi busses, reconfigure the kernel\n");
+ return;
+ }
+ sc_link_proto->scsibus = scsibus;
+ scbus_data[scsibus] = malloc(sizeof(struct scsibus_data), M_TEMP, M_NOWAIT);
+ if(!scbus_data[scsibus]) {
+ panic("scsi_attachdevs: malloc\n");
+ }
+ bzero(scbus_data[scsibus], sizeof(struct scsibus_data));
+ scbus_data[scsibus]->adapter_link = sc_link_proto;
+#if defined(SCSI_DELAY) && SCSI_DELAY > 2
+ printf("%s%d waiting for scsi devices to settle\n",
+ sc_link_proto->adapter->name, sc_link_proto->adapter_unit);
+#else /* SCSI_DELAY > 2 */
+#undef SCSI_DELAY
+#define SCSI_DELAY 2
+#endif /* SCSI_DELAY */
+ DELAY(1000000 * SCSI_DELAY);
+ scsibus++;
+ scsi_probe_bus(scsibus - 1,-1,-1);
+}
+
+/*
+ * Probe the requested scsi bus. It must be already set up.
+ * -1 requests all set up scsi busses.
+ * targ and lun optionally narrow the search if not -1
+ */
+errval
+scsi_probe_busses(int bus, int targ, int lun)
+{
+ if (bus == -1) {
+ for(bus = 0; bus < scsibus; bus++) {
+ scsi_probe_bus(bus, targ, lun);
+ }
+ return 0;
+ } else {
+ return scsi_probe_bus(bus, targ, lun);
+ }
+}
+
+/*
+ * Probe the requested scsi bus. It must be already set up.
+ * targ and lun optionally narrow the search if not -1
+ */
+errval
+scsi_probe_bus(int bus, int targ, int lun)
+{
+ struct scsibus_data *scsi ;
+ int maxtarg,mintarg,maxlun,minlun;
+ struct scsi_link *sc_link_proto;
+ u_int8 scsi_addr ;
+ struct scsidevs *bestmatch = NULL;
+ struct predefined *predef = NULL;
+ struct scsi_link *sc_link = NULL;
+ boolean maybe_more;
+
+ if ((bus < 0 ) || ( bus >= scsibus)) {
+ return ENXIO;
+ }
+ scsi = scbus_data[bus];
+ if(!scsi) return ENXIO;
+ sc_link_proto = scsi->adapter_link;
+ scsi_addr = sc_link_proto->adapter_targ;
+ if(targ == -1){
+ maxtarg = 7;
+ mintarg = 0;
+ } else {
+ if((targ < 0 ) || (targ > 7)) return EINVAL;
+ maxtarg = mintarg = targ;
+ }
+
+ if(lun == -1){
+ maxlun = 7;
+ minlun = 0;
+ } else {
+ if((lun < 0 ) || (lun > 7)) return EINVAL;
+ maxlun = minlun = lun;
+ }
+
+
+ for ( targ = mintarg;targ <= maxtarg; targ++) {
+ maybe_more = 0; /* by default only check 1 lun */
+ if (targ == scsi_addr) {
+ continue;
+ }
+ for ( lun = minlun; lun <= maxlun ;lun++) {
+ /*
+ * The spot appears to already have something
+ * linked in, skip past it. Must be doing a 'reprobe'
+ */
+ if(scsi->sc_link[targ][lun])
+ {/* don't do this one, but check other luns */
+ maybe_more = 1;
+ continue;
+ }
+ /*
+ * If we presently don't have a link block
+ * then allocate one to use while probing
+ */
+ if (!sc_link) {
+ sc_link = malloc(sizeof(*sc_link), M_TEMP, M_NOWAIT);
+ *sc_link = *sc_link_proto; /* struct copy */
+ sc_link->opennings = 1;
+ sc_link->device = &probe_switch;
+ }
+ sc_link->target = targ;
+ sc_link->lun = lun;
+ predef = scsi_get_predef(sc_link, &maybe_more);
+ bestmatch = scsi_probedev(sc_link, &maybe_more);
+ if ((bestmatch) && (predef)) { /* both exist */
+ if (bestmatch->attach_rtn
+ != predef->attach_rtn) {
+ printf("Clash in found/expected devices\n");
+#if NUK > 0
+ if(bestmatch == &unknowndev) {
+ printf("will link in PREDEFINED\n");
+ (*(predef->attach_rtn)) (sc_link);
+ } else
+#endif /*NUK*/
+ {
+ printf("will link in FOUND\n");
+ (*(bestmatch->attach_rtn)) (sc_link);
+ }
+ } else {
+ (*(bestmatch->attach_rtn)) (sc_link);
+ }
+ }
+ if ((bestmatch) && (!predef)) { /* just FOUND */
+ (*(bestmatch->attach_rtn)) (sc_link);
+ }
+ if ((!bestmatch) && (predef)) { /* just predef */
+ (*(predef->attach_rtn)) (sc_link);
+ }
+ if ((bestmatch) || (predef)) { /* one exists */
+ scsi->sc_link[targ][lun] = sc_link;
+ sc_link = NULL; /* it's been used */
+ }
+ if (!(maybe_more)) { /* nothing suggests we'll find more */
+ break; /* nothing here, skip to next targ */
+ }
+ /* otherwise something says we should look further */
+ }
+ }
+ if (sc_link) {
+ free(sc_link, M_TEMP);
+ }
+ return 0;
+}
+
+/*
+ * given a target and lu, check if there is a predefined device for
+ * that address
+ */
+struct predefined *
+scsi_get_predef(sc_link, maybe_more)
+ struct scsi_link *sc_link;
+ boolean *maybe_more;
+{
+ u_int8 unit = sc_link->scsibus;
+ u_int8 target = sc_link->target;
+ u_int8 lu = sc_link->lun;
+ struct scsi_adapter *scsi_adapter = sc_link->adapter;
+ u_int32 upto, numents;
+
+ numents = (sizeof(pd) / sizeof(struct predefined)) - 1;
+
+ for (upto = 0; upto < numents; upto++) {
+ if (pd[upto].scsibus != unit)
+ continue;
+ if (pd[upto].dev != target)
+ continue;
+ if (pd[upto].lu != lu)
+ continue;
+
+ printf("%s%d targ %d lun %d: <%s> - PRECONFIGURED -\n"
+ ,scsi_adapter->name
+ ,unit
+ ,target
+ ,lu
+ ,pd[upto].devname);
+ *maybe_more = pd[upto].flags & SC_MORE_LUS;
+ return (&(pd[upto]));
+ }
+ return ((struct predefined *) 0);
+}
+
+/*
+ * given a target and lu, ask the device what
+ * it is, and find the correct driver table
+ * entry.
+ */
+struct scsidevs *
+scsi_probedev(sc_link, maybe_more)
+ boolean *maybe_more;
+ struct scsi_link *sc_link;
+{
+ u_int8 unit = sc_link->adapter_unit;
+ u_int8 target = sc_link->target;
+ u_int8 lu = sc_link->lun;
+ struct scsi_adapter *scsi_adapter = sc_link->adapter;
+ struct scsidevs *bestmatch = (struct scsidevs *) 0;
+ char *dtype = (char *) 0, *desc;
+ char *qtype;
+ static struct scsi_inquiry_data inqbuf;
+ u_int32 len, qualifier, type;
+ boolean remov;
+ char manu[32];
+ char model[32];
+ char version[32];
+
+ bzero(&inqbuf, sizeof(inqbuf));
+ /*
+ * Ask the device what it is
+ */
+#ifdef SCSIDEBUG
+ if ((target == DEBUGTARG) && (lu == DEBUGLUN))
+ sc_link->flags |= (DEBUGLEVEL);
+ else
+ sc_link->flags &= ~(SDEV_DB1 | SDEV_DB2 | SDEV_DB3 | SDEV_DB4);
+#endif /* SCSIDEBUG */
+ /* catch unit attn */
+ scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT);
+#ifdef DOUBTFULL
+ switch (scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) {
+ case 0: /* said it WAS ready */
+ case EBUSY: /* replied 'NOT READY' but WAS present, continue */
+ case ENXIO:
+ break;
+ case EIO: /* device timed out */
+ case EINVAL: /* Lun not supported */
+ default:
+ return (struct scsidevs *) 0;
+
+ }
+#endif /*DOUBTFULL*/
+#ifdef SCSI_2_DEF
+ /* some devices need to be told to go to SCSI2 */
+ /* However some just explode if you tell them this.. leave it out */
+ scsi_change_def(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT);
+#endif /*SCSI_2_DEF */
+
+ /* Now go ask the device all about itself */
+ if (scsi_inquire(sc_link, &inqbuf, SCSI_NOSLEEP | SCSI_NOMASK) != 0) {
+ return (struct scsidevs *) 0;
+ }
+
+ /*
+ * note what BASIC type of device it is
+ */
+ type = inqbuf.device & SID_TYPE;
+ qualifier = inqbuf.device & SID_QUAL;
+ remov = inqbuf.dev_qual2 & SID_REMOVABLE;
+
+ /*
+ * Any device qualifier that has the top bit set (qualifier&4 != 0)
+ * is vendor specific and won't match in this switch.
+ */
+
+ switch ((int)qualifier) {
+ case SID_QUAL_LU_OK:
+ qtype = "";
+ break;
+
+ case SID_QUAL_LU_OFFLINE:
+ qtype = ", Unit not Connected!";
+ break;
+
+ case SID_QUAL_RSVD:
+ qtype = ", Reserved Peripheral Qualifier!";
+ *maybe_more = 1;
+ return (struct scsidevs *) 0;
+ break;
+
+ case SID_QUAL_BAD_LU:
+ /*
+ * Check for a non-existent unit. If the device is returning
+ * this much, then we must set the flag that has
+ * the searchers keep looking on other luns.
+ */
+ qtype = ", The Target can't support this Unit!";
+ *maybe_more = 1;
+ return (struct scsidevs *) 0;
+
+ default:
+ dtype = "vendor specific";
+ qtype = "";
+ *maybe_more = 1;
+ break;
+ }
+ if (dtype == 0) {
+ switch ((int)type) {
+ case T_DIRECT:
+ dtype = "direct";
+ break;
+ case T_SEQUENTIAL:
+ dtype = "sequential";
+ break;
+ case T_PRINTER:
+ dtype = "printer";
+ break;
+ case T_PROCESSOR:
+ dtype = "processor";
+ break;
+ case T_READONLY:
+ dtype = "readonly";
+ break;
+ case T_WORM:
+ dtype = "worm";
+ break;
+ case T_SCANNER:
+ dtype = "scanner";
+ break;
+ case T_OPTICAL:
+ dtype = "optical";
+ break;
+ case T_CHANGER:
+ dtype = "changer";
+ break;
+ case T_COMM:
+ dtype = "communication";
+ break;
+ case T_NODEVICE:
+ *maybe_more = 1;
+ return (struct scsidevs *) 0;
+ default:
+ dtype = "unknown";
+ break;
+ }
+ }
+ /*
+ * Then if it's advanced enough, more detailed
+ * information
+ */
+ if ((inqbuf.version & SID_ANSII) > 0) {
+ if ((len = inqbuf.additional_length
+ + ((char *) inqbuf.unused
+ - (char *) &inqbuf))
+ > (sizeof(struct scsi_inquiry_data) - 1))
+ len = sizeof(struct scsi_inquiry_data) - 1;
+ desc = inqbuf.vendor;
+ desc[len - (desc - (char *) &inqbuf)] = 0;
+ strncpy(manu, inqbuf.vendor, 8);
+ manu[8] = 0;
+ strncpy(model, inqbuf.product, 16);
+ model[16] = 0;
+ strncpy(version, inqbuf.revision, 4);
+ version[4] = 0;
+ } else
+ /*
+ * If not advanced enough, use default values
+ */
+ {
+ desc = "early protocol device";
+ strncpy(manu, "unknown", 8);
+ strncpy(model, "unknown", 16);
+ strncpy(version, "????", 4);
+ }
+ printf("%s%d targ %d lun %d: type %d(%s) %s SCSI%d\n"
+ ,scsi_adapter->name
+ ,unit
+ ,target
+ ,lu
+ ,type
+ ,dtype
+ ,remov ? "removable" : "fixed"
+ ,inqbuf.version & SID_ANSII
+ );
+ printf("%s%d targ %d lun %d: <%s%s%s>\n"
+ ,scsi_adapter->name
+ ,unit
+ ,target
+ ,lu
+ ,manu
+ ,model
+ ,version
+ );
+ if (qtype[0]) {
+ printf("%s%d targ %d lun %d: qualifier %d(%s)\n"
+ ,scsi_adapter->name
+ ,unit
+ ,target
+ ,lu
+ ,qualifier
+ ,qtype
+ );
+ }
+ /*
+ * Try make as good a match as possible with
+ * available sub drivers
+ */
+ bestmatch = (selectdev(
+ qualifier, type, remov ? T_REMOV : T_FIXED, manu, model, version));
+ if ((bestmatch) && (bestmatch->flags & SC_MORE_LUS)) {
+ *maybe_more = 1;
+ }
+ return (bestmatch);
+}
+/*
+ * Try make as good a match as possible with
+ * available sub drivers
+ */
+struct scsidevs *
+selectdev(qualifier, type, remov, manu, model, rev)
+ u_int32 qualifier, type;
+ boolean remov;
+ char *manu, *model, *rev;
+{
+ u_int32 numents = (sizeof(knowndevs) / sizeof(struct scsidevs)) - 1;
+ u_int32 count = 0;
+ u_int32 bestmatches = 0;
+ struct scsidevs *bestmatch = (struct scsidevs *) 0;
+ struct scsidevs *thisentry = knowndevs;
+
+ type |= qualifier; /* why? */
+
+ thisentry--;
+ while (count++ < numents) {
+ thisentry++;
+ if (type != thisentry->type) {
+ continue;
+ }
+ if (bestmatches < 1) {
+ bestmatches = 1;
+ bestmatch = thisentry;
+ }
+ if (remov != thisentry->removable) {
+ continue;
+ }
+ if (bestmatches < 2) {
+ bestmatches = 2;
+ bestmatch = thisentry;
+ }
+ if (thisentry->flags & SC_SHOWME)
+ printf("\n%s-\n%s-", thisentry->manufacturer, manu);
+ if (strcmp(thisentry->manufacturer, manu)) {
+ continue;
+ }
+ if (bestmatches < 3) {
+ bestmatches = 3;
+ bestmatch = thisentry;
+ }
+ if (thisentry->flags & SC_SHOWME)
+ printf("\n%s-\n%s-", thisentry->model, model);
+ if (strcmp(thisentry->model, model)) {
+ continue;
+ }
+ if (bestmatches < 4) {
+ bestmatches = 4;
+ bestmatch = thisentry;
+ }
+ if (thisentry->flags & SC_SHOWME)
+ printf("\n%s-\n%s-", thisentry->version, rev);
+ if (strcmp(thisentry->version, rev)) {
+ continue;
+ }
+ if (bestmatches < 5) {
+ bestmatches = 5;
+ bestmatch = thisentry;
+ break;
+ }
+ }
+ if (bestmatch == (struct scsidevs *) 0) {
+#if NUK > 0
+ bestmatch = &unknowndev;
+#else
+ printf("No explicit device driver match.\n");
+#endif
+ }
+ return (bestmatch);
+}
diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h
new file mode 100644
index 0000000..f3f9586
--- /dev/null
+++ b/sys/scsi/scsiconf.h
@@ -0,0 +1,249 @@
+/*
+ * Written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems for use under the MACH(2.5) operating system.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * $Id: scsiconf.h,v 1.8 1993/12/19 00:54:55 wollman Exp $
+ */
+#ifndef SCSI_SCSICONF_H
+#define SCSI_SCSICONF_H 1
+typedef int boolean;
+typedef int errval;
+typedef long int int32;
+typedef short int int16;
+typedef char int8;
+typedef unsigned long int u_int32;
+typedef unsigned short int u_int16;
+typedef unsigned char u_int8;
+
+#include <scsi/scsi_debug.h>
+
+/*
+ * The following documentation tries to describe the relationship between the
+ * various structures defined in this file:
+ *
+ * each adapter type has a scsi_adapter struct. This describes the adapter and
+ * identifies routines that can be called to use the adapter.
+ * each device type has a scsi_device struct. This describes the device and
+ * identifies routines that can be called to use the device.
+ * each existing device position (scsibus + target + lun)
+ * can be described by a scsi_link struct.
+ * Only scsi positions that actually have devices, have a scsi_link
+ * structure assigned. so in effect each device has scsi_link struct.
+ * The scsi_link structure contains information identifying both the
+ * device driver and the adapter driver for that position on that scsi bus,
+ * and can be said to 'link' the two.
+ * each individual scsi bus has an array that points to all the scsi_link
+ * structs associated with that scsi bus. Slots with no device have
+ * a NULL pointer.
+ * each individual device also knows the address of it's own scsi_link
+ * structure.
+ *
+ * -------------
+ *
+ * The key to all this is the scsi_link structure which associates all the
+ * other structures with each other in the correct configuration. The
+ * scsi_link is the connecting information that allows each part of the
+ * scsi system to find the associated other parts.
+ */
+
+
+/*
+ * These entrypoints are called by the high-end drivers to get services from
+ * whatever low-end drivers they are attached to each adapter type has one of
+ * these statically allocated.
+ */
+struct scsi_adapter
+{
+/* 04*/ int32 (*scsi_cmd)();
+/* 08*/ void (*scsi_minphys)();
+/* 12*/ int32 (*open_target_lu)();
+/* 16*/ int32 (*close_target_lu)();
+/* 20*/ u_int32 (*adapter_info)(); /* see definitions below */
+/* 24*/ char *name; /* name of scsi bus controller */
+/* 32*/ u_long spare[2];
+};
+
+/*
+ * return values for scsi_cmd()
+ */
+#define SUCCESSFULLY_QUEUED 0
+#define TRY_AGAIN_LATER 1
+#define COMPLETE 2
+#define HAD_ERROR 3 /* do not use this, use COMPLETE */
+#define ESCAPE_NOT_SUPPORTED 4
+
+/*
+ * Format of adapter_info() response data
+ * e.g. maximum number of entries queuable to a device by the adapter
+ */
+#define AD_INF_MAX_CMDS 0x000000FF
+/* 24 bits of other adapter characteristics go here */
+
+/*
+ * These entry points are called by the low-end drivers to get services from
+ * whatever high-end drivers they are attached to. Each device type has one
+ * of these statically allocated.
+ */
+struct scsi_device
+{
+/* 4*/ errval (*err_handler)(); /* returns -1 to say err processing complete */
+/* 8*/ void (*start)();
+/* 12*/ int32 (*async)();
+/* 16*/ int32 (*done)(); /* returns -1 to say done processing complete */
+/* 20*/ char *name; /* name of device type */
+/* 24*/ u_int32 flags; /* device type dependent flags */
+/* 32*/ int32 spare[2];
+};
+
+/*
+ * This structure describes the connection between an adapter driver and
+ * a device driver, and is used by each to call services provided by
+ * the other, and to allow generic scsi glue code to call these services
+ * as well.
+ */
+struct scsi_link
+{
+/* 1*/ u_int8 target; /* targ of this dev */
+/* 2*/ u_int8 lun; /* lun of this dev */
+/* 3*/ u_int8 adapter_targ; /* what are we on the scsi bus */
+/* 4*/ u_int8 adapter_unit; /* e.g. the 0 in aha0 */
+/* 5*/ u_int8 scsibus; /* the Nth scsibus */
+/* 6*/ u_int8 dev_unit; /* e.g. the 0 in sd0 */
+/* 7*/ u_int8 opennings; /* available operations */
+/* 8*/ u_int8 active; /* operations in progress */
+/* 10*/ u_int16 flags; /* flags that all devices have */
+/* 12*/ u_int8 spareb[2]; /* unused */
+/* 16*/ struct scsi_adapter *adapter; /* adapter entry points etc. */
+/* 20*/ struct scsi_device *device; /* device entry points etc. */
+/* 24*/ struct scsi_xfer *active_xs; /* operations under way */
+/* 28*/ void * fordriver; /* for private use by the driver */
+/* 32*/ u_int32 spare;
+};
+#define SDEV_MEDIA_LOADED 0x01 /* device figures are still valid */
+#define SDEV_WAITING 0x02 /* a process is waiting for this */
+#define SDEV_OPEN 0x04 /* at least 1 open session */
+#define SDEV_BOUNCE 0x08 /* unit requires DMA bounce buffer */
+#define SDEV_DBX 0xF0 /* debuging flags (scsi_debug.h) */
+
+/*
+ * One of these is allocated and filled in for each scsi bus.
+ * it holds pointers to allow the scsi bus to get to the driver
+ * That is running each LUN on the bus
+ * it also has a template entry which is the prototype struct
+ * supplied by the adapter driver, this is used to initialise
+ * the others, before they have the rest of the fields filled in
+ */
+struct scsibus_data {
+ struct scsi_link *adapter_link; /* prototype supplied by adapter */
+ struct scsi_link *sc_link[8][8];
+};
+
+/*
+ * Each scsi transaction is fully described by one of these structures
+ * It includes information about the source of the command and also the
+ * device and adapter for which the command is destined.
+ * (via the scsi_link structure) *
+ */
+struct scsi_xfer
+{
+/*04*/ struct scsi_xfer *next; /* when free */
+/*08*/ u_int32 flags;
+/*12*/ struct scsi_link *sc_link; /* all about our device and adapter */
+/*13*/ u_int8 retries; /* the number of times to retry */
+/*16*/ u_int8 spare[3];
+/*20*/ int32 timeout; /* in milliseconds */
+/*24*/ struct scsi_generic *cmd; /* The scsi command to execute */
+/*28*/ int32 cmdlen; /* how long it is */
+/*32*/ u_char *data; /* dma address OR a uio address */
+/*36*/ int32 datalen; /* data len (blank if uio) */
+/*40*/ int32 resid; /* how much buffer was not touched */
+/*44*/ int32 error; /* an error value */
+/*48*/ struct buf *bp; /* If we need to associate with a buf */
+/*80*/ struct scsi_sense_data sense; /* 32 bytes*/
+ /*
+ * Believe it or not, Some targets fall on the ground with
+ * anything but a certain sense length.
+ */
+/*84*/ int32 req_sense_length; /* Explicit request sense length */
+/*88*/ int32 status; /* SCSI status */
+/*100*/ struct scsi_generic cmdstore; /* stash the command in here */
+};
+
+/*
+ * Per-request Flag values
+ */
+#define SCSI_NOSLEEP 0x01 /* Not a user... don't sleep */
+#define SCSI_NOMASK 0x02 /* dont allow interrupts.. booting */
+#define SCSI_NOSTART 0x04 /* left over from ancient history */
+#define SCSI_USER 0x08 /* Is a user cmd, call scsi_user_done */
+#define ITSDONE 0x10 /* the transfer is as done as it gets */
+#define INUSE 0x20 /* The scsi_xfer block is in use */
+#define SCSI_SILENT 0x40 /* Don't report errors to console */
+#define SCSI_ERR_OK 0x80 /* An error on this operation is OK. */
+#define SCSI_RESET 0x100 /* Reset the device in question */
+#define SCSI_DATA_UIO 0x200 /* The data address refers to a UIO */
+#define SCSI_DATA_IN 0x400 /* expect data to come INTO memory */
+#define SCSI_DATA_OUT 0x800 /* expect data to flow OUT of memory */
+#define SCSI_TARGET 0x1000 /* This defines a TARGET mode op. */
+#define SCSI_ESCAPE 0x2000 /* Escape operation */
+
+/*
+ * Escape op codes. This provides an extensible setup for operations
+ * that are not scsi commands. They are intended for modal operations.
+ */
+
+#define SCSI_OP_TARGET 0x0001
+#define SCSI_OP_RESET 0x0002
+#define SCSI_OP_BDINFO 0x0003
+
+/*
+ * Error values an adapter driver may return
+ */
+#define XS_NOERROR 0x0 /* there is no error, (sense is invalid) */
+#define XS_SENSE 0x1 /* Check the returned sense for the error */
+#define XS_DRIVER_STUFFUP 0x2 /* Driver failed to perform operation */
+#define XS_TIMEOUT 0x03 /* The device timed out.. turned off? */
+#define XS_SWTIMEOUT 0x04 /* The Timeout reported was caught by SW */
+#define XS_BUSY 0x08 /* The device busy, try again later? */
+
+void scsi_attachdevs __P((struct scsi_link *sc_link_proto));
+struct scsi_xfer *get_xs( struct scsi_link *sc_link, u_int32 flags);
+void free_xs(struct scsi_xfer *xs, struct scsi_link *sc_link,u_int32 flags);
+u_int32 scsi_size( struct scsi_link *sc_link,u_int32 flags);
+errval scsi_test_unit_ready( struct scsi_link *sc_link, u_int32 flags);
+errval scsi_change_def( struct scsi_link *sc_link, u_int32 flags);
+errval scsi_inquire( struct scsi_link *sc_link,
+ struct scsi_inquiry_data *inqbuf, u_int32 flags);
+errval scsi_prevent( struct scsi_link *sc_link, u_int32 type,u_int32 flags);
+errval scsi_start_unit( struct scsi_link *sc_link, u_int32 flags);
+void scsi_done(struct scsi_xfer *xs);
+errval scsi_scsi_cmd( struct scsi_link *sc_link, struct scsi_generic *scsi_cmd,
+ u_int32 cmdlen, u_char *data_addr,
+ u_int32 datalen, u_int32 retries,
+ u_int32 timeout, struct buf *bp,
+ u_int32 flags);
+errval scsi_do_ioctl __P((struct scsi_link *sc_link, int cmd, caddr_t addr, int f));
+
+void show_scsi_xs(struct scsi_xfer *xs);
+void show_scsi_cmd(struct scsi_xfer *xs);
+void show_mem(unsigned char * , u_int32);
+
+void lto3b __P((int val, u_char *bytes));
+int _3btol __P((u_char *bytes));
+
+extern void sc_print_addr(struct scsi_link *);
+
+#endif /*SCSI_SCSICONF_H*/
+/* END OF FILE */
diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c
new file mode 100644
index 0000000..783de99
--- /dev/null
+++ b/sys/scsi/sd.c
@@ -0,0 +1,1055 @@
+/*
+ * Written by Julian Elischer (julian@dialix.oz.au)
+ * for TRW Financial Systems for use under the MACH(2.5) operating system.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ * Ported to run under 386BSD by Julian Elischer (julian@dialix.oz.au) Sept 1992
+ *
+ * $Id: sd.c,v 1.22 1994/04/05 03:23:32 davidg Exp $
+ */
+
+#define SPLSD splbio
+#define ESUCCESS 0
+#include <sd.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/dkbad.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/buf.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+#include <sys/errno.h>
+#include <sys/disklabel.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsi_disk.h>
+#include <scsi/scsiconf.h>
+#include <vm/vm.h>
+
+u_int32 sdstrats, sdqueues;
+
+#ifdef NetBSD
+#ifdef DDB
+int Debugger();
+#else /* DDB */
+#define Debugger()
+#endif /* DDB */
+#else /* NetBSD */
+#include <ddb.h>
+#if NDDB > 0
+#else /* NDDB > 0 */
+#define Debugger(s)
+#endif /* NDDB > 0 */
+#endif
+
+#define PAGESIZ 4096
+#define SECSIZE 512
+#define PDLOCATION 29
+#define BOOTRECORDSIGNATURE (0x55aa & 0x00ff)
+#define SDOUTSTANDING 2
+#define SDQSIZE 4
+#define SD_RETRIES 4
+#define MAXTRANSFER 8 /* 1 page at a time */
+
+#define MAKESDDEV(maj, unit, part) (makedev(maj,((unit<<3)+part)))
+#define UNITSHIFT 3
+#define PARTITION(z) (minor(z) & 0x07)
+#define RAW_PART 3
+#define UNIT(z) ( (minor(z) >> UNITSHIFT) )
+
+#define WHOLE_DISK(unit) ( (unit << UNITSHIFT) + RAW_PART )
+
+errval sdgetdisklabel __P((unsigned char unit));
+errval sd_get_parms __P((int unit, int flags));
+void sdstrategy __P((struct buf *));
+void sdstart __P((u_int32));
+
+struct scsi_device sd_switch =
+{
+ NULL, /* Use default error handler */
+ sdstart, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+ "sd",
+ 0,
+ { 0, 0 }
+};
+
+struct sd_data {
+ u_int32 flags;
+#define SDINIT 0x04 /* device has been init'd */
+#define SDHAVELABEL 0x10 /* have read the label */
+#define SDDOSPART 0x20 /* Have read the DOS partition table */
+#define SDWRITEPROT 0x40 /* Device in readonly mode (S/W) */
+ struct scsi_link *sc_link; /* contains our targ, lun etc. */
+ u_int32 ad_info; /* info about the adapter */
+ u_int32 cmdscount; /* cmds allowed outstanding by board */
+ boolean wlabel; /* label is writable */
+ struct disk_parms {
+ u_char heads; /* Number of heads */
+ u_int16 cyls; /* Number of cylinders */
+ u_char sectors; /*dubious *//* Number of sectors/track */
+ u_int16 secsiz; /* Number of bytes/sector */
+ u_int32 disksize; /* total number sectors */
+ } params;
+ struct disklabel disklabel;
+#ifdef NetBSD
+ struct cpu_disklabel cpudisklabel;
+#else
+ struct dos_partition dosparts[NDOSPART]; /* DOS view of disk */
+#endif /* NetBSD */
+ u_int32 partflags[MAXPARTITIONS]; /* per partition flags */
+#define SDOPEN 0x01
+ u_int32 openparts; /* one bit for each open partition */
+ u_int32 sd_start_of_unix; /* unix vs dos partitions */
+ struct buf buf_queue;
+ u_int32 xfer_block_wait;
+} *sd_data[NSD];
+
+static u_int32 next_sd_unit = 0;
+
+static struct scsi_xfer sx;
+
+/*
+ * The routine called by the low level scsi routine when it discovers
+ * a device suitable for this driver.
+ */
+errval
+sdattach(sc_link)
+ struct scsi_link *sc_link;
+{
+ u_int32 unit;
+ struct sd_data *sd;
+ struct disk_parms *dp;
+
+ unit = next_sd_unit++;
+ SC_DEBUG(sc_link, SDEV_DB2, ("sdattach: "));
+ /*
+ * Check we have the resources for another drive
+ */
+ if (unit >= NSD) {
+ printf("Too many scsi disks..(%d > %d) reconfigure kernel\n",
+ (unit + 1), NSD);
+ return 0;
+ }
+ if (sd_data[unit]) {
+ printf("sd%d: unit already has storage allocated!\n", unit);
+ return 0;
+ }
+ sd = sd_data[unit] = malloc(sizeof(struct sd_data), M_DEVBUF, M_NOWAIT);
+ if (!sd) {
+ printf("malloc failed in sd.c\n");
+ return (0);
+ }
+ bzero(sd, sizeof(struct sd_data));
+
+ dp = &(sd->params);
+ /*
+ * Store information needed to contact our base driver
+ */
+ sd->sc_link = sc_link;
+ sc_link->device = &sd_switch;
+ sc_link->dev_unit = unit;
+
+ if (sd->sc_link->adapter->adapter_info) {
+ sd->ad_info = ((*(sd->sc_link->adapter->adapter_info)) (sc_link->adapter_unit));
+ sd->cmdscount = sd->ad_info & AD_INF_MAX_CMDS;
+ if (sd->cmdscount > SDOUTSTANDING) {
+ sd->cmdscount = SDOUTSTANDING;
+ }
+ } else {
+ sd->ad_info = 1;
+ sd->cmdscount = 1;
+ }
+ sc_link->opennings = sd->cmdscount;
+ /*
+ * Use the subdriver to request information regarding
+ * the drive. We cannot use interrupts yet, so the
+ * request must specify this.
+ */
+ sd_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK);
+ printf("sd%d: %dMB (%d total sec), %d cyl, %d head, %d sec, bytes/sec %d\n",
+ unit,
+ dp->disksize / ((1024L * 1024L) / dp->secsiz),
+ dp->disksize,
+ dp->cyls,
+ dp->heads,
+ dp->sectors,
+ dp->secsiz);
+ sd->flags |= SDINIT;
+ return 0;
+}
+
+/*
+ * open the device. Make sure the partition info is a up-to-date as can be.
+ */
+errval
+sdopen(dev)
+ int dev; /* XXX should be dev_t, but avoid promotion problems for now */
+{
+ errval errcode = 0;
+ u_int32 unit, part;
+ struct sd_data *sd;
+ struct scsi_link *sc_link;
+
+ unit = UNIT(dev);
+ part = PARTITION(dev);
+ sd = sd_data[unit];
+ /*
+ * Check the unit is legal
+ */
+ if (unit >= NSD) {
+ return (ENXIO);
+ }
+ /*
+ * Make sure the disk has been initialised
+ * At some point in the future, get the scsi driver
+ * to look for a new device if we are not initted
+ */
+ if ((!sd) || (!(sd->flags & SDINIT))) {
+ return (ENXIO);
+ }
+ sc_link = sd->sc_link;
+
+ SC_DEBUG(sc_link, SDEV_DB1,
+ ("sdopen: dev=0x%x (unit %d (of %d),partition %d)\n"
+ ,dev, unit, NSD, part));
+
+ /*
+ * "unit attention" errors should occur here if the
+ * drive has been restarted or the pack changed.
+ * just ingnore the result, it's a decoy instruction
+ * The error code will act on the error though
+ * and invalidate any media information we had.
+ */
+ scsi_test_unit_ready(sc_link, 0);
+
+ /*
+ * If it's been invalidated, then forget the label
+ */
+ sc_link->flags |= SDEV_OPEN; /* unit attn becomes an err now */
+ if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
+ sd->flags &= ~SDHAVELABEL;
+
+ /*
+ * If somebody still has it open, then forbid re-entry.
+ */
+ if (sd->openparts) {
+ errcode = ENXIO;
+ goto bad;
+ }
+ }
+ /*
+ * In case it is a funny one, tell it to start
+ * not needed for most hard drives (ignore failure)
+ */
+ scsi_start_unit(sc_link, SCSI_ERR_OK | SCSI_SILENT);
+
+ /*
+ * Check that it is still responding and ok.
+ */
+ if (scsi_test_unit_ready(sc_link, 0)) {
+ SC_DEBUG(sc_link, SDEV_DB3, ("device not reponding\n"));
+ errcode = ENXIO;
+ goto bad;
+ }
+ SC_DEBUG(sc_link, SDEV_DB3, ("device ok\n"));
+
+ /*
+ * Load the physical device parameters
+ */
+ sd_get_parms(unit, 0); /* sets SDEV_MEDIA_LOADED */
+ if (sd->params.secsiz != SECSIZE) { /* XXX One day... */
+ printf("sd%d: Can't deal with %d bytes logical blocks\n",
+ unit, sd->params.secsiz);
+ Debugger("sd");
+ errcode = ENXIO;
+ goto bad;
+ }
+ SC_DEBUG(sc_link, SDEV_DB3, ("Params loaded "));
+
+ /* Lock the pack in. */
+ scsi_prevent(sc_link, PR_PREVENT, SCSI_ERR_OK | SCSI_SILENT);
+
+ /*
+ * Load the partition info if not already loaded.
+ */
+ if ((errcode = sdgetdisklabel(unit)) && (part != RAW_PART)) {
+ goto bad;
+ }
+ SC_DEBUG(sc_link, SDEV_DB3, ("Disklabel loaded "));
+ /*
+ * Check the partition is legal
+ */
+ if (part >= MAXPARTITIONS) {
+ errcode = ENXIO;
+ goto bad;
+ }
+ SC_DEBUG(sc_link, SDEV_DB3, ("partition ok"));
+
+ /*
+ * Check that the partition exists
+ */
+ if ((sd->disklabel.d_partitions[part].p_size == 0)
+ && (part != RAW_PART)) {
+ errcode = ENXIO;
+ goto bad;
+ }
+ sd->partflags[part] |= SDOPEN;
+ sd->openparts |= (1 << part);
+ SC_DEBUG(sc_link, SDEV_DB3, ("open %d %d\n", sdstrats, sdqueues));
+ return 0;
+
+bad:
+ if (!(sd->openparts)) {
+ scsi_prevent(sc_link, PR_ALLOW, SCSI_ERR_OK | SCSI_SILENT);
+ sc_link->flags &= ~SDEV_OPEN;
+ }
+ return errcode;
+}
+
+/*
+ * close the device.. only called if we are the LAST occurence of an open
+ * device. Convenient now but usually a pain.
+ */
+errval
+sdclose(dev)
+ dev_t dev;
+{
+ unsigned char unit, part;
+ struct sd_data *sd;
+
+ unit = UNIT(dev);
+ part = PARTITION(dev);
+ sd = sd_data[unit];
+ sd->partflags[part] &= ~SDOPEN;
+ sd->openparts &= ~(1 << part);
+ scsi_prevent(sd->sc_link, PR_ALLOW, SCSI_SILENT | SCSI_ERR_OK);
+ if (!(sd->openparts))
+ sd->sc_link->flags &= ~SDEV_OPEN;
+ return 0;
+}
+
+/*
+ * trim the size of the transfer if needed, called by physio
+ * basically the smaller of our max and the scsi driver's
+ * minphys (note we have no max)
+ *
+ * Trim buffer length if buffer-size is bigger than page size
+ */
+void
+sdminphys(bp)
+ struct buf *bp;
+{
+ (*(sd_data[UNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp);
+}
+
+/*
+ * Actually translate the requested transfer into one the physical driver
+ * can understand. The transfer is described by a buf and will include
+ * only one physical transfer.
+ */
+void
+sdstrategy(bp)
+ struct buf *bp;
+{
+ struct buf *dp;
+ u_int32 opri;
+ struct sd_data *sd;
+ u_int32 unit;
+
+ sdstrats++;
+ unit = UNIT((bp->b_dev));
+ sd = sd_data[unit];
+ SC_DEBUG(sd->sc_link, SDEV_DB2, ("sdstrategy "));
+ SC_DEBUG(sd->sc_link, SDEV_DB1,
+ (" %d bytes @ blk%d\n", bp->b_bcount, bp->b_blkno));
+ sdminphys(bp);
+ /*
+ * If the device has been made invalid, error out
+ */
+ if (!(sd->sc_link->flags & SDEV_MEDIA_LOADED)) {
+ sd->flags &= ~SDHAVELABEL;
+ bp->b_error = EIO;
+ goto bad;
+ }
+ /*
+ * "soft" write protect check
+ */
+ if ((sd->flags & SDWRITEPROT) && (bp->b_flags & B_READ) == 0) {
+ bp->b_error = EROFS;
+ goto bad;
+ }
+ /*
+ * If it's a null transfer, return immediatly
+ */
+ if (bp->b_bcount == 0) {
+ goto done;
+ }
+ /*
+ * Decide which unit and partition we are talking about
+ * only raw is ok if no label
+ */
+ if (PARTITION(bp->b_dev) != RAW_PART) {
+ if (!(sd->flags & SDHAVELABEL)) {
+ bp->b_error = EIO;
+ goto bad;
+ }
+ /*
+ * do bounds checking, adjust transfer. if error, process.
+ * if end of partition, just return
+ */
+ if (bounds_check_with_label(bp, &sd->disklabel, sd->wlabel) <= 0)
+ goto done;
+ /* otherwise, process transfer request */
+ } else {
+ bp->b_pblkno = bp->b_blkno;
+ bp->b_resid = 0;
+ }
+ opri = SPLSD();
+ dp = &sd->buf_queue;
+
+ /*
+ * Use a bounce buffer if necessary
+ */
+#ifndef NOBOUNCE
+ if (sd->sc_link->flags & SDEV_BOUNCE)
+ vm_bounce_alloc(bp);
+#endif
+
+ /*
+ * Place it in the queue of disk activities for this disk
+ */
+ cldisksort(dp, bp, 64*1024);
+
+ /*
+ * Tell the device to get going on the transfer if it's
+ * not doing anything, otherwise just wait for completion
+ */
+ sdstart(unit);
+
+ splx(opri);
+ return /*0*/;
+bad:
+ bp->b_flags |= B_ERROR;
+done:
+
+ /*
+ * Correctly set the buf to indicate a completed xfer
+ */
+ bp->b_resid = bp->b_bcount;
+ biodone(bp);
+ return /*0*/;
+}
+
+/*
+ * sdstart looks to see if there is a buf waiting for the device
+ * and that the device is not already busy. If both are true,
+ * It dequeues the buf and creates a scsi command to perform the
+ * transfer in the buf. The transfer request will call scsi_done
+ * on completion, which will in turn call this routine again
+ * so that the next queued transfer is performed.
+ * The bufs are queued by the strategy routine (sdstrategy)
+ *
+ * This routine is also called after other non-queued requests
+ * have been made of the scsi driver, to ensure that the queue
+ * continues to be drained.
+ *
+ * must be called at the correct (highish) spl level
+ * sdstart() is called at SPLSD from sdstrategy and scsi_done
+ */
+void
+sdstart(unit)
+ u_int32 unit;
+{
+ register struct sd_data *sd = sd_data[unit];
+ register struct scsi_link *sc_link = sd->sc_link;
+ struct buf *bp = 0;
+ struct buf *dp;
+ struct scsi_rw_big cmd;
+ u_int32 blkno, nblk;
+ struct partition *p;
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("sdstart "));
+ /*
+ * Check if the device has room for another command
+ */
+ while (sc_link->opennings) {
+
+ /*
+ * there is excess capacity, but a special waits
+ * It'll need the adapter as soon as we clear out of the
+ * way and let it run (user level wait).
+ */
+ if (sc_link->flags & SDEV_WAITING) {
+ return;
+ }
+ /*
+ * See if there is a buf with work for us to do..
+ */
+ dp = &sd->buf_queue;
+ if ((bp = dp->b_actf) == NULL) { /* yes, an assign */
+ return;
+ }
+ dp->b_actf = bp->av_forw;
+
+ /*
+ * If the device has become invalid, abort all the
+ * reads and writes until all files have been closed and
+ * re-openned
+ */
+ if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
+ sd->flags &= ~SDHAVELABEL;
+ goto bad;
+ }
+ /*
+ * We have a buf, now we know we are going to go through
+ * With this thing..
+ *
+ * First, translate the block to absolute
+ */
+ p = sd->disklabel.d_partitions + PARTITION(bp->b_dev);
+ blkno = bp->b_blkno + p->p_offset;
+ nblk = (bp->b_bcount + 511) >> 9;
+
+ /*
+ * Fill out the scsi command
+ */
+ bzero(&cmd, sizeof(cmd));
+ cmd.op_code = (bp->b_flags & B_READ)
+ ? READ_BIG : WRITE_BIG;
+ cmd.addr_3 = (blkno & 0xff000000UL) >> 24;
+ cmd.addr_2 = (blkno & 0xff0000) >> 16;
+ cmd.addr_1 = (blkno & 0xff00) >> 8;
+ cmd.addr_0 = blkno & 0xff;
+ cmd.length2 = (nblk & 0xff00) >> 8;
+ cmd.length1 = (nblk & 0xff);
+ /*
+ * Call the routine that chats with the adapter.
+ * Note: we cannot sleep as we may be an interrupt
+ */
+ if (scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &cmd,
+ sizeof(cmd),
+ (u_char *) bp->b_un.b_addr,
+ bp->b_bcount,
+ SD_RETRIES,
+ 10000,
+ bp,
+ SCSI_NOSLEEP | ((bp->b_flags & B_READ) ?
+ SCSI_DATA_IN : SCSI_DATA_OUT))
+ == SUCCESSFULLY_QUEUED) {
+ sdqueues++;
+ } else {
+bad:
+ printf("sd%d: oops not queued", unit);
+ bp->b_error = EIO;
+ bp->b_flags |= B_ERROR;
+ biodone(bp);
+ }
+ }
+}
+
+/*
+ * Perform special action on behalf of the user
+ * Knows about the internals of this device
+ */
+errval
+sdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
+{
+ /* struct sd_cmd_buf *args; */
+ errval error = 0;
+ unsigned char unit, part;
+ register struct sd_data *sd;
+
+ /*
+ * Find the device that the user is talking about
+ */
+ unit = UNIT(dev);
+ part = PARTITION(dev);
+ sd = sd_data[unit];
+ SC_DEBUG(sd->sc_link, SDEV_DB1, ("sdioctl (0x%x)", cmd));
+
+ /*
+ * If the device is not valid.. abandon ship
+ */
+ if (!(sd->sc_link->flags & SDEV_MEDIA_LOADED))
+ return (EIO);
+ switch (cmd) {
+
+ case DIOCSBAD:
+ error = EINVAL;
+ break;
+
+ case DIOCGDINFO:
+ *(struct disklabel *) addr = sd->disklabel;
+ break;
+
+ case DIOCGPART:
+ ((struct partinfo *) addr)->disklab = &sd->disklabel;
+ ((struct partinfo *) addr)->part =
+ &sd->disklabel.d_partitions[PARTITION(dev)];
+ break;
+
+ case DIOCSDINFO:
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else
+ error = setdisklabel(&sd->disklabel,
+ (struct disklabel *)addr,
+ /*(sd->flags & DKFL_BSDLABEL) ? sd->openparts : */ 0,
+#ifdef NetBSD
+ &sd->cpudisklabel
+#else
+ sd->dosparts
+#endif
+ );
+ if (error == 0) {
+ sd->flags |= SDHAVELABEL;
+ }
+ break;
+
+ case DIOCWLABEL:
+ sd->flags &= ~SDWRITEPROT;
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else
+ sd->wlabel = *(boolean *) addr;
+ break;
+
+ case DIOCWDINFO:
+ sd->flags &= ~SDWRITEPROT;
+ if ((flag & FWRITE) == 0)
+ error = EBADF;
+ else {
+ error = setdisklabel(&sd->disklabel,
+ (struct disklabel *)addr,
+ /*(sd->flags & SDHAVELABEL) ? sd->openparts : */ 0,
+#ifdef NetBSD
+ &sd->cpudisklabel
+#else
+ sd->dosparts
+#endif
+ );
+ if (!error) {
+ boolean wlab;
+
+ /* ok - write will succeed */
+ sd->flags |= SDHAVELABEL;
+
+ /* simulate opening partition 0 so write succeeds */
+ sd->openparts |= (1 << 0); /* XXX */
+ wlab = sd->wlabel;
+ sd->wlabel = 1;
+ error = writedisklabel(dev, sdstrategy,
+ &sd->disklabel,
+#ifdef NetBSD
+ &sd->cpudisklabel
+#else
+ sd->dosparts
+#endif
+ );
+ sd->wlabel = wlab;
+ }
+ }
+ break;
+
+ default:
+ if (part == RAW_PART)
+ error = scsi_do_ioctl(sd->sc_link, cmd, addr, flag);
+ else
+ error = ENOTTY;
+ break;
+ }
+ return error;
+}
+
+/*
+ * Load the label information on the named device
+ */
+errval
+sdgetdisklabel(unsigned char unit)
+{
+ char *errstring;
+ struct sd_data *sd = sd_data[unit];
+
+ /*
+ * If the inflo is already loaded, use it
+ */
+ if (sd->flags & SDHAVELABEL)
+ return (ESUCCESS);
+
+ bzero(&sd->disklabel, sizeof(struct disklabel));
+ /*
+ * make partition 3 the whole disk in case of failure then get pdinfo
+ * for historical reasons, make part a same as raw part
+ */
+ sd->disklabel.d_partitions[0].p_offset = 0;
+ sd->disklabel.d_partitions[0].p_size = sd->params.disksize;
+ sd->disklabel.d_partitions[RAW_PART].p_offset = 0;
+ sd->disklabel.d_partitions[RAW_PART].p_size = sd->params.disksize;
+ sd->disklabel.d_npartitions = MAXPARTITIONS;
+ sd->disklabel.d_secsize = SECSIZE; /* as long as it's not 0 */
+ sd->disklabel.d_ntracks = sd->params.heads;
+ sd->disklabel.d_nsectors = sd->params.sectors;
+ sd->disklabel.d_ncylinders = sd->params.cyls;
+ sd->disklabel.d_secpercyl = sd->params.heads * sd->params.sectors;
+ if (sd->disklabel.d_secpercyl == 0) {
+ sd->disklabel.d_secpercyl = 100;
+ /* as long as it's not 0 - readdisklabel divides by it (?) */
+ }
+ /*
+ * Call the generic disklabel extraction routine
+ */
+ if (errstring = readdisklabel(makedev(0, (unit << UNITSHIFT) + 3),
+ sdstrategy,
+ &sd->disklabel,
+#ifdef NetBSD
+ &sd->cpudisklabel
+#else
+ sd->dosparts,
+ 0,
+ 0
+#endif
+ )) {
+ printf("sd%d: %s\n", unit, errstring);
+ return ENXIO;
+ }
+ sd->flags |= SDHAVELABEL; /* WE HAVE IT ALL NOW */
+ return ESUCCESS;
+}
+
+/*
+ * Find out from the device what it's capacity is
+ */
+u_int32
+sd_size(unit, flags)
+ int unit, flags;
+{
+ struct scsi_read_cap_data rdcap;
+ struct scsi_read_capacity scsi_cmd;
+ u_int32 size;
+
+ /*
+ * make up a scsi command and ask the scsi driver to do
+ * it for you.
+ */
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = READ_CAPACITY;
+
+ /*
+ * If the command works, interpret the result as a 4 byte
+ * number of blocks
+ */
+ if (scsi_scsi_cmd(sd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) & rdcap,
+ sizeof(rdcap),
+ SD_RETRIES,
+ 2000,
+ NULL,
+ flags | SCSI_DATA_IN) != 0) {
+ printf("sd%d: could not get size\n", unit);
+ return (0);
+ } else {
+ size = rdcap.addr_0 + 1;
+ size += rdcap.addr_1 << 8;
+ size += rdcap.addr_2 << 16;
+ size += rdcap.addr_3 << 24;
+ }
+ return (size);
+}
+
+/*
+ * Tell the device to map out a defective block
+ */
+errval
+sd_reassign_blocks(unit, block)
+ int unit, block;
+{
+ struct scsi_reassign_blocks scsi_cmd;
+ struct scsi_reassign_blocks_data rbdata;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ bzero(&rbdata, sizeof(rbdata));
+ scsi_cmd.op_code = REASSIGN_BLOCKS;
+
+ rbdata.length_msb = 0;
+ rbdata.length_lsb = sizeof(rbdata.defect_descriptor[0]);
+ rbdata.defect_descriptor[0].dlbaddr_3 = ((block >> 24) & 0xff);
+ rbdata.defect_descriptor[0].dlbaddr_2 = ((block >> 16) & 0xff);
+ rbdata.defect_descriptor[0].dlbaddr_1 = ((block >> 8) & 0xff);
+ rbdata.defect_descriptor[0].dlbaddr_0 = ((block) & 0xff);
+
+ return (scsi_scsi_cmd(sd_data[unit]->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) & rbdata,
+ sizeof(rbdata),
+ SD_RETRIES,
+ 5000,
+ NULL,
+ SCSI_DATA_OUT));
+}
+#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 )
+
+/*
+ * Get the scsi driver to send a full inquiry to the
+ * device and use the results to fill out the disk
+ * parameter structure.
+ */
+errval
+sd_get_parms(unit, flags)
+ int unit, flags;
+{
+ struct sd_data *sd = sd_data[unit];
+ struct disk_parms *disk_parms = &sd->params;
+ struct scsi_mode_sense scsi_cmd;
+ struct scsi_mode_sense_data {
+ struct scsi_mode_header header;
+ struct blk_desc blk_desc;
+ union disk_pages pages;
+ } scsi_sense;
+ u_int32 sectors;
+
+ /*
+ * First check if we have it all loaded
+ */
+ if (sd->sc_link->flags & SDEV_MEDIA_LOADED)
+ return 0;
+
+ /*
+ * do a "mode sense page 4"
+ */
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = MODE_SENSE;
+ scsi_cmd.page = 4;
+ scsi_cmd.length = 0x20;
+ /*
+ * If the command worked, use the results to fill out
+ * the parameter structure
+ */
+ if (scsi_scsi_cmd(sd->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) & scsi_sense,
+ sizeof(scsi_sense),
+ SD_RETRIES,
+ 2000,
+ NULL,
+ flags | SCSI_DATA_IN) != 0) {
+
+ printf("sd%d could not mode sense (4).", unit);
+ printf(" Using ficticious geometry\n");
+ /*
+ * use adaptec standard ficticious geometry
+ * this depends on which controller (e.g. 1542C is
+ * different. but we have to put SOMETHING here..)
+ */
+ sectors = sd_size(unit, flags);
+ disk_parms->heads = 64;
+ disk_parms->sectors = 32;
+ disk_parms->cyls = sectors / (64 * 32);
+ disk_parms->secsiz = SECSIZE;
+ disk_parms->disksize = sectors;
+ } else {
+
+ SC_DEBUG(sd->sc_link, SDEV_DB3,
+ ("%d cyls, %d heads, %d precomp, %d red_write, %d land_zone\n",
+ _3btol(&scsi_sense.pages.rigid_geometry.ncyl_2),
+ scsi_sense.pages.rigid_geometry.nheads,
+ b2tol(scsi_sense.pages.rigid_geometry.st_cyl_wp),
+ b2tol(scsi_sense.pages.rigid_geometry.st_cyl_rwc),
+ b2tol(scsi_sense.pages.rigid_geometry.land_zone)));
+
+ /*
+ * KLUDGE!!(for zone recorded disks)
+ * give a number of sectors so that sec * trks * cyls
+ * is <= disk_size
+ * can lead to wasted space! THINK ABOUT THIS !
+ */
+ disk_parms->heads = scsi_sense.pages.rigid_geometry.nheads;
+ disk_parms->cyls = _3btol(&scsi_sense.pages.rigid_geometry.ncyl_2);
+ disk_parms->secsiz = _3btol(scsi_sense.blk_desc.blklen);
+
+ sectors = sd_size(unit, flags);
+ disk_parms->disksize = sectors;
+ /* Check if none of these values are zero */
+ if(disk_parms->heads && disk_parms->cyls) {
+ sectors /= (disk_parms->heads * disk_parms->cyls);
+ }
+ else {
+ /* set it to something reasonable */
+ sectors = 32;
+ disk_parms->heads = 64;
+ disk_parms->cyls = sectors / (64 * 32);
+ }
+ disk_parms->sectors = sectors; /* dubious on SCSI *//*XXX */
+ }
+ sd->sc_link->flags |= SDEV_MEDIA_LOADED;
+ return 0;
+}
+
+int
+sdsize(dev_t dev)
+{
+ u_int32 unit = UNIT(dev), part = PARTITION(dev), val;
+ struct sd_data *sd;
+
+ if (unit >= NSD)
+ return -1;
+
+ sd = sd_data[unit];
+ if (!sd)
+ return -1;
+ if ((sd->flags & SDINIT) == 0)
+ return -1;
+ if (sd == 0 || (sd->flags & SDHAVELABEL) == 0) {
+ val = sdopen(MAKESDDEV(major(dev), unit, RAW_PART), FREAD, S_IFBLK, 0);
+ if (val != 0)
+ return -1;
+ }
+ if (sd->flags & SDWRITEPROT)
+ return -1;
+
+ return (int)sd->disklabel.d_partitions[part].p_size;
+}
+
+/*
+ * dump all of physical memory into the partition specified, starting
+ * at offset 'dumplo' into the partition.
+ */
+errval
+sddump(dev_t dev)
+{ /* dump core after a system crash */
+ register struct sd_data *sd; /* disk unit to do the IO */
+ int32 num; /* number of sectors to write */
+ u_int32 unit, part;
+ int32 blkoff, blknum, blkcnt = MAXTRANSFER;
+ int32 nblocks;
+ char *addr;
+ struct scsi_rw_big cmd;
+ extern int Maxmem;
+ static int sddoingadump = 0;
+ extern caddr_t CADDR1; /* map the page we are about to write, here */
+ extern struct pte *CMAP1;
+ struct scsi_xfer *xs = &sx;
+ errval retval;
+ int c;
+
+ addr = (char *) 0; /* starting address */
+
+ /* toss any characters present prior to dump */
+ while ((c = sgetc(1)) && (c != 0x100)); /*syscons and pccons differ */
+
+ /* size of memory to dump */
+ num = Maxmem;
+ unit = UNIT(dev); /* eventually support floppies? */
+ part = PARTITION(dev); /* file system */
+ /* check for acceptable drive number */
+ if (unit >= NSD)
+ return (ENXIO);
+
+ sd = sd_data[unit];
+ if (!sd)
+ return (ENXIO);
+ /* was it ever initialized etc. ? */
+ if (!(sd->flags & SDINIT))
+ return (ENXIO);
+ if (sd->sc_link->flags & SDEV_MEDIA_LOADED != SDEV_MEDIA_LOADED)
+ return (ENXIO);
+ if (sd->flags & SDWRITEPROT)
+ return (ENXIO);
+
+ /* Convert to disk sectors */
+ num = (u_int32) num * NBPG / sd->disklabel.d_secsize;
+
+ /* check if controller active */
+ if (sddoingadump)
+ return (EFAULT);
+
+ nblocks = sd->disklabel.d_partitions[part].p_size;
+ blkoff = sd->disklabel.d_partitions[part].p_offset;
+
+ /* check transfer bounds against partition size */
+ if ((dumplo < 0) || ((dumplo + num) > nblocks))
+ return (EINVAL);
+
+ sddoingadump = 1;
+
+ blknum = dumplo + blkoff;
+ while (num > 0) {
+ *(int *)CMAP1 =
+ PG_V | PG_KW | trunc_page(addr);
+ tlbflush();
+ /*
+ * Fill out the scsi command
+ */
+ bzero(&cmd, sizeof(cmd));
+ cmd.op_code = WRITE_BIG;
+ cmd.addr_3 = (blknum & 0xff000000) >> 24;
+ cmd.addr_2 = (blknum & 0xff0000) >> 16;
+ cmd.addr_1 = (blknum & 0xff00) >> 8;
+ cmd.addr_0 = blknum & 0xff;
+ cmd.length2 = (blkcnt & 0xff00) >> 8;
+ cmd.length1 = (blkcnt & 0xff);
+ /*
+ * Fill out the scsi_xfer structure
+ * Note: we cannot sleep as we may be an interrupt
+ * don't use scsi_scsi_cmd() as it may want
+ * to wait for an xs.
+ */
+ bzero(xs, sizeof(sx));
+ xs->flags |= SCSI_NOMASK | SCSI_NOSLEEP | INUSE;
+ xs->sc_link = sd->sc_link;
+ xs->retries = SD_RETRIES;
+ xs->timeout = 10000; /* 10000 millisecs for a disk ! */
+ xs->cmd = (struct scsi_generic *) &cmd;
+ xs->cmdlen = sizeof(cmd);
+ xs->resid = blkcnt * 512;
+ xs->error = XS_NOERROR;
+ xs->bp = 0;
+ xs->data = (u_char *) CADDR1;
+ xs->datalen = blkcnt * 512;
+
+ /*
+ * Pass all this info to the scsi driver.
+ */
+ retval = (*(sd->sc_link->adapter->scsi_cmd)) (xs);
+ switch (retval) {
+ case SUCCESSFULLY_QUEUED:
+ case HAD_ERROR:
+ return (ENXIO); /* we said not to sleep! */
+ case COMPLETE:
+ break;
+ default:
+ return (ENXIO); /* we said not to sleep! */
+ }
+
+ if ((unsigned) addr % (1024 * 1024) == 0)
+ printf("%d ", num / 2048);
+ /* update block count */
+ num -= blkcnt;
+ blknum += blkcnt;
+ (int) addr += 512 * blkcnt;
+
+ /* operator aborting dump? */
+ if ((c = sgetc(1)) && (c != 0x100))
+ return (EINTR);
+ }
+ return (0);
+}
diff --git a/sys/scsi/st.c b/sys/scsi/st.c
new file mode 100644
index 0000000..b72cb76
--- /dev/null
+++ b/sys/scsi/st.c
@@ -0,0 +1,1936 @@
+/*
+ * Written by Julian Elischer (julian@tfs.com)(now julian@DIALix.oz.au)
+ * for TRW Financial Systems for use under the MACH(2.5) operating system.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ *
+ * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
+ * -------------------- ----- ----------------------
+ * CURRENT PATCH LEVEL: 1 00098
+ * -------------------- ----- ----------------------
+ *
+ * 16 Feb 93 Julian Elischer ADDED for SCSI system
+ * 1.15 is the last version to support MACH and OSF/1
+ */
+/* $Revision: 1.15 $ */
+
+/*
+ * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ * major changes by Julian Elischer (julian@jules.dialix.oz.au) May 1993
+ *
+ * $Id: st.c,v 1.15 1994/01/29 10:30:41 rgrimes Exp $
+ */
+
+/*
+ * To do:
+ * work out some better way of guessing what a good timeout is going
+ * to be depending on whether we expect to retension or not.
+ *
+ */
+
+#include <sys/types.h>
+#include <st.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <fcntl.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/mtio.h>
+
+#include <scsi/scsi_all.h>
+#include <scsi/scsi_tape.h>
+#include <scsi/scsiconf.h>
+
+u_int32 ststrats, stqueues;
+
+/* Defines for device specific stuff */
+#define PAGE_0_SENSE_DATA_SIZE 12
+#define PAGESIZ 4096
+#define DEF_FIXED_BSIZE 512
+#define ST_RETRIES 4 /* only on non IO commands */
+
+#define MODE(z) ( (minor(z) & 0x03) )
+#define DSTY(z) ( ((minor(z) >> 2) & 0x03) )
+#define UNIT(z) ( (minor(z) >> 4) )
+#define CTLMODE 3
+
+#define SCSI_2_MAX_DENSITY_CODE 0x17 /* maximum density code specified
+ * in SCSI II spec. */
+/*
+ * Define various devices that we know mis-behave in some way,
+ * and note how they are bad, so we can correct for them
+ */
+struct modes {
+ u_int32 blksiz;
+ u_int32 quirks; /* same definitions as in rogues */
+ char density;
+ char spare[3];
+};
+
+struct rogues {
+ char *name;
+ char *manu;
+ char *model;
+ char *version;
+ u_int32 quirks; /* valid for all modes */
+ struct modes modes[4];
+};
+
+/* define behaviour codes (quirks) */
+#define ST_Q_NEEDS_PAGE_0 0x00001
+#define ST_Q_FORCE_FIXED_MODE 0x00002
+#define ST_Q_FORCE_VAR_MODE 0x00004
+#define ST_Q_SNS_HLP 0x00008 /* must do READ for good MODE SENSE */
+#define ST_Q_IGNORE_LOADS 0x00010
+#define ST_Q_BLKSIZ 0x00020 /* variable-block media_blksiz > 0 */
+
+static struct rogues gallery[] = /* ends with an all-null entry */
+{
+ {"Such an old device ", "pre-scsi", " unknown model ", "????",
+ 0,
+ {
+ {512, ST_Q_FORCE_FIXED_MODE, 0}, /* minor 0,1,2,3 */
+ {512, ST_Q_FORCE_FIXED_MODE, QIC_24}, /* minor 4,5,6,7 */
+ {0, ST_Q_FORCE_VAR_MODE, HALFINCH_1600}, /* minor 8,9,10,11 */
+ {0, ST_Q_FORCE_VAR_MODE, HALFINCH_6250} /* minor 12,13,14,15 */
+ }
+ },
+ {"Tandberg tdc3600", "TANDBERG", " TDC 3600", "????",
+ ST_Q_NEEDS_PAGE_0,
+ {
+ {0, 0, 0}, /* minor 0,1,2,3 */
+ {0, ST_Q_FORCE_VAR_MODE, QIC_525}, /* minor 4,5,6,7 */
+ {0, 0, QIC_150}, /* minor 8,9,10,11 */
+ {0, 0, QIC_120} /* minor 12,13,14,15 */
+ }
+ },
+ {"Rev 5 of the Archive 2525", "ARCHIVE ", "VIPER 2525 25462", "-005",
+ 0,
+ {
+ {0, ST_Q_SNS_HLP, 0}, /* minor 0,1,2,3 */
+ {0, ST_Q_SNS_HLP, QIC_525}, /* minor 4,5,6,7 */
+ {0, 0, QIC_150}, /* minor 8,9,10,11 */
+ {0, 0, QIC_120} /* minor 12,13,14,15 */
+ }
+ },
+ {"Archive Viper 150", "ARCHIVE ", "VIPER 150", "????",
+ ST_Q_NEEDS_PAGE_0,
+ {
+ {0, 0, 0}, /* minor 0,1,2,3 */
+ {0, 0, QIC_150}, /* minor 4,5,6,7 */
+ {0, 0, QIC_120}, /* minor 8,9,10,11 */
+ {0, 0, QIC_24} /* minor 12,13,14,15 */
+ }
+ },
+ {"Wangtek 5525ES", "WANGTEK ", "5525ES SCSI REV7", "????",
+ 0,
+ {
+ {0, 0, 0}, /* minor 0,1,2,3 */
+ {0, ST_Q_BLKSIZ, QIC_525}, /* minor 4,5,6,7 */
+ {0, 0, QIC_150}, /* minor 8,9,10,11 */
+ {0, 0, QIC_120} /* minor 12,13,14,15 */
+ }
+ },
+ {"WangDAT model 1300", "WangDAT ", "Model 1300", "????",
+ 0,
+ {
+ {0, 0, 0}, /* minor 0,1,2,3 */
+ {512, ST_Q_FORCE_FIXED_MODE, 0x13}, /* minor 4,5,6,7 */
+ {1024, ST_Q_FORCE_FIXED_MODE, 0x13}, /* minor 8,9,10,11 */
+ {0, ST_Q_FORCE_VAR_MODE, 0x13} /* minor 12,13,14,15 */
+ }
+ },
+ {(char *) 0}
+};
+
+errval st_space __P((u_int32 unit, int32 number, u_int32 what, u_int32 flags));
+errval st_rewind __P((u_int32 unit, boolean immed, u_int32 flags));
+errval st_mode_sense __P((u_int32 unit, u_int32 flags));
+errval st_decide_mode __P((u_int32 unit, boolean first_read));
+errval st_rd_blk_lim __P((u_int32 unit, u_int32 flags));
+errval st_touch_tape __P((u_int32 unit));
+errval st_write_filemarks __P((u_int32 unit, int32 number, u_int32 flags));
+errval st_load __P((u_int32 unit, u_int32 type, u_int32 flags));
+errval st_mode_select __P((u_int32 unit, u_int32 flags));
+void ststrategy();
+void stminphys();
+int32 st_chkeod();
+errval stattach();
+void ststart();
+void st_unmount();
+errval st_mount_tape();
+void st_loadquirks();
+void st_identify_drive();
+errval st_interpret_sense();
+
+#define ESUCCESS 0
+#define NOEJECT 0
+#define EJECT 1
+
+struct scsi_device st_switch =
+{
+ st_interpret_sense, /* check errors with us first */
+ ststart, /* we have a queue, and this is how we service it */
+ NULL,
+ NULL, /* use the default 'done' routine */
+ "st",
+ 0,
+ { 0, 0 }
+};
+
+struct st_data {
+/*--------------------present operating parameters, flags etc.----------------*/
+ u_int32 flags; /* see below */
+ u_int32 blksiz; /* blksiz we are using */
+ u_int32 density; /* present density */
+ u_int32 quirks; /* quirks for the open mode */
+ u_int32 last_dsty; /* last density openned */
+/*--------------------device/scsi parameters----------------------------------*/
+ struct scsi_link *sc_link; /* our link to the adpter etc. */
+/*--------------------parameters reported by the device ----------------------*/
+ u_int32 blkmin; /* min blk size */
+ u_int32 blkmax; /* max blk size */
+ struct rogues *rogues; /* if we have a rogue entry */
+/*--------------------parameters reported by the device for this media--------*/
+ u_int32 numblks; /* nominal blocks capacity */
+ u_int32 media_blksiz; /* 0 if not ST_FIXEDBLOCKS */
+ u_int32 media_density; /* this is what it said when asked */
+/*--------------------quirks for the whole drive------------------------------*/
+ u_int32 drive_quirks; /* quirks of this drive */
+/*--------------------How we should set up when openning each minor device----*/
+ struct modes modes[4]; /* plus more for each mode */
+ u_int8 modeflags[4]; /* flags for the modes */
+#define DENSITY_SET_BY_USER 0x01
+#define DENSITY_SET_BY_QUIRK 0x02
+#define BLKSIZE_SET_BY_USER 0x04
+#define BLKSIZE_SET_BY_QUIRK 0x08
+/*--------------------storage for sense data returned by the drive------------*/
+ unsigned char sense_data[12]; /*
+ * additional sense data needed
+ * for mode sense/select.
+ */
+ struct buf *buf_queue; /* the queue of pending IO operations */
+ struct scsi_xfer scsi_xfer; /* scsi xfer struct for this drive */
+ u_int32 xfer_block_wait; /* is a process waiting? */
+} *st_data[NST];
+
+#define ST_INITIALIZED 0x01
+#define ST_INFO_VALID 0x02
+#define ST_OPEN 0x04
+#define ST_BLOCK_SET 0x08 /* block size, mode set by ioctl */
+#define ST_WRITTEN 0x10 /* data have been written, EOD needed */
+#define ST_FIXEDBLOCKS 0x20
+#define ST_AT_FILEMARK 0x40
+#define ST_EIO_PENDING 0x80 /* we couldn't report it then (had data) */
+#define ST_NEW_MOUNT 0x100 /* still need to decide mode */
+#define ST_READONLY 0x200 /* st_mode_sense says write protected */
+#define ST_FM_WRITTEN 0x400 /*
+ * EOF file mark written -- used with
+ * ~ST_WRITTEN to indicate that multiple file
+ * marks have been written
+ */
+#define ST_BLANK_READ 0x800 /* BLANK CHECK encountered already */
+#define ST_2FM_AT_EOD 0x1000 /* write 2 file marks at EOD */
+#define ST_MOUNTED 0x2000 /* Device is presently mounted */
+
+#define ST_PER_ACTION (ST_AT_FILEMARK | ST_EIO_PENDING | ST_BLANK_READ)
+#define ST_PER_MOUNT (ST_INFO_VALID | ST_BLOCK_SET | ST_WRITTEN | \
+ ST_FIXEDBLOCKS | ST_READONLY | \
+ ST_FM_WRITTEN | ST_2FM_AT_EOD | ST_PER_ACTION)
+
+static u_int32 next_st_unit = 0;
+
+/*
+ * The routine called by the low level scsi routine when it discovers
+ * A device suitable for this driver
+ */
+
+errval
+stattach(sc_link)
+ struct scsi_link *sc_link;
+{
+ u_int32 unit;
+ struct st_data *st;
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("stattach: "));
+ /*
+ * Check we have the resources for another drive
+ */
+ unit = next_st_unit++;
+
+ if (unit >= NST) {
+ printf("Too many scsi tapes..(%d > %d) reconfigure kernel\n",
+ (unit + 1), NST);
+ return 0;
+ }
+ if (st_data[unit]) {
+ printf("st%d: Already has storage!\n", unit);
+ return 0;
+ }
+ sc_link->device = &st_switch;
+ sc_link->dev_unit = unit;
+ st = st_data[unit] = malloc(sizeof(struct st_data), M_DEVBUF, M_NOWAIT);
+ if (!st) {
+ printf("st%d: malloc failed in st.c\n", unit);
+ return 0;
+ }
+ bzero(st, sizeof(struct st_data));
+
+ /*
+ * Store information needed to contact our base driver
+ */
+ st->sc_link = sc_link;
+
+ /*
+ * Check if the drive is a known criminal and take
+ * Any steps needed to bring it into line
+ */
+ st_identify_drive(unit);
+
+ /*
+ * Use the subdriver to request information regarding
+ * the drive. We cannot use interrupts yet, so the
+ * request must specify this.
+ */
+ if (st_mode_sense(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) {
+ printf("st%d: drive offline\n", unit);
+ } else {
+ printf("st%d: density code 0x%x, ", unit, st->media_density);
+ if (!scsi_test_unit_ready(sc_link, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT)) {
+ if (st->media_blksiz) {
+ printf("%d-byte", st->media_blksiz);
+ } else {
+ printf("variable");
+ }
+ printf(" blocks, write-%s\n",
+ (st->flags & ST_READONLY) ? "protected" : "enabled");
+ } else {
+ printf(" drive empty\n");
+ }
+ }
+ /*
+ * Set up the buf queue for this device
+ */
+ st->buf_queue = 0;
+ st->flags |= ST_INITIALIZED;
+ return 0;
+}
+
+/*
+ * Use the inquiry routine in 'scsi_base' to get drive info so we can
+ * Further tailor our behaviour.
+ */
+void
+st_identify_drive(unit)
+ u_int32 unit;
+{
+ struct st_data *st = st_data[unit];
+ struct scsi_inquiry_data inqbuf;
+ struct rogues *finger;
+ char manu[32];
+ char model[32];
+ char model2[32];
+ char version[32];
+ u_int32 model_len;
+
+ /*
+ * Get the device type information
+ */
+ if (scsi_inquire(st->sc_link, &inqbuf,
+ SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT) != 0) {
+ printf("st%d: couldn't get device type, using default\n", unit);
+ return;
+ }
+ if ((inqbuf.version & SID_ANSII) == 0) {
+ /*
+ * If not advanced enough, use default values
+ */
+ strncpy(manu, "pre-scsi", 8);
+ manu[8] = 0;
+ strncpy(model, " unknown model ", 16);
+ model[16] = 0;
+ strncpy(version, "????", 4);
+ version[4] = 0;
+ } else {
+ strncpy(manu, inqbuf.vendor, 8);
+ manu[8] = 0;
+ strncpy(model, inqbuf.product, 16);
+ model[16] = 0;
+ strncpy(version, inqbuf.revision, 4);
+ version[4] = 0;
+ }
+
+ /*
+ * Load the parameters for this kind of device, so we
+ * treat it as appropriate for each operating mode.
+ * Only check the number of characters in the array's
+ * model entry, not the entire model string returned.
+ */
+ finger = gallery;
+ while (finger->name) {
+ model_len = 0;
+ while (finger->model[model_len] && (model_len < 32)) {
+ model2[model_len] = model[model_len];
+ model_len++;
+ }
+ model2[model_len] = 0;
+ if ((strcmp(manu, finger->manu) == 0)
+ && (strcmp(model2, finger->model) == 0 ||
+ strcmp("????????????????", finger->model) == 0)
+ && (strcmp(version, finger->version) == 0 ||
+ strcmp("????", finger->version) == 0)) {
+ printf("st%d: %s is a known rogue\n", unit, finger->name);
+ st->rogues = finger;
+ st->drive_quirks = finger->quirks;
+ st->quirks = finger->quirks; /*start value */
+ st_loadquirks(st);
+ break;
+ } else {
+ finger++; /* go to next suspect */
+ }
+ }
+}
+
+/*
+ * initialise the subdevices to the default (QUIRK) state.
+ * this will remove any setting made by the system operator or previous
+ * operations.
+ */
+void
+st_loadquirks(st)
+ struct st_data *st;
+{
+ int i;
+ struct modes *mode;
+ struct modes *mode2;
+
+ if (!st->rogues)
+ return;
+ mode = st->rogues->modes;
+ mode2 = st->modes;
+ for (i = 0; i < 4; i++) {
+ bzero(mode2, sizeof(struct modes));
+ st->modeflags[i] &= ~(BLKSIZE_SET_BY_QUIRK
+ | DENSITY_SET_BY_QUIRK
+ | BLKSIZE_SET_BY_USER
+ | DENSITY_SET_BY_USER);
+ if (mode->blksiz && ((mode->quirks | st->drive_quirks)
+ & (ST_Q_FORCE_FIXED_MODE))) {
+ mode2->blksiz = mode->blksiz;
+ st->modeflags[i] |= BLKSIZE_SET_BY_QUIRK;
+ } else {
+ if ((mode->quirks | st->drive_quirks)
+ & ST_Q_FORCE_VAR_MODE) {
+ mode2->blksiz = 0;
+ st->modeflags[i] |= BLKSIZE_SET_BY_QUIRK;
+ }
+ }
+ if (mode->density) {
+ mode2->density = mode->density;
+ st->modeflags[i] |= DENSITY_SET_BY_QUIRK;
+ }
+ mode++;
+ mode2++;
+ }
+}
+
+/*
+ * open the device.
+ */
+errval
+stopen(dev, flags)
+ dev_t dev;
+ u_int32 flags;
+{
+ u_int32 unit, mode, dsty;
+ errval errno = 0;
+ struct st_data *st;
+ struct scsi_link *sc_link;
+ unit = UNIT(dev);
+ mode = MODE(dev);
+ dsty = DSTY(dev);
+
+ /*
+ * Check the unit is legal
+ */
+ if (unit >= NST) {
+ return (ENXIO);
+ }
+ st = st_data[unit];
+ /*
+ * Make sure the device has been initialised
+ */
+ if ((st == NULL) || (!(st->flags & ST_INITIALIZED)))
+ return (ENXIO);
+
+ sc_link = st->sc_link;
+ SC_DEBUG(sc_link, SDEV_DB1, ("open: dev=0x%x (unit %d (of %d))\n"
+ ,dev, unit, NST));
+ /*
+ * Only allow one at a time
+ */
+ if (st->flags & ST_OPEN) {
+ return (EBUSY);
+ }
+ /*
+ * Throw out a dummy instruction to catch 'Unit attention
+ * errors (the error handling will invalidate all our
+ * device info if we get one, but otherwise, ignore it)
+ */
+ scsi_test_unit_ready(sc_link, SCSI_SILENT);
+
+ sc_link->flags |= SDEV_OPEN; /* unit attn are now errors */
+ /*
+ * If the mode is 3 (e.g. minor = 3,7,11,15)
+ * then the device has been openned to set defaults
+ * This mode does NOT ALLOW I/O, only ioctls
+ */
+ if (mode == CTLMODE)
+ return 0;
+
+ /*
+ * Check that the device is ready to use (media loaded?)
+ * This time take notice of the return result
+ */
+ if (errno = (scsi_test_unit_ready(sc_link, 0))) {
+ printf("st%d: not ready\n", unit);
+ st_unmount(unit, NOEJECT);
+ return (errno);
+ }
+ /*
+ * if it's a different mode, or if the media has been
+ * invalidated, unmount the tape from the previous
+ * session but continue with open processing
+ */
+ if ((st->last_dsty != dsty)
+ || (!(sc_link->flags & SDEV_MEDIA_LOADED))) {
+ st_unmount(unit, NOEJECT);
+ }
+ /*
+ * If we are not mounted, then we should start a new
+ * mount session.
+ */
+ if (!(st->flags & ST_MOUNTED)) {
+ st_mount_tape(dev, flags);
+ st->last_dsty = dsty;
+ }
+ /*
+ * Make sure that a tape opened in write-only mode will have
+ * file marks written on it when closed, even if not written to.
+ * This is for SUN compatibility
+ */
+ if ((flags & O_ACCMODE) == FWRITE)
+ st->flags |= ST_WRITTEN;
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("Open complete\n"));
+
+ st->flags |= ST_OPEN;
+ return (0);
+}
+
+/*
+ * close the device.. only called if we are the LAST
+ * occurence of an open device
+ */
+errval
+stclose(dev)
+ dev_t dev;
+{
+ unsigned char unit, mode;
+ struct st_data *st;
+ struct scsi_link *sc_link;
+
+ unit = UNIT(dev);
+ mode = MODE(dev);
+ st = st_data[unit];
+ sc_link = st->sc_link;
+
+ SC_DEBUG(sc_link, SDEV_DB1, ("closing\n"));
+ if ((st->flags & (ST_WRITTEN | ST_FM_WRITTEN)) == ST_WRITTEN)
+ st_write_filemarks(unit, 1, 0);
+ switch (mode & 0x3) {
+ case 0:
+ case 3: /* for now */
+ st_unmount(unit, NOEJECT);
+ break;
+ case 1: /*leave mounted unless media seems to have been removed */
+ if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
+ st_unmount(unit, NOEJECT);
+ }
+ break;
+ case 2:
+ st_unmount(unit, EJECT);
+ break;
+ }
+ sc_link->flags &= ~SDEV_OPEN;
+ st->flags &= ~ST_OPEN;
+ return (0);
+}
+
+/*
+ * Start a new mount session.
+ * Copy in all the default parameters from the selected device mode.
+ * and try guess any that seem to be defaulted.
+ */
+errval
+st_mount_tape(dev, flags)
+ dev_t dev;
+ u_int32 flags;
+{
+ u_int32 unit, mode, dsty;
+ struct st_data *st;
+ struct scsi_link *sc_link;
+ errval errno = 0;
+
+ unit = UNIT(dev);
+ mode = MODE(dev);
+ dsty = DSTY(dev);
+ st = st_data[unit];
+ sc_link = st->sc_link;
+
+ if (st->flags & ST_MOUNTED)
+ return 0;
+
+ SC_DEBUG(sc_link, SDEV_DB1, ("mounting\n "));
+ st->flags |= ST_NEW_MOUNT;
+ st->quirks = st->drive_quirks | st->modes[dsty].quirks;
+ /*
+ * If the media is new, then make sure we give it a chance to
+ * to do a 'load' instruction. ( We assume it is new)
+ */
+ if (errno = st_load(unit, LD_LOAD, 0)) {
+ return (errno);
+ }
+ /*
+ * Throw another dummy instruction to catch
+ * 'Unit attention' errors. Some drives appear to give
+ * these after doing a Load instruction.
+ * (noteably some DAT drives)
+ */
+ scsi_test_unit_ready(sc_link, SCSI_SILENT);
+
+ /*
+ * Some devices can't tell you much until they have been
+ * asked to look at the media. This quirk does this.
+ */
+ if (st->quirks & ST_Q_SNS_HLP) {
+ if (errno = st_touch_tape(unit))
+ return errno;
+ }
+ /*
+ * Load the physical device parameters
+ * loads: blkmin, blkmax
+ */
+ if (errno = st_rd_blk_lim(unit, 0)) {
+ return errno;
+ }
+ /*
+ * Load the media dependent parameters
+ * includes: media_blksiz,media_density,numblks
+ * As we have a tape in, it should be reflected here.
+ * If not you may need the "quirk" above.
+ */
+ if (errno = st_mode_sense(unit, 0)) {
+ return errno;
+ }
+ /*
+ * If we have gained a permanent density from somewhere,
+ * then use it in preference to the one supplied by
+ * default by the driver.
+ */
+ if (st->modeflags[dsty] & (DENSITY_SET_BY_QUIRK | DENSITY_SET_BY_USER)) {
+ st->density = st->modes[dsty].density;
+ } else {
+ st->density = st->media_density;
+ }
+ /*
+ * If we have gained a permanent blocksize
+ * then use it in preference to the one supplied by
+ * default by the driver.
+ */
+ st->flags &= ~ST_FIXEDBLOCKS;
+ if (st->modeflags[dsty] & (BLKSIZE_SET_BY_QUIRK | BLKSIZE_SET_BY_USER)) {
+ st->blksiz = st->modes[dsty].blksiz;
+ if (st->blksiz) {
+ st->flags |= ST_FIXEDBLOCKS;
+ }
+ } else {
+ if (errno = st_decide_mode(unit, FALSE)) {
+ return errno;
+ }
+ }
+ if (errno = st_mode_select(unit, 0)) {
+ printf("st%d: Cannot set selected mode", unit);
+ return errno;
+ }
+ scsi_prevent(sc_link, PR_PREVENT, 0); /* who cares if it fails? */
+ st->flags &= ~ST_NEW_MOUNT;
+ st->flags |= ST_MOUNTED;
+ sc_link->flags |= SDEV_MEDIA_LOADED; /* move earlier? */
+
+ return 0;
+}
+
+/*
+ * End the present mount session.
+ * Rewind, and optionally eject the tape.
+ * Reset various flags to indicate that all new
+ * operations require another mount operation
+ */
+void
+st_unmount(int unit, boolean eject)
+{
+ struct st_data *st = st_data[unit];
+ struct scsi_link *sc_link = st->sc_link;
+ int32 nmarks;
+
+ if (!(st->flags & ST_MOUNTED))
+ return;
+ SC_DEBUG(sc_link, SDEV_DB1, ("unmounting\n"));
+ st_chkeod(unit, FALSE, &nmarks, SCSI_SILENT);
+ st_rewind(unit, FALSE, SCSI_SILENT);
+ scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT);
+ if (eject) {
+ st_load(unit, LD_UNLOAD, SCSI_SILENT);
+ }
+ st->flags &= ~(ST_MOUNTED | ST_NEW_MOUNT);
+ sc_link->flags &= ~SDEV_MEDIA_LOADED;
+}
+
+/*
+ * Given all we know about the device, media, mode, 'quirks' and
+ * initial operation, make a decision as to how we should be set
+ * to run (regarding blocking and EOD marks)
+ */
+errval
+st_decide_mode(unit, first_read)
+ u_int32 unit;
+ boolean first_read;
+{
+ struct st_data *st = st_data[unit];
+#ifdef SCSIDEBUG
+ struct scsi_link *sc_link = st->sc_link;
+#endif
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("starting block mode decision\n"));
+
+ /*
+ * If the user hasn't already specified fixed or variable-length
+ * blocks and the block size (zero if variable-length), we'll
+ * have to try to figure them out ourselves.
+ *
+ * Our first shot at a method is, "The quirks made me do it!"
+ */
+ switch ((int)(st->quirks & (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE))) {
+ case (ST_Q_FORCE_FIXED_MODE | ST_Q_FORCE_VAR_MODE):
+ printf("st%d: bad quirks\n", unit);
+ return (EINVAL);
+ case ST_Q_FORCE_FIXED_MODE: /*specified fixed, but not what size */
+ st->flags |= ST_FIXEDBLOCKS;
+ if (st->blkmin && (st->blkmin == st->blkmax))
+ st->blksiz = st->blkmin;
+ else if (st->media_blksiz > 0)
+ st->blksiz = st->media_blksiz;
+ else
+ st->blksiz = DEF_FIXED_BSIZE;
+ SC_DEBUG(sc_link, SDEV_DB3, ("Quirks force fixed mode(%d)\n",
+ st->blksiz));
+ goto done;
+ case ST_Q_FORCE_VAR_MODE:
+ st->flags &= ~ST_FIXEDBLOCKS;
+ st->blksiz = 0;
+ SC_DEBUG(sc_link, SDEV_DB3, ("Quirks force variable mode\n"));
+ goto done;
+ }
+ /*
+ * If the drive can only handle fixed-length blocks and only at
+ * one size, perhaps we should just do that.
+ */
+ if (st->blkmin && (st->blkmin == st->blkmax)) {
+ st->flags |= ST_FIXEDBLOCKS;
+ st->blksiz = st->blkmin;
+ SC_DEBUG(sc_link, SDEV_DB3,
+ ("blkmin == blkmax of %d\n", st->blkmin));
+ goto done;
+ }
+ /*
+ * If the tape density mandates (or even suggests) use of fixed
+ * or variable-length blocks, comply.
+ */
+ switch ((int)st->density) {
+ case HALFINCH_800:
+ case HALFINCH_1600:
+ case HALFINCH_6250:
+ case DDS:
+ st->flags &= ~ST_FIXEDBLOCKS;
+ st->blksiz = 0;
+ SC_DEBUG(sc_link, SDEV_DB3, ("density specified variable\n"));
+ goto done;
+ case QIC_11:
+ case QIC_24:
+ case QIC_120:
+ case QIC_150:
+ case QIC_525:
+ case QIC_1320:
+ st->flags |= ST_FIXEDBLOCKS;
+ if (st->media_blksiz > 0) {
+ st->blksiz = st->media_blksiz;
+ } else {
+ st->blksiz = DEF_FIXED_BSIZE;
+ }
+ SC_DEBUG(sc_link, SDEV_DB3, ("density specified fixed\n"));
+ goto done;
+ }
+ /*
+ * If we're about to read the tape, perhaps we should choose
+ * fixed or variable-length blocks and block size according to
+ * what the drive found on the tape.
+ */
+ if (first_read
+ && (!(st->quirks & ST_Q_BLKSIZ)
+ || (st->media_blksiz == 0)
+ || (st->media_blksiz == DEF_FIXED_BSIZE)
+ || (st->media_blksiz == 1024))) {
+ if (st->media_blksiz == 0) {
+ st->flags &= ~ST_FIXEDBLOCKS;
+ } else {
+ st->flags |= ST_FIXEDBLOCKS;
+ }
+ st->blksiz = st->media_blksiz;
+ SC_DEBUG(sc_link, SDEV_DB3,
+ ("Used media_blksiz of %d\n", st->media_blksiz));
+ goto done;
+ }
+ /*
+ * We're getting no hints from any direction. Choose variable-
+ * length blocks arbitrarily.
+ */
+ st->flags &= ~ST_FIXEDBLOCKS;
+ st->blksiz = 0;
+ SC_DEBUG(sc_link, SDEV_DB3, ("Give up and default to variable mode\n"));
+done:
+
+ /*
+ * Decide whether or not to write two file marks to signify end-
+ * of-data. Make the decision as a function of density. If
+ * the decision is not to use a second file mark, the SCSI BLANK
+ * CHECK condition code will be recognized as end-of-data when
+ * first read.
+ * (I think this should be a by-product of fixed/variable..julian)
+ */
+ switch ((int)st->density) {
+/* case 8 mm: What is the SCSI density code for 8 mm, anyway? */
+ case QIC_11:
+ case QIC_24:
+ case QIC_120:
+ case QIC_150:
+ case QIC_525:
+ case QIC_1320:
+ st->flags &= ~ST_2FM_AT_EOD;
+ break;
+ default:
+ st->flags |= ST_2FM_AT_EOD;
+ }
+ return 0;
+}
+
+/*
+ * trim the size of the transfer if needed,
+ * called by physio
+ * basically the smaller of our min and the scsi driver's
+ * minphys
+ */
+void
+stminphys(bp)
+ struct buf *bp;
+{
+ (*(st_data[UNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp);
+}
+
+/*
+ * Actually translate the requested transfer into
+ * one the physical driver can understand
+ * The transfer is described by a buf and will include
+ * only one physical transfer.
+ */
+void
+ststrategy(bp)
+ struct buf *bp;
+{
+ struct buf **dp;
+ unsigned char unit;
+ u_int32 opri;
+ struct st_data *st;
+
+ ststrats++;
+ unit = UNIT((bp->b_dev));
+ st = st_data[unit];
+ SC_DEBUG(st->sc_link, SDEV_DB1,
+ (" strategy: %d bytes @ blk%d\n", bp->b_bcount, bp->b_blkno));
+ /*
+ * If it's a null transfer, return immediatly
+ */
+ if (bp->b_bcount == 0) {
+ goto done;
+ }
+ /*
+ * Odd sized request on fixed drives are verboten
+ */
+ if (st->flags & ST_FIXEDBLOCKS) {
+ if (bp->b_bcount % st->blksiz) {
+ printf("st%d: bad request, must be multiple of %d\n",
+ unit, st->blksiz);
+ bp->b_error = EIO;
+ goto bad;
+ }
+ }
+ /*
+ * as are out-of-range requests on variable drives.
+ */
+ else if (bp->b_bcount < st->blkmin || bp->b_bcount > st->blkmax) {
+ printf("st%d: bad request, must be between %d and %d\n",
+ unit, st->blkmin, st->blkmax);
+ bp->b_error = EIO;
+ goto bad;
+ }
+ stminphys(bp);
+ opri = splbio();
+
+ /*
+ * Use a bounce buffer if necessary
+ */
+#ifndef NOBOUNCE
+ if (st->sc_link->flags & SDEV_BOUNCE)
+ vm_bounce_alloc(bp);
+#endif
+
+ /*
+ * Place it in the queue of activities for this tape
+ * at the end (a bit silly because we only have on user..
+ * (but it could fork() ))
+ */
+ dp = &(st->buf_queue);
+ while (*dp) {
+ dp = &((*dp)->b_actf);
+ }
+ *dp = bp;
+ bp->b_actf = NULL;
+
+ /*
+ * Tell the device to get going on the transfer if it's
+ * not doing anything, otherwise just wait for completion
+ * (All a bit silly if we're only allowing 1 open but..)
+ */
+ ststart(unit);
+
+ splx(opri);
+ return;
+bad:
+ bp->b_flags |= B_ERROR;
+done:
+ /*
+ * Correctly set the buf to indicate a completed xfer
+ */
+ iodone(bp);
+ return;
+}
+
+/*
+ * ststart looks to see if there is a buf waiting for the device
+ * and that the device is not already busy. If both are true,
+ * It dequeues the buf and creates a scsi command to perform the
+ * transfer required. The transfer request will call scsi_done
+ * on completion, which will in turn call this routine again
+ * so that the next queued transfer is performed.
+ * The bufs are queued by the strategy routine (ststrategy)
+ *
+ * This routine is also called after other non-queued requests
+ * have been made of the scsi driver, to ensure that the queue
+ * continues to be drained.
+ * ststart() is called at splbio
+ */
+void
+ststart(unit)
+ u_int32 unit;
+{
+ struct st_data *st = st_data[unit];
+ struct scsi_link *sc_link = st->sc_link;
+ register struct buf *bp = 0;
+ struct scsi_rw_tape cmd;
+ u_int32 flags;
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("ststart "));
+ /*
+ * See if there is a buf to do and we are not already
+ * doing one
+ */
+ while (sc_link->opennings != 0) {
+
+ /* if a special awaits, let it proceed first */
+ if (sc_link->flags & SDEV_WAITING) {
+ sc_link->flags &= ~SDEV_WAITING;
+ wakeup((caddr_t)sc_link);
+ return;
+ }
+ if ((bp = st->buf_queue) == NULL) {
+ return; /* no work to bother with */
+ }
+ st->buf_queue = bp->b_actf;
+
+ /*
+ * if the device has been unmounted byt the user
+ * then throw away all requests until done
+ */
+ if ((!(st->flags & ST_MOUNTED))
+ || (!(sc_link->flags & SDEV_MEDIA_LOADED))) {
+ /* make sure that one implies the other.. */
+ sc_link->flags &= ~SDEV_MEDIA_LOADED;
+ goto badnews;
+ }
+ /*
+ * only FIXEDBLOCK devices have pending operations
+ */
+ if (st->flags & ST_FIXEDBLOCKS) {
+ /*
+ * If we are at a filemark but have not reported it yet
+ * then we should report it now
+ */
+ if (st->flags & ST_AT_FILEMARK) {
+ if ((bp->b_flags & B_READ) == B_WRITE) {
+ /*
+ * Handling of ST_AT_FILEMARK in
+ * st_space will fill in the right file
+ * mark count.
+ * Back up over filemark
+ */
+ if (st_space(unit, 0, SP_FILEMARKS, 0) !=
+ ESUCCESS)
+ goto badnews;
+ } else {
+ bp->b_resid = bp->b_bcount;
+ bp->b_error = 0;
+ bp->b_flags &= ~B_ERROR;
+ st->flags &= ~ST_AT_FILEMARK;
+ biodone(bp);
+ continue; /* seek more work */
+ }
+ }
+ /*
+ * If we are at EIO (e.g. EOM) but have not reported it
+ * yet then we should report it now
+ */
+ if (st->flags & ST_EIO_PENDING) {
+ bp->b_resid = bp->b_bcount;
+ bp->b_error = EIO;
+ bp->b_flags |= B_ERROR;
+ st->flags &= ~ST_EIO_PENDING;
+ biodone(bp);
+ continue; /* seek more work */
+ }
+ }
+ /*
+ * Fill out the scsi command
+ */
+ bzero(&cmd, sizeof(cmd));
+ if ((bp->b_flags & B_READ) == B_WRITE) {
+ cmd.op_code = WRITE_COMMAND_TAPE;
+ st->flags &= ~ST_FM_WRITTEN;
+ st->flags |= ST_WRITTEN;
+ flags = SCSI_DATA_OUT;
+ } else {
+ cmd.op_code = READ_COMMAND_TAPE;
+ flags = SCSI_DATA_IN;
+ }
+ /*
+ * Handle "fixed-block-mode" tape drives by using the
+ * block count instead of the length.
+ */
+ if (st->flags & ST_FIXEDBLOCKS) {
+ cmd.byte2 |= SRWT_FIXED;
+ lto3b(bp->b_bcount / st->blksiz, cmd.len);
+ } else {
+ lto3b(bp->b_bcount, cmd.len);
+ }
+ /*
+ * go ask the adapter to do all this for us
+ */
+ if (scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &cmd,
+ sizeof(cmd),
+ (u_char *) bp->b_un.b_addr,
+ bp->b_bcount,
+ 0, /* can't retry a read on a tape really */
+ 100000,
+ bp,
+ flags | SCSI_NOSLEEP) == SUCCESSFULLY_QUEUED) {
+ stqueues++;
+ } else {
+badnews:
+ printf("st%d: oops not queued\n", unit);
+ bp->b_flags |= B_ERROR;
+ bp->b_error = EIO;
+ biodone(bp);
+ }
+ } /* go back and see if we can cram more work in.. */
+}
+
+/*
+ * Perform special action on behalf of the user;
+ * knows about the internals of this device
+ */
+errval
+stioctl(dev, cmd, arg, flag)
+ dev_t dev;
+ int cmd;
+ caddr_t arg;
+ int flag;
+{
+ errval errcode = 0;
+ unsigned char unit;
+ u_int32 number, flags, dsty;
+ struct st_data *st;
+ u_int32 hold_blksiz;
+ u_int32 hold_density;
+ int32 nmarks;
+ struct mtop *mt = (struct mtop *) arg;
+
+ /*
+ * Find the device that the user is talking about
+ */
+ flags = 0; /* give error messages, act on errors etc. */
+ unit = UNIT(dev);
+ dsty = DSTY(dev);
+ st = st_data[unit];
+ hold_blksiz = st->blksiz;
+ hold_density = st->density;
+
+ switch (cmd) {
+
+ case MTIOCGET:
+ {
+ struct mtget *g = (struct mtget *) arg;
+
+ SC_DEBUG(st->sc_link, SDEV_DB1, ("[ioctl: get status]\n"));
+ bzero(g, sizeof(struct mtget));
+ g->mt_type = 0x7; /* Ultrix compat *//*? */
+ g->mt_density = st->density;
+ g->mt_blksiz = st->blksiz;
+ g->mt_density0 = st->modes[0].density;
+ g->mt_density1 = st->modes[1].density;
+ g->mt_density2 = st->modes[2].density;
+ g->mt_density3 = st->modes[3].density;
+ g->mt_blksiz0 = st->modes[0].blksiz;
+ g->mt_blksiz1 = st->modes[1].blksiz;
+ g->mt_blksiz2 = st->modes[2].blksiz;
+ g->mt_blksiz3 = st->modes[3].blksiz;
+ break;
+ }
+ case MTIOCTOP:
+ {
+
+ SC_DEBUG(st->sc_link, SDEV_DB1, ("[ioctl: op=0x%x count=0x%x]\n",
+ mt->mt_op, mt->mt_count));
+
+ /* compat: in U*x it is a short */
+ number = mt->mt_count;
+ switch ((short) (mt->mt_op)) {
+ case MTWEOF: /* write an end-of-file record */
+ errcode = st_write_filemarks(unit, number, flags);
+ break;
+ case MTBSF: /* backward space file */
+ number = -number;
+ case MTFSF: /* forward space file */
+ errcode = st_chkeod(unit, FALSE, &nmarks, flags);
+ if (errcode == ESUCCESS)
+ errcode = st_space(unit, number - nmarks,
+ SP_FILEMARKS, flags);
+ break;
+ case MTBSR: /* backward space record */
+ number = -number;
+ case MTFSR: /* forward space record */
+ errcode = st_chkeod(unit, TRUE, &nmarks, flags);
+ if (errcode == ESUCCESS)
+ errcode = st_space(unit, number, SP_BLKS, flags);
+ break;
+ case MTREW: /* rewind */
+ errcode = st_rewind(unit, FALSE, flags);
+ break;
+ case MTOFFL: /* rewind and put the drive offline */
+ st_unmount(unit, EJECT);
+ break;
+ case MTNOP: /* no operation, sets status only */
+ case MTCACHE: /* enable controller cache */
+ case MTNOCACHE: /* disable controller cache */
+ break;
+ case MTSETBSIZ: /* Set block size for device */
+#ifdef NOTYET
+ if (!(st->flags & ST_NEW_MOUNT)) {
+ uprintf("re-mount tape before changing blocksize");
+ errcode = EINVAL;
+ break;
+ }
+#endif
+ if (number == 0) {
+ st->flags &= ~ST_FIXEDBLOCKS;
+ } else {
+ if ((st->blkmin || st->blkmax) /* they exist */
+ &&((number < st->blkmin
+ || number > st->blkmax))) {
+ errcode = EINVAL;
+ break;
+ }
+ st->flags |= ST_FIXEDBLOCKS;
+ }
+ st->blksiz = number;
+ st->flags |= ST_BLOCK_SET; /*XXX */
+ goto try_new_value;
+
+ case MTSETDNSTY: /* Set density for device and mode */
+ if (number > SCSI_2_MAX_DENSITY_CODE) {
+ errcode = EINVAL;
+ } else {
+ st->density = number;
+ }
+ goto try_new_value;
+
+ default:
+ errcode = EINVAL;
+ }
+ break;
+ }
+ case MTIOCIEOT:
+ case MTIOCEEOT:
+ break;
+ default:
+ if(MODE(dev) == CTLMODE)
+ errcode = scsi_do_ioctl(st->sc_link,cmd,arg,flag);
+ else
+ errcode = ENOTTY;
+ break;
+ }
+ return errcode;
+/*-----------------------------*/
+try_new_value:
+ /*
+ * Check that the mode being asked for is aggreeable to the
+ * drive. If not, put it back the way it was.
+ */
+ if (errcode = st_mode_select(unit, 0)) { /* put it back as it was */
+ printf("st%d: Cannot set selected mode", unit);
+ st->density = hold_density;
+ st->blksiz = hold_blksiz;
+ if (st->blksiz) {
+ st->flags |= ST_FIXEDBLOCKS;
+ } else {
+ st->flags &= ~ST_FIXEDBLOCKS;
+ }
+ return (errcode);
+ }
+ /*
+ * As the drive liked it, if we are setting a new default,
+ * set it into the structures as such.
+ *
+ * The means for deciding this are not finalised yet
+ */
+ if (MODE(dev) == 0x03) {
+ /* special mode */
+ /* XXX */
+ switch ((short) (mt->mt_op)) {
+ case MTSETBSIZ:
+ st->modes[dsty].blksiz = st->blksiz;
+ st->modeflags[dsty] |= BLKSIZE_SET_BY_USER;
+ break;
+ case MTSETDNSTY:
+ st->modes[dsty].density = st->density;
+ st->modeflags[dsty] |= DENSITY_SET_BY_USER;
+ break;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Do a synchronous read.
+ */
+errval
+st_read(unit, buf, size, flags)
+ u_int32 unit, size, flags;
+ char *buf;
+{
+ struct scsi_rw_tape scsi_cmd;
+ struct st_data *st = st_data[unit];
+
+ /*
+ * If it's a null transfer, return immediatly
+ */
+ if (size == 0) {
+ return (ESUCCESS);
+ }
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = READ_COMMAND_TAPE;
+ if (st->flags & ST_FIXEDBLOCKS) {
+ scsi_cmd.byte2 |= SRWT_FIXED;
+ lto3b(size / (st->blksiz ? st->blksiz : DEF_FIXED_BSIZE),
+ scsi_cmd.len);
+ } else {
+ lto3b(size, scsi_cmd.len);
+ }
+ return (scsi_scsi_cmd(st->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) buf,
+ size,
+ 0, /* not on io commands */
+ 100000,
+ NULL,
+ flags | SCSI_DATA_IN));
+}
+#ifdef __STDC__
+#define b2tol(a) (((unsigned)(a##_1) << 8) + (unsigned)a##_0 )
+#else
+#define b2tol(a) (((unsigned)(a/**/_1) << 8) + (unsigned)a/**/_0 )
+#endif
+
+/*
+ * Ask the drive what it's min and max blk sizes are.
+ */
+errval
+st_rd_blk_lim(unit, flags)
+ u_int32 unit, flags;
+{
+ struct scsi_blk_limits scsi_cmd;
+ struct scsi_blk_limits_data scsi_blkl;
+ struct st_data *st = st_data[unit];
+ errval errno;
+ struct scsi_link *sc_link = st->sc_link;
+
+ /*
+ * First check if we have it all loaded
+ */
+ if ((sc_link->flags & SDEV_MEDIA_LOADED))
+ return 0;
+
+ /*
+ * do a 'Read Block Limits'
+ */
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = READ_BLK_LIMITS;
+
+ /*
+ * do the command, update the global values
+ */
+ if (errno = scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) & scsi_blkl,
+ sizeof(scsi_blkl),
+ ST_RETRIES,
+ 5000,
+ NULL,
+ flags | SCSI_DATA_IN)) {
+ return errno;
+ }
+ st->blkmin = b2tol(scsi_blkl.min_length);
+ st->blkmax = _3btol(&scsi_blkl.max_length_2);
+
+ SC_DEBUG(sc_link, SDEV_DB3,
+ ("(%d <= blksiz <= %d)\n", st->blkmin, st->blkmax));
+ return 0;
+}
+
+/*
+ * Get the scsi driver to send a full inquiry to the
+ * device and use the results to fill out the global
+ * parameter structure.
+ *
+ * called from:
+ * attach
+ * open
+ * ioctl (to reset original blksize)
+ */
+errval
+st_mode_sense(unit, flags)
+ u_int32 unit, flags;
+{
+ u_int32 scsi_sense_len;
+ errval errno;
+ char *scsi_sense_ptr;
+ struct scsi_mode_sense scsi_cmd;
+ struct scsi_sense {
+ struct scsi_mode_header header;
+ struct blk_desc blk_desc;
+ } scsi_sense;
+
+ struct scsi_sense_page_0 {
+ struct scsi_mode_header header;
+ struct blk_desc blk_desc;
+ unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE];
+ /* Tandberg tape drives returns page 00
+ * with the sense data, whether or not
+ * you want it( ie the don't like you
+ * saying you want anything less!!!!!
+ * They also expect page 00
+ * back when you issue a mode select
+ */
+ } scsi_sense_page_0;
+ struct st_data *st = st_data[unit];
+ struct scsi_link *sc_link = st->sc_link;
+
+ /*
+ * Define what sort of structure we're working with
+ */
+ if (st->quirks & ST_Q_NEEDS_PAGE_0) {
+ scsi_sense_len = sizeof(scsi_sense_page_0);
+ scsi_sense_ptr = (char *) &scsi_sense_page_0;
+ } else {
+ scsi_sense_len = sizeof(scsi_sense);
+ scsi_sense_ptr = (char *) &scsi_sense;
+ }
+ /*
+ * Set up a mode sense
+ */
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = MODE_SENSE;
+ scsi_cmd.length = scsi_sense_len;
+
+ /*
+ * do the command, but we don't need the results
+ * just print them for our interest's sake, if asked,
+ * or if we need it as a template for the mode select
+ * store it away.
+ */
+ if (errno = scsi_scsi_cmd(sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) scsi_sense_ptr,
+ scsi_sense_len,
+ ST_RETRIES,
+ 5000,
+ NULL,
+ flags | SCSI_DATA_IN)) {
+ return errno;
+ }
+ st->numblks = _3btol(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.nblocks);
+ st->media_blksiz = _3btol(((struct scsi_sense *)scsi_sense_ptr)->blk_desc.blklen);
+ st->media_density = ((struct scsi_sense *) scsi_sense_ptr)->blk_desc.density;
+ if (((struct scsi_sense *) scsi_sense_ptr)->header.dev_spec &
+ SMH_DSP_WRITE_PROT) {
+ st->flags |= ST_READONLY;
+ }
+ SC_DEBUG(sc_link, SDEV_DB3,
+ ("density code 0x%x, %d-byte blocks, write-%s, ",
+ st->media_density, st->media_blksiz,
+ st->flags & ST_READONLY ? "protected" : "enabled"));
+ SC_DEBUG(sc_link, SDEV_DB3,
+ ("%sbuffered\n",
+ ((struct scsi_sense *) scsi_sense_ptr)->header.dev_spec
+ & SMH_DSP_BUFF_MODE ? "" : "un"));
+ if (st->quirks & ST_Q_NEEDS_PAGE_0) {
+ bcopy(((struct scsi_sense_page_0 *) scsi_sense_ptr)->sense_data,
+ st->sense_data,
+ sizeof(((struct scsi_sense_page_0 *) scsi_sense_ptr)->sense_data));
+ }
+ sc_link->flags |= SDEV_MEDIA_LOADED;
+ return 0;
+}
+
+/*
+ * Send a filled out parameter structure to the drive to
+ * set it into the desire modes etc.
+ */
+errval
+st_mode_select(unit, flags)
+ u_int32 unit, flags;
+{
+ u_int32 dat_len;
+ char *dat_ptr;
+ struct scsi_mode_select scsi_cmd;
+ struct dat {
+ struct scsi_mode_header header;
+ struct blk_desc blk_desc;
+ } dat;
+ struct dat_page_0 {
+ struct scsi_mode_header header;
+ struct blk_desc blk_desc;
+ unsigned char sense_data[PAGE_0_SENSE_DATA_SIZE];
+ } dat_page_0;
+ struct st_data *st = st_data[unit];
+
+ /*
+ * Define what sort of structure we're working with
+ */
+ if (st->quirks & ST_Q_NEEDS_PAGE_0) {
+ dat_len = sizeof(dat_page_0);
+ dat_ptr = (char *) &dat_page_0;
+ } else {
+ dat_len = sizeof(dat);
+ dat_ptr = (char *) &dat;
+ }
+ /*
+ * Set up for a mode select
+ */
+ bzero(dat_ptr, dat_len);
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = MODE_SELECT;
+ scsi_cmd.length = dat_len;
+ ((struct dat *) dat_ptr)->header.blk_desc_len = sizeof(struct blk_desc);
+ ((struct dat *) dat_ptr)->header.dev_spec |= SMH_DSP_BUFF_MODE_ON;
+ ((struct dat *) dat_ptr)->blk_desc.density = st->density;
+ if (st->flags & ST_FIXEDBLOCKS) {
+ lto3b(st->blksiz, ((struct dat *) dat_ptr)->blk_desc.blklen);
+ }
+ if (st->quirks & ST_Q_NEEDS_PAGE_0) {
+ bcopy(st->sense_data, ((struct dat_page_0 *) dat_ptr)->sense_data,
+ sizeof(((struct dat_page_0 *) dat_ptr)->sense_data));
+ /* the Tandberg tapes need the block size to */
+ /* be set on each mode sense/select. */
+ }
+ /*
+ * do the command
+ */
+ return (scsi_scsi_cmd(st->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ (u_char *) dat_ptr,
+ dat_len,
+ ST_RETRIES,
+ 5000,
+ NULL,
+ flags | SCSI_DATA_OUT));
+}
+
+/*
+ * skip N blocks/filemarks/seq filemarks/eom
+ */
+errval
+st_space(unit, number, what, flags)
+ u_int32 unit, what, flags;
+ int32 number;
+{
+ errval error;
+ struct scsi_space scsi_cmd;
+ struct st_data *st = st_data[unit];
+
+ switch ((int)what) {
+ case SP_BLKS:
+ if (st->flags & ST_PER_ACTION) {
+ if (number > 0) {
+ st->flags &= ~ST_PER_ACTION;
+ return (EIO);
+ } else if (number < 0) {
+ if (st->flags & ST_AT_FILEMARK) {
+ /*
+ * Handling of ST_AT_FILEMARK
+ * in st_space will fill in the
+ * right file mark count.
+ */
+ error = st_space(unit, 0, SP_FILEMARKS,
+ flags);
+ if (error)
+ return (error);
+ }
+ if (st->flags & ST_BLANK_READ) {
+ st->flags &= ~ST_BLANK_READ;
+ return (EIO);
+ }
+ st->flags &= ~ST_EIO_PENDING;
+ }
+ }
+ break;
+ case SP_FILEMARKS:
+ if (st->flags & ST_EIO_PENDING) {
+ if (number > 0) { /* pretend we just discover the error */
+ st->flags &= ~ST_EIO_PENDING;
+ return (EIO);
+ } else if (number < 0) { /* back away from the error */
+ st->flags &= ~ST_EIO_PENDING;
+ }
+ }
+ if (st->flags & ST_AT_FILEMARK) {
+ st->flags &= ~ST_AT_FILEMARK;
+ number--;
+ }
+ if ((st->flags & ST_BLANK_READ) && (number < 0)) { /* back away from unwritten tape */
+ st->flags &= ~ST_BLANK_READ;
+ number++; /* dubious */
+ }
+ }
+ if (number == 0) {
+ return (ESUCCESS);
+ }
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = SPACE;
+ scsi_cmd.byte2 = what & SS_CODE;
+ lto3b(number, scsi_cmd.number);
+ return (scsi_scsi_cmd(st->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 0, /* no retries please , just fail */
+ 600000, /* 10 mins enough? */
+ NULL,
+ flags));
+}
+
+/*
+ * write N filemarks
+ */
+errval
+st_write_filemarks(unit, number, flags)
+ u_int32 unit, flags;
+ int32 number;
+{
+ struct scsi_write_filemarks scsi_cmd;
+ struct st_data *st = st_data[unit];
+
+ /*
+ * It's hard to write a negative number of file marks.
+ * Don't try.
+ */
+ if (number < 0) {
+ return EINVAL;
+ }
+ switch ((int)number) {
+ case 0: /* really a command to sync the drive's buffers */
+ break;
+ case 1:
+ if (st->flags & ST_FM_WRITTEN) { /* already have one down */
+ st->flags &= ~ST_WRITTEN;
+ } else {
+ st->flags |= ST_FM_WRITTEN;
+ }
+ st->flags &= ~ST_PER_ACTION;
+ break;
+ default:
+ st->flags &= ~(ST_PER_ACTION | ST_WRITTEN);
+ }
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = WRITE_FILEMARKS;
+ lto3b(number, scsi_cmd.number);
+ return scsi_scsi_cmd(st->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ 0, /* no retries, just fail */
+ 100000, /* 10 secs.. (may need to repos head ) */
+ NULL,
+ flags);
+}
+
+/*
+ * Make sure the right number of file marks is on tape if the
+ * tape has been written. If the position argument is true,
+ * leave the tape positioned where it was originally.
+ *
+ * nmarks returns the number of marks to skip (or, if position
+ * true, which were skipped) to get back original position.
+ */
+int32
+st_chkeod(unit, position, nmarks, flags)
+ u_int32 unit;
+ boolean position;
+ int32 *nmarks;
+ u_int32 flags;
+{
+ errval error;
+ struct st_data *st = st_data[unit];
+
+ switch ((int)(st->flags & (ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD))) {
+ default:
+ *nmarks = 0;
+ return (ESUCCESS);
+ case ST_WRITTEN:
+ case ST_WRITTEN | ST_FM_WRITTEN | ST_2FM_AT_EOD:
+ *nmarks = 1;
+ break;
+ case ST_WRITTEN | ST_2FM_AT_EOD:
+ *nmarks = 2;
+ }
+ error = st_write_filemarks(unit, *nmarks, flags);
+ if (position && (error == ESUCCESS))
+ error = st_space(unit, -*nmarks, SP_FILEMARKS, flags);
+ return (error);
+}
+
+/*
+ * load/unload (with retension if true)
+ */
+errval
+st_load(unit, type, flags)
+ u_int32 unit, type, flags;
+{
+ struct scsi_load scsi_cmd;
+ struct st_data *st = st_data[unit];
+ struct scsi_link *sc_link = st->sc_link;
+
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ if (type != LD_LOAD) {
+ errval error;
+ int32 nmarks;
+
+ error = st_chkeod(unit, FALSE, &nmarks, flags);
+ if (error != ESUCCESS)
+ return (error);
+ sc_link->flags &= ~SDEV_MEDIA_LOADED;
+ }
+ if (st->quirks & ST_Q_IGNORE_LOADS)
+ return (0);
+ scsi_cmd.op_code = LOAD_UNLOAD;
+ scsi_cmd.how |= type;
+ return (scsi_scsi_cmd(st->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ ST_RETRIES,
+ 300000, /* 5 min */
+ NULL,
+ flags));
+}
+
+/*
+ * Rewind the device
+ */
+errval
+st_rewind(unit, immed, flags)
+ u_int32 unit, flags;
+ boolean immed;
+{
+ struct scsi_rewind scsi_cmd;
+ struct st_data *st = st_data[unit];
+ errval error;
+ int32 nmarks;
+
+ error = st_chkeod(unit, FALSE, &nmarks, flags);
+ if (error != ESUCCESS)
+ return (error);
+ st->flags &= ~ST_PER_ACTION;
+ bzero(&scsi_cmd, sizeof(scsi_cmd));
+ scsi_cmd.op_code = REWIND;
+ scsi_cmd.byte2 = immed ? SR_IMMED : 0;
+ return (scsi_scsi_cmd(st->sc_link,
+ (struct scsi_generic *) &scsi_cmd,
+ sizeof(scsi_cmd),
+ 0,
+ 0,
+ ST_RETRIES,
+ immed ? 5000 : 300000, /* 5 sec or 5 min */
+ NULL,
+ flags));
+}
+
+#ifdef NETBSD
+#define SIGNAL_SHORT_READ
+#else
+#define SIGNAL_SHORT_READ bp->b_flags |= B_ERROR;
+#endif
+
+/*
+ * Look at the returned sense and act on the error and detirmine
+ * The unix error number to pass back... (0 = report no error)
+ * (-1 = continue processing)
+ */
+errval
+st_interpret_sense(xs)
+ struct scsi_xfer *xs;
+{
+ struct scsi_link *sc_link = xs->sc_link;
+ struct scsi_sense_data *sense = &(xs->sense);
+ boolean silent = xs->flags & SCSI_SILENT;
+ struct buf *bp = xs->bp;
+ u_int32 unit = sc_link->dev_unit;
+ struct st_data *st = st_data[unit];
+ u_int32 key;
+ int32 info;
+
+ /*
+ * Get the sense fields and work out what code
+ */
+ if (sense->error_code & SSD_ERRCODE_VALID) {
+ info = ntohl(*((int32 *) sense->ext.extended.info));
+ } else {
+ info = xs->datalen; /* bad choice if fixed blocks */
+ }
+ if ((sense->error_code & SSD_ERRCODE) != 0x70) {
+ return (-1); /* let the generic code handle it */
+ }
+ if (st->flags & ST_FIXEDBLOCKS) {
+ xs->resid = info * st->blksiz;
+ if (sense->ext.extended.flags & SSD_EOM) {
+ st->flags |= ST_EIO_PENDING;
+ if (bp) {
+ bp->b_resid = xs->resid;
+ SIGNAL_SHORT_READ
+ }
+ }
+ if (sense->ext.extended.flags & SSD_FILEMARK) {
+ st->flags |= ST_AT_FILEMARK;
+ if (bp) {
+ bp->b_resid = xs->resid;
+ SIGNAL_SHORT_READ
+ }
+ }
+ if (sense->ext.extended.flags & SSD_ILI) {
+ st->flags |= ST_EIO_PENDING;
+ if (bp) {
+ bp->b_resid = xs->resid;
+ SIGNAL_SHORT_READ
+ }
+ if (sense->error_code & SSD_ERRCODE_VALID &&
+ !silent)
+ printf("st%d: block wrong size"
+ ", %d blocks residual\n", unit
+ ,info);
+
+ /*
+ * This quirk code helps the drive read
+ * the first tape block, regardless of
+ * format. That is required for these
+ * drives to return proper MODE SENSE
+ * information.
+ */
+ if ((st->quirks & ST_Q_SNS_HLP) &&
+ !(sc_link->flags & SDEV_MEDIA_LOADED)) {
+ st->blksiz -= 512;
+ }
+ }
+ /*
+ * If no data was tranfered, do it immediatly
+ */
+ if (xs->resid >= xs->datalen) {
+ if (st->flags & ST_EIO_PENDING) {
+ return EIO;
+ }
+ if (st->flags & ST_AT_FILEMARK) {
+ if (bp) {
+ bp->b_resid = xs->resid;
+ SIGNAL_SHORT_READ
+ }
+ return 0;
+ }
+ }
+ } else { /* must be variable mode */
+ xs->resid = xs->datalen; /* to be sure */
+ if (sense->ext.extended.flags & SSD_EOM) {
+ return (EIO);
+ }
+ if (sense->ext.extended.flags & SSD_FILEMARK) {
+ if (bp)
+ bp->b_resid = bp->b_bcount;
+ return 0;
+ }
+ if (sense->ext.extended.flags & SSD_ILI) {
+ if (info < 0) {
+ /*
+ * the record was bigger than the read
+ */
+ if (!silent)
+ printf("st%d: %d-byte record "
+ "too big\n", unit,
+ xs->datalen - info);
+ return (EIO);
+ }
+ xs->resid = info;
+ if (bp) {
+ bp->b_resid = info;
+ SIGNAL_SHORT_READ
+ }
+ }
+ }
+ key = sense->ext.extended.flags & SSD_KEY;
+
+ if (key == 0x8) {
+ /*
+ * This quirk code helps the drive read the
+ * first tape block, regardless of format. That
+ * is required for these drives to return proper
+ * MODE SENSE information.
+ */
+ if ((st->quirks & ST_Q_SNS_HLP) &&
+ !(sc_link->flags & SDEV_MEDIA_LOADED)) { /* still starting */
+ st->blksiz -= 512;
+ } else if (!(st->flags & (ST_2FM_AT_EOD | ST_BLANK_READ))) {
+ st->flags |= ST_BLANK_READ;
+ xs->resid = xs->datalen;
+ if (bp) {
+ bp->b_resid = xs->resid;
+ /*return an EOF */
+ }
+ return (ESUCCESS);
+ }
+ }
+ return (-1); /* let the default/generic handler handle it */
+}
+
+/*
+ * The quirk here is that the drive returns some value to st_mode_sense
+ * incorrectly until the tape has actually passed by the head.
+ *
+ * The method is to set the drive to large fixed-block state (user-specified
+ * density and 1024-byte blocks), then read and rewind to get it to sense the
+ * tape. If that doesn't work, try 512-byte fixed blocks. If that doesn't
+ * work, as a last resort, try variable- length blocks. The result will be
+ * the ability to do an accurate st_mode_sense.
+ *
+ * We know we can do a rewind because we just did a load, which implies rewind.
+ * Rewind seems preferable to space backward if we have a virgin tape.
+ *
+ * The rest of the code for this quirk is in ILI processing and BLANK CHECK
+ * error processing, both part of st_interpret_sense.
+ */
+errval
+st_touch_tape(unit)
+ u_int32 unit;
+{
+ struct st_data *st = st_data[unit];
+ char *buf;
+ u_int32 readsiz;
+ errval errno;
+
+ buf = malloc(1024, M_TEMP, M_NOWAIT);
+ if (!buf)
+ return (ENOMEM);
+
+ if (errno = st_mode_sense(unit, 0)) {
+ goto bad;
+ }
+ st->blksiz = 1024;
+ do {
+ switch ((int)st->blksiz) {
+ case 512:
+ case 1024:
+ readsiz = st->blksiz;
+ st->flags |= ST_FIXEDBLOCKS;
+ break;
+ default:
+ readsiz = 1;
+ st->flags &= ~ST_FIXEDBLOCKS;
+ } if (errno = st_mode_select(unit, 0)) {
+ goto bad;
+ }
+ st_read(unit, buf, readsiz, SCSI_SILENT);
+ if (errno = st_rewind(unit, FALSE, 0)) {
+bad: free(buf, M_TEMP);
+ return (errno);
+ }
+ } while (readsiz != 1 && readsiz > st->blksiz);
+ free(buf, M_TEMP);
+ return 0;
+}
diff --git a/sys/scsi/su.c b/sys/scsi/su.c
new file mode 100644
index 0000000..de4f017
--- /dev/null
+++ b/sys/scsi/su.c
@@ -0,0 +1,4 @@
+
+/* this will be a special user scsi device */
+/* not written yet */
+
diff --git a/sys/scsi/uk.c b/sys/scsi/uk.c
new file mode 100644
index 0000000..149e2df
--- /dev/null
+++ b/sys/scsi/uk.c
@@ -0,0 +1,158 @@
+/*
+ * Dummy driver for a device we can't identify.
+ * by Julian Elischer (julian@tfs.com)
+ *
+ * $Id: uk.c,v 1.2 1993/11/25 01:37:35 wollman Exp $
+ */
+
+#include <sys/param.h>
+#include "systm.h"
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <scsi/scsi_all.h>
+#include <scsi/scsiconf.h>
+#define NUK 16
+
+/*
+ * This driver is so simple it uses all the default services
+ */
+struct scsi_device uk_switch =
+{
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "uk",
+ 0,
+ 0, 0
+};
+
+struct uk_data {
+ u_int32 flags;
+ struct scsi_link *sc_link; /* all the inter level info */
+} uk_data[NUK];
+
+#define UK_KNOWN 0x02
+
+static u_int32 next_uk_unit = 0;
+
+/*
+ * The routine called by the low level scsi routine when it discovers
+ * a device suitable for this driver.
+ */
+errval
+ukattach(sc_link)
+ struct scsi_link *sc_link;
+{
+ u_int32 unit, i, stat;
+ unsigned char *tbl;
+
+ SC_DEBUG(sc_link, SDEV_DB2, ("ukattach: "));
+ /*
+ * Check we have the resources for another drive
+ */
+ unit = next_uk_unit++;
+ if (unit >= NUK) {
+ printf("Too many unknown devices..(%d > %d) reconfigure kernel\n",
+ (unit + 1), NUK);
+ return (0);
+ }
+ /*
+ * Store information needed to contact our base driver
+ */
+ uk_data[unit].sc_link = sc_link;
+ sc_link->device = &uk_switch;
+ sc_link->dev_unit = unit;
+
+ printf("uk%d: unknown device\n", unit);
+ uk_data[unit].flags = UK_KNOWN;
+
+ return 1; /* XXX ??? */
+
+}
+
+/*
+ * open the device.
+ */
+errval
+ukopen(dev)
+ dev_t dev;
+{
+ errval errcode = 0;
+ u_int32 unit, mode;
+ struct scsi_link *sc_link;
+ unit = minor(dev);
+
+ /*
+ * Check the unit is legal
+ */
+ if (unit >= NUK) {
+ printf("uk%d: uk %d > %d\n", unit, unit, NUK);
+ return ENXIO;
+ }
+
+ /*
+ * Make sure the device has been initialised
+ */
+ if((uk_data[unit].flags & UK_KNOWN) == 0) {
+ printf("uk%d: not set up\n", unit);
+ return ENXIO;
+ }
+
+ /*
+ * Only allow one at a time
+ */
+ sc_link = uk_data[unit].sc_link;
+ if (sc_link->flags & SDEV_OPEN) {
+ printf("uk%d: already open\n", unit);
+ return ENXIO;
+ }
+ sc_link->flags |= SDEV_OPEN;
+ SC_DEBUG(sc_link, SDEV_DB1, ("ukopen: dev=0x%x (unit %d (of %d))\n"
+ ,dev, unit, NUK));
+ /*
+ * Catch any unit attention errors.
+ */
+ return 0;
+}
+
+/*
+ * close the device.. only called if we are the LAST
+ * occurence of an open device
+ */
+errval
+ukclose(dev)
+ dev_t dev;
+{
+ unsigned char unit = 0, mode; /* XXX !!! XXX FIXME!!! 0??? */
+ struct scsi_link *sc_link;
+
+ sc_link = uk_data[unit].sc_link;
+
+ SC_DEBUG(sc_link, SDEV_DB1, ("Closing device"));
+ sc_link->flags &= ~SDEV_OPEN;
+ return (0);
+}
+
+/*
+ * Perform special action on behalf of the user
+ * Only does generic scsi ioctls.
+ */
+errval
+ukioctl(dev, cmd, arg, mode)
+ dev_t dev;
+ u_int32 cmd;
+ caddr_t arg;
+ int mode;
+{
+ unsigned char unit;
+ struct scsi_link *sc_link;
+
+ /*
+ * Find the device that the user is talking about
+ */
+ unit = minor(dev);
+ sc_link = uk_data[unit].sc_link;
+ return(scsi_do_ioctl(sc_link,cmd,arg,mode));
+}
+
diff --git a/sys/sys/bitstring.h b/sys/sys/bitstring.h
new file mode 100644
index 0000000..88437e7
--- /dev/null
+++ b/sys/sys/bitstring.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Vixie.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)bitstring.h 8.1 (Berkeley) 7/19/93
+ */
+
+#ifndef _BITSTRING_H_
+#define _BITSTRING_H_
+
+typedef unsigned char bitstr_t;
+
+/* internal macros */
+ /* byte of the bitstring bit is in */
+#define _bit_byte(bit) \
+ ((bit) >> 3)
+
+ /* mask for the bit within its byte */
+#define _bit_mask(bit) \
+ (1 << ((bit)&0x7))
+
+/* external macros */
+ /* bytes in a bitstring of nbits bits */
+#define bitstr_size(nbits) \
+ ((((nbits) - 1) >> 3) + 1)
+
+ /* allocate a bitstring */
+#define bit_alloc(nbits) \
+ (bitstr_t *)calloc(1, \
+ (unsigned int)bitstr_size(nbits) * sizeof(bitstr_t))
+
+ /* allocate a bitstring on the stack */
+#define bit_decl(name, nbits) \
+ (name)[bitstr_size(nbits)]
+
+ /* is bit N of bitstring name set? */
+#define bit_test(name, bit) \
+ ((name)[_bit_byte(bit)] & _bit_mask(bit))
+
+ /* set bit N of bitstring name */
+#define bit_set(name, bit) \
+ (name)[_bit_byte(bit)] |= _bit_mask(bit)
+
+ /* clear bit N of bitstring name */
+#define bit_clear(name, bit) \
+ (name)[_bit_byte(bit)] &= ~_bit_mask(bit)
+
+ /* clear bits start ... stop in bitstring */
+#define bit_nclear(name, start, stop) { \
+ register bitstr_t *_name = name; \
+ register int _start = start, _stop = stop; \
+ register int _startbyte = _bit_byte(_start); \
+ register int _stopbyte = _bit_byte(_stop); \
+ if (_startbyte == _stopbyte) { \
+ _name[_startbyte] &= ((0xff >> (8 - (_start&0x7))) | \
+ (0xff << ((_stop&0x7) + 1))); \
+ } else { \
+ _name[_startbyte] &= 0xff >> (8 - (_start&0x7)); \
+ while (++_startbyte < _stopbyte) \
+ _name[_startbyte] = 0; \
+ _name[_stopbyte] &= 0xff << ((_stop&0x7) + 1); \
+ } \
+}
+
+ /* set bits start ... stop in bitstring */
+#define bit_nset(name, start, stop) { \
+ register bitstr_t *_name = name; \
+ register int _start = start, _stop = stop; \
+ register int _startbyte = _bit_byte(_start); \
+ register int _stopbyte = _bit_byte(_stop); \
+ if (_startbyte == _stopbyte) { \
+ _name[_startbyte] |= ((0xff << (_start&0x7)) & \
+ (0xff >> (7 - (_stop&0x7)))); \
+ } else { \
+ _name[_startbyte] |= 0xff << ((_start)&0x7); \
+ while (++_startbyte < _stopbyte) \
+ _name[_startbyte] = 0xff; \
+ _name[_stopbyte] |= 0xff >> (7 - (_stop&0x7)); \
+ } \
+}
+
+ /* find first bit clear in name */
+#define bit_ffc(name, nbits, value) { \
+ register bitstr_t *_name = name; \
+ register int _byte, _nbits = nbits; \
+ register int _stopbyte = _bit_byte(_nbits), _value = -1; \
+ for (_byte = 0; _byte <= _stopbyte; ++_byte) \
+ if (_name[_byte] != 0xff) { \
+ _value = _byte << 3; \
+ for (_stopbyte = _name[_byte]; (_stopbyte&0x1); \
+ ++_value, _stopbyte >>= 1); \
+ break; \
+ } \
+ *(value) = _value; \
+}
+
+ /* find first bit set in name */
+#define bit_ffs(name, nbits, value) { \
+ register bitstr_t *_name = name; \
+ register int _byte, _nbits = nbits; \
+ register int _stopbyte = _bit_byte(_nbits), _value = -1; \
+ for (_byte = 0; _byte <= _stopbyte; ++_byte) \
+ if (_name[_byte]) { \
+ _value = _byte << 3; \
+ for (_stopbyte = _name[_byte]; !(_stopbyte&0x1); \
+ ++_value, _stopbyte >>= 1); \
+ break; \
+ } \
+ *(value) = _value; \
+}
+
+#endif /* !_BITSTRING_H_ */
diff --git a/sys/sys/cdio.h b/sys/sys/cdio.h
new file mode 100644
index 0000000..c49dfed
--- /dev/null
+++ b/sys/sys/cdio.h
@@ -0,0 +1,170 @@
+/*
+ * 16 Feb 93 Julian Elischer (julian@dialix.oz.au)
+ *
+ * $Id: cdio.h,v 1.5 1994/01/29 10:31:20 rgrimes Exp $
+ */
+/* Shared between kernel & process */
+#ifndef _SYS_CDIO_H_
+#define _SYS_CDIO_H_
+
+union msf_lba {
+ struct {
+ unsigned char unused;
+ unsigned char minute;
+ unsigned char second;
+ unsigned char frame;
+ } msf;
+ int lba;
+ u_char addr[4];
+};
+
+struct cd_toc_entry {
+ u_char :8;
+ u_char control:4;
+ u_char addr_type:4;
+ u_char track;
+ u_char :8;
+ union msf_lba addr;
+};
+
+struct cd_sub_channel_header {
+ u_char :8;
+ u_char audio_status;
+#define CD_AS_AUDIO_INVALID 0x00
+#define CD_AS_PLAY_IN_PROGRESS 0x11
+#define CD_AS_PLAY_PAUSED 0x12
+#define CD_AS_PLAY_COMPLETED 0x13
+#define CD_AS_PLAY_ERROR 0x14
+#define CD_AS_NO_STATUS 0x15
+ u_char data_len[2];
+};
+
+struct cd_sub_channel_position_data {
+ u_char data_format;
+ u_char control:4;
+ u_char addr_type:4;
+ u_char track_number;
+ u_char index_number;
+ union msf_lba absaddr;
+ union msf_lba reladdr;
+};
+
+struct cd_sub_channel_media_catalog {
+ u_char data_format;
+ u_char :8;
+ u_char :8;
+ u_char :8;
+ u_char :7;
+ u_char mc_valid:1;
+ u_char mc_number[15];
+};
+
+struct cd_sub_channel_track_info {
+ u_char data_format;
+ u_char :8;
+ u_char track_number;
+ u_char :8;
+ u_char :7;
+ u_char ti_valid:1;
+ u_char ti_number[15];
+};
+
+struct cd_sub_channel_info {
+ struct cd_sub_channel_header header;
+ union {
+ struct cd_sub_channel_position_data position;
+ struct cd_sub_channel_media_catalog media_catalog;
+ struct cd_sub_channel_track_info track_info;
+ } what;
+};
+
+/***************************************************************\
+* Ioctls for the CD drive *
+\***************************************************************/
+struct ioc_play_track
+{
+ u_char start_track;
+ u_char start_index;
+ u_char end_track;
+ u_char end_index;
+};
+
+#define CDIOCPLAYTRACKS _IOW('c',1,struct ioc_play_track)
+struct ioc_play_blocks
+{
+ int blk;
+ int len;
+};
+#define CDIOCPLAYBLOCKS _IOW('c',2,struct ioc_play_blocks)
+
+struct ioc_read_subchannel {
+ u_char address_format;
+#define CD_LBA_FORMAT 1
+#define CD_MSF_FORMAT 2
+ u_char data_format;
+#define CD_SUBQ_DATA 0
+#define CD_CURRENT_POSITION 1
+#define CD_MEDIA_CATALOG 2
+#define CD_TRACK_INFO 3
+ u_char track;
+ int data_len;
+ struct cd_sub_channel_info *data;
+};
+#define CDIOCREADSUBCHANNEL _IOWR('c', 3 , struct ioc_read_subchannel )
+
+
+struct ioc_toc_header {
+ u_short len;
+ u_char starting_track;
+ u_char ending_track;
+};
+
+#define CDIOREADTOCHEADER _IOR('c',4,struct ioc_toc_header)
+
+struct ioc_read_toc_entry {
+ u_char address_format;
+ u_char starting_track;
+ u_short data_len;
+ struct cd_toc_entry *data;
+};
+#define CDIOREADTOCENTRYS _IOWR('c',5,struct ioc_read_toc_entry)
+
+struct ioc_patch
+{
+ u_char patch[4]; /* one for each channel */
+};
+#define CDIOCSETPATCH _IOW('c',9,struct ioc_patch)
+struct ioc_vol
+{
+ u_char vol[4]; /* one for each channel */
+};
+#define CDIOCGETVOL _IOR('c',10,struct ioc_vol)
+#define CDIOCSETVOL _IOW('c',11,struct ioc_vol)
+#define CDIOCSETMONO _IO('c',12)
+#define CDIOCSETSTERIO _IO('c',13)
+#define CDIOCSETMUTE _IO('c',14)
+#define CDIOCSETLEFT _IO('c',15)
+#define CDIOCSETRIGHT _IO('c',16)
+#define CDIOCSETDEBUG _IO('c',17)
+#define CDIOCCLRDEBUG _IO('c',18)
+#define CDIOCPAUSE _IO('c',19)
+#define CDIOCRESUME _IO('c',20)
+#define CDIOCRESET _IO('c',21)
+#define CDIOCSTART _IO('c',22)
+#define CDIOCSTOP _IO('c',23)
+#define CDIOCEJECT _IO('c',24)
+#define CDIOCALLOW _IO('c',25)
+#define CDIOCPREVENT _IO('c',26)
+
+struct ioc_play_msf
+{
+ u_char start_m;
+ u_char start_s;
+ u_char start_f;
+ u_char end_m;
+ u_char end_s;
+ u_char end_f;
+};
+#define CDIOCPLAYMSF _IOW('c',25,struct ioc_play_msf)
+
+#endif /* _SYS_CDIO_H_ */
diff --git a/sys/sys/chio.h b/sys/sys/chio.h
new file mode 100644
index 0000000..10fa51d
--- /dev/null
+++ b/sys/sys/chio.h
@@ -0,0 +1,92 @@
+/*
+ * 16 Feb 93 Julian Elischer ADDED for SCSI system
+ *
+ * $Id: chio.h,v 1.3 1993/10/16 17:16:27 rgrimes Exp $
+ */
+
+/* This is a "convertet" mtio.h from 386BSD
+ Stefan Grefen grefen@goofy.zdv.uni-mainz.de
+ */
+
+/*
+ * Structures and definitions for changer io control commands
+ */
+#ifndef _SYS_CHIO_H_
+#define _SYS_CHIO_H_
+
+#define CH_INVERT 0x10000
+#define CH_ADDR_MASK 0xffff
+struct chop {
+ short ch_op; /* operations defined below */
+ short result; /* The result */
+ union {
+ struct {
+ int chm; /* Transport element */
+ int from;
+ int to;
+ } move;
+ struct {
+ int chm; /* Transport element */
+ int to;
+ } position;
+ struct {
+ short chmo; /* Offset of first CHM */
+ short chms; /* No. of CHM */
+ short slots; /* No. of Storage Elements */
+ short sloto; /* Offset of first SE */
+ short imexs; /* No. of Import/Export Slots */
+ short imexo; /* Offset of first IM/EX */
+ short drives; /* No. of CTS */
+ short driveo; /* Offset of first CTS */
+ short rot; /* CHM can rotate */
+ } getparam;
+ struct {
+ int type;
+#define CH_CHM 1
+#define CH_STOR 2
+#define CH_IMEX 3
+#define CH_CTS 4
+ int from;
+ struct {
+ u_char elema_1;
+ u_char elema_0;
+ u_char full:1;
+ u_char rsvd:1;
+ u_char except:1;
+ u_char :5;
+ u_char rsvd2;
+ union {
+ struct {
+ u_char add_sense_code;
+ u_char add_sense_code_qualifier;
+ } specs;
+ short add_sense;
+/* WARINING LSB only */
+#define CH_CHOLDER 0x0290 /* Cartridge holder is missing */
+#define CH_STATUSQ 0x0390 /* Status is questionable */
+#define CH_CTS_CLOSED 0x0490 /* CTS door is closed */
+
+ } ch_add_sense;
+ u_char rsvd3[3];
+ u_char :6;
+ u_char invert:1;
+ u_char svalid:1;
+ u_char source_1;
+ u_char source_0;
+ u_char rsvd4[4];
+ } elem_data;
+ } get_elem_stat;
+ } u;
+};
+
+/* operations */
+#define CHMOVE 1
+#define CHPOSITION 2
+#define CHGETPARAM 3
+#define CHGETELEM 4
+
+
+/* Changer IO control command */
+#define CHIOOP _IOWR('c', 1, struct chop) /* do a mag tape op */
+
+#endif /*_SYS_CHIO_H*/
diff --git a/sys/sys/cons.h b/sys/sys/cons.h
new file mode 100644
index 0000000..5e0f30d
--- /dev/null
+++ b/sys/sys/cons.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1988 University of Utah.
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)cons.h 7.2 (Berkeley) 5/9/91
+ * $Id: cons.h,v 1.3 1993/11/07 17:41:33 wollman Exp $
+ */
+
+#ifndef _MACHINE_CONS_H_
+#define _MACHINE_CONS_H_ 1
+
+struct consdev {
+ int (*cn_probe)(); /* probe hardware and fill in consdev info */
+ int (*cn_init)(); /* turn on as console */
+ int (*cn_getc)(); /* kernel getchar interface */
+ int (*cn_putc)(); /* kernel putchar interface */
+ struct tty *cn_tp; /* tty structure for console device */
+ dev_t cn_dev; /* major/minor of device */
+ short cn_pri; /* pecking order; the higher the better */
+};
+
+/* values for cn_pri - reflect our policy for console selection */
+#define CN_DEAD 0 /* device doesn't exist */
+#define CN_NORMAL 1 /* device exists but is nothing special */
+#define CN_INTERNAL 2 /* "internal" bit-mapped display */
+#define CN_REMOTE 3 /* serial interface with remote bit set */
+
+/* XXX */
+#define CONSMAJOR 0
+
+#ifdef KERNEL
+extern struct consdev constab[];
+extern struct consdev *cn_tab;
+extern struct tty *cn_tty;
+
+struct proc; struct uio;
+
+/* cdevsw[] entries */
+extern int cnopen(int /*dev_t*/, int, int, struct proc *);
+extern int cnclose(int /*dev_t*/, int, int, struct proc *);
+extern int cnread(int /*dev_t*/, struct uio *, int);
+extern int cnwrite(int /*dev_t*/, struct uio *, int);
+extern int cnioctl(int /*dev_t*/, int, caddr_t, int, struct proc *);
+extern int cnselect(int /*dev_t*/, int, struct proc *);
+
+/* other kernel entry points */
+extern void cninit(void);
+extern int cngetc(void);
+extern void cnputc(int /*char*/);
+extern int pg(const char *, ...);
+
+#endif /* KERNEL */
+#endif /* _MACHINE_CONS_H_ */
diff --git a/sys/sys/fdcio.h b/sys/sys/fdcio.h
new file mode 100644
index 0000000..2e3ac31
--- /dev/null
+++ b/sys/sys/fdcio.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 1992-1993 by Joerg Wunsch, Dresden
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _IOCTL_FD_H
+#define _IOCTL_FD_H
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#define FD_FORMAT_VERSION 110 /* used to validate before formatting */
+#define FD_MAX_NSEC 36 /* highest known number of spt - allow for */
+ /* 2.88 MB drives */
+
+struct fd_formb {
+ int format_version; /* == FD_FORMAT_VERSION */
+ int cyl, head;
+ int transfer_rate; /* fdreg.h: FDC_???KBPS */
+
+ union {
+ struct fd_form_data {
+ /*
+ * DO NOT CHANGE THE LAYOUT OF THIS STRUCTS
+ * it is hardware-dependant since it exactly
+ * matches the byte sequence to write to FDC
+ * during its `format track' operation
+ */
+ u_char secshift; /* 0 -> 128, ...; usually 2 -> 512 */
+ u_char nsecs; /* must be <= FD_MAX_NSEC */
+ u_char gaplen; /* GAP 3 length; usually 84 */
+ u_char fillbyte; /* usually 0xf6 */
+ struct fd_idfield_data {
+ /*
+ * data to write into id fields;
+ * for obscure formats, they mustn't match
+ * the real values (but mostly do)
+ */
+ u_char cylno; /* 0 thru 79 (or 39) */
+ u_char headno; /* 0, or 1 */
+ u_char secno; /* starting at 1! */
+ u_char secsize; /* usually 2 */
+ } idfields[FD_MAX_NSEC]; /* 0 <= idx < nsecs used */
+ } structured;
+ u_char raw[1]; /* to have continuous indexed access */
+ } format_info;
+};
+
+/* make life easier */
+# define fd_formb_secshift format_info.structured.secshift
+# define fd_formb_nsecs format_info.structured.nsecs
+# define fd_formb_gaplen format_info.structured.gaplen
+# define fd_formb_fillbyte format_info.structured.fillbyte
+/* these data must be filled in for(i = 0; i < fd_formb_nsecs; i++) */
+# define fd_formb_cylno(i) format_info.structured.idfields[i].cylno
+# define fd_formb_headno(i) format_info.structured.idfields[i].headno
+# define fd_formb_secno(i) format_info.structured.idfields[i].secno
+# define fd_formb_secsize(i) format_info.structured.idfields[i].secsize
+
+struct fd_type {
+ int sectrac; /* sectors per track */
+ int secsize; /* size code for sectors */
+ int datalen; /* data len when secsize = 0 */
+ int gap; /* gap len between sectors */
+ int tracks; /* total num of tracks */
+ int size; /* size of disk in sectors */
+ int steptrac; /* steps per cylinder */
+ int trans; /* transfer speed code */
+ int heads; /* number of heads */
+ int f_gap; /* format gap len */
+ int f_inter; /* format interleave factor */
+};
+
+#define FD_FORM _IOW('F', 61, struct fd_formb) /* format a track */
+#define FD_GTYPE _IOR('F', 62, struct fd_type) /* get drive type */
+
+#endif /* !def _IOCTL_FD_H */
diff --git a/sys/sys/imgact.h b/sys/sys/imgact.h
new file mode 100644
index 0000000..8cba997
--- /dev/null
+++ b/sys/sys/imgact.h
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 1993, David Greenman
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: imgact.h,v 1.1 1993/12/12 12:31:40 davidg Exp $
+ */
+
+#ifndef __h_imgact
+#define __h_imgact 1
+
+#include "proc.h"
+#include "namei.h"
+#include "vnode.h"
+
+struct execve_args {
+ char *fname; /* file name */
+ char **argv; /* pointer to table of argument pointers */
+ char **envv; /* pointer to table of environment pointers */
+};
+
+struct image_params {
+ struct proc *proc; /* our process struct */
+ struct execve_args *uap; /* syscall arguments */
+ struct vnode *vnodep; /* pointer to vnode of file to exec */
+ struct vattr *attr; /* attributes of file */
+ const char *image_header; /* head of file to exec */
+ char *stringbase; /* base address of tmp string storage */
+ char *stringp; /* current 'end' pointer of tmp strings */
+ int stringspace; /* space left in tmp string storage area */
+ int argc, envc; /* count of argument and environment strings */
+ unsigned long entry_addr; /* entry address of target executable */
+ char vmspace_destroyed; /* flag - we've blown away original vm space */
+ char interpreted; /* flag - this executable is interpreted */
+ char interpreter_name[64]; /* name of the interpreter */
+};
+
+struct execsw {
+ int (*ex_imgact)(struct image_params *);
+};
+
+extern const struct execsw **execsw;
+
+#endif /* __h_imgact */
diff --git a/sys/sys/link_aout.h b/sys/sys/link_aout.h
new file mode 100644
index 0000000..3a5b6aa
--- /dev/null
+++ b/sys/sys/link_aout.h
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 1993 Paul Kranenburg
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Paul Kranenburg.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+/*
+ * RRS section definitions.
+ *
+ * The layout of some data structures defined in this header file is
+ * such that we can provide compatibility with the SunOS 4.x shared
+ * library scheme.
+ */
+
+#ifndef _LINK_H_
+#define _LINK_H_
+
+/*
+ * A `Shared Object Descriptor' descibes a shared object that is needed
+ * to complete the link edit process of the object containing it.
+ * A list of such objects (chained through `sod_next') is pointed at
+ * by `sdt_sods' in the section_dispatch_table structure.
+ */
+
+struct sod { /* Shared Object Descriptor */
+ long sod_name; /* name (relative to load address) */
+ u_int sod_library : 1, /* Searched for by library rules */
+ sod_reserved : 31;
+ short sod_major; /* major version number */
+ short sod_minor; /* minor version number */
+ long sod_next; /* next sod */
+};
+
+/*
+ * `Shared Object Map's are used by the run-time link editor (ld.so) to
+ * keep track of all shared objects loaded into a process' address space.
+ * These structures are only used at run-time and do not occur within
+ * the text or data segment of an executable or shared library.
+ */
+struct so_map { /* Shared Object Map */
+ caddr_t som_addr; /* Address at which object mapped */
+ char *som_path; /* Path to mmap'ed file */
+ struct so_map *som_next; /* Next map in chain */
+ struct sod *som_sod; /* Sod responsible for this map */
+ caddr_t som_sodbase; /* Base address of this sod */
+ u_int som_write : 1; /* Text is currently writable */
+ struct _dynamic *som_dynamic; /* _dynamic structure */
+ caddr_t som_spd; /* Private data */
+};
+
+/*
+ * Symbol description with size. This is simply an `nlist' with
+ * one field (nz_size) added.
+ * Used to convey size information on items in the data segment
+ * of shared objects. An array of these live in the shared object's
+ * text segment and is addressed by the `sdt_nzlist' field.
+ */
+struct nzlist {
+ struct nlist nlist;
+ u_long nz_size;
+#define nz_un nlist.n_un
+#define nz_strx nlist.n_un.n_strx
+#define nz_name nlist.n_un.n_name
+#define nz_type nlist.n_type
+#define nz_value nlist.n_value
+#define nz_desc nlist.n_desc
+#define nz_other nlist.n_other
+};
+
+#define N_AUX(p) ((p)->n_other & 0xf)
+#define N_RESERVED(p) (((unsigned int)(p)->n_other >> 4) & 0xf)
+#define N_OTHER(r, v) (((unsigned int)(r) << 4) | ((v) & 0xf))
+
+#define AUX_OBJECT 1
+#define AUX_FUNC 2
+
+
+/*
+ * The `section_dispatch_table' structure contains offsets to various data
+ * structures needed to do run-time relocation.
+ */
+struct section_dispatch_table {
+ struct so_map *sdt_loaded; /* List of loaded objects */
+ long sdt_sods; /* List of shared objects descriptors */
+ long sdt_filler1; /* Unused (was: search rules) */
+ long sdt_got; /* Global offset table */
+ long sdt_plt; /* Procedure linkage table */
+ long sdt_rel; /* Relocation table */
+ long sdt_hash; /* Symbol hash table */
+ long sdt_nzlist; /* Symbol table itself */
+ long sdt_filler2; /* Unused (was: stab_hash) */
+ long sdt_buckets; /* Number of hash buckets */
+ long sdt_strings; /* Symbol strings */
+ long sdt_str_sz; /* Size of symbol strings */
+ long sdt_text_sz; /* Size of text area */
+ long sdt_plt_sz; /* Size of procedure linkage table */
+};
+
+/*
+ * RRS symbol hash table, addressed by `sdt_hash' in section_dispatch_table.
+ * Used to quickly lookup symbols of the shared object by hashing
+ * on the symbol's name. `rh_symbolnum' is the index of the symbol
+ * in the shared object's symbol list (`sdt_nzlist'), `rh_next' is
+ * the next symbol in the hash bucket (in case of collisions).
+ */
+struct rrs_hash {
+ int rh_symbolnum; /* Symbol number */
+ int rh_next; /* Next hash entry */
+};
+
+/*
+ * `rt_symbols' is used to keep track of run-time allocated commons
+ * and data items copied from shared objects.
+ */
+struct rt_symbol {
+ struct nzlist *rt_sp; /* The symbol */
+ struct rt_symbol *rt_next; /* Next in linear list */
+ struct rt_symbol *rt_link; /* Next in bucket */
+ caddr_t rt_srcaddr; /* Address of "master" copy */
+ struct so_map *rt_smp; /* Originating map */
+};
+
+/*
+ * Debugger interface structure.
+ */
+struct so_debug {
+ int dd_version; /* Version # of interface */
+ int dd_in_debugger; /* Set when run by debugger */
+ int dd_sym_loaded; /* Run-time linking brought more
+ symbols into scope */
+ char *dd_bpt_addr; /* Address of rtld-generated bpt */
+ int dd_bpt_shadow; /* Original contents of bpt */
+ struct rt_symbol *dd_cc; /* Allocated commons/copied data */
+};
+
+/*
+ * Entry points into ld.so - user interface to the run-time linker.
+ */
+struct ld_entry {
+ void *(*dlopen) __P((char *, int));
+ int (*dlclose) __P((void *));
+ void *(*dlsym) __P((void *, char *));
+ int (*dlctl) __P((void *, int, void *));
+};
+
+/*
+ * dlctl() commands
+ */
+#define DL_GETERRNO 1
+
+/*
+ * dl*() prototypes.
+ */
+extern void *dlopen __P((char *, int));
+extern int dlclose __P((void *));
+extern void *dlsym __P((void *, char *));
+extern int dlctl __P((void *, int, void *));
+
+
+/*
+ * This is the structure pointed at by the __DYNAMIC symbol if an
+ * executable requires the attention of the run-time link editor.
+ * __DYNAMIC is given the value zero if no run-time linking needs to
+ * be done (it is always present in shared objects).
+ * The union `d_un' provides for different versions of the dynamic
+ * linking mechanism (switched on by `d_version'). The last version
+ * used by Sun is 3. We leave some room here and go to version number
+ * 8 for NetBSD, the main difference lying in the support for the
+ * `nz_list' type of symbols.
+ */
+
+struct _dynamic {
+ int d_version; /* version # of this interface */
+ struct so_debug *d_debug;
+ union {
+ struct section_dispatch_table *d_sdt;
+ } d_un;
+ struct ld_entry *d_entry;
+};
+
+#define LD_VERSION_SUN (3)
+#define LD_VERSION_BSD (8)
+#define LD_VERSION_NZLIST_P(v) ((v) >= 8)
+
+#define LD_GOT(x) ((x)->d_un.d_sdt->sdt_got)
+#define LD_PLT(x) ((x)->d_un.d_sdt->sdt_plt)
+#define LD_REL(x) ((x)->d_un.d_sdt->sdt_rel)
+#define LD_SYMBOL(x) ((x)->d_un.d_sdt->sdt_nzlist)
+#define LD_HASH(x) ((x)->d_un.d_sdt->sdt_hash)
+#define LD_STRINGS(x) ((x)->d_un.d_sdt->sdt_strings)
+#define LD_NEED(x) ((x)->d_un.d_sdt->sdt_sods)
+#define LD_BUCKETS(x) ((x)->d_un.d_sdt->sdt_buckets)
+
+#define LD_GOTSZ(x) ((x)->d_un.d_sdt->sdt_plt - (x)->d_un.d_sdt->sdt_got)
+#define LD_RELSZ(x) ((x)->d_un.d_sdt->sdt_hash - (x)->d_un.d_sdt->sdt_rel)
+#define LD_HASHSZ(x) ((x)->d_un.d_sdt->sdt_nzlist - (x)->d_un.d_sdt->sdt_hash)
+#define LD_STABSZ(x) ((x)->d_un.d_sdt->sdt_strings - (x)->d_un.d_sdt->sdt_nzlist)
+#define LD_PLTSZ(x) ((x)->d_un.d_sdt->sdt_plt_sz)
+#define LD_STRSZ(x) ((x)->d_un.d_sdt->sdt_str_sz)
+#define LD_TEXTSZ(x) ((x)->d_un.d_sdt->sdt_text_sz)
+
+/*
+ * Interface to ld.so
+ */
+struct crt_ldso {
+ int crt_ba; /* Base address of ld.so */
+ int crt_dzfd; /* "/dev/zero" file decriptor (SunOS) */
+ int crt_ldfd; /* ld.so file descriptor */
+ struct _dynamic *crt_dp; /* Main's __DYNAMIC */
+ char **crt_ep; /* environment strings */
+ caddr_t crt_bp; /* Breakpoint if run from debugger */
+ char *crt_prog; /* Program name */
+};
+
+/*
+ * Version passed from crt0 to ld.so (1st argument to _rtld()).
+ */
+#define CRT_VERSION_SUN 1
+#define CRT_VERSION_BSD 2
+#define CRT_VERSION_BSD_2 2
+#define CRT_VERSION_BSD_3 3
+
+
+/*
+ * Maximum number of recognized shared object version numbers.
+ */
+#define MAXDEWEY 8
+
+/*
+ * Header of the hints file.
+ */
+struct hints_header {
+ long hh_magic;
+#define HH_MAGIC 011421044151
+ long hh_version; /* Interface version number */
+#define LD_HINTS_VERSION_1 1
+ long hh_hashtab; /* Location of hash table */
+ long hh_nbucket; /* Number of buckets in hashtab */
+ long hh_strtab; /* Location of strings */
+ long hh_strtab_sz; /* Size of strings */
+ long hh_ehints; /* End of hints (max offset in file) */
+};
+
+#define HH_BADMAG(hdr) ((hdr).hh_magic != HH_MAGIC)
+
+/*
+ * Hash table element in hints file.
+ */
+struct hints_bucket {
+ /* namex and pathx are indices into the string table */
+ int hi_namex; /* Library name */
+ int hi_pathx; /* Full path */
+ int hi_dewey[MAXDEWEY]; /* The versions */
+ int hi_ndewey; /* Number of version numbers */
+#define hi_major hi_dewey[0]
+#define hi_minor hi_dewey[1]
+ int hi_next; /* Next in this bucket */
+};
+
+#define _PATH_LD_HINTS "/var/run/ld.so.hints"
+
+#endif /* _LINK_H_ */
+
diff --git a/sys/sys/link_elf.h b/sys/sys/link_elf.h
new file mode 100644
index 0000000..3a5b6aa
--- /dev/null
+++ b/sys/sys/link_elf.h
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 1993 Paul Kranenburg
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Paul Kranenburg.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+/*
+ * RRS section definitions.
+ *
+ * The layout of some data structures defined in this header file is
+ * such that we can provide compatibility with the SunOS 4.x shared
+ * library scheme.
+ */
+
+#ifndef _LINK_H_
+#define _LINK_H_
+
+/*
+ * A `Shared Object Descriptor' descibes a shared object that is needed
+ * to complete the link edit process of the object containing it.
+ * A list of such objects (chained through `sod_next') is pointed at
+ * by `sdt_sods' in the section_dispatch_table structure.
+ */
+
+struct sod { /* Shared Object Descriptor */
+ long sod_name; /* name (relative to load address) */
+ u_int sod_library : 1, /* Searched for by library rules */
+ sod_reserved : 31;
+ short sod_major; /* major version number */
+ short sod_minor; /* minor version number */
+ long sod_next; /* next sod */
+};
+
+/*
+ * `Shared Object Map's are used by the run-time link editor (ld.so) to
+ * keep track of all shared objects loaded into a process' address space.
+ * These structures are only used at run-time and do not occur within
+ * the text or data segment of an executable or shared library.
+ */
+struct so_map { /* Shared Object Map */
+ caddr_t som_addr; /* Address at which object mapped */
+ char *som_path; /* Path to mmap'ed file */
+ struct so_map *som_next; /* Next map in chain */
+ struct sod *som_sod; /* Sod responsible for this map */
+ caddr_t som_sodbase; /* Base address of this sod */
+ u_int som_write : 1; /* Text is currently writable */
+ struct _dynamic *som_dynamic; /* _dynamic structure */
+ caddr_t som_spd; /* Private data */
+};
+
+/*
+ * Symbol description with size. This is simply an `nlist' with
+ * one field (nz_size) added.
+ * Used to convey size information on items in the data segment
+ * of shared objects. An array of these live in the shared object's
+ * text segment and is addressed by the `sdt_nzlist' field.
+ */
+struct nzlist {
+ struct nlist nlist;
+ u_long nz_size;
+#define nz_un nlist.n_un
+#define nz_strx nlist.n_un.n_strx
+#define nz_name nlist.n_un.n_name
+#define nz_type nlist.n_type
+#define nz_value nlist.n_value
+#define nz_desc nlist.n_desc
+#define nz_other nlist.n_other
+};
+
+#define N_AUX(p) ((p)->n_other & 0xf)
+#define N_RESERVED(p) (((unsigned int)(p)->n_other >> 4) & 0xf)
+#define N_OTHER(r, v) (((unsigned int)(r) << 4) | ((v) & 0xf))
+
+#define AUX_OBJECT 1
+#define AUX_FUNC 2
+
+
+/*
+ * The `section_dispatch_table' structure contains offsets to various data
+ * structures needed to do run-time relocation.
+ */
+struct section_dispatch_table {
+ struct so_map *sdt_loaded; /* List of loaded objects */
+ long sdt_sods; /* List of shared objects descriptors */
+ long sdt_filler1; /* Unused (was: search rules) */
+ long sdt_got; /* Global offset table */
+ long sdt_plt; /* Procedure linkage table */
+ long sdt_rel; /* Relocation table */
+ long sdt_hash; /* Symbol hash table */
+ long sdt_nzlist; /* Symbol table itself */
+ long sdt_filler2; /* Unused (was: stab_hash) */
+ long sdt_buckets; /* Number of hash buckets */
+ long sdt_strings; /* Symbol strings */
+ long sdt_str_sz; /* Size of symbol strings */
+ long sdt_text_sz; /* Size of text area */
+ long sdt_plt_sz; /* Size of procedure linkage table */
+};
+
+/*
+ * RRS symbol hash table, addressed by `sdt_hash' in section_dispatch_table.
+ * Used to quickly lookup symbols of the shared object by hashing
+ * on the symbol's name. `rh_symbolnum' is the index of the symbol
+ * in the shared object's symbol list (`sdt_nzlist'), `rh_next' is
+ * the next symbol in the hash bucket (in case of collisions).
+ */
+struct rrs_hash {
+ int rh_symbolnum; /* Symbol number */
+ int rh_next; /* Next hash entry */
+};
+
+/*
+ * `rt_symbols' is used to keep track of run-time allocated commons
+ * and data items copied from shared objects.
+ */
+struct rt_symbol {
+ struct nzlist *rt_sp; /* The symbol */
+ struct rt_symbol *rt_next; /* Next in linear list */
+ struct rt_symbol *rt_link; /* Next in bucket */
+ caddr_t rt_srcaddr; /* Address of "master" copy */
+ struct so_map *rt_smp; /* Originating map */
+};
+
+/*
+ * Debugger interface structure.
+ */
+struct so_debug {
+ int dd_version; /* Version # of interface */
+ int dd_in_debugger; /* Set when run by debugger */
+ int dd_sym_loaded; /* Run-time linking brought more
+ symbols into scope */
+ char *dd_bpt_addr; /* Address of rtld-generated bpt */
+ int dd_bpt_shadow; /* Original contents of bpt */
+ struct rt_symbol *dd_cc; /* Allocated commons/copied data */
+};
+
+/*
+ * Entry points into ld.so - user interface to the run-time linker.
+ */
+struct ld_entry {
+ void *(*dlopen) __P((char *, int));
+ int (*dlclose) __P((void *));
+ void *(*dlsym) __P((void *, char *));
+ int (*dlctl) __P((void *, int, void *));
+};
+
+/*
+ * dlctl() commands
+ */
+#define DL_GETERRNO 1
+
+/*
+ * dl*() prototypes.
+ */
+extern void *dlopen __P((char *, int));
+extern int dlclose __P((void *));
+extern void *dlsym __P((void *, char *));
+extern int dlctl __P((void *, int, void *));
+
+
+/*
+ * This is the structure pointed at by the __DYNAMIC symbol if an
+ * executable requires the attention of the run-time link editor.
+ * __DYNAMIC is given the value zero if no run-time linking needs to
+ * be done (it is always present in shared objects).
+ * The union `d_un' provides for different versions of the dynamic
+ * linking mechanism (switched on by `d_version'). The last version
+ * used by Sun is 3. We leave some room here and go to version number
+ * 8 for NetBSD, the main difference lying in the support for the
+ * `nz_list' type of symbols.
+ */
+
+struct _dynamic {
+ int d_version; /* version # of this interface */
+ struct so_debug *d_debug;
+ union {
+ struct section_dispatch_table *d_sdt;
+ } d_un;
+ struct ld_entry *d_entry;
+};
+
+#define LD_VERSION_SUN (3)
+#define LD_VERSION_BSD (8)
+#define LD_VERSION_NZLIST_P(v) ((v) >= 8)
+
+#define LD_GOT(x) ((x)->d_un.d_sdt->sdt_got)
+#define LD_PLT(x) ((x)->d_un.d_sdt->sdt_plt)
+#define LD_REL(x) ((x)->d_un.d_sdt->sdt_rel)
+#define LD_SYMBOL(x) ((x)->d_un.d_sdt->sdt_nzlist)
+#define LD_HASH(x) ((x)->d_un.d_sdt->sdt_hash)
+#define LD_STRINGS(x) ((x)->d_un.d_sdt->sdt_strings)
+#define LD_NEED(x) ((x)->d_un.d_sdt->sdt_sods)
+#define LD_BUCKETS(x) ((x)->d_un.d_sdt->sdt_buckets)
+
+#define LD_GOTSZ(x) ((x)->d_un.d_sdt->sdt_plt - (x)->d_un.d_sdt->sdt_got)
+#define LD_RELSZ(x) ((x)->d_un.d_sdt->sdt_hash - (x)->d_un.d_sdt->sdt_rel)
+#define LD_HASHSZ(x) ((x)->d_un.d_sdt->sdt_nzlist - (x)->d_un.d_sdt->sdt_hash)
+#define LD_STABSZ(x) ((x)->d_un.d_sdt->sdt_strings - (x)->d_un.d_sdt->sdt_nzlist)
+#define LD_PLTSZ(x) ((x)->d_un.d_sdt->sdt_plt_sz)
+#define LD_STRSZ(x) ((x)->d_un.d_sdt->sdt_str_sz)
+#define LD_TEXTSZ(x) ((x)->d_un.d_sdt->sdt_text_sz)
+
+/*
+ * Interface to ld.so
+ */
+struct crt_ldso {
+ int crt_ba; /* Base address of ld.so */
+ int crt_dzfd; /* "/dev/zero" file decriptor (SunOS) */
+ int crt_ldfd; /* ld.so file descriptor */
+ struct _dynamic *crt_dp; /* Main's __DYNAMIC */
+ char **crt_ep; /* environment strings */
+ caddr_t crt_bp; /* Breakpoint if run from debugger */
+ char *crt_prog; /* Program name */
+};
+
+/*
+ * Version passed from crt0 to ld.so (1st argument to _rtld()).
+ */
+#define CRT_VERSION_SUN 1
+#define CRT_VERSION_BSD 2
+#define CRT_VERSION_BSD_2 2
+#define CRT_VERSION_BSD_3 3
+
+
+/*
+ * Maximum number of recognized shared object version numbers.
+ */
+#define MAXDEWEY 8
+
+/*
+ * Header of the hints file.
+ */
+struct hints_header {
+ long hh_magic;
+#define HH_MAGIC 011421044151
+ long hh_version; /* Interface version number */
+#define LD_HINTS_VERSION_1 1
+ long hh_hashtab; /* Location of hash table */
+ long hh_nbucket; /* Number of buckets in hashtab */
+ long hh_strtab; /* Location of strings */
+ long hh_strtab_sz; /* Size of strings */
+ long hh_ehints; /* End of hints (max offset in file) */
+};
+
+#define HH_BADMAG(hdr) ((hdr).hh_magic != HH_MAGIC)
+
+/*
+ * Hash table element in hints file.
+ */
+struct hints_bucket {
+ /* namex and pathx are indices into the string table */
+ int hi_namex; /* Library name */
+ int hi_pathx; /* Full path */
+ int hi_dewey[MAXDEWEY]; /* The versions */
+ int hi_ndewey; /* Number of version numbers */
+#define hi_major hi_dewey[0]
+#define hi_minor hi_dewey[1]
+ int hi_next; /* Next in this bucket */
+};
+
+#define _PATH_LD_HINTS "/var/run/ld.so.hints"
+
+#endif /* _LINK_H_ */
+
diff --git a/sys/sys/nlist_aout.h b/sys/sys/nlist_aout.h
new file mode 100644
index 0000000..11e0a43
--- /dev/null
+++ b/sys/sys/nlist_aout.h
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)nlist.h 8.2 (Berkeley) 1/21/94
+ */
+
+#ifndef _NLIST_H_
+#define _NLIST_H_
+
+/*
+ * Symbol table entry format. The #ifdef's are so that programs including
+ * nlist.h can initialize nlist structures statically.
+ */
+struct nlist {
+#ifdef _AOUT_INCLUDE_
+ union {
+ char *n_name; /* symbol name (in memory) */
+ long n_strx; /* file string table offset (on disk) */
+ } n_un;
+#else
+ char *n_name; /* symbol name (in memory) */
+#endif
+
+#define N_UNDF 0x00 /* undefined */
+#define N_ABS 0x02 /* absolute address */
+#define N_TEXT 0x04 /* text segment */
+#define N_DATA 0x06 /* data segment */
+#define N_BSS 0x08 /* bss segment */
+#define N_COMM 0x12 /* common reference */
+#define N_FN 0x1e /* file name */
+
+#define N_EXT 0x01 /* external (global) bit, OR'ed in */
+#define N_TYPE 0x1e /* mask for all the type bits */
+ unsigned char n_type; /* type defines */
+
+ char n_other; /* spare */
+#define n_hash n_desc /* used internally by ld(1); XXX */
+ short n_desc; /* used by stab entries */
+ unsigned long n_value; /* address/value of the symbol */
+};
+
+#define N_FORMAT "%08x" /* namelist value format; XXX */
+#define N_STAB 0x0e0 /* mask for debugger symbols -- stab(5) */
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int nlist __P((const char *, struct nlist *));
+__END_DECLS
+
+#endif /* !_NLIST_H_ */
diff --git a/sys/sys/rlist.h b/sys/sys/rlist.h
new file mode 100644
index 0000000..f241f0f
--- /dev/null
+++ b/sys/sys/rlist.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 1992 William Jolitz. All rights reserved.
+ * Written by William Jolitz 1/92
+ *
+ * Redistribution and use in source and binary forms are freely permitted
+ * provided that the above copyright notice and attribution and date of work
+ * and this paragraph are duplicated in all such forms.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Resource lists.
+ *
+ * Usage:
+ * rlist_free(&swapmap, 100, 200); add space to swapmap
+ * rlist_alloc(&swapmap, 100, &loc); obtain 100 sectors from swap
+ *
+ * from: unknown?
+ * $Id: rlist.h,v 1.5 1993/11/07 17:52:59 wollman Exp $
+ */
+
+#ifndef _SYS_RLIST_H_
+#define _SYS_RLIST_H_
+
+/* A resource list element. */
+struct rlist {
+ unsigned rl_start; /* boundaries of extent - inclusive */
+ unsigned rl_end; /* boundaries of extent - inclusive */
+ struct rlist *rl_next; /* next list entry, if present */
+};
+
+/* Functions to manipulate resource lists. */
+extern void rlist_free __P((struct rlist **, unsigned, unsigned));
+int rlist_alloc __P((struct rlist **, unsigned, unsigned *));
+extern void rlist_destroy __P((struct rlist **));
+
+
+/* heads of lists */
+extern struct rlist *swapmap;
+
+#endif /* _SYS_RLIST_H_ */
diff --git a/sys/sys/scsiio.h b/sys/sys/scsiio.h
new file mode 100644
index 0000000..05753e4
--- /dev/null
+++ b/sys/sys/scsiio.h
@@ -0,0 +1,63 @@
+
+#ifndef _SYS_SCSIIO_H_
+#define _SYS_SCSIIO_H_
+
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#define SENSEBUFLEN 48
+
+typedef struct scsireq {
+ u_long flags; /* info about the request status and type */
+ u_long timeout;
+ u_char cmd[16]; /* 12 is actually the max */
+ u_char cmdlen;
+ caddr_t databuf; /* address in user space of buffer */
+ u_long datalen; /* size of user buffer (request) */
+ u_long datalen_used; /* size of user buffer (used)*/
+ u_char sense[SENSEBUFLEN]; /* returned sense will be in here */
+ u_char senselen; /* sensedata request size (MAX of SENSEBUFLEN)*/
+ u_char senselen_used; /* return value only */
+ u_char status; /* what the scsi status was from the adapter */
+ u_char retsts; /* the return status for the command */
+ int error; /* error bits */
+} scsireq_t;
+
+/* bit defintions for flags */
+#define SCCMD_READ 0x00000001
+#define SCCMD_WRITE 0x00000002
+#define SCCMD_IOV 0x00000004
+#define SCCMD_ESCAPE 0x00000010
+#define SCCMD_TARGET 0x00000020
+
+
+/* definitions for the return status (retsts) */
+#define SCCMD_OK 0x00
+#define SCCMD_TIMEOUT 0x01
+#define SCCMD_BUSY 0x02
+#define SCCMD_SENSE 0x03
+#define SCCMD_UNKNOWN 0x04
+
+#define SCIOCCOMMAND _IOWR('Q', 1, scsireq_t)
+
+#define SC_DB_CMDS 0x00000001 /* show all scsi cmds and errors */
+#define SC_DB_FLOW 0x00000002 /* show routines entered */
+#define SC_DB_FLOW2 0x00000004 /* show path INSIDE routines */
+#define SC_DB_DMA 0x00000008 /* show DMA segments etc */
+#define SCIOCDEBUG _IOW('Q', 2, int) /* from 0 to 15 */
+
+struct scsi_addr {
+ int scbus; /* -1 if wildcard */
+ int target; /* -1 if wildcard */
+ int lun; /* -1 if wildcard */
+} ;
+
+#define SCIOCREPROBE _IOW('Q', 3, struct scsi_addr) /* look for new devs */
+#define SCIOCIDENTIFY _IOR('Q', 4, struct scsi_addr) /* where are you? */
+#define SCIOCDECONFIG _IO('Q', 5) /* please dissappear */
+#define SCIOCRECONFIG _IO('Q', 6) /* please check again */
+#define SCIOCRESET _IO('Q', 7) /* reset the device */
+
+
+#endif /* _SYS_SCSIIO_H_ */
diff --git a/sys/sys/soundcard.h b/sys/sys/soundcard.h
new file mode 100644
index 0000000..ce28a14
--- /dev/null
+++ b/sys/sys/soundcard.h
@@ -0,0 +1,763 @@
+#ifndef _SOUNDCARD_H_
+#define _SOUNDCARD_H_
+/*
+ * Copyright by Hannu Savolainen 1993
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *
+ */
+
+ /*
+ * If you make modifications to this file, please contact me before
+ * distributing the modified version. There is already enough
+ * divercity in the world.
+ *
+ * Regards,
+ * Hannu Savolainen
+ * hannu@voxware.pp.fi, Hannu.Savolainen@helsinki.fi
+ */
+
+#define SOUND_VERSION 205
+#define VOXWARE
+
+#include <sys/ioctl.h>
+
+/*
+ * Supported card ID numbers (Should be somewhere else?)
+ */
+
+#define SNDCARD_ADLIB 1
+#define SNDCARD_SB 2
+#define SNDCARD_PAS 3
+#define SNDCARD_GUS 4
+#define SNDCARD_MPU401 5
+#define SNDCARD_SB16 6
+#define SNDCARD_SB16MIDI 7
+
+/***********************************
+ * IOCTL Commands for /dev/sequencer
+ */
+
+#ifndef _IOWR
+/* @(#)ioctlp.h */
+
+/* Ioctl's have the command encoded in the lower word,
+ * and the size of any in or out parameters in the upper
+ * word. The high 2 bits of the upper word are used
+ * to encode the in/out status of the parameter; for now
+ * we restrict parameters to at most 128 bytes.
+ */
+/* #define IOCTYPE (0xff<<8) */
+#define IOCPARM_MASK 0x7f /* parameters must be < 128 bytes */
+#define IOC_VOID 0x00000000 /* no parameters */
+#define IOC_OUT 0x20000000 /* copy out parameters */
+#define IOC_IN 0x40000000 /* copy in parameters */
+#define IOC_INOUT (IOC_IN|IOC_OUT)
+/* the 0x20000000 is so we can distinguish new ioctl's from old */
+#define _IO(x,y) ((int)(IOC_VOID|(x<<8)|y))
+#define _IOR(x,y,t) ((int)(IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y))
+#define _IOW(x,y,t) ((int)(IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y))
+/* this should be _IORW, but stdio got there first */
+#define _IOWR(x,y,t) ((int)(IOC_INOUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y))
+#endif /* !_IOWR */
+
+#define SNDCTL_SEQ_RESET _IO ('Q', 0)
+#define SNDCTL_SEQ_SYNC _IO ('Q', 1)
+#define SNDCTL_SYNTH_INFO _IOWR('Q', 2, struct synth_info)
+#define SNDCTL_SEQ_CTRLRATE _IOWR('Q', 3, int) /* Set/get timer resolution (HZ) */
+#define SNDCTL_SEQ_GETOUTCOUNT _IOR ('Q', 4, int)
+#define SNDCTL_SEQ_GETINCOUNT _IOR ('Q', 5, int)
+#define SNDCTL_SEQ_PERCMODE _IOW ('Q', 6, int)
+#define SNDCTL_FM_LOAD_INSTR _IOW ('Q', 7, struct sbi_instrument) /* Valid for FM only */
+#define SNDCTL_SEQ_TESTMIDI _IOW ('Q', 8, int)
+#define SNDCTL_SEQ_RESETSAMPLES _IOW ('Q', 9, int)
+#define SNDCTL_SEQ_NRSYNTHS _IOR ('Q',10, int)
+#define SNDCTL_SEQ_NRMIDIS _IOR ('Q',11, int)
+#define SNDCTL_MIDI_INFO _IOWR('Q',12, struct midi_info)
+#define SNDCTL_SEQ_TRESHOLD _IOW ('Q',13, int)
+#define SNDCTL_SYNTH_MEMAVL _IOWR('Q',14, int) /* in=dev#, out=memsize */
+#define SNDCTL_FM_4OP_ENABLE _IOW ('Q',15, int) /* in=dev# */
+#define SNDCTL_PMGR_ACCESS _IOWR('Q',16, struct patmgr_info)
+
+/*
+ * Sample loading mechanism for internal synthesizers (/dev/sequencer)
+ * The following patch_info structure has been designed to support
+ * Gravis UltraSound. It tries to be universal format for uploading
+ * sample based patches but is propably too limited.
+ */
+
+struct patch_info {
+ short key; /* Use GUS_PATCH here */
+#define GUS_PATCH 0x04fd
+#define OBSOLETE_GUS_PATCH 0x02fd
+ short device_no; /* Synthesizer number */
+ short instr_no; /* Midi pgm# */
+
+ unsigned long mode;
+/*
+ * The least significant byte has the same format than the GUS .PAT
+ * files
+ */
+#define WAVE_16_BITS 0x01 /* bit 0 = 8 or 16 bit wave data. */
+#define WAVE_UNSIGNED 0x02 /* bit 1 = Signed - Unsigned data. */
+#define WAVE_LOOPING 0x04 /* bit 2 = looping enabled-1. */
+#define WAVE_BIDIR_LOOP 0x08 /* bit 3 = Set is bidirectional looping. */
+#define WAVE_LOOP_BACK 0x10 /* bit 4 = Set is looping backward. */
+#define WAVE_SUSTAIN_ON 0x20 /* bit 5 = Turn sustaining on. (Env. pts. 3)*/
+#define WAVE_ENVELOPES 0x40 /* bit 6 = Enable envelopes - 1 */
+ /* (use the env_rate/env_offs fields). */
+/* Linux specific bits */
+#define WAVE_VIBRATO 0x00010000 /* The vibrato info is valid */
+#define WAVE_TREMOLO 0x00020000 /* The tremolo info is valid */
+#define WAVE_SCALE 0x00040000 /* The scaling info is valid */
+/* Other bits must be zeroed */
+
+ long len; /* Size of the wave data in bytes */
+ long loop_start, loop_end; /* Byte offsets from the beginning */
+
+/*
+ * The base_freq and base_note fields are used when computing the
+ * playback speed for a note. The base_note defines the tone frequency
+ * which is heard if the sample is played using the base_freq as the
+ * playback speed.
+ *
+ * The low_note and high_note fields define the minimum and maximum note
+ * frequencies for which this sample is valid. It is possible to define
+ * more than one samples for a instrument number at the same time. The
+ * low_note and high_note fields are used to select the most suitable one.
+ *
+ * The fields base_note, high_note and low_note should contain
+ * the note frequency multiplied by 1000. For example value for the
+ * middle A is 440*1000.
+ */
+
+ unsigned int base_freq;
+ unsigned long base_note;
+ unsigned long high_note;
+ unsigned long low_note;
+ int panning; /* -128=left, 127=right */
+ int detuning;
+
+/* New fields introduced in version 1.99.5 */
+
+ /* Envelope. Enabled by mode bit WAVE_ENVELOPES */
+ unsigned char env_rate[ 6 ]; /* GUS HW ramping rate */
+ unsigned char env_offset[ 6 ]; /* 255 == 100% */
+
+ /*
+ * The tremolo, vibrato and scale info are not supported yet.
+ * Enable by setting the mode bits WAVE_TREMOLO, WAVE_VIBRATO or
+ * WAVE_SCALE
+ */
+
+ unsigned char tremolo_sweep;
+ unsigned char tremolo_rate;
+ unsigned char tremolo_depth;
+
+ unsigned char vibrato_sweep;
+ unsigned char vibrato_rate;
+ unsigned char vibrato_depth;
+
+ int scale_frequency;
+ unsigned int scale_factor; /* from 0 to 2048 or 0 to 2 */
+
+ int volume;
+ int spare[4];
+ char data[1]; /* The waveform data starts here */
+ };
+
+
+/*
+ * Patch management interface (/dev/sequencer, /dev/patmgr#)
+ * Don't use these calls if you want to maintain compatibility with
+ * the future versions of the driver.
+ */
+
+#define PS_NO_PATCHES 0 /* No patch support on device */
+#define PS_MGR_NOT_OK 1 /* Plain patch support (no mgr) */
+#define PS_MGR_OK 2 /* Patch manager supported */
+#define PS_MANAGED 3 /* Patch manager running */
+
+#define SNDCTL_PMGR_IFACE _IOWR('P', 1, struct patmgr_info)
+
+/*
+ * The patmgr_info is a fixed size structure which is used for two
+ * different purposes. The intended use is for communication between
+ * the application using /dev/sequencer and the patch manager daemon
+ * associated with a synthesizer device (ioctl(SNDCTL_PMGR_ACCESS)).
+ *
+ * This structure is also used with ioctl(SNDCTL_PGMR_IFACE) which allows
+ * a patch manager daemon to read and write device parameters. This
+ * ioctl available through /dev/sequencer also. Avoid using it since it's
+ * extremely hardware dependent. In addition access trough /dev/sequencer
+ * may confuse the patch manager daemon.
+ */
+
+struct patmgr_info { /* Note! size must be < 4k since kmalloc() is used */
+ unsigned long key; /* Don't worry. Reserved for communication
+ between the patch manager and the driver. */
+#define PM_K_EVENT 1 /* Event from the /dev/sequencer driver */
+#define PM_K_COMMAND 2 /* Request from a application */
+#define PM_K_RESPONSE 3 /* From patmgr to application */
+#define PM_ERROR 4 /* Error returned by the patmgr */
+ int device;
+ int command;
+
+/*
+ * Commands 0x000 to 0xfff reserved for patch manager programs
+ */
+#define PM_GET_DEVTYPE 1 /* Returns type of the patch mgr interface of dev */
+#define PMTYPE_FM2 1 /* 2 OP fm */
+#define PMTYPE_FM4 2 /* Mixed 4 or 2 op FM (OPL-3) */
+#define PMTYPE_WAVE 3 /* Wave table synthesizer (GUS) */
+#define PM_GET_NRPGM 2 /* Returns max # of midi programs in parm1 */
+#define PM_GET_PGMMAP 3 /* Returns map of loaded midi programs in data8 */
+#define PM_GET_PGM_PATCHES 4 /* Return list of patches of a program (parm1) */
+#define PM_GET_PATCH 5 /* Return patch header of patch parm1 */
+#define PM_SET_PATCH 6 /* Set patch header of patch parm1 */
+#define PM_READ_PATCH 7 /* Read patch (wave) data */
+#define PM_WRITE_PATCH 8 /* Write patch (wave) data */
+
+/*
+ * Commands 0x1000 to 0xffff are for communication between the patch manager
+ * and the client
+ */
+#define _PM_LOAD_PATCH 0x100
+
+/*
+ * Commands above 0xffff reserved for device specific use
+ */
+
+ long parm1;
+ long parm2;
+ long parm3;
+
+ union {
+ unsigned char data8[4000];
+ unsigned short data16[2000];
+ unsigned long data32[1000];
+ struct patch_info patch;
+ } data;
+ };
+
+/*
+ * When a patch manager daemon is present, it will be informed by the
+ * driver when something important happens. For example when the
+ * /dev/sequencer is opened or closed. A record with key == PM_K_EVENT is
+ * returned. The command field contains the event type:
+ */
+#define PM_E_OPENED 1 /* /dev/sequencer opened */
+#define PM_E_CLOSED 2 /* /dev/sequencer closed */
+#define PM_E_PATCH_RESET 3 /* SNDCTL_RESETSAMPLES called */
+#define PM_E_PATCH_LOADED 4 /* A patch has been loaded by appl */
+
+/*
+ * /dev/sequencer input events.
+ *
+ * The data written to the /dev/sequencer is a stream of events. Events
+ * are records of 4 or 8 bytes. The first byte defines the size.
+ * Any number of events can be written with a write call. There
+ * is a set of macros for sending these events. Use these macros if you
+ * want to maximize portability of your program.
+ *
+ * Events SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO. Are also input events.
+ * (All input events are currently 4 bytes long. Be prepared to support
+ * 8 byte events also. If you receive any event having first byte >= 0xf0,
+ * it's a 8 byte event.
+ *
+ * The events are documented at the end of this file.
+ *
+ * Normal events (4 bytes)
+ * There is also a 8 byte version of most of the 4 byte events. The
+ * 8 byte one is recommended.
+ */
+#define SEQ_NOTEOFF 0
+#define SEQ_FMNOTEOFF SEQ_NOTEOFF /* Just old name */
+#define SEQ_NOTEON 1
+#define SEQ_FMNOTEON SEQ_NOTEON
+#define SEQ_WAIT 2
+#define SEQ_PGMCHANGE 3
+#define SEQ_FMPGMCHANGE SEQ_PGMCHANGE
+#define SEQ_SYNCTIMER 4
+#define SEQ_MIDIPUTC 5
+#define SEQ_DRUMON 6 /*** OBSOLETE ***/
+#define SEQ_DRUMOFF 7 /*** OBSOLETE ***/
+#define SEQ_ECHO 8 /* For synching programs with output */
+#define SEQ_AFTERTOUCH 9
+#define SEQ_CONTROLLER 10
+#define CTRL_PITCH_BENDER 255
+#define CTRL_PITCH_BENDER_RANGE 254
+#define CTRL_EXPRESSION 253
+#define CTRL_MAIN_VOLUME 252
+#define SEQ_BALANCE 11
+#define SEQ_VOLMODE 12
+
+/*
+ * Volume mode decides how volumes are used
+ */
+
+#define VOL_METHOD_ADAGIO 1
+#define VOL_METHOD_LINEAR 2
+
+/*
+ * Note! SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO are used also as
+ * input events.
+ */
+
+/*
+ * Event codes 0xf0 to 0xfc are reserved for future extensions.
+ */
+
+#define SEQ_FULLSIZE 0xfd /* Long events */
+/*
+ * SEQ_FULLSIZE events are used for loading patches/samples to the
+ * synthesizer devices. These events are passed directly to the driver
+ * of the associated synthesizer device. There is no limit to the size
+ * of the extended events. These events are not queued but executed
+ * immediately when the write() is called (execution can take several
+ * seconds of time).
+ *
+ * When a SEQ_FULLSIZE message is written to the device, it must
+ * be written using exactly one write() call. Other events cannot
+ * be mixed to the same write.
+ *
+ * For FM synths (YM3812/OPL3) use struct sbi_instrument and write it to the
+ * /dev/sequencer. Don't write other data together with the instrument structure
+ * Set the key field of the structure to FM_PATCH. The device field is used to
+ * route the patch to the corresponding device.
+ *
+ * For Gravis UltraSound use struct patch_info. Initialize the key field
+ * to GUS_PATCH.
+ */
+#define SEQ_PRIVATE 0xfe /* Low level HW dependent events (8 bytes) */
+#define SEQ_EXTENDED 0xff /* Extended events (8 bytes) */
+
+/*
+ * Extended events for synthesizers (8 bytes)
+ *
+ * Format:
+ *
+ * b0 = SEQ_EXTENDED
+ * b1 = command
+ * b2 = device
+ * b3-b7 = parameters
+ *
+ * Command b3 b4 b5 b6 b7
+ * ----------------------------------------------------------------------------
+ * SEQ_NOTEON voice note volume 0 0
+ * SEQ_NOTEOFF voice note volume 0 0
+ * SEQ_PGMCHANGE voice pgm 0 0 0
+ * SEQ_DRUMON (voice) drum# volume 0 0
+ * SEQ_DRUMOFF (voice) drum# volume 0 0
+ */
+
+/*
+ * Record for FM patches
+ */
+
+typedef unsigned char sbi_instr_data[32];
+
+struct sbi_instrument {
+ unsigned short key; /* Initialize to FM_PATCH or OPL3_PATCH */
+#define FM_PATCH 0x01fd
+#define OPL3_PATCH 0x03fd
+ short device; /* Synth# (0-4) */
+ int channel; /* Program# to be initialized */
+ sbi_instr_data operators; /* Register settings for operator cells (.SBI format) */
+ };
+
+struct synth_info { /* Read only */
+ char name[30];
+ int device; /* 0-N. INITIALIZE BEFORE CALLING */
+ int synth_type;
+#define SYNTH_TYPE_FM 0
+#define SYNTH_TYPE_SAMPLE 1
+
+ int synth_subtype;
+#define FM_TYPE_ADLIB 0x00
+#define FM_TYPE_OPL3 0x01
+
+#define SAMPLE_TYPE_GUS 0x10
+
+ int perc_mode; /* No longer supported */
+ int nr_voices;
+ int nr_drums; /* Obsolete field */
+ int instr_bank_size;
+ unsigned long capabilities;
+#define SYNTH_CAP_PERCMODE 0x00000001 /* No longer used */
+#define SYNTH_CAP_OPL3 0x00000002 /* Set if OPL3 supported */
+ int dummies[19]; /* Reserve space */
+ };
+
+struct midi_info {
+ char name[30];
+ int device; /* 0-N. INITIALIZE BEFORE CALLING */
+ unsigned long capabilities; /* To be defined later */
+ int dev_type;
+ int dummies[18]; /* Reserve space */
+ };
+
+/********************************************
+ * IOCTL commands for /dev/dsp and /dev/audio
+ */
+
+#define SNDCTL_DSP_RESET _IO ('P', 0)
+#define SNDCTL_DSP_SYNC _IO ('P', 1)
+#define SNDCTL_DSP_SPEED _IOWR('P', 2, int)
+#define SNDCTL_DSP_STEREO _IOWR('P', 3, int)
+#define SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int)
+#define SNDCTL_DSP_SAMPLESIZE _IOWR('P', 5, int) /* 8, 12 or 16 */
+#define SOUND_PCM_WRITE_CHANNELS _IOWR('P', 6, int)
+#define SOUND_PCM_WRITE_FILTER _IOWR('P', 7, int)
+#define SNDCTL_DSP_POST _IO ('P', 8)
+#define SNDCTL_DSP_SUBDIVIDE _IOWR('P', 9, int)
+
+#define SOUND_PCM_READ_RATE _IOR ('P', 2, int)
+#define SOUND_PCM_READ_CHANNELS _IOR ('P', 6, int)
+#define SOUND_PCM_READ_BITS _IOR ('P', 5, int)
+#define SOUND_PCM_READ_FILTER _IOR ('P', 7, int)
+
+/* Some alias names */
+#define SOUND_PCM_WRITE_BITS SNDCTL_DSP_SAMPLESIZE
+#define SOUND_PCM_WRITE_RATE SNDCTL_DSP_SPEED
+#define SOUND_PCM_POST SNDCTL_DSP_POST
+#define SOUND_PCM_RESET SNDCTL_DSP_RESET
+#define SOUND_PCM_SYNC SNDCTL_DSP_SYNC
+#define SOUND_PCM_SUBDIVIDE SNDCTL_DSP_SUBDIVIDE
+
+/*********************************************
+ * IOCTL commands for /dev/mixer
+ */
+
+/*
+ * Mixer devices
+ *
+ * There can be up to 20 different analog mixer channels. The
+ * SOUND_MIXER_NRDEVICES gives the currently supported maximum.
+ * The SOUND_MIXER_READ_DEVMASK returns a bitmask which tells
+ * the devices supported by the particular mixer.
+ */
+
+#define SOUND_MIXER_NRDEVICES 12
+#define SOUND_MIXER_VOLUME 0
+#define SOUND_MIXER_BASS 1
+#define SOUND_MIXER_TREBLE 2
+#define SOUND_MIXER_SYNTH 3
+#define SOUND_MIXER_PCM 4
+#define SOUND_MIXER_SPEAKER 5
+#define SOUND_MIXER_LINE 6
+#define SOUND_MIXER_MIC 7
+#define SOUND_MIXER_CD 8
+#define SOUND_MIXER_IMIX 9 /* Recording monitor */
+#define SOUND_MIXER_ALTPCM 10
+#define SOUND_MIXER_RECLEV 11 /* Recording level */
+
+/* Some on/off settings (SOUND_SPECIAL_MIN - SOUND_SPECIAL_MAX) */
+/* Not counted to SOUND_MIXER_NRDEVICES, but use the same number space */
+#define SOUND_ONOFF_MIN 28
+#define SOUND_ONOFF_MAX 30
+#define SOUND_MIXER_MUTE 28 /* 0 or 1 */
+#define SOUND_MIXER_ENHANCE 29 /* Enhanced stereo (0, 40, 60 or 80) */
+#define SOUND_MIXER_LOUD 30 /* 0 or 1 */
+
+/* Note! Number 31 cannot be used since the sign bit is reserved */
+
+#define SOUND_DEVICE_LABELS {"Vol ", "Bass ", "Trebl", "Synth", "Pcm ", "Spkr ", "Line ", \
+ "Mic ", "CD ", "Mix ", "Pcm2 ", "rec"}
+
+#define SOUND_DEVICE_NAMES {"vol", "bass", "treble", "synth", "pcm", "speaker", "line", \
+ "mic", "cd", "mix", "pcm2", "rec"}
+
+/* Device bitmask identifiers */
+
+#define SOUND_MIXER_RECSRC 0xff /* Arg contains a bit for each recording source */
+#define SOUND_MIXER_DEVMASK 0xfe /* Arg contains a bit for each supported device */
+#define SOUND_MIXER_RECMASK 0xfd /* Arg contains a bit for each supported recording source */
+#define SOUND_MIXER_CAPS 0xfc
+ #define SOUND_CAP_EXCL_INPUT 0x00000001 /* Only one recording source at a time */
+#define SOUND_MIXER_STEREODEVS 0xfb /* Mixer channels supporting stereo */
+
+/* Device mask bits */
+
+#define SOUND_MASK_VOLUME (1 << SOUND_MIXER_VOLUME)
+#define SOUND_MASK_BASS (1 << SOUND_MIXER_BASS)
+#define SOUND_MASK_TREBLE (1 << SOUND_MIXER_TREBLE)
+#define SOUND_MASK_SYNTH (1 << SOUND_MIXER_SYNTH)
+#define SOUND_MASK_PCM (1 << SOUND_MIXER_PCM)
+#define SOUND_MASK_SPEAKER (1 << SOUND_MIXER_SPEAKER)
+#define SOUND_MASK_LINE (1 << SOUND_MIXER_LINE)
+#define SOUND_MASK_MIC (1 << SOUND_MIXER_MIC)
+#define SOUND_MASK_CD (1 << SOUND_MIXER_CD)
+#define SOUND_MASK_IMIX (1 << SOUND_MIXER_IMIX)
+#define SOUND_MASK_ALTPCM (1 << SOUND_MIXER_ALTPCM)
+#define SOUND_MASK_RECLEV (1 << SOUND_MIXER_RECLEV)
+
+#define SOUND_MASK_MUTE (1 << SOUND_MIXER_MUTE)
+#define SOUND_MASK_ENHANCE (1 << SOUND_MIXER_ENHANCE)
+#define SOUND_MASK_LOUD (1 << SOUND_MIXER_LOUD)
+
+#define MIXER_READ(dev) _IOR('M', dev, int)
+#define SOUND_MIXER_READ_VOLUME MIXER_READ(SOUND_MIXER_VOLUME)
+#define SOUND_MIXER_READ_BASS MIXER_READ(SOUND_MIXER_BASS)
+#define SOUND_MIXER_READ_TREBLE MIXER_READ(SOUND_MIXER_TREBLE)
+#define SOUND_MIXER_READ_SYNTH MIXER_READ(SOUND_MIXER_SYNTH)
+#define SOUND_MIXER_READ_PCM MIXER_READ(SOUND_MIXER_PCM)
+#define SOUND_MIXER_READ_SPEAKER MIXER_READ(SOUND_MIXER_SPEAKER)
+#define SOUND_MIXER_READ_LINE MIXER_READ(SOUND_MIXER_LINE)
+#define SOUND_MIXER_READ_MIC MIXER_READ(SOUND_MIXER_MIC)
+#define SOUND_MIXER_READ_CD MIXER_READ(SOUND_MIXER_CD)
+#define SOUND_MIXER_READ_IMIX MIXER_READ(SOUND_MIXER_IMIX)
+#define SOUND_MIXER_READ_ALTPCM MIXER_READ(SOUND_MIXER_ALTPCM)
+#define SOUND_MIXER_READ_RECLEV MIXER_READ(SOUND_MIXER_RECLEV)
+#define SOUND_MIXER_READ_MUTE MIXER_READ(SOUND_MIXER_MUTE)
+#define SOUND_MIXER_READ_ENHANCE MIXER_READ(SOUND_MIXER_ENHANCE)
+#define SOUND_MIXER_READ_LOUD MIXER_READ(SOUND_MIXER_LOUD)
+
+#define SOUND_MIXER_READ_RECSRC MIXER_READ(SOUND_MIXER_RECSRC)
+#define SOUND_MIXER_READ_DEVMASK MIXER_READ(SOUND_MIXER_DEVMASK)
+#define SOUND_MIXER_READ_RECMASK MIXER_READ(SOUND_MIXER_RECMASK)
+#define SOUND_MIXER_READ_STEREODEVS MIXER_READ(SOUND_MIXER_STEREODEVS)
+#define SOUND_MIXER_READ_CAPS MIXER_READ(SOUND_MIXER_CAPS)
+
+#define MIXER_WRITE(dev) _IOWR('M', dev, int)
+#define SOUND_MIXER_WRITE_VOLUME MIXER_WRITE(SOUND_MIXER_VOLUME)
+#define SOUND_MIXER_WRITE_BASS MIXER_WRITE(SOUND_MIXER_BASS)
+#define SOUND_MIXER_WRITE_TREBLE MIXER_WRITE(SOUND_MIXER_TREBLE)
+#define SOUND_MIXER_WRITE_SYNTH MIXER_WRITE(SOUND_MIXER_SYNTH)
+#define SOUND_MIXER_WRITE_PCM MIXER_WRITE(SOUND_MIXER_PCM)
+#define SOUND_MIXER_WRITE_SPEAKER MIXER_WRITE(SOUND_MIXER_SPEAKER)
+#define SOUND_MIXER_WRITE_LINE MIXER_WRITE(SOUND_MIXER_LINE)
+#define SOUND_MIXER_WRITE_MIC MIXER_WRITE(SOUND_MIXER_MIC)
+#define SOUND_MIXER_WRITE_CD MIXER_WRITE(SOUND_MIXER_CD)
+#define SOUND_MIXER_WRITE_IMIX MIXER_WRITE(SOUND_MIXER_IMIX)
+#define SOUND_MIXER_WRITE_ALTPCM MIXER_WRITE(SOUND_MIXER_ALTPCM)
+#define SOUND_MIXER_WRITE_RECLEV MIXER_WRITE(SOUND_MIXER_RECLEV)
+#define SOUND_MIXER_WRITE_MUTE MIXER_WRITE(SOUND_MIXER_MUTE)
+#define SOUND_MIXER_WRITE_ENHANCE MIXER_WRITE(SOUND_MIXER_ENHANCE)
+#define SOUND_MIXER_WRITE_LOUD MIXER_WRITE(SOUND_MIXER_LOUD)
+
+#define SOUND_MIXER_WRITE_RECSRC MIXER_WRITE(SOUND_MIXER_RECSRC)
+
+/*
+ * The following mixer ioctl calls are compatible with the BSD driver by
+ * Steve Haehnichen <shaehnic@ucsd.edu>
+ *
+ * Since this interface is entirely SB specific, it will be dropped in the
+ * near future.
+ */
+
+typedef unsigned char S_BYTE;
+typedef unsigned char S_FLAG;
+struct stereo_vol
+{
+ S_BYTE l; /* Left volume */
+ S_BYTE r; /* Right volume */
+};
+
+#define MIXER_IOCTL_SET_LEVELS _IOW ('s', 20, struct sb_mixer_levels)
+#define MIXER_IOCTL_SET_PARAMS _IOW ('s', 21, struct sb_mixer_params)
+#define MIXER_IOCTL_READ_LEVELS _IOR ('s', 22, struct sb_mixer_levels)
+#define MIXER_IOCTL_READ_PARAMS _IOR ('s', 23, struct sb_mixer_params)
+#define MIXER_IOCTL_RESET _IO ('s', 24)
+
+/*
+ * Mixer volume levels for MIXER_IOCTL_SET_VOL & MIXER_IOCTL_READ_VOL
+ */
+struct sb_mixer_levels
+{
+ struct stereo_vol master; /* Master volume */
+ struct stereo_vol voc; /* DSP Voice volume */
+ struct stereo_vol fm; /* FM volume */
+ struct stereo_vol line; /* Line-in volume */
+ struct stereo_vol cd; /* CD audio */
+ S_BYTE mic; /* Microphone level */
+};
+
+/*
+ * Mixer parameters for MIXER_IOCTL_SET_PARAMS & MIXER_IOCTL_READ_PARAMS
+ */
+struct sb_mixer_params
+{
+ S_BYTE record_source; /* Recording source (See SRC_xxx below) */
+ S_FLAG hifreq_filter; /* Filter frequency (hi/low) */
+ S_FLAG filter_input; /* ANFI input filter */
+ S_FLAG filter_output; /* DNFI output filter */
+ S_FLAG dsp_stereo; /* 1 if DSP is in Stereo mode */
+};
+
+#define SRC_MIC 1 /* Select Microphone recording source */
+#define SRC_CD 3 /* Select CD recording source */
+#define SRC_LINE 7 /* Use Line-in for recording source */
+
+#if !defined(KERNEL) && !defined(INKERNEL)
+/*
+ * Some convenience macros to simplify programming of the
+ * /dev/sequencer interface
+ *
+ * These macros define the API which should be used when possible.
+ */
+
+void seqbuf_dump(void); /* This function must be provided by programs */
+
+/* Sample seqbuf_dump() implementation:
+ *
+ * SEQ_DEFINEBUF (2048); -- Defines a buffer for 2048 bytes
+ *
+ * int seqfd; -- The file descriptor for /dev/sequencer.
+ *
+ * void
+ * seqbuf_dump ()
+ * {
+ * if (_seqbufptr)
+ * if (write (seqfd, _seqbuf, _seqbufptr) == -1)
+ * {
+ * perror ("write /dev/sequencer");
+ * exit (-1);
+ * }
+ * _seqbufptr = 0;
+ * }
+ */
+
+#define SEQ_DEFINEBUF(len) unsigned char _seqbuf[len]; int _seqbuflen = len; int _seqbufptr = 0
+#define SEQ_DECLAREBUF() extern unsigned char _seqbuf[]; extern int _seqbuflen;extern int _seqbufptr
+#define SEQ_PM_DEFINES struct patmgr_info _pm_info
+#define _SEQ_NEEDBUF(len) if ((_seqbufptr+(len)) > _seqbuflen) seqbuf_dump()
+#define _SEQ_ADVBUF(len) _seqbufptr += len
+#define SEQ_DUMPBUF seqbuf_dump
+#define PM_LOAD_PATCH(dev, bank, pgm) (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \
+ _pm_info.device=dev, _pm_info.data.data8[0]=pgm, \
+ _pm_info.parm1 = bank, _pm_info.parm2 = 1, \
+ ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info))
+#define PM_LOAD_PATCHES(dev, bank, pgm) (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \
+ _pm_info.device=dev, memcpy(_pm_info.data.data8, pgm, 128), \
+ _pm_info.parm1 = bank, _pm_info.parm2 = 128, \
+ ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info))
+
+#define SEQ_VOLUME_MODE(dev, mode) {_SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+ _seqbuf[_seqbufptr+1] = SEQ_VOLMODE;\
+ _seqbuf[_seqbufptr+2] = (dev);\
+ _seqbuf[_seqbufptr+3] = (mode);\
+ _seqbuf[_seqbufptr+4] = 0;\
+ _seqbuf[_seqbufptr+5] = 0;\
+ _seqbuf[_seqbufptr+6] = 0;\
+ _seqbuf[_seqbufptr+7] = 0;\
+ _SEQ_ADVBUF(8);}
+
+#define SEQ_START_NOTE(dev, voice, note, vol) {_SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+ _seqbuf[_seqbufptr+1] = SEQ_NOTEON;\
+ _seqbuf[_seqbufptr+2] = (dev);\
+ _seqbuf[_seqbufptr+3] = (voice);\
+ _seqbuf[_seqbufptr+4] = (note);\
+ _seqbuf[_seqbufptr+5] = (vol);\
+ _seqbuf[_seqbufptr+6] = 0;\
+ _seqbuf[_seqbufptr+7] = 0;\
+ _SEQ_ADVBUF(8);}
+
+#define SEQ_STOP_NOTE(dev, voice, note, vol) {_SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+ _seqbuf[_seqbufptr+1] = SEQ_NOTEOFF;\
+ _seqbuf[_seqbufptr+2] = (dev);\
+ _seqbuf[_seqbufptr+3] = (voice);\
+ _seqbuf[_seqbufptr+4] = (note);\
+ _seqbuf[_seqbufptr+5] = (vol);\
+ _seqbuf[_seqbufptr+6] = 0;\
+ _seqbuf[_seqbufptr+7] = 0;\
+ _SEQ_ADVBUF(8);}
+
+#define SEQ_CHN_PRESSURE(dev, voice, pressure) {_SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+ _seqbuf[_seqbufptr+1] = SEQ_AFTERTOUCH;\
+ _seqbuf[_seqbufptr+2] = (dev);\
+ _seqbuf[_seqbufptr+3] = (voice);\
+ _seqbuf[_seqbufptr+4] = (pressure);\
+ _seqbuf[_seqbufptr+5] = 0;\
+ _seqbuf[_seqbufptr+6] = 0;\
+ _seqbuf[_seqbufptr+7] = 0;\
+ _SEQ_ADVBUF(8);}
+
+#define SEQ_PANNING(dev, voice, pos) {_SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+ _seqbuf[_seqbufptr+1] = SEQ_BALANCE;\
+ _seqbuf[_seqbufptr+2] = (dev);\
+ _seqbuf[_seqbufptr+3] = (voice);\
+ (char)_seqbuf[_seqbufptr+4] = (pos);\
+ _seqbuf[_seqbufptr+5] = 0;\
+ _seqbuf[_seqbufptr+6] = 0;\
+ _seqbuf[_seqbufptr+7] = 0;\
+ _SEQ_ADVBUF(8);}
+
+#define SEQ_CONTROL(dev, voice, controller, value) {_SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+ _seqbuf[_seqbufptr+1] = SEQ_CONTROLLER;\
+ _seqbuf[_seqbufptr+2] = (dev);\
+ _seqbuf[_seqbufptr+3] = (voice);\
+ _seqbuf[_seqbufptr+4] = (controller);\
+ *(short *)&_seqbuf[_seqbufptr+5] = (value);\
+ _seqbuf[_seqbufptr+7] = 0;\
+ _SEQ_ADVBUF(8);}
+
+#define SEQ_PITCHBEND(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_PITCH_BENDER, value)
+#define SEQ_BENDER_RANGE(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_PITCH_BENDER_RANGE, value)
+#define SEQ_EXPRESSION(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_EXPRESSION, value)
+#define SEQ_MAIN_VOLUME(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_MAIN_VOLUME, value)
+
+#define SEQ_START_TIMER() {_SEQ_NEEDBUF(4);\
+ _seqbuf[_seqbufptr] = SEQ_SYNCTIMER;\
+ _seqbuf[_seqbufptr+1] = 0;\
+ _seqbuf[_seqbufptr+2] = 0;\
+ _seqbuf[_seqbufptr+3] = 0;\
+ _SEQ_ADVBUF(4);}
+#define SEQ_SET_PATCH(dev, voice, patch) {_SEQ_NEEDBUF(8);\
+ _seqbuf[_seqbufptr] = SEQ_EXTENDED;\
+ _seqbuf[_seqbufptr+1] = SEQ_PGMCHANGE;\
+ _seqbuf[_seqbufptr+2] = (dev);\
+ _seqbuf[_seqbufptr+3] = (voice);\
+ _seqbuf[_seqbufptr+4] = (patch);\
+ _seqbuf[_seqbufptr+5] = 0;\
+ _seqbuf[_seqbufptr+6] = 0;\
+ _seqbuf[_seqbufptr+7] = 0;\
+ _SEQ_ADVBUF(8);}
+
+#define SEQ_WAIT_TIME(ticks) {_SEQ_NEEDBUF(4);\
+ *(unsigned long *)&_seqbuf[_seqbufptr] = SEQ_WAIT | ((ticks) << 8);\
+ _SEQ_ADVBUF(4);}
+
+#define SEQ_ECHO_BACK(key) {_SEQ_NEEDBUF(4);\
+ *(unsigned long *)&_seqbuf[_seqbufptr] = SEQ_ECHO | ((key) << 8);\
+ _SEQ_ADVBUF(4);}
+
+#define SEQ_MIDIOUT(device, byte) {_SEQ_NEEDBUF(4);\
+ _seqbuf[_seqbufptr] = SEQ_MIDIPUTC;\
+ _seqbuf[_seqbufptr+1] = (byte);\
+ _seqbuf[_seqbufptr+2] = (device);\
+ _seqbuf[_seqbufptr+3] = 0;\
+ _SEQ_ADVBUF(4);}
+#define SEQ_WRPATCH(patchx, len) {if (_seqbufptr) seqbuf_dump();\
+ if (write(seqfd, (char*)(patchx), len)==-1) \
+ perror("Write patch: /dev/sequencer");}
+
+#endif
+long soundcard_init(long mem_start);
+#endif /* _SOUNDCARD_H_ */
OpenPOWER on IntegriCloud