PDA

View Full Version : [char devices] impossibile scrivere e leggere


Dawidh
28-05-2008, 11:14
:ave: chiedo perdono a ilsensine per aver aperto il thread un attivo fa e aver cannato di brutto il titolo :p

allora riposto il problema:
devo aver tolto qualcosa o forse il problema è solo della debian emulata in qemu (spero!!) boh non so, sta di fatto che adesso il device si crea e si toglie senza problemi ma se provo a leggere o scrivere mi restituisce
cat: /dev/module: No such device or address
il modulo c'è ma probabilmete è un problema dell'indirizzo?? Vi posto anche tutto il codice, gradirei se potete commenti del tipo, così è meglio non fare :D non è il metodo corretto :D lo so anche io ma sto seguendo l'esempio del prof e di rubini (scull).
Se riuscite a trovare l'eroore ve ne sarò eternamente grato.
Ciao.

#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/config.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/errno.h> /* error codes */
#include <linux/proc_fs.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <linux/seq_file.h>
#include <linux/cdev.h>

#include <asm/system.h> /* cli(), *_flags */
#include <asm/uaccess.h> /* copy_*_user */

#include <linux/mm.h>
#include <linux/kdev_t.h>
#include <asm/page.h>
#include <linux/device.h>



MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Davide");

static char *whom = "world";
static int howmany = 1;
module_param(howmany, int, S_IRUGO);
module_param(whom, charp, S_IRUGO);

struct scull_dev {
// struct scull_qset *data; /* Pointer to first quantum set */
// int quantum; /* the current quantum size */
// int qset; /* the current array size */
// unsigned long size; /* amount of data stored here */
struct semaphore priv_reader, priv_writer;
struct semaphore sem; /* mutual exclusion semaphore */
struct cdev cdev; /* Char device structure */
};
struct scull_dev *scull_devices; /* allocated in scull_init_module */



int module_minor = 0;
int module_major = 0;
int scull_nr_devs = 1;
char *my_pointer;
char anello[1024] = "1";
int testa = 0, coda = 0;
int *controllo;


int scull_open(struct inode *inode, struct file *filp)
{
printk(KERN_NOTICE "It's OK");
struct scull_dev *dev; /* device information */

dev = container_of(inode->i_cdev, struct scull_dev, cdev);
filp->private_data = dev; /* for other methods */

/* now trim to 0 the length of the device if open was write-only */
if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) {
if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
up(&dev->sem);
}
return 0; /* success */


// struct cdev dev; /* device information */
// controllo=kmalloc(sizeof(int), GFP_USER);
// controllo=0;
// dev = container_of(inode->i_cdev, struct scull_dev, cdev);
// filp->private_data = dev; /* for other methods */
// printk(KERN_NOTICE "It's OK");
// dev->size = 1024;
// return 0; /* success */
}

int scull_release(struct inode *inode, struct file *filp)
{
return 0;
}



ssize_t scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{

struct scull_dev *dev = filp->private_data;
down_interruptible(&dev->sem);
ssize_t retval = 0;
if ((int)controllo == 1)
up(&dev->sem);
return 0;
// count = dev->size;
if (copy_to_user(buf, anello, count)) {
retval = -EFAULT;
goto out;
}
retval = count;
out:
up(&dev->sem);
return retval;
}

ssize_t scull_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
// struct scull_dev *dev = filp->private_data;
ssize_t retval = 0;
int err;
if (my_pointer) {
return -1;
}
my_pointer = kmalloc(count, GFP_USER);
if (my_pointer == NULL) {
return -1;
}
err = copy_from_user(my_pointer, buf, count);
if (err) {
return -EFAULT;
}

strcat(anello, my_pointer);
my_pointer = NULL;
kfree(my_pointer);
retval = count;
return retval;
}




static struct file_operations my_fops = {
.owner = THIS_MODULE,
// .llseek = scull_llseek,
.read = scull_read,
.write = scull_write,
// .ioctl = scull_ioctl,
.open = scull_open,
.release = scull_release,
};


void scull_cleanup_module(void)
{
int i;
dev_t devno = MKDEV(module_major, module_minor);

/* Get rid of our char dev entries */
if (scull_devices) {
for (i = 0; i < scull_nr_devs; i++) {
cdev_del(&scull_devices[i].cdev);
}
kfree(scull_devices);
}

#ifdef SCULL_DEBUG /* use proc only if debugging */
scull_remove_proc();
#endif

/* cleanup_module is never called if registering failed */
unregister_chrdev_region(devno, scull_nr_devs);
}


