Подскажите с f->f_op->read
RXL:
Приведи ф-ий полностью - кусками плохо смотреть.
opushkin:
Сетевой драйвер - демонструха со связью через СОМ порт; 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]).
RXL:
Макрос 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.
Остальной код пока не смотрел.
opushkin:
М..да... О сколько нам открытий чудных.... Я в Линухе недавно.
Ещё раз спасибо.
opushkin:
Чтение оживает если напрямую разрешать прерывания по приёму в регистре управления прерываниями 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);
В общем :wow: переходящее в :o
Навигация