Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Подскажите с f->f_op->read  (Прочитано 22272 раз)
0 Пользователей и 1 Гость смотрят эту тему.
opushkin
Гость
« : 12-01-2006 13:21 » 

Подскажите кто знает!
Читаю-пишу в ttyS0 из прерывания таймера примерно так:
void ndt_irq (unsigned long data)
{
spin_lock_bh(&timer_lock);
struct my_buf *tbf;
tbf = &rbuffer;

fs=get_fs();
set_fs(KERNEL_DS);
if (f && f->f_dentry &&
 f->f_op && f->f_op->read) {
 .......
 retval = f->f_op->read(f, &tbf->rc, 1, &f->f_pos);
 ........
 f->f_op->write(f, "NICHEVO NE CHITAET", 18, &f->f_pos);
 
 if (retval <= 0) printk("<0> ^tstnd: READE returns: %d\n", retval);
 }
 else printk("<0> ^tstnd: stuct FILE is empty\n");
set_fs(fs);

mod_timer(&timer, jiffies + HZ);
spin_unlock_bh(&timer_lock);
}
Передаётся всё нормально, но ничего не читает. Возвращает код -11 (типа: пилите Шура - они золотые)
Если циклить на чтении - пилит до бесконечности.
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #1 : 12-01-2006 13:47 » 

Не вижу назначение f
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
opushkin
Гость
« Ответ #2 : 13-01-2006 09:16 » 

Назначение при инициализации модуля  такое:
fs=get_fs();
set_fs(KERNEL_DS);
  f=filp_open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY, 0666);
   if(f == NULL) printk (KERN_WARNING "^tstnd: Error opening ttyS.\n");
set_fs(fs);

p.s. Прошу прощенья за задержку ответа - понадеялся на оповещение через email.
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #3 : 13-01-2006 17:29 » 

Цитата
Код:
   if(f == NULL) printk (KERN_WARNING "^tstnd: Error opening ttyS.\n");

Код:
if (IS_ERROR(f)) ...
Ошибкой является не NULL, а ERR_PTR(error). См. исходники fs/open.c
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
opushkin
Гость
« Ответ #4 : 14-01-2006 06:55 » 

Спасибо.
У меня эта функция определена как IS_ERR(), но всё равно никаких ERR нету, и чтения тоже.
Смутно помню, где то мелькало, что макросы set_fr/get_fs в обработчиках прерываний не работают, и нужно использовать очереди, но чего очереди не уточнялось и не могу найти -где видел. Да и если бы они сдесь не работали, так оно бы не работали и для write.
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #5 : 14-01-2006 12:53 » 

Приведи ф-ий полностью - кусками плохо смотреть.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
opushkin
Гость
« Ответ #6 : 14-01-2006 14:07 » 

Сетевой драйвер - демонструха со связью через СОМ порт; ttyS0 конфигурируется скриптом; f открывается при инициализации модуля; передача при вызове _xmit через ->write работает; чтение хочется сделать по опросу через таймер, но оно не работает. Привожу весь код. Прошу сильно не бить - эксперимент в процессе, много несуразностей, но не критичных (я та-ак думаю).
Код: (C)
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/sched.h>    /* For current */
#include <linux/tty.h>      /* For the tty declarations */
#include <linux/jiffies.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/inet.h>
#include <linux/skbuff.h>
#include <linux/mm.h>
#include <asm/segment.h>
#include <linux/slab.h>
#include <linux/file.h>
#include <linux/mman.h>
#include <linux/a.out.h>
#include <linux/stat.h>
#include <linux/timer.h>
#include <linux/timex.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
spinlock_t timer_lock = SPIN_LOCK_UNLOCKED;
spinlock_t tx_lock = SPIN_LOCK_UNLOCKED;
/*Структура пакета*/
struct iphdr
  {
    unsigned int ihl:4;
    unsigned int version:4;
    u_int8_t tos;
    u_int16_t tot_len;
    u_int16_t id;
    u_int16_t frag_off;
    u_int8_t ttl;
    u_int8_t protocol;
    u_int16_t check;
    unsigned char saddr[4]; /* IP address of originator */
    unsigned char daddr[4]; /* IP address of destination */
    /*The options start here. */
  };
struct my_buf {
int rlen;
unsigned char *rdata;
char rc;
        union rbuffer{
        unsigned char rbuff[1024];
        struct iphdr rhdr;
        }rb;
};
struct file *f;
struct net_device_stats *stats;
struct timer_list timer;
struct my_buf rbf;

static int ndt_xmit(struct sk_buff *skb, struct net_device *dev);
static struct net_device_stats *ndt_get_stats(struct net_device *dev);
/*static void load_pack(struct my_buf *xbf);*/
static void ttys_write(const char *buf, size_t lenbuf);

int fd, retval, shift;
mm_segment_t fs;

