Versuche einen Devicetreiber mit BCC unter DOS zu schreiben. Dabei soll z.B. der Serielle Interrupt 12 durch meine Interrupt-Funktion ersetzt werden. In einem RS232-Testprogramm klappt das schon einwandfrei, doch im SYS-File leider nicht. Beim rs232.com-File gehts z.B. nur mit #pragma option k (also Standard-Stack), beim rs232.sys nur mit option k- (sonst stürzt alles nach Auslösen des ersten Interrupts ab). Meine Interruptroutine sieht wie folgt aus: typedef void DUMMY; DUMMY far new_in(DUMMY) { asm cli; asm pop di; // da BCC schon bei jeder void-Fkt push di/si macht asm pop si; asm push ax; asm push bx; asm push cx; asm push dx; asm push es; asm push ds; asm push si; asm push di; asm push bp; asm mov bp,cs; // statt ursprünglichem asm mov bp,cs:DGROUP@ asm mov ds,bp; asm mov bp,sp; ... Hier Code "Zeichen auf Schnitstelle ausgeben" einfügen asm pop bp; asm pop di; asm pop si; asm pop ds; asm pop es; asm pop dx; asm pop cx; asm pop bx; asm pop ax; asm sti; asm iret; } Vielleicht findet sich ja jemand, der (im Idealfall sogar mit BCC.EXE) schon einmal eine Interruptroutine mit einem selbstgebauten Deviece-Treiber ersetzt hat oder jemanden kennt, der jemanden kennt, der sich mit so etwas auskennt.
Ich habe sowas vor viiiiielen Jahren mal als TSR gschrieben, vielleicht kannst Du damit was anfangen?
schau mal in PCintern 3.0 das ist ein 1000 seiten dickes Buch, da findest du Beispiele für zeichenorientierte Devicetreiber. Wenn du Zeichen auf der seriellen Schnittstelle mitloggen willst, kannst du das aber mit einem TSR wesentlich schneller erreichen.
@Wolfram: Habe hier PCintern 2.0, aber bei den Devicetreibern scheint der Interrupt glaube ich nicht wirklich ersetzt zu werden. @DOSi: Kann zwar praktisch kein Assembler, muß mich aber wohl doch da mal einarbeiten. Der Treiber soll aber später noch etwas mehr können und ist als Device-Treiber leider von den existierenden Anwenderprogrammen vorgeschrieben (ein TSR-DOS-Programm geht also leider nicht). Das Hauptproblem ist wohl, daß man beim Initialisieren zwar die Interruptfunktion mit new_int(); aufrufen kann und sie dann auch ein Zeichen ausgibt, aber sie eben wohl nicht resident mit dem Interruptvektor erreichbar ist (auch wenn's als .com-Datei ja klapt) Dabei brauche ich den alten Vector nicht einmal sichern, weil der neue vollständig ist und den alten für immer ersetzt. Den seriellen Int.-Vector 12 ersetze ich übrigens durch mein selber gebasteltes: int_vector = (unsigned int far *) MK_FP(0,0); asm cli; int_vector[24]=(unsigned int)(FP_OFF(new_int)); int_vector[25]=(unsigned int) _DS; asm sti; was soweit im COM-File ganz gut klappt. Vielleicht lädt DOS den Treiber einfach an eine Stelle, die dem Linker nicht bekannt ist? (Kenne mich auch mit far-Zeigern noch nicht so wirklich aus...) Schaue mir auf jeden Fall das INTSER.ASM mal genau an und sehe was ich wie davon in C übernehmen kann (oder ob ich doch alles in ASM machen muß). Danke auf jeden Fall schon einmal für das Programm!
poste mal den ganzen Code deines Com Programmes und den deines Gerätetreibers. IntVector 12 ist das eine PS/2 Mouse? COM1/COM2 haben normalerweise die Int 4 und 3 wofuer soll der Devicetreiber eigentlich sein? in deiner Interruptroutine benutzt du den Stack des Programmes in Assembler kann man sowas machen, solange man den Stack nicht stark belastet. Wenn du in deiner Interruptroutine C Code benutzt dann würde ich den Stack des Gerätetreibers benutzen.(SS:SP). Wie hast du die Interruptfunktion aufgerufen? (call new_int() oder pushf;call new_int)
Unten erst einmal das Programm zum Test der seriellen Schnittstelle, aber es tut ja hier eigentlich nichts zur Sache, welcher Interrupt ersetzt wird. Einzige Bedingung ist, daß der Device-Treiber zeichenorientiert ist (und der Interrupt resident bleibt und mit dem Devicetreiberkern sowohl von der Interruptroutine her als auch von den Anwenderprogrammen Daten austauscht (schade auch, daß es hier offenbar keine PMs gibt). Wie ich den Stack in ein C-Programm einbinden kann weiß ich leider nicht. Wie gesagt stürzt das .COM-Programm mit option k- ab und der .sys-Treiber gerade mit option k (Standard Stack frame ein , was immer das bedeutet; muß mir wohl mal das Assemlerlisting dazu durcharbeiten). Hier das com-Programm, auch wenn es mit dem Treiber-Problem ja wenig zu tun hat und ja auch läuft ( compiliert mit BCC -mt -S rs232.c und dann tasm rs232.asm und dann tlink /t /v c0t.obj+rs232.obj,rs232.com,,graphics.lib emu.lib maths.lib cs.lib ) // RS232-Test-Programm // This Programm sends out an 'X' to RS232 when a character comes in via RS232 // (And also sends an 'X' when you press a key for testing via RS232) #pragma inline #pragma option -k //#pragma option -k- // TSR standard stack frame #include <dos.h> #include <conio.h> typedef void DUMMY; DUMMY far new_int(DUMMY); //////////////////////////////////////////////////////////////////////vo id main() { unsigned int far *int_vector = (int far *) 0x00000000; unsigned int temp; unsigned int key; // initializing RS232 to 115kBaud: inport(0x3F8); // clear pending interrupts inport(0x3FD); inport(0x3FE); outport(0x3FA,0x06); outportb(0x3F9,0x00); // disable interrupt outportb(0x3FA,0x00); // disabble fifo temp = inportb(0x3FB); // set Baudrate outportb(0x3FB,(temp | 0x80)); // set Baudrate outportb(0x3F8,0x01); // set Baudrate outportb(0x3F9,0x00); // set Baudrate outportb(0x3FB,temp); // set Baudrate outportb(0x3FB,0x0b); // 8bit, no parity, one stop bit outportb(0x3FC,0x08); // int. enable, RTS disable outportb(0x21, (inportb(0x21) & 0xE7)); outportb(0x20,0x20); outportb(0x3F9,0x01); // enable receive ready interrupt outportb(0x3FB,(inportb(0x3FB) & 0xC7) | 0x38); outportb(0x3F9,0x01); //disable tx interrupt //replacing int 12 Vector: int_vector = (unsigned int far *) MK_FP(0,0); // far asm cli; int_vector[24]=(unsigned int)(FP_OFF(new_int)); int_vector[25]=(unsigned int)_DS; asm sti; key=0; while(key !=27){ // quit with "escape" if(kbhit()){ key = getch(); outportb(0x3F9,0x02); // enable tx empty interrupt } } } //////////////////////////////////////////////////////////////////////DU MMY far new_int(DUMMY) { asm pop di; asm pop si; asm pop bp; // because bcc made push bp; mov bp,sp asm push ax; asm push bx; asm push cx; asm push dx; asm push es; asm push ds; asm push si; asm push di; asm push bp; // asm mov bp,cs:DGROUP@ asm mov bp,cs; asm mov ds,bp; asm mov bp,sp; outportb(0x20,0x20); outportb(0x3F8,'X'); outportb(0x3F9,0x01); // enable receive ready interrupt inportb (0x3F8); asm pop bp; asm pop di; asm pop si; asm pop ds; asm pop es; asm pop dx; asm pop cx; asm pop bx; asm pop ax; asm iret; } //////////////////////////////////////////////////////////////////////
In der Interruptroutine solltest du noch die Flags sichern.(pushf/popf) deine ersetzung des Intvektors ist etwas compilerspezifisch? was macht MK_FP,FP_OFF? //replacing int 12 Vector: int_vector = (unsigned int far *) MK_FP(0,0); // far asm cli; int_vector[24]=(unsigned int)(FP_OFF(new_int)); int_vector[25]=(unsigned int)_DS; asm sti; soweit ich das verstehe benutzt du das datensegment (DS) um die segmentadresse deiner Interruptroutine anzugeben,diese liegt aber im Codesegment!(CS) bei einem COMProgramm sind diese segmente gleich ,ich bin mir aber nicht sicher ob dies auch fuer einen Devicetreiber gilt. der offset der interruptroutine ist auf jeden fall auf cs bezogen. vom Compilermodell solltest du entweder ein gemeinsames Code/Datensegment wählen oder Code/Datensegment jeweils maximal 64K. ersteres wird wahrscheinlich unproblematischer. was soll in deiner Interruptroutine eigentlich das nochmalige aktivieren des receiveinterrupts? Du restaurierst den Interruptvektor in deinem COMprogramm beim beenden nicht wieder. Das heisst die Interruptroutine bleibt existent im Speicher obwohl der Speicher nicht mehr dem Programm gehört und damit jederzeit überschrieben werden kann. Damit dürfte es irgendwann zu einem Absturz kommen. Einen Gerätetreiber in C habe ich auch nicht als quellcode(ist auch nicht in PCIntern3.0) wenn du keinen findest und nicht weiterkommst wäre noch eine Möglichkeit einen alten Dosgerätetreiber über 15K zu nehmen(der ist garantiert in C oder so geschrieben) und diesen zu disassemblieren. effektiv brauchst du nur die Strategie und Interruptroutine des Treibers um zu sehen was alles gesichert wird und wie der Stackframe für den inneren C Teil aufgebaut wird. Einen einfachen Gerätetreiber hats du in assembler aber wahrscheinlich schneller geschrieben. Wozu soll das ganze eigentlich dienen, dass du dir die mühe machst noch einen Dostreiber zu schreiben?
> In der Interruptroutine solltest du noch die Flags
sichern.(pushf/popf)
Wozu denn das ? Wird doch beim x86 automatisch gemacht wenn ein
Interrupt ausgelöst wird.
>Wozu denn das ? Wird doch beim x86 automatisch gemacht wenn ein >Interrupt ausgelöst wird. Will sagen, wenn ein Interrupt ausgelöst wird, werden die Flags, und CS:IP gesichert, IRET stellt die flags wieder her und springt zur Rückkehradresse.
Zunächst: Einen Gerätetreiber in C (den einzigen, den ich je fand) gibt es unter http://ada2.unipv.it/biblio/trickyc/18c.htm (zwar auch ein zeichenorientierter, aber leider offenbar ohne Interruptersetzen :( ). Da ich beim Compiler mit mt Tiny als Modell wähle, dürfte sowieso CS=DS sein (Änderung macht im Programm auch keinen Unterschied). Das Progrämmchen oben ist übrigens kein TSR sondern war nur mal so zum Test gedacht, also kann es nach Beendigung ruhig überschrieben werden. Komisch ist, daß wenn ich mit option -k in rs232.com ein void far interrupt newinterrupt(void); deklariere, der Interrupt wie folgt aussieht (Erzeuge mit BCC S ein Assemblerlisting): push ax push bx push cx push dx push es push ds push si push di push bp mov bp,cs:DGROUP@ mov ds,bp mov bp,sp ...eigentliches Interruptprogramm... pop bp pop di pop si pop ds pop es pop dx pop cx pop bx pop ax iret Compiliere ich dagegen in meinem Devicetreiber rs232.sys ohne Standardstack, so erhalte ich Den Linkererror Error: Undefined symbol DGROUP@ in module rs232.c und als Listing push ax push bx push cx push dx push es push ds push si push di push bp mov bp,DGROUP mov ds,bp ... eigentliches Interruptprogramm... pop bp pop di pop si pop ds pop es pop dx pop cx pop bx pop ax iret Aber grundsätzlich stelle ich mir als Halblaie die Frage, ob die Adresse meiner Interruptfunktion new_int() im Treiber überhaupt als die durch FP_OFF(new_int) : _CS ermittelte Adresse auch beim Laden des Treibers beim Booten an diese Adresse in den Speicher gelegt wird (und falls nicht, wie ich die wahre Adresse erhalte).
Ich dreh' hier noch am Rad. Warum klappt das nicht. Jetzt bekomme ich sogar (was vorher nicht ging) ein scheinbar korrektes debug-Listing: Wenn ich nämlich nach Installation des .SYS-Treibers debug d 0:30 starte, erhalte ich folgende Interruptadrsse: 0000:0030 AD 00 02 12 6F EF 00 F0-9A 00 9E 09 65 04 usw. wenn ich also dann u 1202:00AD eingebe, erhalte ich: 1202:00AD 56 PUSH SI 1202:00AE 57 PUSH DI 1202:00AF FA CLI 1202:00B0 5F POP DI 1202:00B1 5E POP SI 1202:00B2 50 PUSH AX 1202:00B3 53 PUSH BX 1202:00B4 51 PUSH CX 1202:00B5 52 PUSH DX 1202:00B6 06 PUSH ES 1202:00B7 1E PUSH DS 1202:00B8 56 PUSH SI 1202:00B9 57 PUSH DI 1202:00BA 55 PUSH BP 1202:00BB 8CCD MOV BP,CS 1202:00BD 8EDD MOV DS,BP 1202:00BF 8BEC MOV BP,SP 1202:00C1 BA2000 MOV DX,0020 1202:00C4 B020 MOV AL,20 1202:00C6 EE OUT DX,AL 1202:00C7 BAF803 MOV DX,03F8 1202:00CA B058 MOV AL,58 1202:00CC EE OUT DX,AL usw. , was doch durchaus schon so wie mein Interrupt aussieht!? Da kann doch eigentlich (fast) nichts mehr verkehrt sein?
Es kommt nicht drauf an das du sauber in den Interrupt reinkommst,sondern das du auch sauber wieder rauskommst (gleiche Stackhöhe richtige rücksprungadresse) installiere deinen Gerätetreiber und starte im Dos debug ruf den Interrupt auf und trace diesen Interrupt. achte auf stack ob cs und ds gleich sind und ob du wieder sauber am ende des Interrupts bei deinem Interruptaufruf landest.(die Stackhöhe muss dem entsprechen die sie vor dem aufruf hatte und alle registerwerte muessen den vorhergehenden registerwerten entsprechen) wenn ich dein assemblerlisting betrachte fällt mir auf das cs nicht gesichert wird aber im Interrupt verändert wird! du solltest im mindesten alle register sichern die im interrupt verändert werden. Wenn es dich tröstet: es ist der richtige interrupt outportb(0x20,0x20); -> MOV DX,0020 1202:00C4 B020 MOV AL,20 1202:00C6 EE OUT DX,AL Es wäre hilfreich, wenn du sagen würdest was du im Interrupt machen willst, wahrscheinlich ist das mit ein paar zeilen assembler erledigt und wenn du mit debug zurechtkommst, sollte dies auch keine Hürde mehr darstellen.
Hallo Wolfram, was der Interrupt machen soll sieht man im .com-File weiter oben: Einfach bei eingehenden Zeichen ein X ausgeben. Wenn ich bei der Initialisierungsroutine im Treiber einmal asm int 12; schreibe, wird er ja auch aufgerufen und ein X ausgegeben. Aber wenn dann im Betrieb ein Zeichen über die Schnittstelle kommt, passiert im .sys nichts; im .com wird dagegen X korrekt zurückgegeben. Der Treiber wird also dann nicht einmal korrekt ausgeführt, bevor er danach möglicherweise falsch verlassen wird. Würde daher erst einmal den Eintritt des Interrupt in Frage stellen (und zu erreichen versuchen), zumal ein falsches Verlassen meist durch eine Windows-Messagebox mit unbekanntem Fehler angezeigt wird.
Windows-Messagebox und DOS-Devicetreiber? Was eigenartiges hast Du da vor?
Also ich dachte du arbeitest unter reinem Dos! Das erklärt warum du keine Probleme mit einem instabilen System nach dem Beenden deines COM-Programmes hast. Wenn du sowas unter windows macht dann wird sich deine Änderung des Interruptvektors auf die jeweilige Dosbox auswirken und auch nur auf sie. Auf jedenfall würde ich damit rechnen das die Windowsgerätetreiber in jedem Fall Vorrang haben. Du hast folgende Möglichkeiten: 1. Du benutzt reines Dos ohne das ein Windows dazwischen pfuscht Allerdings frage ich mich schon warum im Jahre 2005 dies noch sein muss 2. Schreiben eines Windowsgerätetreibers hier können durchaus auch RealMode teile enthalten sein 3. Schreiben eines Programmes mit einem Hook Das ist am ehesten vergleichbar mit einem Umgebogenen Interrupt 4.Portmonitor benutzen z.B. von Sysinternals z.B. Wenn du eigentlich nur die Schnittstelle Debuggen willst bezüglich Traffic Welche dieser Möglichkeiten die beste ist, kann man nur sagen wenn du beschreiben würdest, WAS du erreichen willst und warum es deiner meinung nach ein Dosgerätetreiber sein muss. CU Wolfram
Es gibt für Windows und zeichenorientierte Device-driver ein sehr gutes DOS-Simulations-Tool. Das wäre ja auch verdammt zeitaufwendig, jedesmal den PC neu zu booten und unter DOS zu programmieren... Das Betriebssystem DOS schreiben übrigens die existierenden Programme und sogar eine Art Norm für diesen Fall vor (also nichts anderes zu machen). Die Devicesimulation läuft in der DOS-BOX wie ganz normales DOS. Natürlich muß ich in der gleichen DOS-Box vor Beendigung derselben auch das debug starten (klar, daß der Interrupt nicht so bleibt, wenn Windows die Box schließt!). Die Schnittstelle beobachte ich mit einem zweiten PC (alter Laptop mit term90; reicht völlig) Noch einmal zusammengefaßt, was ich vorhabe bzw. wo das eigentliche, einzige Problem ist: Ich habe einen Devicetreiber (nennen wir ihn z.B. COMDRV.SYS) in C geschrieben, der den Interrupt 12 (COM1) Durch eine Routine ersetzt, die z.B. bei einem eingehenden Zeichen via COM1 ein X zurückgibt. Aus dem Treiber in der Initialisierungsroutine nach der Initialisierung mit asm int 12 aufgerufen gibt die neue,Interruptfunktion er auch tatsächlich ein X aus (soweit so gut). Doch wenn anschließend über die RS232 ein Zeichen hereinkommt (die Baudrate u.a. stimmen natürlich) passiert nichts. Mit BCC S erhalte ich für die Interruptfunktion wie gesagt folgendes Assemblerlisting: ; DUMMY far new_int(DUMMY) assume cs:_TEXT _new_int proc far push si push di cli pop di pop si push ax push bx push cx push dx push es push ds push si push di push bp mov bp,cs mov ds,bp mov bp,sp ;// ab hier die eigentliche Interruptfunktion (soweit OK) mov dx,32 mov al,32 out dx,al mov dx,1016 mov al,154 out dx,al mov dx,1017 mov al,1 out dx,al mov dx,1016 in al,dx ;// Ende der eigentlichen Interruptfunktion pop bp pop di pop si pop ds pop es pop dx pop cx pop bx pop ax sti iret pop di pop si ret _new_int endp
Solltest Du mit "DOS-Box" die DOS-VDM aktuellerer Windows-Versionen meinen, so solltest Du Dir darüber klar sein, daß Dein DOS-Devicetreiber darunter niemals mit der echten Hardware zu tun bekommt, sondern immer nur mit einer mehr oder weniger brauchbar virtualisierten Hardware. Windows gaukelt DOS-Programmen die Standard-PC-Hardware (Serielle Schnittstellen, Interrupt-Controller, Timer, DMA-Controller etc.) vor, und das Verhalten dieser virtualisierten Geräte muss nicht zwingend exakt den physikalischen Gegebenheiten unter "nacktem" DOS entsprechen, es ist bloß recht genau angenähert. Gerade bei den seriellen Schnittstellen gibt es größere Abweichungen, daher funktionieren erstaunlich viele DOS-Programme, die die seriellen Schnittstellen befummeln, nicht vernünftig unter Windows. Das mag auch an der vergurkten Programmierung von Interrupt-Treibern für DOS liegen, die sich manche Programmierer so einfallen lassen. Ein (echter) Hardwareinterrupt der seriellen Schnittstelle wird zunächst vom windows-eigenen Devicetreiber behandelt, dann wird dieser Interrupt der DOS-VDM übergeben, die wiederum ihrer Hardwareemulation mitteilt, daß sie einen simulierten Interrupt auslösen soll. Die wiederum teil der simulierten seriellen Schnittstelle und dem simulierten Interruptcontroller entsprechendes mit ... Du wirst erahnen können, was das für ein Aufriss ist und wieviel Rechenzeit das ganze kostet. Auch unter einem Hardwarevirtualisierer wie VMWare oder VirtualPC sieht das so aus, auch wenn dort die Hardwareemulation, die das DOS-Programm zu sehen bekommt, sich deutlich genauer an der reellen Hardware orientiert. Auch hier ist die gesamte Hardware virtualisiert, und das DOS-Programm bekommt niemals die echte Hardware zu "sehen". Vom Zeitverhalten her entspricht daher weder die DOS-VDM noch VMWare etc. dem echter Hardware. Damit sind bestimmte timingkritische Operationen weder in einer VDM noch unter VMWare möglich. Wenn jetzt jemand auf die Idee kommt, sich das Leben mit Windows-Devicetreibern à la "giveio.sys" zu vereinfachen, dann sollte er das tunlichst sein lassen. Hardware, die Interrupts auslösen kann (und dazu gehören die seriellen Schnittstellen nunmal), sollte man damit auf gar keinen Fall manipulieren. Bestenfalls funktioniert es einfach nicht (Interrupts kommen gar nicht erst in der DOS-VDM an), schlimmstenfalls geht die Angelegenheit mächtig in die blaue Hose (Blue Screen). Letzlich bleibt noch die Frage, warum in drei Teufels Namen jemand sich im Jahre 2005 hinsetzt und DOS-Devicetreiber programmiert ...
Will sicher nicht undankbar sein, auch wenn bei so einem speziellen Posting nach meiner Erfahrung ja nicht immer direkt ein Vorschlag zum eigentlichen Problem (hier Interrupt) kommt. Trotzdem danke für die Antworten. Zu den letzten beiden Bemerkungen: 1. Die Devicetreiberemulation (ein ganz simples Programm namens device.com) klappt durchaus schon fehlerfrei (habs eben sicherheitshalber aber auch noch einmal unter reinem DOS probiert) Und 2. Zur Farge warum .sys unter DOS habe ich weiter oben schon erwähnt daß das wegen bestehender Programme von Fremdherstellern und normierter Vorschriften leider nun einmal sein muß (sorry, liegt leider wirklich nicht in meiner Macht, das zu ändern). Bleibt das Problem, warum die Interruptfunktion beim treiberinternen Aufruf klapppt und beim externen COM1-Event nichts passiert...
> Bleibt das Problem, warum die Interruptfunktion beim > treiberinternen Aufruf klapppt und beim externen > COM1-Event nichts passiert... Weil a) das "COM1-Event" gar nicht ausgelöst wird, es b) wegen fehlerhafter Programmierung des Interruptcontrollers nicht weitergeleitet wird oder c) es in den Tiefen der DOS-VDM verschluckt wird? Hast Du das ganze mal unter "reinem" DOS ausprobiert?
Ich kann mich Rufus nur anschließen Teste unter reinem Dos! Wenn du wissen willst ob der interrupt im SYS-Treiber überhaupt ausgelöst wird schreibe in die Interruptroutine einen "int 3" aufruf und starte auf dem Computer wo der Gerätetreiber läuft einen älteren Debugger. Dieser biegt den Int 3 auf sich um. Du kannst dir genauso mit dem Debugger die Interruptroutine des Devicetreibers suchen und da einen Breakpoint setzen (das ist das gleiche) Sende dann vom Laptop Terminalprogramm ein Zeichen. Wenn Interruptcontroller und Serielle Schnittstelle richtig programmiert sind solltest du dich im Debugger an der Stelle wieder finden. Überprüfe was passiert wenn du aus der Interruptroutine rausgehst. Wenn du nicht in der Interruptroutine landest ist eine der 3 von Rufus geschilderten Möglichkeiten eingetreten oder nach dem Laden deines Devicetreibers macht nach irgendein anderer Devicetreiber oder Programm etwas mit der seriellen Schnittstelle/Interruptcontroller zur Initialisierung und killt dir irgendwas. Kontrolliere die gesamten Portregister. Zur Not noch folgender Versuch mach das was dein COM Programm tut in einer Funktion des Devicetreibers. Rufe diese Funktion über einen IOCTL Aufruf auf und teste danach nochmals ob es nicht funktioniert. Wofür ist das ganze eigentlich Schule/Studium/Praktikum oder Arbeit? Das ganze ist ein ziemliches Stochern im Trüben wenn du so ein Geheimnis um den Quellcode deines Gerätetreibers machst und einem nur Stücken vorwirfst. Wer weiss was im Rest für Fehler gemacht werden. Es steht dir auch die Möglichkeit mit Windowsgerätetreiber mit Realmodeanteilen offen, dann könntest du dir sicher sein dass kein Windows dazwischenfunkt.
Hab' doch direkt oben geschrieben, daß der Fehler ohne device.com bei reinem Dos auch auftritt (im übrigen funktioniert device.com wirklich bei allen zeichenorientierten Treibern, warum immer dieses Mißtrauen?) Debuggen will ich gar nicht, zumal ich mich da überhaupt nicht auskenne (und das bei Devicetreibern beim Start ja auch nicht so einfach möglich ist, da ja in dem Zustand beim Booten nicht einmal DOS komplett geladen ist). Debug.com hatte ich nur mal so gestartet um zu sehen, ob der Interrupt auch wirklich ersetzt wurde (im Speicher liegt). Bei den Portregistern liegt es ganz sicher nicht (s.u.), zumal es nicht um die serielle Schnittstelle geht, sondern wie man bei einem Device-Treiber in C überhaupt einen Interrupt ersetzt. Könnte da auch jeden anderen Interrupt ersetzen. Das würde im Moment noch genau so wenig laufen. Den Quellcode würde ich dabei ungern gleich komplett veröffentlichen, sondern einzelnen wie Wolfram zuschicken wollen, aber das geht ja hier glaube ich leider nicht. Auf jeden Fall liegt es totsicher, erwiesenermaßen nicht an Windows oder falschen UART-Registern. Das Ganze hat wie ich von anderer Stelle gerade erfahre auch vermutlich viel mit Stack und Compileroptionen zu tun. Wenn ich übrigens bei INPUT, IOCTL_IN, OUTPUT, OPEN oder CLOSE asm int 12 einfüge, läuft die Interruptfunktion jeweils einwandfrei und gibt Xe aus. Nur eben bei eingehenden Zeichen per COM1 passiert unerklärlicherweise nichts. Also liegt sie vielleicht doch an falscher Stelle im Speicher, was nach obigem debug aber auch wieder nicht sein kann!?
Es ist definitiv kein Misstrauen, deine Informationspolitik bringt nur einige Probleme mit sich. Ich versuche sie mal darzustellen. 1. das ganze läuft unter windows (sehr wichtige Info) ein Windowsgerätetreiber (ist er installiert oder nicht?) kann jederzeit einstellungen an den Portregistern ändern wie Abschalten der interrupts die dieses Gerät auslöst ganz davon abgesehen das er dies auch am Interruptcontroller tun könnte also besten mischt sich da überhaupt kein WindowsTreiber ein 2. gehört Int12 exklusiv der Karte? sonst reagierst du auf Interrupts die eventuell gar nicht der Karte gehören beziehungsweise reagiert möglicherweise ein anderer (windows-)Treiber 3. Ist es eine normale serielle Schnittstelle oder was ist das (16450/16550 etc.?) 4. Das es an Stack und Compileroptionen liegt ist sehr naheliegend deswegen kam schon in mehreren Postings die Empfehlung in den Interrupt reinzutracen in ihm die Register zu überprüfen besonders die segmentregister (CS=DS?) und besonders beim rausgehen auf die gleichen werte wie beim reingehen zu achten ->darauf kam bei dir bis jetzt keine Reaktion ,das was du tust ist ein Indiz das es wahrscheinlich korrekt ist 5. Die Interruptnummer die du angibst ist recht ungewöhnlich für eine normale serielle Schnittstelle laut deinem Programmlisting meinst du int 12 dezimal, bist du dir da sicher? Nicht das ein ganz anderer Interrupt ausgelöst wird. Die optionen die du für BCC 3.1 angibst sind relativ nichtssagend Einen so alten Dos C Compiler benutzt man schon eine ganze weile nicht mehr. bitte schreibe dazu Programmiermodell /Segmentanordnung also auch was sie bedeuten 6. Um das debuggen wirst du nicht herumkommen, das muesste ich auch tun wenn ich sowas entwickeln muesste, ausserdem ist es der einzige Weg zu ueberpruefen ob das ganze auch korrekt ablaeuft. Eigentlich muss ich bei jedem Projekt einer gewissen Grösse mit dem Debugger überprüfen was los ist. Manchmal auch bis in die Maschinenspracheebene. Du bist hier ganz einfach an einem Punkt wo du auch in C beachten musst welche Segmentregister beteiligt sind und was in den Portregistern ablaeuft. Das dieses Wissen mit einem Assemblerhintergrund eher vorhanden ist, ja das ist so. 7. Ob der entsprechende Interrupt ausgelöst wird, kann man am ehesten mit der Int3 methode überprüfen, es sei denn du willst dich direkt an die Hardwareinterruptleitung hängen und diese mit dem Oszi überwachen. Wenn er nicht ausgelöst wird könnte es sein das du am falschen Int hängst (dann wundert es mich aber das es mit dem COM Porggi funktioniert) oder jemand anderes hat den Int zwischenzeitlich umgeleitet oder abgeschaltet. 8. Ich verstehe nicht ganz warum du nicht sagst wofür das ganze ist. Das irgendjemand deine Idee für einen Dosgerätetreiber klaut ist wohl im Jahre 2005 äusserst unwahrscheinlich. Es dürfte wohl eher dazu führen das auch andere Leute dir aus Nostalgiegründen helfen. Ist übrigens auch mein Grund, ich habe ziemlich viel in x86 Assembler geschrieben und den x86 sehr hardwarenah programmiert. Allerdings muss man da sehr genau wissen auf WELCHE HARDWARE man zugreift. Ein funktionstuechtiger zeichenorientierter Gerätetreiber in C der einen Interrupt auf sich verbiegt wäre eine Grundlage auf der man effektiv diskutieren könnte. Die eigentlichen Funtionen kannst du ja leer lassen. Alles andere ist nur stochern im Nebel und das bringt nichts. Es gäbe da noch andere Interruptquellen an die du deine Interruptroutine erstmal testweise dranhängen könntest z.B. int 9h Keyboard bei jedem Tastendruck oder int 1Ch 18,2mal pro sekunde allerdings würde dies erfordern dass du innerhalb der Interruptroutine in die alte verzweigst.
Nochmal zu den einzelnen z.Teil so nicht ganz richtig dargestellten Punkten: 1. Das ganze läuft unter DOS (nicht Windows!). 2. Int 12 ist der Interrupt von COM1 und funktioniert. (siehe mein testhalber baugleich geschriebenes RS232.COM) 3. Es ist die ganz normale COM1 . 4. Der interrupt ist 6 Postings weiter oben abgedruckt (Fehler tritt sowohl bei int_vector[25]= _CS wie auch bei _DS auf). 5. Die serielle Schnittstelle COM1 hat den Interrupt 12 (dez) = 0Ch ! Die Optionen zu BCC kann ich auch nicht näher erklären, sie werden als Hilfetext ausgegeben, wenn man BCC.EXE eintippt. Den Compiler samt Hilfedatei kann man sich unter dem Suchbegriff "Wolfenstein" als "Free BCC" aus dem Netz downloaden und ich gehe schon davon aus, daß jemand, der mir helfen kann, ihn einmal ausprobiert haben muß. 6. Das Debuggen in Echtzeit dürfte bei einem Devicetreiber fast unmöglich aber auch nicht erforderlich sein (zumal DOS zur Treiberladezeit noch gar nicht vollständig geladen ist). 7. Sobald bei korrektem Device-Treiber der Interrupt ausgelöst wird, erscheint das Echo auf meinem Laptop. Mit asm int 12 läuft es ja auch. Und mit meinem COM-Programm (s.o.) klappt ja auch der Interrupt. Da verbiegt übrigens auch niemand etwas (weder Windows noch sonst ein Task). 8. Es gibt schon eine wenn auch sehr kleine Gefahr, daß jemand die Idee klaut, auch wenn der Markt klein ist. Habe einfach schon zu viel Arbeitszeit in die Fehlersuche hineingesteckt, als daß ich der Konkurrenz ein paar tausend Euro Entwicklungsarbeit schenken möchte (so Preise berechnen die nämlich; sind ja nicht alle arbeitslos wie ich). Auf Int9 umzusteigen ist zwar denkbar, aber mein Laptop und die Interruptfunktion selber funktionieren ja gut, so daß ich keine neuen Experimente brauche. Aber es gibt Profis, die über so etwas alles nur lachen und das mal eben (ohne Debugging) aus dem Ärmel schütteln (nur helfen die einem meist nicht umsonst und beobachten wohl auch nicht so ein Forum.....).
So Ihr lieben. Habe soeben von einem Profi die Lösung erfahren. Will Euch diese hier auch nicht vorenthalten: Man kann nämlich bei bcc mit dem Aufruf 'bcc +compile.cfg ...' eine Optionsdatei wie z.B. 'compile.cfg' angeben (gaht etwas länglich auch über die Kommandozeile aus dem Batch), in der man auch alle Segmente auf ein Segment legen kann; etwa in der Art -zCCOMMON -zPCGROUP -zACOMMON -zRCOMMON -zSCGROUP usw. - Jetzt klappt alles! Aber allen erst einmal Danke für das Bemühen und noch viel Erfolg bei Euren eigenen Projekten!
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.