System Linux
kernel 2.6.27.7
Hallo,
ich habe ein verständnissproblem mit dem Datentransfer, zwischen meiner
Messkarte die auf dem Pci-X Bus hängt.
Und zwar geht es mir speziell um den Zugriff auf die
PCI_Base1+0x00D8(r/w).
Ich habe bereits auf die Karte schreiben und lesen können dies geschah
allerdings mit Treiberbefehlen die bereits vorhanden waren
(z.B. int rc = ioctl (hnd, ICS554_GET_IoInfo,pInfo);).
Bin momentan ratlos wie ich auf die PCI_Base1+0x00D8(r/w) schreiben
kann.
Ich finde keinen Befehl oder ähnliches.
Jemand eine Idee?? Für tipps bin ich dankbar.
Hi,
> Bin momentan ratlos wie ich auf die PCI_Base1+0x00D8(r/w) schreiben> kann.> Ich finde keinen Befehl oder ähnliches.
Wenn Dein Treiber diese Möglichkeit nicht bietet, dann geht es so
einfach auch nicht.
>> Jemand eine Idee?? Für tipps bin ich dankbar.
Du kommst dann nicht umhin
- den Treiber mit einem neuen IOCTL entsprechend anzupassen (falls du
die Quellen dafür hast)
- selbst einen Treiber zu schreiben (dann bräuchte man das genaue
Datenblatt für die Karte)
Das Standardwerk für solche Zwecke ist "Linux device drivers" in der
dritten Auflage. Wahrscheinlich würde für Deine Zwecke ein einfacher
char-driver reichen.
Es gibt allerdings auch inzwischen ein User-Mode-Treiber Framework, was
für Deine Zwecke sicherlich einfacher ist, ich habe die Entwicklung
hierbei allerdings nicht verfolgt und kann dazu wenig sagen.
Gruß, Oliver
Hallo,
> Das wesentlich bessere Buch ist "Essential Linux Device Drivers" - wenn> man sich schon so ein Buch leisten möchte.
interessant, dieses Buch kannte ich noch gar nicht. Zu meiner
Verteidigung muss ich allerdings sagen, dass dieses Buch auch noch gar
nicht existierte, als ich meine letzten Treiber schrieb.
Habe ich glatt in meine Bestellliste aufgenommen!
Gruß, Oliver
Oliver R. schrieb:> Wenn Dein Treiber diese Möglichkeit nicht bietet, dann geht es so> einfach auch nicht.
Mein treiber bietet diese Möglichkeit. Ich besitze das
Software/Operating Manuel allerdings kann ich nicht finden wie ich
speziell auf diese Base/adresse schreiben kann. Normalerweise gibt es
Funktionen wie
"StatusGet(hDevice, &Stat);" // diese fkt funktioniert mit IOCTL
mit denen kann man auf bestimmte Registerbänke zugreifen.
wie schreibt man einen neuen IOCTL?? muss ich unbedingt ein buch lesen?
oder gibt es Bibs oder ähnlichen mit Fkt. wie
PCIset(PCIadr,BaseNr,W/R?,ÜbergabeWert);
oder stelle ich mir das zu leicht vor??
Hi,
> Oliver R. schrieb:>> Wenn Dein Treiber diese Möglichkeit nicht bietet, dann geht es so>> einfach auch nicht.>> Mein treiber bietet diese Möglichkeit. Ich besitze das
Offensichtlich bietet er doch KEINE Möglichkeit auf diese Adresse zu
schreiben/lesen.
> Software/Operating Manuel allerdings kann ich nicht finden wie ich> speziell auf diese Base/adresse schreiben kann. Normalerweise gibt es> Funktionen wie>> "StatusGet(hDevice, &Stat);" // diese fkt funktioniert mit IOCTL>> mit denen kann man auf bestimmte Registerbänke zugreifen.>> wie schreibt man einen neuen IOCTL?? muss ich unbedingt ein buch lesen?
Du kannst auf die Hardware NUR mit einem Treiber zugreifen! Einen neuen
IOCTL schreibst Du, indem du den Treiber veränderst, neu kompilierst und
das Treibermodul austauschst bzw. den Kernel. Dazu brauchst Du die
Treiberquellen und ein Kernel-compilierfähiges System.
Ja, ein Buch hilft dabei weiter, es gibt aber auch im Netz viele
Anleitungen. Im Treiber könnte die IOCTL-Behandlungsfunktion ungefähr so
aussehen:
/*
* ioctl entry point.
*/
static int mein_ioctl(struct inode* inode, struct file* file, unsigned
int cmd, unsigned long arg )
{
[...]
}
Diese Stelle muss man finden und um einen IOCTL ergänzen, der auf das
gewünschte Register schreibt/liest.
> oder gibt es Bibs oder ähnlichen mit Fkt. wie>> PCIset(PCIadr,BaseNr,W/R?,ÜbergabeWert);
Auf die Hardware direkt zugreifen darf nur der Kernel und seine
Treibermodule. Aus Deiner Anwendung (die im User-Mode läuft) heraus geht
das nicht (Ausnahmen s. meine erste Mail).
>> oder stelle ich mir das zu leicht vor??
Bedauerlicherweise: Ja!
Gruß,
Oliver
Oliver R. schrieb:> Im Treiber könnte die IOCTL-Behandlungsfunktion ungefähr so> aussehen:>> /*> * ioctl entry point.> */
.
.
.
Ich glaube da habe ich etwas gefunden im header hardwlow.h.
int ADCOverRangeReset (HANDLE hnd, STATUS *pStat)
{
int rc;
rc = ioctl (hnd, Hardw_SET_ADCOverRangeReset, pStat);
Hardw_FORMAT_RESULT(hnd,rc,"ADCOverRangeReset");
return((int)rc);
}
könnte das eine Behandlungstrucktur sein?
"SET_ADCOverRangeReset" finde ich ich in einen anderen header nämlich im
Hardwioctl.h
#define..
.
.
"#define Hardw_GET_OverflowDone _IOW(Hardw_IO_MAGIC, 134, u32)"
.
.
und in der Hardwload.c
case
.
.
case Hardw_SET_ADCOverRangeReset:
{
if(copy_from_user(&val64,(void*)arg,sizeof(u64))) {
return -EFAULT;
}
PDEBUG("hardw(ioctl_Hardw): SET_ADCOverRangeReset0x%llx\n",val64);
WRITE_ICSDEV_U32(board, STATUS_OFFSET, (u32)(0xFLL & val64));
break;
}
.
.
Ich finde allerdings nichts was auf eine PCI_Adresse hindeutet oder irre
ich mich da??
Hi nochmal,
>> Ich glaube da habe ich etwas gefunden im header hardwlow.h.>> int ADCOverRangeReset (HANDLE hnd, STATUS *pStat)> {> int rc;>> rc = ioctl (hnd, Hardw_SET_ADCOverRangeReset, pStat);> Hardw_FORMAT_RESULT(hnd,rc,"ADCOverRangeReset");> return((int)rc);> }
Nein, das ist eine Usermode-Funktion, da ioctl() auch eine
Usermode-Funktion ist. Sie dient zur Kommunikation mit dem Treiber bei
"unüblichen" Kommandos, sprich Spezialfunktionen, die über das
Lesen/Schreiben hinausgehen. Zur Identifikation benutzen aber sowohl
Usermode-Programm als auch der Treiber eine gemeinsame IOCTL-Definition
(s.u.)
>> könnte das eine Behandlungstrucktur sein?> "SET_ADCOverRangeReset" finde ich ich in einen anderen header nämlich im>> Hardwioctl.h> #define..> .> .>> "#define Hardw_GET_OverflowDone _IOW(Hardw_IO_MAGIC, 134, u32)"> .
Hier wird in der Tat ein IOCTL definiert, hier könntest Du einen eigenen
IOCTL hinzufügen.
>> und in der Hardwload.c> case> .> .>> case Hardw_SET_ADCOverRangeReset:> {> if(copy_from_user(&val64,(void*)arg,sizeof(u64))) {> return -EFAULT;> }> PDEBUG("hardw(ioctl_Hardw): SET_ADCOverRangeReset0x%llx\n",val64);>> WRITE_ICSDEV_U32(board, STATUS_OFFSET, (u32)(0xFLL & val64));> break;> }>
Ja, das könnte die IOCTL-Behandlungsfunktion sein. Du hast leider nicht
den Funktionskopf mit angehangen.
>> Ich finde allerdings nichts was auf eine PCI_Adresse hindeutet oder irre> ich mich da??
Ich kenne ja den Treiber nicht, aber hier sieht es so aus, als ob die
Variable "board" auf die Basisadresse der PCI-Karte zeigt. Deren
Register/Speicher werden in den Adressraum des Kernels eingeblendet.
"STATUS_OFFSET" scheint dann der Offset zu "board" zu sein und
adressiert ein bestimmtes Register. Du könntest also evtl. mit
"WRITE_ICSDEV_U32(board,0x00D8,Wert)" einen uint an die von Dir
gewünschte Adresse schreiben. Schau im Code nach, was die Funktion genau
macht.
Gruß,
Oliver
Oliver R. schrieb:> Ja, das könnte die IOCTL-Behandlungsfunktion sein. Du hast leider nicht> den Funktionskopf mit angehangen.
danke für die Erklärung.
Hier noch der Kopf.
switch (cmd)
{
case..:
..
case
..
}
Ich glaube ich habe da was gefunden:
//IOCTL wird definiert/////////////////////////////////7
Hardw.h
#define FIFO_CLOCK_OFFSET 0xD8
//IOCTL-Behandlungsfunktion////////////////////////////
Hardwload.h:
switch (cmd)
{
case Hardw_SET_FifoClock:
{
u32 dwval, i;
if(copy_from_user(&val64,(void*)arg,sizeof(u64))) {
return -EFAULT;
}
PDEBUG("Hardw(ioctl_Hardw): Hardw_SET_FifoClock 0x%llx\n",val64);
dwval = (u32)(0xFFFFFFFFLL & val64);
for(i = 0; i < 32; i++) {
WRITE_ICSDEV_U32(board, FIFO_CLOCK_OFFSET, (u32)(0x1L & dwval));
udelay(10);
dwval >>= 1;
}
break;
}
}
//Usermode-Funktion///////////////////////////////////////
Hardwlow.c
int HardwFifoClockSet (HANDLE hnd, unsigned long long *pClock)
{
int rc;
rc = ioctl (hnd, Hardw_SET_FifoClock, pClock);
ICS_FORMAT_RESULT(hnd,rc,"FifoClockSet");
return((int)rc);
}
es deutet allerdings nichts bis auf
#define FIFO_CLOCK_OFFSET 0xD8
darauf hin, das es die BASE1+0X00D8 ist(FifoLevelControl).
Könnte trotzdem so sein das sei was ich suche??
Nochmal danke für die gute Hilfe
Hallo,
>> es deutet allerdings nichts bis auf> #define FIFO_CLOCK_OFFSET 0xD8>> darauf hin, das es die BASE1+0X00D8 ist(FifoLevelControl).> Könnte trotzdem so sein das sei was ich suche??
Schwer zu sagen, FIFO clock und FIFO level hören sich ja doch
unterschiedlich an. Schau Dir mal im Treiber an, wo die Variable "board"
belegt wird. Evtl. in einer Zeile wie dieser:
board = pci_resource_start(dev, BAR3);
Gruß,