void ndt_irq (unsigned long data)
{
spin_lock_bh(&timer_lock);
struct my_buf *tbf;
tbf = &rbf;

fs=get_fs();
set_fs(KERNEL_DS);
if (f && f->f_dentry &&
       f->f_op && f->f_op->read) {
 
     /*do retval = f->f_op->read(f, &tbf->rc, 1, &f->f_pos);
     while (retval == -11);*/

     retval = f->f_op->read(f, &tbf->rc, 1, &f->f_pos);
     f->f_op->write(f, "!==END READ==!", 14, &f->f_pos);
printk(KERN_WARNING "^tstnd: ===PIC=== retval= %d char= %s.\n", retval, &tbf->rc);
        if (retval > 0){
        shift = tbf->rlen++;
        tbf->rb.rbuff[shift] = tbf->rc;
        ttys_write("!==PUT CHAR==!", 14);
                if (tbf->rlen > 9) {
                ttys_write(tbf->rb.rbuff, tbf->rlen);
                tbf->rlen = 0;
                ttys_write("!==SENT BUFF==!", 15);
                }
        }
    }
   else  printk("<0> ^tstnd: stuct FILE is empty\n");
set_fs(fs);

mod_timer(&timer, jiffies + 1 * HZ);
spin_unlock_bh(&timer_lock);
}
/*Вызывается IFCONFIG */
int ndt_open (struct net_device *dev)
{
        printk(KERN_WARNING "^tstnd: ndt_open called.\n");
        netif_start_queue (dev);
/*указатель на начало данных*/
rbf.rdata = &rbf.rb.rbuff[0];
/*инициализация таймера*/
init_timer(&timer);
timer.expires = jiffies + 2 * HZ;
timer.function = ndt_irq;
add_timer(&timer);
return 0;
}
/*Вызывается IFCONFIG */
int ndt_stop (struct net_device *dev)
{
/*остановка таймера*/
del_timer_sync(&timer);
        printk (KERN_WARNING "^tstnd: ndt_stop called.\n");
        netif_stop_queue(dev);
        return 0;
}
/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
static int ndt_xmit (struct sk_buff *skb, struct net_device *dev)
{
struct net_device_stats *stats = dev->priv;
/*unsigned char *sad;
unsigned char *dad;
unsigned char sadd[4];
unsigned char dadd[4];*/


spin_lock_bh(&tx_lock);
fs=get_fs();
set_fs(KERNEL_DS);
     f->f_op->write(f, skb->data, skb->len, &f->f_pos);
     f->f_op->write(f, "===PACK_END===", 14, &f->f_pos);
set_fs(fs);
spin_unlock_bh(&tx_lock);

/*Передача пакета через буфер приёмника назад*/
/*              rbf.rlen = skb->len;
        shift = 0;
                while (shift + 1 <= skb->len) {
                rbf.rb.rbuff[shift] = skb->data[shift];
                shift++;
                }
sad = &rbf.rb.rhdr.saddr[0];
dad = &rbf.rb.rhdr.daddr[0];
        shift = 0;
                while (shift + 1 <= 4) {
                sadd[shift] = sad[shift];
                shift++;
                }
        shift = 0;
                while (shift + 1 <= 4) {
                dadd[shift] = dad[shift];
                shift++;
                }
sad = &sadd[0];
dad = &dadd[0];
        shift = 0;
                while (shift + 1 <= 4) {
                rbf.rb.rhdr.daddr[shift] = sad[shift];
                shift++;
                }
        shift = 0;
                while (shift + 1 <= 4) {
                rbf.rb.rhdr.saddr[shift] = dad[shift];
                shift++;
                }
load_pack(&rbf);*/


        dev_kfree_skb(skb);
        stats->tx_bytes += skb->len;
        stats->tx_packets++;
return 0;
}

static struct net_device_stats *ndt_get_stats(struct net_device *dev)
{
        return dev->priv;
}
struct net_device tstnd_dev = {
        .open                   = ndt_open,
        .stop                   = ndt_stop,
        .hard_start_xmit        = ndt_xmit,
};

int ndt_init_module (void)
{
strcpy (tstnd_dev.name, "tstnd");
        stats = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
        if (stats) {
                memset(stats, 0, sizeof(struct net_device_stats));
                tstnd_dev.priv = stats;
                tstnd_dev.get_stats = &ndt_get_stats;
        }

if ((retval = register_netdev (&tstnd_dev))) {
        printk (KERN_WARNING "^tstnd: Error %d  of initializing module.\n",retval);
        return retval;
        }
printk(KERN_WARNING "^tstnd: initializing the Module.\n");

spin_lock_bh(&tx_lock);
fs=get_fs();
set_fs(KERNEL_DS);
  f=filp_open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY, 0666);
   if(IS_ERR(f)) printk (KERN_WARNING "^tstnd: Error opening ttyS.\n");
