Problem mit ioctl



  • Hallo,

    ich habe folgenden Quellcode:

    #include <linux/fs.h>
    #include <linux/version.h>
    #include <linux/module.h>
    #include <linux/init.h>
    #include <asm/uaccess.h>  
    #include <linux/ioctl.h>
    #include <asm/io.h>
    #include <linux/kernel.h>
    
    // Peripherieinformationen  
    #define Peripherie_Basis	0x20000000													// Startadresse der Peripherie						
    #define GPIO_Basis			(Peripherie_Basis + 0x200000)								// Startadresse des GPIO-Controllers
    #define I2C1_Basis			(Peripherie_Basis + 0x804000)								// Startadresse des I2C-Controllers
    
    // Treiberinformationen
    #define NAME				"ADS1015"													// Name des Treibers
    #define DRIVER_MAJOR 		240															// Major Nummer
    
    // BSC Status
    #define DONE 				(1 << 1)
    
    // ADC
    #define ADC_Data 			0
    #define ADC_Config 			1
    #define LO_Tresh			2
    #define HI_Tresh			3
    
    static volatile uint32_t Bus = 1;
    static volatile uint32_t Address = 0x48;
    static volatile uint32_t Config = 0x40E3;
    
    // Programmierer
    MODULE_AUTHOR("Daniel Kampert");
    MODULE_LICENSE("GPL");
    MODULE_DESCRIPTION("Driver for ADS1015 I2C ADC");
    MODULE_SUPPORTED_DEVICE("Raspberry Pi 512MB");       
    
    static volatile uint32_t  *GPIO; 
    static volatile uint32_t  *I2C1; 
    
    void I2C_Send_SingleByte(int Bus, int Data, int Address)
    {
    	// Adresse speichern
    	*(I2C1 + 3)  = Address;
    
    	// Anzahl zu übermittelnder Bytes festlegen
    	*(I2C1 + 2) = 1; 
    
    	// Daten speichern
    	*(I2C1 + 4) = Data;
    
    	// Statusbits löschen
    	*(I2C1 + 1) = (1 << 9) | (1 << 8) | (1 << 1);
    
    	// Übertragung starten
    	*(I2C1) = (1 << 15) | (1 << 7); 	
    	while(!(*(I2C1 + 1) & DONE));
    }
    
    void I2C_Send_Byte(int Bus, int Register, int Data, int Address)
    {
    	// Adresse speichern
    	*(I2C1 + 3)  = Address;
    
    	// Anzahl zu übermittelnder Bytes festlegen
    	*(I2C1 + 2) = 2; 
    
    	// Daten speichern
    	*(I2C1 + 4) = Register;
    	*(I2C1 + 4) = Data;
    
    	// Statusbits löschen
    	*(I2C1 + 1) = (1 << 9) | (1 << 8) | (1 << 1);
    
    	// Übertragung starten
    	*(I2C1) = (1 << 15) | (1 << 7); 	
    	while(!(*(I2C1 + 1) & DONE));
    }
    
    void I2C_Send_Short(int Bus, int Register, int Data, int Address)
    {
    	int MSB = 0;
    	int LSB = 0;
    
    	// Daten aufteilen
    	MSB = Data & 0xFF00;
    	MSB = MSB >> 8;
    	LSB = Data & 0xFF;
    
    	// Adresse speichern
    	*(I2C1 + 3)  = Address;
    
    	// Anzahl zu übermittelnder Bytes festlegen
    	*(I2C1 + 2) = 3; 
    
    	// Daten im FIFO speichern
    	*(I2C1 + 4) = Register;
    	*(I2C1 + 4) = MSB;
    	*(I2C1 + 4) = LSB;
    
    	// Statusbits löschen
    	*(I2C1 + 1) = (1 << 9) | (1 << 8) | (1 << 1);
    
    	// Übertragung starten
    	*(I2C1) = (1 << 15) | (1 << 7); 	
    	while(!(*(I2C1 + 1) & DONE));
    }
    
    int I2C_Read_Short(int Bus, int Register, int Address)
    {
    	int MSB = 0;
    	int LSB = 0;
    
    	// Registeradresse setzen
    	I2C_Send_SingleByte(Bus, Register, Address);
    
    	// Adresse speichern
    	*(I2C1 + 3)  = Address;
    
    	// Anzahl zu übermittelnder Bytes festlegen
    	*(I2C1 + 2) = 2; 
    
    	// Statusbits löschen
    	*(I2C1 + 1) = (1 << 9) | (1 << 8) | (1 << 1);
    
    	// Übertragung starten
    	*(I2C1) = (1 << 15) | (1 << 7) | (1 << 4) | (1 << 0); 	
    
    	// Auf Daten warten
    	while(!(*(I2C1 + 1) & DONE));
    
    	// Daten empfangen
    	MSB = (*(I2C1 + 4) & 255);
    	LSB = (*(I2C1 + 4) & 255);
    
    	return (MSB << 8) | LSB;
    }
    
    static int driver_open(struct inode *geraete_datei, struct file *instanz )
    {
    	// Speicherbereich der IO maskieren
    	GPIO = (uint32_t *)ioremap(GPIO_Basis, 4096);
    
    	// Speicherplatz des I2C Controllers maskieren
    	I2C1 = (uint32_t *)ioremap(I2C1_Basis, 4096);
    
    	// Bitmuster löschen
    	*(GPIO) &= ~(7 << 6);												
    	*(GPIO) &= ~(7 << 9);
    
    	// Alternative Funktion 1 aktivieren
    	*(GPIO) |= 4 << 6;
    	*(GPIO) |= 4 << 9;
    
    	// Systemlog Ausgabe
    	printk("Treiber geoeffnet\n");
    	printk("ADC wird konfiguriert\n");
    
    	// ADC konfigurieren
    	I2C_Send_Short(Bus, ADC_Config, Config, Address);
    
        return 0;
    }
    
    static int driver_close(struct inode *geraete_datei, struct file *instanz )
    {
    	printk(NAME);
        printk(" wird beendet....\n");
        return 0;
    }
    
    static ssize_t driver_read(struct file *instanz, char *User, size_t Count, loff_t *offset )
    {
    	int ret;
    	int Data = 0; 
    	int Konfiguration = 0;
    
    	Konfiguration = I2C_Read_Short(Bus, ADC_Config, Address);
    
    	// ADC auslesen
    	Data = I2C_Read_Short(Bus, ADC_Data, Address);
    	Data = Data >> 4;
    
    	// Ausgabe im Systemlog
    	printk("Konfiguration: %i\n", Konfiguration);
    	printk("ADC wird ausgelesen: %i\n", Data);
    
    	// Daten in den Userspace kopieren
    	ret = copy_to_user(User, &Data, Count);
    
    	return Count;	
    }
    
    static ssize_t driver_write(struct file *Instanz, const char *Buffer, size_t Count, loff_t *offs)
    {
    	int ret;
    	char Recieve[10];
    
    	// Daten übernehmen
    	ret = copy_from_user(&Recieve, Buffer, Count);
    	printk(Recieve);
    	printk("\n");
    
    	return Count;
    }
    
    static int driver_ioctl(struct inode *inode, struct file *instanz, unsigned int cmd, unsigned long arg)
    {
    	printk("IO-Control: %i\n", cmd);
    	printk("Argument: %ul\n", arg);
    	return 0;
    }
    
    // Fileoperations
    static struct file_operations fops = {                     
        .owner   			= THIS_MODULE,
        .read    			= driver_read,
    	.write   			= driver_write,
        .open    			= driver_open, 
    	.unlocked_ioctl		= driver_ioctl,
        .release 			= driver_close,
    };
    
    // Treiber beim Betriebssystem anmelden
    static int __init Init(void)
    {
        if(register_chrdev(DRIVER_MAJOR, NAME, &fops) == 0) 
    	{
    		printk(NAME);
    		printk(" erfolgreich angemeldet!\n");
            return 0;
    	}
    	else
    	{
    	    printk("Anmeldung fehlgeschlagen!\n");
    		return -EIO;
    	}
    }
    
    // Treiber vom Betriebssystem abmelden
    static void __exit Exit(void)
    {
        unregister_chrdev(DRIVER_MAJOR, NAME);  
    }
    
    module_init(Init);
    module_exit(Exit);
    

    In diesem Code möchte ich einfach nur die Parameter von einem ioctl-Aufruf ausgeben lassen (erst einmal).
    Im Userspace verwende ich dieses Programm:

    #include <fcntl.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <stdio.h>
    #include <sys/ioctl.h>
    
    int main(int argc, char** argv)               																
    {
    	int fd;
    	int Status;
    
    	fd = open("/dev/ADC", O_RDWR);
    	read(fd, &Status, 2);
    	printf("ADC-Wert: %i", Status);
    	printf("\n");
    	write(fd, "10", 3);
    	ioctl(fd, 1, 2);
    	sleep(1);
    
    	close (fd);	
    
    	return 0;
    }
    

    Wenn ich dieses Programm nun aufrufe erhalte ich beim ioctl nicht 1 und 2 als Ausgabe, sondern das hier:

    Sep 18 10:10:04 RaspberryPi kernel: [178461.099175] IO-Control: 2
    Sep 18 10:10:04 RaspberryPi kernel: [178461.118115] Argument: 3205640228l

    Wieso erhalte ich diese komischen Ausgaben?

    Danke für die Hilfe!



  • Kampi schrieb:

    Wieso erhalte ich diese komischen Ausgaben?

    Welche Ausgabe erwartest du?

    Stell mal den Warnlevel von deinem Compiler höher ein und beachte auch die Warnungen.

    %i ist der falsche Formatspecifier für ein unsigned int
    %ul ist der falsche Formatspecifier für ein unsigned long

    Man sollte auch nie eine Variable, deren Inhalt man nicht unter Kontrolle hat, als Formatsring für printf (& co) nehmen.



  • Hey,

    eigentlich habe ich gedacht ich würde die durch den ioctl übergebenen Parameter da ausgegeben bekommen, sprich einmal die "1" als Befehl und die "2" als Argument.



  • Kampi schrieb:

    Hey,

    eigentlich habe ich gedacht ich würde die durch den ioctl übergebenen Parameter da ausgegeben bekommen, sprich einmal die "1" als Befehl und die "2" als Argument.

    Dann nimm erstmal die richtigen Formatspecifier für die Argumente.

    Und rufe ioctl mit der richtigen Anzahl Parameter auf (auch in der richtigen Reihenfolge).



  • Die richtigen Formatspecifier habe ich nun eingebaut.
    Ich habe mich an dieses Beispiel gehalten:

    http://linux.die.net/lkmpg/x892.html

    Da haben die auch drei Argumente genommen.....und soweit ich gelesen habe stellen die ersten beiden Argumente den Filedescriptor dar.
    Was fehlt den dann in meinem Aufruf oder habe ich was falsch verstanden?


Anmelden zum Antworten