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
|
|
« Ответ #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
|
|
« Ответ #3 : 13-01-2006 17:29 » |
|
if(f == NULL) printk (KERN_WARNING "^tstnd: Error opening ttyS.\n"); Ошибкой является не NULL, а ERR_PTR(error). См. исходники fs/open.c
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
opushkin
Гость
|
|
« Ответ #4 : 14-01-2006 06:55 » |
|
Спасибо. У меня эта функция определена как IS_ERR(), но всё равно никаких ERR нету, и чтения тоже. Смутно помню, где то мелькало, что макросы set_fr/get_fs в обработчиках прерываний не работают, и нужно использовать очереди, но чего очереди не уточнялось и не могу найти -где видел. Да и если бы они сдесь не работали, так оно бы не работали и для write.
|
|
|
Записан
|
|
|
|
RXL
|
|
« Ответ #5 : 14-01-2006 12:53 » |
|
Приведи ф-ий полностью - кусками плохо смотреть.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
opushkin
Гость
|
|
« Ответ #6 : 14-01-2006 14:07 » |
|
Сетевой драйвер - демонструха со связью через СОМ порт; ttyS0 конфигурируется скриптом; f открывается при инициализации модуля; передача при вызове _xmit через ->write работает; чтение хочется сделать по опросу через таймер, но оно не работает. Привожу весь код. Прошу сильно не бить - эксперимент в процессе, много несуразностей, но не критичных (я та-ак думаю). #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: 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 Скрипт для запуска: #!/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 Скрипт для удаления: #!/bin/sh ifconfig tstnd down rmmod forex Библиотек многовато - поубирал кое что из текста, а их убирать - надо возиться.
Поправил твой пост. Оформлять внешний вид надо! Теперь знаешь как (нажми "редактировать" и посмотри теги [code]).
|
|
« Последнее редактирование: 14-01-2006 14:19 от RXL »
|
Записан
|
|
|
|
RXL
|
|
« Ответ #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, а приём по опросу таймером, прямо читая рег состояния линии и данных. При выгрузке модуля - ругается как сапожник, но ничего не отваливается. 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. Варварство конечно. Чтение в таком виде: При инициализации: #define BASE 0x3f8 // базовый адрес #define ICR_N 1 // регистр управления прерываниями
outb_p(10, BASE + ICR_N); В прерывании таймера: //ЧТЕНИЕ РЕГИСТРА СОСТОЯНИЯ ЛИНИИ 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
|
|
« Ответ #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
|
|
« Ответ #12 : 15-01-2006 21:00 » |
|
Не рекомендую работать с железом напрямую. Можно вызвать конфликт с существующими драйверами.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
opushkin
Гость
|
|
« Ответ #13 : 16-01-2006 06:42 » |
|
Согласен, но сдесь вроде железяка (UART) локализована и ресурсы ни с кем не делит. Программирование сводится к прямому отключению прерываний и буферизации (к сожалению завязана с прерываниями), а дальше работа только с регистром данных. А вдруг прояснится с file, так всегда можно переделать.
|
|
|
Записан
|
|
|
|
RXL
|
|
« Ответ #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
|
|
« Ответ #18 : 22-05-2006 08:12 » |
|
opushkin, молодец!
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
|