set_fs(fs);
spin_unlock_bh(&tx_lock);
return 0;
}

void ndt_cleanup (void)
{
spin_lock_bh(&tx_lock);
fs=get_fs();
set_fs(KERNEL_DS);
  filp_close(f,0);
set_fs(fs);
spin_unlock_bh(&tx_lock);
        unregister_netdev (&tstnd_dev);
        printk (KERN_WARNING "^tstnd: Cleaning Up the Module.\n");
        return;
}

module_init (ndt_init_module);
module_exit (ndt_cleanup);
/*=================================================================================*/
/* Вывод строки на ttyS0 */
static void ttys_write(const char *buf, size_t lenbuf)
{
spin_lock_bh(&tx_lock);
fs=get_fs();
set_fs(KERNEL_DS);
   if(f != NULL) {
     f->f_op->write(f, buf, lenbuf, &f->f_pos);
    }
   else  printk(KERN_WARNING "^tstnd: stuct FILE is empty\n");
 set_fs(fs);
spin_unlock_bh(&tx_lock);
}

/* Изменение формата адреса из двоичного в текстовый.*/
void printAddr(unsigned char *addr)
{
int j;
        for ( j = 0; j < 4; j++ )
        {
        printk("%d", addr[j]);
        if ( j < 3 )
                printk(".");
        }
}
/* Вывод содержимого пакета в лог*/
/*void pdumpk(void* b, int len)
{
int i;
struct iphdr *ip = b;

        printk("----------------\n");
        for ( i = 0; i < len; i++ )
        {
                if ( !(i & 15) ) printk("\n%04X:  ", i);
                printk("%02X ", ((unsigned char*)b)[i]);
        }
        printk("\n");
        printk("IPv%d: hdr-size=%d pkt-size=%d protocol=%d TTL=%d ",
                ip->version, ip->ihl*4, ntohs(ip->tot_len), ip->protocol,
                ip->ttl);
printk("\n");
        printk("rst= ");
printAddr(ip->saddr);
        printk(" dst= ");
printAddr(ip->daddr);
printk("\n");
}*/

void spdumpk(struct my_buf *sxbf)
{
int i;
        printk("\n----------------");
        for ( i = 0; i < sxbf->rlen; i++ )
        {
                if ( !(i & 15) ) printk("\n%04X:  ", i);
                printk("%02X ", ((unsigned char*)sxbf->rb.rbuff)[i]);
        }
        printk("\n");
        printk("IPv%d: hdr-size=%d pkt-size=%d protocol=%d TTL=%d ",
                sxbf->rb.rhdr.version, sxbf->rb.rhdr.ihl*4, ntohs(sxbf->rb.rhdr.tot_len),
                sxbf->rb.rhdr.protocol, sxbf->rb.rhdr.ttl);
printk("\n");
        printk("rst= ");
printAddr(sxbf->rb.rhdr.saddr);
        printk(" dst= ");
printAddr(sxbf->rb.rhdr.daddr);
printk("\n");
}

/*static void load_pack(struct my_buf *xbf)
{
        struct net_device_stats *stats = tstnd_dev.priv;
        struct sk_buff *r_skb;
        int count;
        count = xbf->rlen;
        printk(KERN_WARNING "^tstnd: Принят пакет.\n");
        r_skb = dev_alloc_skb(count);
                if (r_skb == NULL)  {
                        printk(KERN_WARNING "^tstnd: memory squeeze, dropping packet.\n");
                        stats->rx_dropped++;
                        return;
                }
        r_skb->dev = &tstnd_dev;
        memcpy(skb_put(r_skb, count), xbf->rb.rbuff, count);
        r_skb->mac.raw=r_skb->data;
        r_skb->protocol=htons(ETH_P_IP);
       
        spdumpk(xbf);*/

        /*pdumpk(r_skb->data, count);*/
/*      netif_rx(r_skb);
        stats->rx_bytes += xbf->rlen;
        stats->rx_packets++;
}*/
MAKEFILE:
Код: (Text)
TARGET = forex
OBJS = forex.o
MDIR = drivers/misc
EXTRA_CFLAGS = -DEXPORT_SYMTAB
CURRENT = $(shell uname -r)
KDIR = /lib/modules/$(CURRENT)/build
PWD = $(shell pwd)
DEST = /lib/modules/$(CURRENT)/kernel/$(MDIR)
obj-m      := $(TARGET).o
default:
        make -C $(KDIR) SUBDIRS=$(PWD) modules
$(TARGET).o: $(OBJS)
        $(LD) $(LD_RFLAG) -r -o $@ $(OBJS)
ifneq (,$(findstring 2.4.,$(CURRENT)))
install:
        su -c "cp -v $(TARGET).o $(DEST) && /sbin/depmod -a"
else
install:
        su -c "cp -v $(TARGET).ko $(DEST) && /sbin/depmod -a"