/*
* Set up the char_dev structure for this device.
*/
static void scull_setup_cdev(struct scull_dev *dev, int index)
{
int err, devno = MKDEV(module_major, module_minor + index);

cdev_init(&dev->cdev, &my_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &my_fops;
err = cdev_add (&dev->cdev, devno, 1);
/* Fail gracefully if need be */
if (err)
printk(KERN_NOTICE "Error %d adding scull%d", err, index);
}


static int __init hello_init (void) {

int result, i;
dev_t dev = 0;
if (module_major) {
dev = MKDEV(module_major, module_minor);
result = register_chrdev_region(dev, scull_nr_devs, "module");
} else {
result = alloc_chrdev_region(&dev, module_minor, scull_nr_devs,
"module");
module_major = MAJOR(dev);
}
if (result < 0) {
printk(KERN_WARNING "module: can't get major %d\n", module_major);
return result;
}
/*
* allocate the devices -- we can't have them static, as the number
* can be specified at load time
*/
scull_devices = kmalloc(scull_nr_devs * sizeof(struct scull_dev), GFP_KERNEL);
if (!scull_devices) {
result = -ENOMEM;
goto fail; /* Make this more graceful */
}
memset(scull_devices, 0, scull_nr_devs * sizeof(struct scull_dev));

/* Initialize each device. */
for (i = 0; i < scull_nr_devs; i++) {
sema_init(&scull_devices[i].priv_reader, 1);
sema_init(&scull_devices[i].priv_writer, 1);
init_MUTEX(&scull_devices[i].sem);
scull_setup_cdev(&scull_devices[i], i);
}

/* At this point call the init function for any friend device */
dev = MKDEV(module_major, module_minor + scull_nr_devs);

#ifdef SCULL_DEBUG /* only when debugging */
scull_create_proc();
#endif

return 0; /* succeed */

fail:
scull_cleanup_module();
return result;
}
static void __exit hello_exit (void) {
int i;
dev_t devno = MKDEV(module_major, module_minor);

/* Get rid of our char dev entries */
if (scull_devices) {
for (i = 0; i < scull_nr_devs; i++) {
cdev_del(&scull_devices[i].cdev);
}
kfree(scull_devices);
}

#ifdef SCULL_DEBUG /* use proc only if debugging */
scull_remove_proc();
#endif

/* cleanup_module is never called if registering failed */
unregister_chrdev_region(devno, scull_nr_devs);
}
module_init(hello_init);
module_exit(hello_exit);


Ora come ora mi basta farlo andare, non farlo corretto!Grazie.

Dawidh
28-05-2008, 11:29
Era solo un problema dela macchina virtuale, sbagliando qualcosa mi ha sballato il kernel senza che me ne accorgessi, infatti ne ho fatta partire un'altra e il tutto funziona.....
Allora già che ci sono volevo chiedervi perché se faccio 2 cat consecutive poi si blocca (credo sul semaforo)?
Forse non ho capito bene l'uso del semaforo?boh ma a me sembra corretto così...
Chiedo lumi.
grazie

ilsensine
28-05-2008, 11:34
La read ha un errore grossolano, per questo si blocca.

Veramente pretendono di insegnarti la scrittura di driver partendo in questo modo? In che università stai?

Dawidh
28-05-2008, 11:44
La read ha un errore grossolano, per questo si blocca.
Si ho notato, me ne vergogno.... ma con questo cavolo di progetto sono completamente fuso e non vedo neanche più le cose banali, infatti adesso funziona ottimamente.

Veramente pretendono di insegnarti la scrittura di driver partendo in questo modo? In che università stai?
Si si, sono a informatica a trento, spiegano un pò perché hanno un sacco di programma da fare e tre possibili progetti da spiegarci quindi il tempo è tiratissimo....per tutto il resto ti lascianoun pò in balia della fortuna :( (fortuna che c'è hwupgrade)
cmq è SO1 quindi le cose si fanno molto superficialmente, ho già fatto SO2 che è del 3° anno e lì si fanno molto meglio, con i misc device, tipo la guida che hai fatto tu insomma, kthread etc. molto molto meglio.

ilsensine
28-05-2008, 11:52
Comunque ti faccio un rapido review, senza pretese di essere troppo corretto.

#include <world.h>

Sequenza interminabile di include, molti ridondanti. linux/config.h non esiste sui kernel recenti.


int scull_open(struct inode *inode, struct file *filp)
{
...
dev = container_of(inode->i_cdev, struct scull_dev, cdev);
filp->private_data = dev; /* for other methods */

mmm dev è desumibile dempre dall'inode, che è desumibile sempre da filp. Gli "other methods" possono recuperarlo così, se ne hanno bisogno.
private_data serve in genere per contenere dati specifici per _questa_ istanza aperta dell'inode.
E' solo un consiglio; nulla vieta di fare come stai facendo.


/* now trim to 0 the length of the device if open was write-only */
if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) {

Perché prendi il lock solo con O_WRONLY?

if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
up(&dev->sem);

Significato pratico di questo codice?


ssize_t scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
...
down_interruptible(&dev->sem);

Manca il controllo sul valore di ritorno.
Se il file è aperto con O_NONBLOCK, dovresti usare down_trylock e ritornare -EAGAIN in caso di insuccesso.

if ((int)controllo == 1)

Eh?

up(&dev->sem);
return 0;

Queste righe devono essere raggruppate da {} presumo. Il blocco che stai osservando è dovuto a questo.


if (copy_to_user(buf, anello, count)) {

Se count>sizeof(anello)?

ssize_t scull_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)

Riscrivi questa funzione, è piena di errori...

my_pointer = NULL;
kfree(my_pointer);

...ma attento a queste chicche :D

Dawidh
28-05-2008, 12:05
Grazie per le dritte.
Per il blocco mi ero accorto delle graffe, e me ne vergogno di aver dovuto chiedere.. :D
su count metterò il controllo anche perché anello deve diventare un array circolare per cui devo aggiungere parecchi if ancora.
Le parti che ti sembrano oscure e che non fanno niente in realtà servivano solo nel codice originale prima dei miei cut quindi ora ho tolto il superfluo.

Grazie ancora, continuo a creare questa specie di Krankestein del C mettendo pezzi di codice presi qui e la.. :D

P.S. se non si fosse capito faccio informatica ma non mi piace programmare, mi piace molto di più il resto, reti, algoritmi, etc. ma C e Java :nono: