Hi,
bei meinem Netzwerk/SPI-Modul lässt sich das Modul mitfolgender
Initialisierung leider nicht per insmod einbinden, das System(Raspbian)
reagiert auf nichts mehr. Wenn ich allerdings tx_ring in probe als
lokale Variable deklariere funktioniert alles einwand frei. Hat jemand
eine Idee wo hier eine Unsauberkeit oder ein Fehler liegt?
So sollte man das sowieso nicht machen, vermeide globale Pointer.
struct tps1_net *tps;
hast du tps denn irgendwo allokiert? Besser du definierst diese nur fuer
die jeweilige Instanz und nicht global. Wenn der Treiber nun aus
irgendeinem Grund die Probe Funktion ein 2. Mal aufruft wuerdest du die
Werte erneut ueberschreiben.
Ohne die gesamte Datei gesehen zu haben aber auch etwas schwierig.
Also:
Ich habe jetzt in der probe Funktion es per priv = netdev_priv(dev);
realisiert. Trotzdem lässt sich das Modul nicht laden??
Mit einer lokalen Variable (struct sk_buff_head *tx_ring;) in probe
jedoch schon?!
Mein erster Ansatz mit globale Pointer lag daran, dass ich Funktionen
einer API aufrufe die am Ende meine TPS1_SendReceiveData-Funktion
aufrufen(für die SPI-Komm), da in dieser Funktion aber tps->spi
benpötigt wird, hieße es dass ich den dev-Parameter quer durch die ganze
API mitschleppen muss. Da der Treiber jedoch sowieso nur einmal geladen
wird, habe ich mir den Aufwand die API umzuschreiben gespart.
Danke für jede Hilfe
Auf welches tps1_net Objekt zeigt denn dein Zeiger tps?
Ich kann in deinem Code weder eine Allokierung eines entsprechenden
Objektes finden, noch sonst irgendetwas, wie der Zeiger je auf ein
derartiges Objekt zeigen könnte.
Nur weil du eine entsprechende Pointer Variable hast, hast du deswegen
noch lange kein derartiges Objekt!
Genauso die ganzen Pointer in
1
structtps1_net{
2
structnet_device*netdev;
3
structspi_device*spi;
4
structsk_skbuff*tx_skb;
5
structsk_buff_head*tx_ring;
6
u32msg_enable;
7
u8spi_transfer_buf[1200];
8
};
die zeigen nicht magisch irgendwo hin, sondern du musst sie auf
entsprechende Objekte zeigen lassen, in dem du den Pointern mal irgendwo
gültige Adresse von existierenden Objekten zuweist.
> Mein erster Ansatz ...
Mit Verlaub. Aber dein erster Ansatz sollte sein, erst mal C von der
Pieke auf zu lernen.
>Mit Verlaub. Aber dein erster Ansatz sollte sein, erst mal C von der>Pieke auf zu lernen.
Könnte besser sein, da hast du recht.
Die Pointer netdev und spi werden in probe mit Objekten verheiratet und
tx_ring wird mit skb_queue_head_init() initialisiert, dabei habe ich mal
angenommen das hier die allocation vorgenommen wird. Oder??
Das Problem liegt in der probe-Funktion da sich das modul nicht einmal
laden lässt. Um genau zu sein an skb_queue_head_init(priv->tx_ring); .
Ohne geht es. Oder sehe ich das falsch?
Markus R. schrieb:>>Mit Verlaub. Aber dein erster Ansatz sollte sein, erst mal C von der>>Pieke auf zu lernen.> Könnte besser sein, da hast du recht.> Die Pointer netdev und spi werden in probe mit Objekten verheiratet und> tx_ring wird mit skb_queue_head_init() initialisiert, dabei habe ich mal> angenommen das hier die allocation vorgenommen wird. Oder??
Ich hab jetzt nicht alles analysiert.
Ich hab nach Verwendungen des Zeigers tps, dem hier
1
structtps1_net*tps;
gesucht, weil der es ist, der in der ersten Funktion verwendet wird.
bzw. sinngemäss dann auch in anderen Funktionen.
Und ich habe keine Zuweisung dafür gefunden. Damit zeigt dieser Pointer
'in den Wald' (ist NULL), es sei denn ich hab übersehen, wo dieser
POinter entsprechend bearbeitet wird um auf ein Objekt zu zeigen.
Markus R. schrieb:>>Mit Verlaub. Aber dein erster Ansatz sollte sein, erst mal C von der>>Pieke auf zu lernen.> Könnte besser sein, da hast du recht.> Die Pointer netdev und spi werden in probe mit Objekten verheiratet und> tx_ring wird mit skb_queue_head_init() initialisiert, dabei habe ich mal> angenommen das hier die allocation vorgenommen wird. Oder??>>
1
>structnet_device*netdev;
2
>structspi_device*spi;
3
>structsk_skbuff*tx_skb;
4
>structsk_buff_head*tx_ring;
5
>
6
>priv->netdev=dev;
7
>priv->spi=spi;
8
>skb_queue_head_init(priv->tx_ring);
9
>
und was hat das alles mit dem Pointer tps zu tun?
Der ist es, der zb hier
Also, ich habe zuerst in probe Funktion auch alles mit dem globalen
Pointer tps implementiert:
1
tps->netdev=dev;
2
tps->spi=spi;
So hat alles funktionert. Dann habe ich mit
1
skb_queue_head_init(tps->tx_ring);
die queue initialisiert, was auch kompiliert wird. Jedoch lässt es sich
nicht als Modul einbinden. Warum? Der Grund warum ich es mit einem
globalen Pointer mache ist, ich müsste den dev oder priv pointer durch
die ganze API bis zur TPS1_SendReceiveData-Methode durchschleppen, ->
großer Aufwand, die API ist nicht gerade klein. Und weil dieses Modul
sowieso nur einmal eingebunden wird , kann ich auch globale Pointer
benutzten. Oder hat dies noch weitere Nachteile?
Markus R. schrieb:> Also, ich habe zuerst in probe Funktion auch alles mit dem globalen> Pointer tps implementiert:>
1
>tps->netdev=dev;
2
>tps->spi=spi;
3
>
> So hat alles funktionert.
Sagen wir so: Es ist nicht gleich abgestürzt.
Funktionieren im Sinne von 'so ist es richtig' ist was anderes.
> Dann habe ich mit>
1
>skb_queue_head_init(tps->tx_ring);
2
>
> die queue initialisiert, was auch kompiliert wird. Jedoch lässt es sich> nicht als Modul einbinden. Warum? Der Grund warum ich es mit einem> globalen Pointer mache ist, ich müsste den dev oder priv pointer durch> die ganze API bis zur TPS1_SendReceiveData-Methode durchschleppen, ->> großer Aufwand, die API ist nicht gerade klein. Und weil dieses Modul> sowieso nur einmal eingebunden wird , kann ich auch globale Pointer> benutzten. Oder hat dies noch weitere Nachteile?
Dann frage ich mich, wozu du überhaupt Pointer benutzt.
Man nimmt keine Pointer wenn man nicht muss.
Wozu soll das hier
1
intj;
2
int*pj;
3
4
voidfoo()
5
{
6
*pj=5;
7
}
8
9
intmain()
10
{
11
pj=&j;
12
foo();
13
}
gut sein, wenn ein simples
1
intj;
2
3
voidfoo()
4
{
5
j=5;
6
}
7
8
intmain()
9
{
10
foo();
11
}
genau dasselbe macht? Wozu über einen Pointer auf ein tatsächliches
Objekt verweisen, wenn es nicht sein muss und da du auf globalen
Variablen bestehst, auch nichts bringt?
1
intj;
2
3
voidfoo(int*tmp)
4
{
5
*tmp=5;
6
}
7
8
intmain()
9
{
10
foo(&j);
11
}
das wäre insofern besser, als dann die Funktion mit allen möglichen
int-Variablen aufgerufen werden kann und nicht an die globale Variable
gebunden ist.
... funktioniert deshalb, weil es eine int-Variable gibt (j), und dafür
gesorgt wird, dass der Pointer auf ein int Objekt zeigt ( pj = &j; ).
UNd genau das vermisse ich in deinem Code. Dein Pointer zeigt nicht auf
ein Objekt. Ob man dieses Objekt jetzt bekommt, weil man es sowieso
anlegt
1
...
2
3
structtps1_nettps_object;
4
structtps1_net*tps=&tps1_object;
5
....
oder weil man es dynamisch allokiert
1
...
2
structtps1_net*tps;
3
4
intmain()
5
{
6
tps=malloc(sizeof(structtps1_net));
7
8
....
9
10
11
free(tps);
12
}
ist erst mal egal. Wichtig ist, dass der Pointer auf ein Objekt zeigen
muss! Das tut er nicht automatisch. Nur weil du einen Pointer hast, hast
du nicht automatisch auch das dahinterliegende Objekt.
Ein POinter ist nichts anderes als ein Kartekärtchen in einer
Bibliothek, auf dem steht, wo das echte Buch zu finden ist. Aber nur
weil du das Karteikärtchen in der Hand hast, hast du noch lange nicht
das Buch. Und umgekehrt: nur weil du ein Karteikärtchen anlegst, taucht
nicht magisch das zugehörige BUch in den Regalen auf. Erst mal musst du
das Buch haben, dann kannst du ein Karteikärtchen anlegen, auf dem
vermerkt ist, in welchem Regal das Buch zu finden ist.
Was dann in dem Buch steht und ob du da Notizen reinscheibst, ist wieder
eine andere Sache. Aber um das tun zu können, brauchst du das Buch! Und
nicht einfach nur ein Karteikärtchen auf dem auf ein fiktives Buch
verwiesen wird.
wird lediglich ein Zeiger tps zugewiesen, der bereits hier
1
dev=alloc_etherdev(sizeof(structtps1_net));
allokiert wurde!!
Es wird, wie ich es aus dem enc28j60-Treiber verstehe immer durch *dev
auf die "Hauptstruktur" zugegriffen(in meinem Fall tps). Dh. tps zeigt
auf die Adresse: "netdev_priv(dev)".
Nun zu meinem eigentlichen Problem: Mit
1
skb_queue_head_init(tps->tx_ring);
stürtzt das System bei insmod ab, ohne nicht. (tx_ring-alloc erledigt)
Jemand eine Idee?
hi,
ich bin schon lange weg von linux treiber entwicklung aber mir kommt da
so manches komisch vor:
1
printk("probe called!\n");
2
structnet_device*dev;
3
structtps1_net*priv;
4
intret=0;
5
6
dev=alloc_etherdev(sizeof(structtps1_net));
dev ist vom type net_device allozierst aber tps1_net größe, sind die
gleich groß, ist das die gleich struktur?
1
if(!dev){
2
3
if(netif_msg_drv(&debug))
4
dev_err(&spi->dev,DRV_NAME": unable to alloc new ethernet\n");
5
ret=-ENOMEM;
6
gotoerror_alloc;
7
}
8
9
priv=netdev_priv(dev);
10
11
priv->netdev=dev;/* tps to netdev reference */
12
priv->spi=spi;/* tps to spi reference */
13
14
dev->netdev_ops=&tps1_netdev_ops;
15
random_ether_addr(dev->dev_addr);
16
//SET_ETHTOOL_OPS(dev, &tps1_ethtool_ops);
zuerst weißt du mithilfe von dev priv zu und dann verwendest du in der
priv struct dev... und dev registrierst du dann. so aus dem bauch ist
das etwas komisch, aber ist schon mehr als 5 jahre her ...
Markus R. schrieb:> Nun zu meinem eigentlichen Problem:> Mitskb_queue_head_init(tps->tx_ring);> stürtzt das System bei insmod ab, ohne nicht. (tx_ring-alloc erledigt)> Jemand eine Idee?
Ja. tps->tx_ring ist nicht initialisiert, zeigt also nicht auf ein
struct sk_buff_head. Zumindest sehe ich hier nirgends eine Allokation.
Markus R. schrieb:> bekommt auch nirgendswo eine Speicher-Allokierung. Mit>
1
>tps=netdev_priv(dev);
2
>
> wird lediglich ein Zeiger tps zugewiesen, der bereits hier>
1
>dev=alloc_etherdev(sizeof(structtps1_net));
2
>
> allokiert wurde!!
wo genau passiert das in dem von dir geposteten Code?
Also der erste Teil
1
tps=netdev_priv(dev);
> auf die "Hauptstruktur" zugegriffen(in meinem Fall tps). Dh. tps zeigt> auf die Adresse: "netdev_priv(dev)".
Auch das ist für mich mit dem geposteten Code nicht nachvollziehbar
> Nun zu meinem eigentlichen Problem: Mit
Das IST dein eigentliches Problem!
Der Pointer tps ist nicht gültig! Der zeigt auf kein Objekt sondern ist
höchst wahrscheinlich ein NULL-Pointer.
Wie oft denn noch?
dev_err(&spi->dev,DRV_NAME": unable to alloc new ethernet\n");
12
ret=-ENOMEM;
13
gotoerror_alloc;
14
}
15
16
tps=netdev_priv(dev);
17
18
tps->netdev=dev;/* tps to netdev reference */
19
tps->spi=spi;/* tps to spi reference */
20
...
dann hast du auch deinen globalen tps Pointer eingerichtet.
Und dann natürlich auch
1
skb_queue_head_init(tps->tx_ring);
wobei ich jetzt nauch rauskriegen muss, ob das überhaupt so stimmt. Denn
wieder. Der tx_ring member zeigt ja im Moment noch auf gar nichts. WIe
soll skb denn da jetzt eine Queue darauf einrichten?
> wobei ich jetzt nauch rauskriegen muss, ob das überhaupt so stimmt. Denn> wieder. Der tx_ring member zeigt ja im Moment noch auf gar nichts. WIe> soll skb denn da jetzt eine Queue darauf einrichten?
Je mehr ich lese, desto überzeugter bin ich, dass das eigentlich so
lange weg schrieb:
> dev = alloc_etherdev(sizeof(struct tps1_net));>dev ist vom type net_device allozierst aber tps1_net größe, sind die>gleich groß, ist das die gleich struktur?
Es wird in dem enc28j60 Treiber genauso gehandhabt. Ich habe mich daran
mehr oder weniger orientiert. Ich gehe mal davon aus das der einwandfrei
funktioniert.
(http://www.cs.fsu.edu/~baker/devices/lxr/http/source/linux/drivers/net/enc28j60.c)
Andreas B. schrieb:
>Ja. tps->tx_ring ist nicht initialisiert, zeigt also nicht auf ein>struct sk_buff_head. Zumindest sehe ich hier nirgends eine Allokation.
Thanks. Daran hat es gelegen!
Karl Heinz Buchegger schrieb:
>wo genau passiert das in dem von dir geposteten Code?
? In probe.
Karl Heinz Buchegger schrieb:
>eigentlich so lauten sollte
Genauso habe ich es, und so funktioniert es..
Karl Heinz Buchegger schrieb:
>..Je mehr ich lese, desto überzeugter bin ich, dass das eigentlich so
Erklär mir mal bitte wo hier der Unterschied liegt, ob man über einen
Pointer den Inhalt ausliest oder direkt.
Auf jedenfall funkioniert die skb_queue_len-Methode nur so
1
skb_queue_len(&(tps->tx_ring))
also mit struct sk_buff_head tx_ring; im tps struct.
Nicht jedoch wenn ich über den Pointer zugreife:
1
skb_queue_len(tps->tx_ring)
Was passiert intern genau? Scheint wohl doch einen Unterschied zu machen
ob man Pointer benutzt oder nicht..
Es macht wenig Sinn, die sk_buff_head noch einmal auszulagern und extra
zu allokieren — erstens ist sie nicht groß, und zweitens wird sie
ohnehin immer gebraucht. Da müsste sie immer zusammen mit der tps1_net
Struktur allokiert werden und zusammen mit ihr freigegeben werden. Kann
man also genauso gut direkt reinpacken.
Und es gibt keinen Unterschied: Die skb_queue Funktionen verlangen einen
Pointer auf sk_buff_head Strukturen. Auch sk_buff_init(), das
initialisiert nur eine existierende Struktur.
ich muss da Leider Karl Heinz Buchegger recht geben
Nach ein wenig suchen
1
structtps1_net{
2
structnet_device*netdev;
3
structspi_device*spi;
4
structsk_skbuff*tx_skb;
5
-structsk_buff_head*tx_ring;
6
+structsk_buff_headtx_ring;
7
u32msg_enable;
8
u8spi_transfer_buf[1200];
9
};
1
if(init_gpios()){
2
printk("GPIO Initialization unsuccessful!\n");
3
return;
4
}else{
5
printk("GPIO Initialization successful!\n");
6
}
7
8
-skb_queue_head_init(priv->tx_ring);
9
+skb_queue_head_init(&priv->tx_ring);
10
11
return0;
12
error_alloc:
Und für dein skb_queue_len
1
len=skb_queue_len(&priv->tx_ring);
Den Rest kannst du in
include/linux/skbuff.h
lesen
Wie die Queue aufgebaut ist siehe im Device Driver Buch Seite 295
Das steht zwar "Linked List", aber die ersten zwei Elemente von
struct sk_buff_head ist deine Liste
Markus R. schrieb:> Karl Heinz Buchegger schrieb:>>..Je mehr ich lese, desto überzeugter bin ich, dass das eigentlich so>> Erklär mir mal bitte wo hier der Unterschied liegt, ob man über einen> Pointer den Inhalt ausliest oder direkt.
Du hast eines noch nicht kapiert.
Nur weil eine (oder mehrere) Funktion einen Pointer als Argument will,
bedeutet das nicht zwangsläufig, dass der Aufrufer auch nur eine
Pointer-Variable braucht.
Verdammt noch mal. Irgendwo muss es das zugehörige Objekt geben! Lern
das endlich mal!
1
voidfoo(int*pI)
2
{
3
*pI=5;
4
}
5
6
intmain()
7
{
8
int*Ptr;
9
10
foo(Ptr);
11
}
das hier geht schief!
Und zwar ganz grauslich! Weil es keinen int gibt, sondern immer nur
Pointer. Aber irgendwo muss mal ein int im Spiel sein! Denn die 5 müssen
in einen int bugsiert werden - also muss es auch einen int geben.
Irgendwo. Nur wo? Im ganzen Programm gibt es keinen!
Das kann jetzt so sein:
1
voidfoo(int*pI)
2
{
3
*pI=5;
4
}
5
6
intmain()
7
{
8
intderInt;
9
int*Ptr;
10
11
Ptr=&derInt;
12
foo(Ptr);
13
}
so wäre das ok.
Aber wozu das ganze? Wozu brauch ich in main die Pointer-Variable? Eben,
ich brauch sie überhaupt nicht. Die Adresse des int kann ich auch direkt
übergeben und spar mir eine Variable ein um die ich mich kümmern muss
1
voidfoo(int*pI)
2
{
3
*pI=5;
4
}
5
6
intmain()
7
{
8
intderInt;
9
10
foo(&derInt);
11
}
und fertig.
Alles in Butter.
Es gibt einen int und die Funktion kriegt die Adresse von ihm, um mit
ihm zu arbeiten.
Und bei dir ist das nicht anders. Es reicht nicht, wenn du in deiner
struct einen Pointer auf einen sbk_queue_head hast. Denn du hast dann
nur einen Pointer der auf einen skb_queue_head zeigen kann. Du BRAUCHST
aber ein skb_queue_head OBJEKT! Du hast aber KEINES! Wenn du eines
hättest, dann könntest du den Pointer drauf zeigen lassen, aber du hast
keines! Genauso wie ich im ersten Beispeil hier keinen int hatte. Ich
hatte zwar einen Pointer auf einen int - aber den int selber hatte ich
nicht.
Klar könnte man in Analogie zum zweiten Beispiel einen extra
skb_queue_head anlegen und den Pointer in der Struktur drauf zeigen
lassen. Könnte man. Aber in völliger Analogie zum zweiten Beispiel hier:
Wozu?
Leg dir doch gleich den skb_head_queue in die Struktur und gut ists.
Wenn eine Funktion eien Pointer auf ein skb_queue_head haben willst,
dann gibst du ihm die Adresse davon und gut ists.
> Auf jedenfall funkioniert die skb_queue_len-Methode nur so>
1
>skb_queue_len(&(tps->tx_ring))
2
>
> also mit struct sk_buff_head tx_ring; im tps struct.>> Nicht jedoch wenn ich über den Pointer zugreife:>>
1
>skb_queue_len(tps->tx_ring)
2
>
Du schmeisst Kraut und Rüben durcheinander, dass es nur so eine Freude
ist (d.h. das ist eigentlich traurig und keine Freude. Wer Kernel-Driver
programmieren will, für den sollte das alles kein Problem mehr sein. Es
hilft nichts - man muss sein Handwerrkszeug bzw. grundlegende Techniken
schon verstehen und nicht einfach nur Unverstandenes aus Tutorien
"abmalen")
OK! Der Grund meines letzten Beitrags.
Nehmen wir mal an ich hab im struct tps noch den sk_buff_head pointer.
Um den auf ein OBJEKT zeigen zu lassen mache ich folgendes:
Alles in der Funktion probe:
1
structsk_buff_headring;//<<-- OBJEKT!!!
2
tps->tx_ring=&ring//<<-- tps->tx_ring zeigt jetzt auf ein OBJEKT
Macht zwar wenig Sinn da ich es gleich ohne pointer machen könnte, aber
mich interessiert das Ergebnis.
So. Jetzt initialisier ich es, und frage mal die Länge ab mit
1
skb_queue_len(tps->tx_ring)
Wird auch orgnungsgemäß 0 ausgegeben. Ich probiers nochmal mit einem
enqueue/dequeue -> funktioniert. Länge 0->1->0, korrekt!
Ab hier in der send-Packet-Funkion(hard_xmit) die vom Kernel aufgerufen
wird:
Wenn jetzt ein Frame vom Kernel ankommt und der mittels
enqueue(tps->tx_ring, skb) dem tx_ring zugefügt wird, stürzt das system
ab. Warum?
Dazu gibt skb_queue_len(tps->tx_ring) die Länge -60.....Tausend
irgendwas aus. Warum? Alle Addressen(von tps, tx_ring, tx_ring.qlen)
sind mit dem Aufruf aus probe identisch!
Hängt es damit zusammen das jetzt aus einem anderen Thread zugegriffen
wird?? Kann eigenthlich nicht sein weil ohne einem
skb_queue_head-Pointer im tps struct funktioniert alles..
Daher die Frage: Wo liegt der Unterschied ob auf ein existierendes(!!)
Objekt mittels eines Pointer oder direkt zugegriffen wird?
Wenn ich in die Bücherei gehe und das gewolltes Buch von der Rezeption
bekomme, so sollte es dasselbe sein als wenn ich es mit einem
Adresskärtchen aus dem Regal hole.
Markus R. schrieb:>> Hängt es damit zusammen das jetzt aus einem anderen Thread zugegriffen> wird?? Kann eigenthlich nicht sein weil ohne einem> skb_queue_head-Pointer im tps struct funktioniert alles..> Daher die Frage: Wo liegt der Unterschied ob auf ein existierendes(!!)> Objekt mittels eines Pointer oder direkt zugegriffen wird?> Wenn ich in die Bücherei gehe und das gewolltes Buch von der Rezeption> bekomme, so sollte es dasselbe sein als wenn ich es mit einem> Adresskärtchen aus dem Regal hole.
Fang mal endlich an Code von anderen Leuten zulesen ...
Ein
1
gitgrepskb_queue_head_initdrivers/net/
gibt mir diesen Output
1
drivers/net/ethernet/marvell/mv643xx_eth.c:
2
skb_queue_head_init(&txq->tx_skb);
die anderen Zeilen habe ich hier ausgeblendet.
Dann mal nach
1
gitgreptx_skbdrivers/net/ethernet/marvell
Gibt
1
drivers/net/ethernet/marvell/mv643xx_eth.c:
2
__skb_queue_tail(&txq->tx_skb,skb);
Wieder die anderen Zeilen brauch' ich nicht
Da ist in
include/linux/skbuff.h definiert
Und bevor du noch einen Fehler machst:
Was ist der Unterschied zwischen :
void skb_queue_tail (struct sk_buff_head *list, struct sk_buff *newsk);
und
void __skbqueue_tail (struct sk_buff_head *list, struct sk_buff *newsk);
Welche der beiden Codeabschnitte wird hier funktionieren.
Hans Ulli Kroll schrieb:> Und bevor du noch einen Fehler machst:>> Was ist der Unterschied zwischen :> void skb_queue_tail (struct sk_buff_head *list, struct sk_buff *newsk);> und> void __skbqueue_tail (struct sk_buff_head *list, struct sk_buff *newsk);>> Welche der beiden Codeabschnitte wird hier funktionieren.>