endif
clean:
        -rm -f *.o *.ko .*.cmd .*.flags *.mod.c
-include $(KDIR)/Rules.make
Скрипт для запуска:
Код: (Bash)
#!/bin/sh
insmod ./forex.ko
ifconfig tstnd 192.168.2.1 up
ifconfig tstnd netmask 255.255.255.0
#route add 192.168.2.0 tstnd
Скрипт для удаления:
Код: (Bash)
#!/bin/sh
ifconfig tstnd down
rmmod forex
Библиотек многовато - поубирал кое что из текста, а их убирать - надо возиться.





Поправил твой пост. Оформлять внешний вид надо! Теперь знаешь как (нажми "редактировать" и посмотри теги [code]).
« Последнее редактирование: 14-01-2006 14:19 от RXL » Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #7 : 14-01-2006 14:19 » 

Макрос set_fs() описан в include/asm/uaccess.h . Просто макрос. Изменяет current->addr_limit.
Там же черным по белому:
Цитата
The fs value determines whether argument validity checking should be
performed or not.  If get_fs() == USER_DS, checking is performed, with
get_fs() == KERNEL_DS, checking is bypassed.

For historical reasons, these macros are grossly misnamed.

Остальной код пока не смотрел.
« Последнее редактирование: 14-01-2006 14:27 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
opushkin
Гость
« Ответ #8 : 14-01-2006 19:26 » 

М..да... О сколько нам открытий чудных.... Я в Линухе недавно.
Ещё раз спасибо.
Записан
opushkin
Гость
« Ответ #9 : 15-01-2006 14:56 » 

Чтение оживает если напрямую разрешать прерывания по приёму в регистре управления прерываниями UART. Но работает в режиме эха - скидывает принятое назад. Адекватно себя ведёт если опять же напрямую прописать в этот рег разрешение на передачу и по CTS/DSR. Передача через ->write, а приём по опросу таймером, прямо читая рег состояния линии и данных. При  выгрузке модуля - ругается как сапожник, но ничего не отваливается.
Код: (Bash)
Jan 15 17:23:35 localhost kernel: ^tstnd: ndt_stop called.
Jan 15 17:23:35 localhost kernel: bad: scheduling while atomic!
Jan 15 17:23:35 localhost kernel:  [dump_stack+30/32] dump_stack+0x1e/0x20
Jan 15 17:23:35 localhost kernel:  [<c0107bfe>] dump_stack+0x1e/0x20
Jan 15 17:23:35 localhost kernel:  [schedule+1101/1168] schedule+0x44d/0x490
Jan 15 17:23:35 localhost kernel:  [<c02cf7ad>] schedule+0x44d/0x490
Jan 15 17:23:35 localhost kernel:  [schedule_timeout+90/176] schedule_timeout+0x5a/0xb0
Jan 15 17:23:35 localhost kernel:  [<c02cfb2a>] schedule_timeout+0x5a/0xb0
Jan 15 17:23:35 localhost kernel:  [tty_wait_until_sent+171/240] tty_wait_until_sent+0xab/0xf0
Jan 15 17:23:35 localhost kernel:  [<c01fa1db>] tty_wait_until_sent+0xab/0xf0
Jan 15 17:23:35 localhost kernel:  [uart_close+152/480] uart_close+0x98/0x1e0
Jan 15 17:23:35 localhost kernel:  [<c0209958>] uart_close+0x98/0x1e0
Jan 15 17:23:35 localhost kernel:  [release_dev+1364/1712] release_dev+0x554/0x6b0
Jan 15 17:23:35 localhost kernel:  [<c01f5b04>] release_dev+0x554/0x6b0
Jan 15 17:23:35 localhost kernel:  [tty_release+17/32] tty_release+0x11/0x20
Jan 15 17:23:35 localhost kernel:  [<c01f60f1>] tty_release+0x11/0x20
Jan 15 17:23:35 localhost kernel:  [__fput+240/288] __fput+0xf0/0x120
Jan 15 17:23:35 localhost kernel:  [<c01576c0>] __fput+0xf0/0x120
Jan 15 17:23:35 localhost kernel:  [filp_close+80/144] filp_close+0x50/0x90
Jan 15 17:23:35 localhost kernel:  [<c0155d50>] filp_close+0x50/0x90
Jan 15 17:23:35 localhost kernel:  [pg0+544732060/1069613056] ndt_cleanup+0x4c/0x80 [tmrcdr]
Jan 15 17:23:35 localhost kernel:  [<e0b6d39c>] ndt_cleanup+0x4c/0x80 [tmrcdr]
Jan 15 17:23:35 localhost kernel:  [sys_delete_module+306/384] sys_delete_module+0x132/0x180
Jan 15 17:23:35 localhost kernel:  [<c0131902>] sys_delete_module+0x132/0x180
Jan 15 17:23:35 localhost kernel:  [sysenter_past_esp+82/113] sysenter_past_esp+0x52/0x71
Jan 15 17:23:35 localhost kernel:  [<c0106dcd>] sysenter_past_esp+0x52/0x71
Jan 15 17:23:35 localhost kernel: Attempt to kill tasklet from interrupt
Jan 15 17:23:35 localhost net.agent[6640]: remove event not handled
Jan 15 17:23:35 localhost kernel: ^tstnd: Cleaning Up the Module.
Варварство конечно. Чтение в таком виде:
При инициализации:
Код: (C)
#define BASE     0x3f8      // базовый адрес
#define ICR_N     1         // регистр управления прерываниями

outb_p(10, BASE + ICR_N);
В прерывании таймера:
Код: (C)
//ЧТЕНИЕ РЕГИСТРА СОСТОЯНИЯ ЛИНИИ
data = inb_p(BASE + LSR_N);
printk(KERN_WARNING "^tstnd: Control line registr is: %x\n", data);
reg_lsr.byte = data;
//ПРЯМОЕ ЧТЕНИЕ ИЗ ПОРТА ttyS0
   if (reg_lsr.bit_reg.in_ready != 0) {
   rbf.rc = inb_p(BASE);
   printk(KERN_WARNING "^tstnd: ===PIC=== Reseived char= %s.\n", &rbf.rc);
        shift = tbf->rlen++;
        tbf->rb.rbuff[shift] = tbf->rc;
                if (tbf->rlen > 9) {
                ttys_write(tbf->rb.rbuff, tbf->rlen);
                tbf->rlen = 0;
                }
   } else printk(KERN_WARNING "^tstnd: ===PIC=== Input is empty.%x\n", data);
В общем  Не может быть... переходящее в  Быть такого не может
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #10 : 15-01-2006 18:55 » 

Я так и не понял, зачем ты используешь spin_lock_bh - тебе, как я понимаю, надо тут только проверить, первый ли раз загружен модуль?
Посмотри исходники чужих драйверов - умных мыслей там хватает.

Рекомендую почитать книгу Linux Device Drivers. Она лежит на club.sheltk.com в разделе файлов.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
opushkin
Гость
« Ответ #11 : 15-01-2006 19:56 » 

spin_lock_bh везде кроме прерывания таймера - это паранойя. Книга эта у меня есть, с переводами, главу 14 тоже смотрел, ну не хочется мне связываться с прерываниями на приёме - громоздко получается, да и не всё там в Линухе себе пока представляю. Нужна простая и наглядная вещь для демонстрации, пусть даже и плохо работающая (всмысле -медленно). А что ему, этому read надо так и не могу понять. Кстати, вышеприведённый вариант тоже как надо не работает. Попробую пока сделать полностью передачу и приём по опросу с таймером через FIFO UART. А эту проблему оставлю для досуга, вместо кросворда.
Спасибо за помощь. Здесь была моя ладья...
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #12 : 15-01-2006 21:00 » 

Не рекомендую работать с железом напрямую. Можно вызвать конфликт с существующими драйверами.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
opushkin
Гость
« Ответ #13 : 16-01-2006 06:42 » 

Согласен, но сдесь вроде железяка (UART) локализована и ресурсы ни с кем не делит. Программирование сводится к прямому отключению прерываний и буферизации (к сожалению завязана с прерываниями), а дальше работа только с регистром данных. А вдруг прояснится с file, так всегда можно переделать.
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #14 : 16-01-2006 17:33 » 

Давай позже разберем - чейчас -
Я несколько лет назад пробовал брайвер писать - надо тоько вспомнить, что зачем. Пиво!
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
opushkin
Гость
« Ответ #15 : 17-01-2006 05:56 » 

Давай. У меня пока вот что получилось. Работает, но слегка теряет пакеты. На 38400 - 3% на пинге, чем выше скорость тем меньше.
Код:
/***************************************************************************
 *   Copyright (C) 2005 by Igor Timoshenko                                 *
 *   timigor@yandex.ru                                                     *
 *   Simple SLIP                                                           *
 ***************************************************************************/
MODULE_LICENSE("GNU");
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/jiffies.h>
#include <asm/io.h>
#include <linux/skbuff.h>
#include <linux/timer.h>

#define TIMEOUT     HZ/50
#define TIMEPIC     HZ/100
/*РЕГИСТРЫ СОМ ПОРТА*/
#define BASE     0x3f8      // базовый адрес для СОМ1
#define ICR_N     1         // регистр управления прерываниями 3f9
#define IIDR_N    2         // регистр идент прерывания / упр. буферизацией 3fa
#define MCR_N     4         // регистр управления модемом 3fc
#define LSR_N     5         // регистр состояния линии 3fd
#define MSR_N     6         // регистр состояния модема 3fe
// регистр управления модемом
typedef union  _MCR_ {
   struct {
      unsigned char dtr : 1;
      unsigned char rts : 1;
      unsigned char out1 : 1;
      unsigned char out2 : 1;
      unsigned char diag : 1;
      unsigned char reserv : 3;
   } bit_reg;
   unsigned char byte;
} MCR;
MCR reg_mcr;
// регистр состояния модема
typedef union _MSR_ {
   struct {
      unsigned char change_cts : 1;
      unsigned char change_dsr : 1;
      unsigned char change_ri : 1;
      unsigned char change_dcd : 1;
      unsigned char cts : 1;
      unsigned char dsr : 1;
      unsigned char ri : 1;
      unsigned char dcd : 1;
   } bit_reg;
   unsigned char byte;
} MSR;
MSR reg_msr;
// регистр состояния линии
typedef union _LSR_ {
   struct {
      unsigned char in_ready : 1;
      unsigned char overflow : 1;
      unsigned char parity : 1;
      unsigned char synxr : 1;
      unsigned char break_detect : 1;
      unsigned char out_ready : 1;
      unsigned char shift_ready : 1;
      unsigned char taimout : 1;
   } bit_reg;
   unsigned char byte;
} LSR;
LSR reg_lsr;
/*Структура IP пакета*/
struct iphdr  {
    unsigned int ihl:4;
    unsigned int version:4;
    u_int8_t tos;
    u_int16_t tot_len;
    u_int16_t id;
    u_int16_t frag_off;
    u_int8_t ttl;
    u_int8_t protocol;
    u_int16_t check;
    unsigned char saddr[4]; /* IP address of originator */
    unsigned char daddr[4]; /* IP address of destination */
    /*The options start here. */
  };
struct my_buf {
int rlen;
unsigned char rtail[2];
union rbuffer{
unsigned char rbuff[1024];
struct iphdr rhdr;
}rb;
int tlen;
union tbuffer{
unsigned char tbuff[1024];
struct iphdr thdr;
}tb;
};

int ssl_stop (struct net_device *dev);
int ssl_open (struct net_device *dev);
static int ssl_xmit(struct sk_buff *skb, struct net_device *dev);
static struct net_device_stats *ssl_get_stats(struct net_device *dev);
static void load_pack(struct my_buf *xbf);
//void tpdumpk(struct my_buf *txbf);
//void rpdumpk(struct my_buf *sxbf);

struct net_device ssl_dev = {
.open = ssl_open,
.stop = ssl_stop,
.hard_start_xmit = ssl_xmit,
};

struct net_device_stats *stats;
struct timer_list timer;
struct my_buf xbf;
spinlock_t timer_lock = SPIN_LOCK_UNLOCKED;
spinlock_t tx_lock = SPIN_LOCK_UNLOCKED;

unsigned long timeout;
unsigned char data;
int retval, shift, i;

/*ПРЕРЫВАНИЕ ТАЙМЕРА=##########*/
void ssl_irq (unsigned long data)
{
spin_lock_bh(&timer_lock);
struct net_device_stats *stats = ssl_dev.priv;
struct my_buf *qbf;
qbf = &xbf;
//ПРЯМОЕ ЧТЕНИЕ ИЗ ПОРТА ttyS0 УПРАВЛЕНИЕ RTS->  DSR<-
reg_msr.byte = inb_p(BASE + MSR_N);
if (reg_msr.bit_reg.dsr != 0) { //ждём запроса от передатчика
reg_mcr.bit_reg.rts = 1;
outb_p(reg_mcr.byte, BASE + MCR_N); //подтверждаем готовность приёма
     shift = 0;
     while (reg_msr.bit_reg.dsr == 1) { //принимаем пока передают
  while ((inb_p(BASE + LSR_N) & 1)==0);
qbf->rb.rbuff[++shift-2] = inb_p(BASE);
if (shift > 1024) {
printk(KERN_WARNING "ssl: R_buffer is small and overfull, dropping packet.\n");
stats->rx_dropped++;
goto r_out;
}
     reg_msr.byte = inb_p(BASE + MSR_N);
     } //Пакет принят
      if (shift == 0) {
printk(KERN_WARNING "ssl: Packet is 0 byte, dropping packet.\n");
stats->rx_dropped++;
goto r_out;
}
     qbf->rlen = shift-2;
     //rpdumpk(&xbf); //Дамп принятого в буфер пакета в логе
     load_pack(&xbf); //Отправка принятого пакета в SKB
} //else printk(KERN_WARNING "ssl: Line DSR is free.\n");
r_out:
reg_mcr.bit_reg.rts = 0;
outb_p(reg_mcr.byte, BASE + MCR_N);  //снимаем подтверждение приёма
//ПРЯМАЯ ЗАПИСЬ В ПОРТ ttyS0 УПРАВЛЕНИЕ DTR->  CTS<-
reg_lsr.byte = inb_p(BASE + LSR_N);
if (reg_lsr.bit_reg.out_ready != 0) {
if (qbf->tlen > 0) {
reg_msr.byte = inb_p(BASE + MSR_N);
if (reg_msr.bit_reg.cts == 0) {
reg_mcr.bit_reg.dtr = 1;
outb_p(reg_mcr.byte, BASE + MCR_N); //занял линию
timeout = jiffies + TIMEOUT;
while (reg_msr.bit_reg.cts == 0) {  //ждём ответа CTS от приёмника
reg_msr.byte = inb_p(BASE + MSR_N); //таймаут
if (jiffies > timeout) {
printk(KERN_WARNING "ssl: Rerly CTS is absen - timeout, dropping packet.\n");
stats->tx_dropped++;
goto t_out;
}
}
shift = 0;
while (shift + 1 <= qbf->tlen) { //передаём до конца буфера
while ((inb_p(BASE + LSR_N) & 0x20)==0);
outb_p(qbf->tb.tbuff[shift], BASE);
shift++;
}
while ((inb_p(BASE + LSR_N) & 0x20)==0); //Push bufer UART
outb_p(0, BASE);
while ((inb_p(BASE + LSR_N) & 0x20)==0);
outb_p(0, BASE);
//tpdumpk(&xbf);   //Дамп из буфера переданного пакета
} //else printk(KERN_WARNING "ssl: Line CTS is busy.\n");
} //else printk(KERN_WARNING "ssl: Transmit buf is empty.\n");
} //else printk(KERN_WARNING "ssl: Out is full.\n");
t_out:
qbf->tlen = 0;
reg_mcr.bit_reg.dtr = 0;
outb_p(reg_mcr.byte, BASE + MCR_N); //освободил линию

mod_timer(&timer, jiffies + TIMEPIC);
spin_unlock_bh(&timer_lock);
}
/*ПЕРЕДАЧА ПАКЕТА###########################*/
static int ssl_xmit (struct sk_buff *skb, struct net_device *dev)
{
struct net_device_stats *stats = dev->priv;
struct my_buf *qbf;
qbf = &xbf;

spin_lock_bh(&tx_lock);
if (skb->len > 1024 - 3) {
printk(KERN_WARNING "ssl: T_buffer is small, dropping packet.\n");
stats->tx_dropped++;
} else {
//printk(KERN_WARNING "ssl: CALL TRANSMIT.\n");
if (qbf->tlen == 0) {
//Передача пакета в буфер передатчика
xbf.tlen = skb->len;
shift = 0;
while (shift + 1 <= skb->len) {
xbf.tb.tbuff[shift] = skb->data[shift];
shift++;
}
qbf->tlen = skb->len;
//printk(KERN_WARNING "ssl: TRANSMIT.\n");
stats->tx_bytes += skb->len;
stats->tx_packets++;
} else {
printk(KERN_WARNING "ssl: T_buffer is busy, dropping packet.\n");
stats->tx_dropped++;
}
}
spin_unlock_bh(&tx_lock);
dev_kfree_skb(skb);
  stats->tx_bytes += skb->len;
stats->tx_packets++;
return 0;
}
/*===================ПРИЁМ ПАКЕТА=========================*/
static void load_pack(struct my_buf *xbf)
{
struct net_device_stats *stats = ssl_dev.priv;
struct sk_buff *r_skb;
int count;
count = xbf->rlen;
//printk(KERN_WARNING "ssl: Принят пакет.\n");
r_skb = dev_alloc_skb(count);
if (r_skb == NULL)  {
printk(KERN_WARNING "ssl: memory squeeze, dropping packet.\n");
stats->rx_dropped++;
return;
}
r_skb->dev = &ssl_dev;
memcpy(skb_put(r_skb, count), xbf->rb.rbuff, count);
r_skb->mac.raw=r_skb->data;
r_skb->protocol=htons(ETH_P_IP);

//rpdumpk(xbf);   //Дамп из буфера принятого пакета
netif_rx(r_skb);
stats->rx_bytes += xbf->rlen;
stats->rx_packets++;
}

static struct net_device_stats *ssl_get_stats(struct net_device *dev)
{ return dev->priv; }

/*ИНИЦИАЛИЗАЦИЯ ИНТЕРФЕЙСА ####################*/
int ssl_open (struct net_device *dev)
{
printk(KERN_WARNING "ssl: open ssl.\n");
netif_start_queue (dev);
//ИНИЦИАЛИЗАЦИЯ COM1
outb_p(0, BASE + IIDR_N); //запрет буферизации
outb_p(0, BASE + ICR_N); //запрет прерываний
//printk (KERN_WARNING "ssl: Initializing ttySn succesful!.\n");
reg_mcr.byte = 0;
//инициализация таймера
init_timer(&timer);
timer.expires = jiffies + HZ;
timer.function = ssl_irq;
add_timer(&timer);
return 0;
}
/*УБИЕНИЕ ИНТЕРФЕЙСА #############################*/
int ssl_stop (struct net_device *dev)
{
outb_p(0, BASE + MCR_N); //освободим линии модема
del_timer_sync(&timer); //остановка таймера
printk (KERN_WARNING "ssl: stop ssl.\n");
netif_stop_queue(dev);
return 0;
}
/*=============ИНИЦИАЛИЗАЦИЯ МОДУЛЯ================*/
int ssl_init_module (void)
{
strcpy (ssl_dev.name, "ssl");
stats = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
if (stats) {
memset(stats, 0, sizeof(struct net_device_stats));
ssl_dev.priv = stats;
ssl_dev.get_stats = &ssl_get_stats;
}
if ((retval = register_netdev (&ssl_dev))) {
printk (KERN_WARNING "ssl: Error %d  of initializing ssl module.\n",retval);
return retval;
}
printk(KERN_WARNING "ssl: initializing ssl module.\n");

return 0;
}
/*============ВЫГРУЗКА МОДУЛЯ==========================*/
void ssl_cleanup (void)
{
unregister_netdev (&ssl_dev);
printk (KERN_WARNING "ssl: Cleaning Up ssl module.\n");
return;
}

module_init (ssl_init_module);
module_exit (ssl_cleanup);
/*#############################################################*/
/*===ДЛЯ ИСПОЛЬЗОВАНИЯ В ДЕМОНСТРАЦИОННЫХ ЦЕЛЯХ=======*/
/*##############################################################*/
// Изменение формата адреса из двоичного в текстовый.*/
/*void printAddr(unsigned char *addr)
{
int j;
for ( j = 0; j < 4; j++ )
{
printk("%d", addr[j]);
if ( j < 3 )
printk(".");
}
}
// Дамп буфера передатчика
void tpdumpk(struct my_buf *txbf)
{
int i;
printk("\n----------------");
for ( i = 0; i < txbf->tlen; i++ )
{
if ( !(i & 15) ) printk("\n%04X:  ", i);
printk("%02X ", ((unsigned char*)txbf->tb.tbuff)[i]);
}
printk("\n");
printk("IPv%d: hdr-size=%d pkt-size=%d protocol=%d TTL=%d ",
txbf->tb.thdr.version, txbf->tb.thdr.ihl*4, ntohs(txbf->tb.thdr.tot_len),
txbf->tb.thdr.protocol, txbf->tb.thdr.ttl);
printk("\n");
printk("rst= ");
printAddr(txbf->tb.thdr.saddr);
printk(" dst= ");
printAddr(txbf->tb.thdr.daddr);
printk("\n");
}
//Дамп буфера приёмника
void rpdumpk(struct my_buf *sxbf)
{
int i;
printk("\n----------------");
for ( i = 0; i < sxbf->rlen; i++ )
{
if ( !(i & 15) ) printk("\n%04X:  ", i);
printk("%02X ", ((unsigned char*)sxbf->rb.rbuff)[i]);
}
printk("\n");
printk("IPv%d: hdr-size=%d pkt-size=%d protocol=%d TTL=%d ",
sxbf->rb.rhdr.version, sxbf->rb.rhdr.ihl*4, ntohs(sxbf->rb.rhdr.tot_len),
sxbf->rb.rhdr.protocol, sxbf->rb.rhdr.ttl);
printk("\n");
printk("rst= ");
printAddr(sxbf->rb.rhdr.saddr);
printk(" dst= ");
printAddr(sxbf->rb.rhdr.daddr);
printk("\n");
}
*/
Записан
opushkin
Гость
« Ответ #16 : 24-01-2006 02:42 » 

Наверное это уже совсем другая история, но драйвер может работать гораздо лучше и кода будет существенно меньше если отказаться от промежуточноо буфера (my_buf) и работать прямо с SKB. При передаче передавать указатель на текущий SKB в прерывание таймера и освобождать его только после полной передачи через СОМ. (Тогда и пакеты теряться не будут) На приёме - сразу резервировать SKB и ждать пакета от передатчика. По окончанию приёма вызывать функцию netif_rx. У меня на ближайший месяц цейтнот, и в теперешнем варианте драйвер всё что надо делает, так что если я этим займусь из любви к искуству, то поздже.
Записан
opushkin
Гость
« Ответ #17 : 22-05-2006 07:16 » 

Ну вот, сила любви к искуству пересилила природную лень. Расписал всё как в методичке по лабе, подправил некоторые корявости и отправил в "Linux format", а там - напечатали. Так-что начало можно посмотреть в апрельском номере, а в майском будет продолжение. Называется - "Драйвер своими руками". http://www.linuxformat.ru/anons.phtml
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #18 : 22-05-2006 08:12 » new

opushkin, молодец!
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines