[an error occurred while processing this directive]
Могу предложить только исходники драйвера для PC
(«Телесистемы»: Конференция «Микроконтроллеры и их применение»)

миниатюрный аудио-видеорекордер mAVR

Отправлено ++ 20 октября 2006 г. 13:17
В ответ на: Ответ: отправлено <font color=gray>Why</font> 20 октября 2006 г. 13:09


/* - can4linux SJA1000 driver module rev 3.3.4
* This file is subject to the terms and conditions of the GNU General Public License.
* See the file "COPYING" in the main directory of this archive for more details.
* Copyright (c) 2001 port GmbH Halle/Saale (c) 2001 Heinz-Jьrgen Oertel (oe@port.de) Claus Schroeter (clausi@chemie.fu-berlin.de)
* Copyright (c) 2003 Phil Wilshire ( philwil@sysdcs.com)
*------------------------------------------------------------------*/

// #include
// #include
// #include


#include
#include
#include
#include
#include
#include "can_sja1000.h"

int can_errno = 0;
char *version = "can4linux sja1000 driver module rev 3.3.4";
char *chipset = "sja1000";
static struct can_dev *can_chdev;
static int io= SJA1000_IOBASE, irq= SJA1000_IRQ; /* базовый адрес портов ввода-вывода, irq */
static int chip_mode = SJA1000_MODE_BASIC;
static int verbose= 0; /* вывод по dev_read() ascii промежуточных диагностических сообщений */
/* 0 - без дополнительной информации */
/* 1 - расширенная информация об ошибках драйвера и платы */
/* 2 - + расширенная информация о выполняемых операциях */
module_param(io, int, 0); /* usage: insmod sja1000 io=0x160: базовый адрес ввода-вывода */
module_param(irq, int, 0); /* usage: insmod sja1000 irq=0x160: базовый адрес ввода-вывода */
module_param(verbose, int, 0); /* usage: insmod sja1000 verbose=2: диагностические сообщения */
module_param(chip_mode, int, 0); /* usage: insmod sja1000 chip_mode=1: режим (базовый can/ pelican) */
int Outc = 0x0;
int TxErr = 0x0;
int RxErr = 0x0;
int Overrun =0x0;

#ifdef DEBUG_COUNTER
int Cnt1[MAX_CHANNELS] = { 0x0 };
int Cnt2[MAX_CHANNELS] = { 0x0 };
#endif /* DEBUG_COUNTER */
/* ----- the sysctl table */
ctl_table Can_sysctl_table[] =
{{SYSCTL_VERSION, "version", &version, PROC_VER_LENGTH, 0444, NULL, &proc_dostring, &sysctl_string},
{ SYSCTL_CHIPSET, "Chipset", &Chipset, PROC_CHIPSET_LENGTH, 0444, NULL, &proc_dostring, &sysctl_string},
{ SYSCTL_chip_mode, "chip_mode", &chip_mode, MAX_CHANNELS + 1, 0444, NULL, &proc_dostring, &sysctl_string},
{ SYSCTL_irq, "irq", (void *) irq, MAX_CHANNELS*sizeof(int), 0644, NULL, &proc_dointvec, NULL},
{ SYSCTL_BASE, "Base", (void *) Base, MAX_CHANNELS*sizeof(int), 0644, NULL, &proc_dointvec, NULL},
{ SYSCTL_BAUD, "Baud", (void *) Baud, MAX_CHANNELS*sizeof(int), 0666, NULL, &proc_dointvec, NULL},
{ SYSCTL_ACCCODE, "acc_code", (void *) can_chdev->acc_code, MAX_CHANNELS*sizeof(int), 0644, NULL, &proc_dointvec, NULL},
{ SYSCTL_ACCMASK, "acc_mask", (void *) can_chdev->acc_mask, MAX_CHANNELS*sizeof(int), 0644, NULL, &proc_dointvec, NULL},
{ SYSCTL_TIMEOUT, "tmout",(void *) can_chdev->tmout, MAX_CHANNELS*sizeof(int), 0644, NULL, &proc_dointvec, NULL},
{ SYSCTL_OUTC, "Outc", (void *) Outc, MAX_CHANNELS*sizeof(int), 0644, NULL, &proc_dointvec, NULL},
{ SYSCTL_TXERR, "TxErr", (void *) TxErr, MAX_CHANNELS*sizeof(int), 0444, NULL, &proc_dointvec, NULL},
{ SYSCTL_RXERR, "RxErr", (void *) RxErr, MAX_CHANNELS*sizeof(int), 0444, NULL, &proc_dointvec, NULL},
{ SYSCTL_OVERRUN, "Overrun", (void *) Overrun, MAX_CHANNELS*sizeof(int), 0444, NULL, &proc_dointvec, NULL},
{ SYSCTL_DBGMASK, "dbgMask",(void *) &dbgMask, 1*sizeof(int), 0644, NULL, &proc_dointvec, NULL},
#ifdef DEBUG_COUNTER
{ SYSCTL_CNT1, "cnt1", (void *) Cnt1, MAX_CHANNELS*sizeof(int), 0444, NULL, &proc_dointvec , NULL},
{ SYSCTL_CNT2, "cnt2", (void *) Cnt2, MAX_CHANNELS*sizeof(int), 0444, NULL, &proc_dointvec , NULL},
#endif /* DEBUG_COUNTER */
{0}
};
/* ----- the main directory entry in /proc/sys */
ctl_table Can_sys_table[] = {{SYSCTL_Can, "Can", NULL, 0, 0555, Can_sysctl_table},{0}};
/*==================================================================================================*/
/* Инициализация структуры файловых операций драйвера. */
struct file_operations can_fops = {
.read= can_read,
.write= can_write,
.ioctl= can_ioctl,
.open= can_open,
.poll= can_poll,
.release= can_release};

/* ----- register and unregister entrys */
struct ctl_table_header *Can_systable = NULL;
void register_systables(void)
{can_systable = register_sysctl_table( Can_sys_table, 0 );}
void unregister_systables(void)
{unregister_sysctl_table(Can_systable);}

/***************************************************************************/
int Error(int err)
{can_errno = err; return 0;}
/*==================================================================================================*/
void inline can_out(int offs, unsigned char v)
{if(verbose > 3 ) (printk("outb_p(%02x,%04x);\r\n",v, io+ offs);
outb_p (v, io + offs);
return;
}
int inline can_in(int offs)
{if(verbose > 3 ) (printk("outb_p(%02x,%04x);\r\n",v, io+ offs);
return inb_p (io + offs);
}
void inline can_set(int offs, unsigned char mask)
{unsigned char v;
v= inb_p (io + offs) | mask;
outb_p (v, io + offs);
if(verbose > 3 ) (printk("outb_p(%02x,%04x);\r\n",v, io+ offs);
return;
}
void inline can_clr(int offs, unsigned char mask)
{unsigned char v;
v= inb_p (io + offs) & ~mask;
outb_p (v, io + offs);
if(verbose > 3 ) (printk("outb_p(%02x,%04x);\r\n",v, io+ offs);
return;
}
int inline can_test(int offs, unsigned char mask)
{return inb_p (io + offs) & mask;
}
/*==================================================================================================*/
/* вывод символа в выходной кольцевой буфер драйвера */
void my_putchar(char c)
{struct can_buf *rdbuf;
if(can_chdev==NULL) return;
rdbuf= &can_chdev->rdbuf;
*(rdbuf->head)= c;
if(++rdbuf->head >= rdbuf->buf+ BUFSIZE) {rdbuf->head= rdbuf->buf;}
*(rdbuf->head)= 0;
return;
}
/*==================================================================================================*/
/* вывод ascii строки в выходной кольцевой буфер драйвера */
void my_puts(char * s)
{char *ptr;
for(ptr= (char *)can_devname; *ptr; ptr++) my_putchar(*ptr);
my_putchar('>'); my_putchar(' ');
if (verbose >= 2) printk(KERN_ERR "%s\r\n", s);
while(*s){my_putchar(*s); s++;}
my_putchar(0x0a); my_putchar(0x0d);
wake_up_interruptible(&can_chdev->outq); /* для user ф-ии select() - данные готовы */
return;
}
/*==================================================================================================*/
/* вывод ascii строки в выходной кольцевой буфер драйвера */
void my_putsc(const char * s)
{char *ptr;
for(ptr= (char *)can_devname; *ptr; ptr++) my_putchar(*ptr);
my_putchar('>'); my_putchar(' ');
if (verbose >= 2) printk(KERN_ERR "%s\r\n", s);
while(*s){my_putchar(*s); s++;}
my_putchar(0x0a); my_putchar(0x0d);
wake_up_interruptible(&can_chdev->outq); /* для user ф-ии select() - данные готовы */
return;
}
/*==================================================================================================*/
/* наличие свободного места в буферах для read/write("/dev/can", ... ) */
static int wr_ready(void)
{struct can_buf *wrbuf;
wrbuf= &can_chdev->wrbuf;
return (wrbuf->head != wrbuf->tail) 0 : BUFSIZE;
}
static int rd_ready(void)
{struct can_buf *rdbuf;
rdbuf= &can_chdev->rdbuf;
return (rdbuf->tail != rdbuf->head)? 1 : 0;
}
/*==================================================================================================*/
static char *memrchr_noprint(char *head, char *tail)
{char *ptr;
for(ptr= tail; ptr > head; ptr--)if(*ptr < 0x0a) return ptr;
return NULL;
}
/*==================================================================================================*/
/* отработка драйвером read("/dev/can", ... ) файловой операции */
/* rdbuf->buf[BUFSIZE] -> userspace read("/dev/can", ... ) */
static int can_read (struct file *filp, char *buffer, size_t nbytes, loff_t *ppos)
{int n, k;
struct can_buf *rdbuf;

rdbuf= &can_chdev->rdbuf;
if(!access_ok(VERIFY_WITE, (void __user *)buffer, nbytes) ) {DEBUG(_ESPIPE, NULL); can_chdev->exchange_err++; return -ESPIPE;}
down_interruptible(&can_chdev->sem); /* семафор */
while(rdbuf->tail== rdbuf->head) /* пока (rdbuf->buf[BUFSIZE] пуст) -> блокируем user_read(/dev/can) */
{up(&can_chdev->sem);
if (filp->f_flags & O_NONBLOCK){DEBUG(_ENODATA, NULL); return -EAGAIN;}
if (wait_event_interruptible(can_chdev->outq, (rdbuf->tail != rdbuf->head))) /* блокируем user_read(/dev/can) */
return (can_chdev->errcode= -ERESTARTSYS); /* signal: tell the fs layer to handle it */
if(down_interruptible(&can_chdev->sem));
}
/* rdbuf->buf[BUFSIZE] не пуст */
if (rdbuf->head > rdbuf->tail)
{n= MIN(rdbuf->head- rdbuf->tail, nbytes);
if(copy_to_user(buffer, rdbuf->tail, n)) {can_chdev->exchange_err++; up(&can_chdev->sem); return -EBADE;}
rdbuf->tail+= n;
up(&can_chdev->sem); wake_up_interruptible(&can_chdev->outq);
return n;
}
k= MIN(BUFSIZE - (rdbuf->tail- rdbuf->buf), nbytes);
if(copy_to_user(buffer, rdbuf->tail, k)) {DEBUG(_EBADE, NULL); can_chdev->exchange_err++; up(&can_chdev->sem); return -EBADE;}
rdbuf->tail+=k;
if(rdbuf->tail-rdbuf->buf >= BUFSIZE) rdbuf->tail= rdbuf->buf;
if(k== nbytes){up(&can_chdev->sem); wake_up_interruptible(&can_chdev->outq); return k;}
rdbuf->tail= rdbuf->buf;
n= MIN((rdbuf->head- rdbuf->buf), nbytes-k);
if(copy_to_user(buffer+ k, rdbuf->buf, n)) {DEBUG(_EBADE, NULL); can_chdev->exchange_err++; up(&can_chdev->sem); return -EBADE;}
rdbuf->tail+= n;
n+=k;
up(&can_chdev->sem); wake_up_interruptible(&can_chdev->outq);
return n;
}
/*==================================================================================================*/
/* отработка драйвером write("/dev/can", ... ) файловой операции */
/* wrbuf->buf[BUFSIZE] <- userspace write("/dev/can", ... ) */
static int can_write (struct file *filp, const char *buffer, size_t nbytes, loff_t *ppos)
{int w, n, k=0;
char *p, *p0;
struct can_buf *wrbuf;

if(!wr_ready()) return 0;
wrbuf= &can_chdev->wrbuf;
if(!access_ok(VERIFY_READ, (void __user *)buffer, nbytes) ) {DEBUG(_ESPIPE, NULL); can_chdev->exchange_err++; return -ESPIPE;}
down_interruptible(&can_chdev->sem);
for(w=0; w < nbytes; w+= n)
{if((n= MIN(wrbuf->head- wrbuf->buf, nbytes- w))<= 0)
{if(verbose >= 2) printk( KERN_ERR "%s> %s.\r\n", can_devname, _EXFULL);
wrbuf->tail= wrbuf->head= wrbuf->buf;
can_chdev->exchange_err++;
up(&can_chdev->sem);
wake_up_interruptible(&can_chdev->inq);
return -EAGAIN;
}
if(copy_from_user(wrbuf->head, buffer+ w, n)) {DEBUG(_EBADE, NULL); can_chdev->exchange_err++; up(&can_chdev->sem); return -EBADE;}
wrbuf->head+= n; *wrbuf->head= 0;
for(wrbuf->tail = wrbuf->buf; (p=memchr(wrbuf->tail,'\n', (wrbuf->head-wrbuf->tail)))!=NULL; wrbuf->tail=++p) /* признаком наличия команды считаем наличие во входном буфере */
{while((*wrbuf->tail <= 0x0d) && (wrbuf->tail < wrbuf->head)) wrbuf->tail++;
if( (p0=memrchr_noprint(wrbuf->tail, p))!=NULL) {wrbuf->tail= p0;}
if(wrbuf->tail >=p) continue;
*p=0; can_chdev->errcode= parse_ascii_usrcmd(wrbuf->tail);
}
if((k=wrbuf->head-wrbuf->tail) >= BUFSIZE-1) {wrbuf->tail=wrbuf->head=wrbuf->buf; continue;}
if(wrbuf->tail != wrbuf->buf)
{memcpy(wrbuf->buf, wrbuf->tail, k);
wrbuf->tail= wrbuf->buf;
wrbuf->head= wrbuf->buf+ k;
}
}
up(&can_chdev->sem); wake_up_interruptible(&can_chdev->inq);
return w;
}
/*==================================================================================================*/
/* отработка драйвером select(... ) файловой операции */
static unsigned int can_poll(struct file *filp, poll_table *wait)
{ unsigned int mask = 0;
if(verbose >= 3) printk( KERN_ERR "%s> can_poll . . .", can_devname);
down(&can_chdev->sem);
// poll_wait(filp, &can_chdev->inq, wait);
poll_wait(filp, &can_chdev->outq, wait);
if (rd_ready()) mask = POLLIN | POLLRDNORM; /* 0x041 readable */
if (wr_ready()) mask|= POLLOUT| POLLWRNORM; /* 0x104 writable */
if(verbose >= 3) printk( KERN_ERR "mask= %04x; ", mask);
up (&can_chdev->sem);
return mask;
}

/* timing values */
unsigned char sja1000_timing[10][2]={{SJA1000_TIM0_10K, SJA1000_TIM1_10K},{SJA1000_TIM0_20K, SJA1000_TIM1_20K},{SJA1000_TIM0_50K, SJA1000_TIM1_50K},{SJA1000_TIM0_100K, SJA1000_TIM1_100K}, \
{SJA1000_TIM0_125K, SJA1000_TIM1_125K},{SJA1000_TIM0_250K, SJA1000_TIM1_250K}, {SJA1000_TIM0_500K, SJA1000_TIM1_500K}, {SJA1000_TIM0_800K, SJA1000_TIM1_800K}, {SJA1000_TIM0_1000K,SJA1000_TIM1_1000K}};
/*==================================================================================================*/
void can_printstatus (int mode)
{printk(" MODE 0x%x,", can_inp(CTRL_REG));
printk(" STAT 0x%x,", can_inp(STATUS_REG));
printk(" irqE 0x%x,", can_inp(IRQENABLE_REG));
printk(" INT 0x%x\n", can_inp(IRQ_REG));
printk("\n");
}

/* sja1000_stat - read back as many status information as possible
*
* Because the SJA1000 protocol itself describes different kind of information already, and the driver has some generic information
* (e.g about it's buffers) we can define a more or less hardware independent format.
* exception:
* ERROR WARNING LIMIT REGISTER (EWLR)
* The SJA1000 defines a EWLR, reaching this Error Warning Level an Error Warning interrupt can be generated.
* The default value (after hardware reset) is 96. In reset mode this register appears to the CPU as a read/write
* memory. In operating mode it is read only.
* Note, that a content change of the EWLR is only possible, if the reset mode was entered previously. An error status
* change (see status register; Table 14) and an error warning interrupt forced by the new register content will not
* occur until the reset mode is cancelled again.*/
int sja1000_stat(struct inode *inode, STATUS_REGusPar_t *stat )
{msg_fifo_t *Fifo;
unsigned long flags;
stat->baud = baud;
stat->status = can_inp(STATUS_REG);
stat->error_warning_limit = can_inp(ERORR_WARNING_LIMIT_REG);
stat->rx_errors = can_inp(RXERROR_COUNTER_REG);
stat->tx_errors = can_inp(TXERROR_COUNTER_REG);
stat->error_code= can_inp(ERROR_CODE_CAPTURE_REG);
local_irq_save(flags);
Fifo = &Rx_Buf;
stat->rx_buffer_size = MAX_BUFSIZE; /**< size of rx buffer */
stat->rx_buffer_used = (Fifo->head < Fifo->tail) ? (MAX_BUFSIZE - Fifo->tail + Fifo->head) : (Fifo->head - Fifo->tail);
Fifo = &Tx_Buf[board];
stat->tx_buffer_size = MAX_BUFSIZE; /* size of tx buffer */
/* number of messages */
stat->tx_buffer_used = (Fifo->head < Fifo->tail) ? (MAX_BUFSIZE - Fifo->tail + Fifo->head) : (Fifo->head - Fifo->tail);
local_irq_restore(flags);
return 0;
}
/*==================================================================================================*/
int sja1000_reset (int board)
{unsigned int status;
unsigned char c;
debug("%s reset", chipset);
can_outp(CTRL_REG, SJA1000_RESET_REQUEST);
udelay(10);
status = can_inp(STATUS_REG);
debug(DBG_DATA,("status=0x%x mode=0x%x", status, can_inp(board, CTRL_REG) ));
if( ! (can_inp(board, CTRL_REG) & SJA1000_RESET_REQUEST ) ){printk("ERROR: no board present!"); debug();return -1;}
debug(DBG_DATA, ("%s> SJA1000_mode 0x%02x\n", chipset, can_inp(board, CTRL_REG)));
can_outp(CLK_DIVISOR_REG, SJA1000_MODE_PELISJA1000 | SJA1000_MODE_CLK);
can_outp(CTRL_REG, SJA1000_RESET_REQUEST | io_mode);
debug(DBG_DATA, ("%s> SJA1000_mode 0x%02x\n", chipset, can_inp(board, CTRL_REG)));
/* Board specific output control */
if(!hw_mode) hw_mode= SJA1000_OUTCTRL_DEFAULT;
can_outp(OUTPUT_CONTROL_REG, hw_mode);
sja100_set_baudrate(baudrate);
can_setmask(acc_code, acc_mask);
return 0;
}
/*==================================================================================================*/
int sja100_set_baudrate (int baud)
{int i = 5;
unsigned char c;
can_outp(CLK_DIVISOR_REG, SJA1000_MODE_PELISJA1000 | SJA1000_MODE_CLK2); /* 20MHz Osc, pelican mode */
switch(baud)
{case 10: i = 0; break;
case 20: i = 1; break;
case 50: i = 2; break;
case 100: i = 3; break;
case 125: i = 4; break;
case 250: i = 5; break;
case 500: i = 6; break;
case 800: i = 7; break;
case 1000: i = 8; break;
default : can_outp(BUS_TIMING_REG1, c=(unsigned char) (baud >> 8) & 0xff);
if(c != can_inp(board, BUS_TIMING_REG1)) {debug("%s> %s ",chipset, _EIO); return 0;}
can_outp(BUS_TIMING_REG2, c=(unsigned char) (baud & 0xff ));
if(c != can_inp(board, BUS_TIMING_REG2)) {debug("%s> %s ",chipset, _EIO); return 0;}
debug("%s> set custom baudrate/timing: BUS_TIMING_REG=0x%02x BT1=0x%02x ",chipset, can_inp(board, BUS_TIMING_REG1), can_inp(board, BUS_TIMING_REG2));
return 1;
}
can_outp(BUS_TIMING_REG1, (unsigned char) sja1000_timing[i][0]);
if(c != can_inp(board, BUS_TIMING_REG1)) {debug("%s> %s ",chipset, _EIO); return 0;}
can_outp(BUS_TIMING_REG2, (unsigned char) sja1000_timing[i][1]);
if(c != can_inp(board, BUS_TIMING_REG1)) {debug("%s> %s ",chipset, _EIO); return 0;}
printk("%s> set baudrate=%d/timing: BUS_TIMING_REG=0x%02x BT1=0x%02x ",chipset, baud, can_inp(board, BUS_TIMING_REG1), can_inp(board, BUS_TIMING_REG2));
return 1;
}
/*============================================================================*/
int sja1000_up (void)
{RxErr[board] = TxErr[board] = 0L;
debug("%s> chip up; can_mode= 0x%02x\r\n", chipset, io_mode);
udelay(10);
can_inp(IRQ_REG); /* clear interrupts */
/* Interrupts on Rx, TX, any Status change and data overrun */
can_set(IRQENABLE_REG, (SJA1000_OVERRUN_INT_ENABLE | SJA1000_ERROR_INT_ENABLE | SJA1000_TRANSMIT_INT_ENABLE | SJA1000_RECEIVE_INT_ENABLE ));
can_clr(CTRL_REG, SJA1000_RESET_REQUEST );
return 0;
}
/*============================================================================*/
int sja1000_down (void)
{debug("sja1000_down");
can_set(CTRL_REG, SJA1000_RESET_REQUEST);
return 0;
}
/*============================================================================*/
/* set value of the output control register */
int sja1000_set_tx_hwmode (int arg)
{debug(DBG_DATA,("%s> set data tx hardware mode=0x%02x", chipset, arg));
can_outp(OUTPUT_CONTROL_REG, arg);
return 0;
}
/*============================================================================*/
void can_listenmode (int arg)
{debug("%s> listenmode=%s", chipset, (arg)? "on":"off");
if (arg) {can_set(CTRL_REG, SJA1000_LISTEN_ONLY_MODE);}
else {can_clr(CTRL_REG, SJA1000_LISTEN_ONLY_MODE );}
return ;
}
/*============================================================================*/
int can_setmask (unsigned int code, unsigned int mask)
{debug("can_setmask");
debug(DBG_DATA,("%s> acc=0x%02x mask=0x%02x", chipset, code, mask));
can_outp(TXFRAME_INFO_REG, (unsigned char)((unsigned int)(code >> 24) & 0xff));
can_outp(RXEFFID_REG1, (unsigned char)((unsigned int)(code >> 16) & 0xff));
can_outp(RXEFFID_REG2, (unsigned char)((unsigned int)(code >> 8) & 0xff));
can_outp(RXEFFID_REG3, (unsigned char)((unsigned int)(code >> 0) & 0xff));
can_outp(RXEFFID_REG4, (unsigned char)((unsigned int)(mask >> 24) & 0xff));
can_outp(frame.extframe.canxdata[0 * R_OFF],(unsigned char)((unsigned int)(mask >> 16) & 0xff));
can_outp(frame.extframe.canxdata[1 * R_OFF],(unsigned char)((unsigned int)(mask >> 8) & 0xff));
can_outp(frame.extframe.canxdata[2 * R_OFF],(unsigned char)((unsigned int)(mask >> 0) & 0xff));
return 0;
}
/*============================================================================*/
int sja1000_send_frame (struct can_mgg *tx)
{int i;
int ext; /* message format to send */
unsigned char tx2reg, stat;
debug("%s> msgsend(tx.flags=%d tx.id=0x%08lx tx.length=%d stat=0x%02x)", chipset, tx->flags, tx->id, tx->length, stat);
while ( !(stat=can_inp(minor, STATUS_REG)) & SJA1000_TRANSMIT_BUFFER_EMPTY) {cond_resched();}
tx->length %= 9; /* limit SJA1000 message length to 8 */
ext = (tx->flags & MSG_EXT); /* read message format */
/* fill the frame info and identifier fields */
tx2reg = tx->length;
if( tx->flags & MSG_RTR) {tx2reg |= SJA1000_RTR;}
if(ext)
{debug("---> send ext message \n");
can_outp(TXFRAME_INFO_REG, SJA1000_EFF | tx2reg);
can_outp(TXEFFID_REG1, (unsigned char)(tx->id >> 21));
can_outp(TXEFFID_REG2, (unsigned char)(tx->id >> 13));
can_outp(TXEFFID_REG3, (unsigned char)(tx->id >> 5));
can_outp(TXEFFID_REG4, (unsigned char)(tx->id << 3) & 0xff);
}
else
{debug("---> send std message \n");
can_outp(TXFRAME_INFO_REG, SJA1000_SFF | tx2reg);
can_outp(TXEFFID_REG1, (unsigned char)((tx->id) >> 3) );
can_outp(TXEFFID_REG2, (unsigned char)(tx->id << 5 ) & 0xe0);
}
/* - fill data ---------------------------------------------------- */
if(ext) {for( i=0; i < tx->length ; i++) {can_outp(RXEFFBUF+ i, tx->data[i]);}} /* SLOW_DOWN_IO; SLOW_DOWN_IO; */
else {for( i=0; i < tx->length ; i++) {can_outp(RXSFFBUF+ i, tx->data[i]);}} /* SLOW_DOWN_IO; SLOW_DOWN_IO; */
/* - /end --------------------------------------------------------- */
can_outp(CMD_REG, SJA1000_TRANSMISSION_REQUEST);
if(selfreception) {memcpy((void *)&last_Tx_object[minor], (void *)tx, sizeof(canmsg_t));} /* prepare for next TX Interrupt and selfreception */
return i;
}
/*============================================================================*/
/* can_msgrecv is used in Polling Mode with ioctl() !!!! curently not working for the PELISJA1000 mode and BASIC SJA1000 mode code already removed !!!! */
int can_msgrecv (int minor, canmsg_t *rx )
{unsigned char dummy = 0, stat;
int i = 0;
debug("can_msgrecv");
stat = can_inp(minor, STATUS_REG);
rx->flags = 0;
rx->length = 0;
if( stat & SJA1000_DATA_OVERRUN ) {debug(DBG_DATA,("Rx: overrun!\n")); Overrun[minor]++;}
if( stat & SJA1000_RECEIVE_BUFFER_STATUS )
{ dummy &= 0x0f; /* strip length code */
rx->length = dummy;
debug(DBG_DATA,("rx.id=0x%lx rx.length=0x%x", rx->id, dummy));
dummy %= 9;
for( i = 0; i < dummy; i++) {debug(DBG_DATA,("rx[%d]: 0x%x ('%c')",i,rx->data[i],rx->data[i] ));}/* missing code here */
can_outp(minor, CMD_REG, SJA1000_RELEASE_RECEIVE_BUFFER | SJA1000_CLEAR_OVERRUN_STATUS );
}
else {i=0;}
return i;
}

/* The plain SJA1000 interrupt
* RX ISR TX ISR
* 8/0 byte
* _____ _ ___
* _____| |____ ___| |_| |__
*---------------------------------------------------------------------------
* 1) CPUPentium 75 - 200
* 75 MHz, 149.91 bogomips
* AT-SJA1000-MINI 42/27µs 50 µs
* ---------------------------------------------------------------------------
* 2) AMD Athlon(tm) Processor 1M
* 2011.95 bogomips
* AT-SJA1000-MINI std 24/12µs ?? µs
* ext id /14µs
* 1) 1Byte = (42-27)/8 = 1.87 µs
* 2) 1Byte = (24-12)/8 = 1.5 µs
* RX Int with to Receive channels:
* 1) _____ ___
* _____| |_| |__
* 30 5 20 µs
* first ISR normal length,
* time between the two ISR -- short
* sec. ISR shorter than first, why? it's the same message */
static irqreturn_t can_irq(int irq, void *dev_id, struct pt_regs *regs)
{int i;
unsigned long flags;
int ext; /* flag for extended message format */
int iir, dummy;
struct can_buf *txbuf, *rxbuf;
struct can_msg *txmsg, *rxmsg;

txbuf= &can->txbuf; rxbuf= &can->rxbuf;
do
{/* loop as long as the SJA1000 controller shows interrupts */
debug("%s> got irq[%d]\n", chipset, irq);
rxmsg=rxbuf->head; txmsg=txbuf->head;
do_gettimeofday(&(rxbuf->head.) + TIMESTAMP);
rxmsg->flags =(RxFifo->status & BUF_OVERRUN) ? MSG_BOVR : 0; /* preset flags */
iir= can_inp(IRQ_REG);
if(iir & SJA1000_RECEIVE_INT) /*=========== receive interrupt ===============*/
{dummy= can_inp(TXFRAME_INFO_REG);
if(dummy & SJA1000_RTR ) {rxmsg->flags|= MSG_RTR;}
if(dummy & SJA1000_EFF ) {rxmsg->flags|= MSG_EXT;}
ext= (dummy & SJA1000_EFF);
if(ext) {rxmsg->id= ((unsigned int)(can_inp(minor, frame.extframe.canid1))<<21)| ((unsigned int)(can_inp(minor, frame.extframe.canid2))<<13)| ((unsigned int)(can_inp(minor, frame.extframe.canid3))<<5)| ((unsigned int)(can_inp(minor, frame.extframe.canid4))>>3);}
else {rxmsg->id= ((unsigned int)(can_inp(minor, frame.stdframe.canid1))<< 3)| ((unsigned int)(can_inp(minor, frame.stdframe.canid2))>> 5);}
dummy&= 0x0f; /* get message length */
rxmsg->length= dummy;
dummy%= 9; /* limit count to 8 bytes */
for( i = 0; i < dummy; i++)
{if(ext){rxmsg->data[i] =can_inp(RXEFFBUF+ i);continue;}
rxmsg->data[i] =can_inp(RXSFFBUF+ i);
}
rxbuf->status= BUF_OK; rxbuf->head++;
if((rxbuf->head- rxbuf->frame) >= BUFSIZE * sizeof(struct can_msg)) {rxbuf->head= rxbuf->frame;}
if( rxbuf->head== rxbuf->tail) {debug("%s> ERROR [rx FIFO overrun];\n",chip); rxbuf->status = BUF_OVERRUN;}
wake_up_interruptible(&CanWait ); /*---------- kick the select() call -*/
can_outp(CMD_REG, SJA1000_RELEASE_RECEIVE_BUFFER);
if(can_inp(STATUS_REG) & SJA1000_DATA_OVERRUN) {debug("%s> ERROR [rx FIFO overrun];\n", chip); can_outp(CMD_REG, SJA1000_CLEAR_OVERRUN_STATUS);}
}
if(irqsrc & SJA1000_TRANSMIT_INT) /*========== transmit interrupt */
{unsigned char tx2reg; /* SJA1000 frame successfully sent */
unsigned int id;
if(selfreception)
{otxmsg->timestamp= txmsg->timestamp;
memcpy((void *)rxmsg, (void *)otxmsg, sizeof(struct can_msg));/* selfreception means, placing the last transmitted frame in the rx fifo too use time stamp sampled with last INT */
rxmsg->flags|= MSG_SELF; /* Mark message as 'self sent/received' */
rxbuf->status = BUF_OK; rxbuf->head++;
rxbuf->head = ++(RxFifo->head) % MAX_BUFSIZE;
if((rxbuf->head- rxbuf->frame)/sizeof(struct can_msg) >= BUFSIZE) {rxbuf->head= rxbuf->frame;}
if( rxbuf->head== rxbuf->tail) {printk("%s> ERROR [rx FIFO overrun];\n",chip); RxFifo->status = BUF_OVERRUN;}
wake_up_interruptible( &CanWait );
} /* selfreception */
if(txbuf->head== txbuf->tail))
{txbuf->status = BUF_EMPTY; /* TX FIFO empty, nothing more to sent */
txbuf->active = 0;
wake_up_interruptible( &CanOutWait); /*---------- kick the select() call -*/
continue;;
}
/* The TX message FIFO contains other SJA1000 frames to be sent The next frame in the FIFO is copied into the last_Tx_object and directly into the hardware of the SJA1000 controller*/
/* save_flags(flags);cli(); */
local_irq_save(flags);
tx2reg = txmsg->length;
if( txmsg->flags & MSG_RTR) {tx2reg |= SJA1000_RTR;}
ext = (txmsg->flags & MSG_EXT);
id = txmsg->id;
if(ext)
{debug("---> send ext message \n");
can_outp(TXFRAME_INFO_REG, SJA1000_EFF + tx2reg);
can_outp(RXEFFID_REG1, (unsigned char)(id >> 21));
can_outp(RXEFFID_REG2, (unsigned char)(id >> 13));
can_outp(RXEFFID_REG3, (unsigned char)(id >> 5));
can_outp(RXEFFID_REG4, (unsigned char)(id << 3) & 0xff);
}
else
{debug("---> send std message \n");
can_outp(TXFRAME_INFO_REG, SJA1000_SFF + tx2reg);
can_outp(TXSFFID_REG1, (unsigned char)(id >> 3) );
can_outp(TXSFFID_REG2, (unsigned char)(id << 5 ) & 0xe0);
}
tx2reg &= 0x0f; /* restore length only */
if(ext) {for( i=0; i < tx2reg ; i++) {can_outp(RXEFFBUF+ i, txmsg->data[i]);}}
else {for( i=0; i < tx2reg ; i++) {can_outp(RXSFFBUF+ i, txmsg->data[i]);}}
can_outp(CMD_REG, SJA1000_TRANSMISSION_REQUEST );
txbuf->tail++;
if((txbuf->tail- txbuf->frame)/sizeof(struct can_msg) >= BUFSIZE) {txbuf->tail= txbuf->frame;}
if( rxbuf->head== rxbuf->tail) {printk("%s> ERROR [rx FIFO overrun];\n",chip); RxFifo->status = BUF_OVERRUN;}
TxFifo->free[TxFifo->tail] = BUF_EMPTY; /* now this entry is EMPTY */
TxFifo->tail = ++(TxFifo->tail) % MAX_BUFSIZE;
/* leave critical section */
local_irq_restore(flags);
}
Tx_done:
/*========== error status */
if( irqsrc & SJA1000_ERROR_INT )
{int s;
/* printk("SJA1000[%d]: error interrupt!\n", minor); */
TxErr[minor]++;
/* insert error */
s = can_inp(minor,STATUS_REG);
if(s & SJA1000_BUS_STATUS ) (RxFifo->data[RxFifo->head]).flags += MSG_BUSOFF;
if(s & SJA1000_ERROR_STATUS) (RxFifo->data[RxFifo->head]).flags += MSG_PASSIVE;
(RxFifo->data[RxFifo->head]).id = 0xFFFFFFFF;
/* (RxFifo->data[RxFifo->head]).length = 0; */
/* (RxFifo->data[RxFifo->head]).data[i] = 0; */
RxFifo->status = BUF_OK;
RxFifo->head = ++(RxFifo->head) % MAX_BUFSIZE;
if(RxFifo->head == RxFifo->tail) {printk("SJA1000[%d] RX: FIFO overrun\n", minor);RxFifo->status = BUF_OVERRUN;}
/* tell someone that there is a new error message */
wake_up_interruptible( &CanWait[minor] );
}
if( irqsrc & SJA1000_OVERRUN_INT )
{int s;
printk("SJA1000[%d]: overrun!\n", minor);
Overrun[minor]++;
/* insert error */
s = can_inp(minor,STATUS_REG);
if(s & SJA1000_DATA_OVERRUN) (RxFifo->data[RxFifo->head]).flags += MSG_OVR;
(RxFifo->data[RxFifo->head]).id = 0xFFFFFFFF;
/* (RxFifo->data[RxFifo->head]).length = 0; */
/* (RxFifo->data[RxFifo->head]).data[i] = 0; */
RxFifo->status = BUF_OK;
RxFifo->head = ++(RxFifo->head) % MAX_BUFSIZE;
if(RxFifo->head == RxFifo->tail) {printk("SJA1000[%d] RX: FIFO overrun\n", minor);RxFifo->status = BUF_OVERRUN;}
/* tell someone that there is a new error message */
wake_up_interruptible( &CanWait[minor] );
can_outp(minor, CMD_REG, SJA1000_CLEAR_OVERRUN_STATUS );
}
} while( (irqsrc = can_inp(minor, IRQ_REG)) != 0);
/* irqdone: */
debug(DBG_DATA, (" => leave irq[%d]\n", minor));
return irq_RETVAL(irq_HANDLED);
}


volatile int irq2minormap[MAX_irqNUMBER] = { 0 };
volatile int irq2pidmap[MAX_irqNUMBER] = { 0 };

canmsg_t last_Tx_object[MAX_CHANNELS];

int selfreception[MAX_CHANNELS] = {0}; /* flag indicating that selfreception
of frames is allowed */


#ifdef SJA1000_RTR_CONFIG
int Can_ConfigRTR( int minor, unsigned message, canmsg_t *Tx )
{canmsg_t *tmp;
debug("Can_ConfigRTR");
if( (tmp = kmalloc ( sizeof(canmsg_t), GFP_ATOMIC )) == NULL ){debug(DBG_BRANCH,("memory problem")); debug(); return -1;}
rx_filter[minor].filter[message].rtr_response = tmp;
memcpy( rx_filter[minor].filter[message].rtr_response , Tx, sizeof(canmsg_t));
debug(); return 1;
return 0;
}

int Can_UnConfigRTR( int minor, unsigned message )
{canmsg_t *tmp;
debug("Can_UnConfigRTR");
if( rx_filter[minor].filter[message].rtr_response != NULL )
{kfree(rx_filter[minor].filter[message].rtr_response);
rx_filter[minor].filter[message].rtr_response = NULL;
}
debug(); return 1;
}
#endif
/*============================================================================*/
/* Dump the SJA1000 controllers register contents, identified by the device minr number to stdout iobase should contain the virtual adress */
void sja1000_dump(int minor)
{int i, j;
int index = 0;
printk(" SJA1000 at Adress 0x%lx\n", io);
for(i = 0; i < 2; i++)
{for(j = 0; j < 16; j++) {printk("%02x ",inb((int) (iobase + index)) ); index += REG_OFFSET;} printk("\n");}
}
/*============================================================================*/
/* отработка драйвером fclose("/dev/can") файловой операции */
static int can_close (struct inode *inode, struct file *filp)
{if(verbose >= 3) printk(KERN_ERR "%s> fclose(/dev/can);\r\n", can_devname);
down_interruptible(&can_chdev->sem);
can_chdev->ports_usage--;
sja1000_down();
up(&can_chdev->sem);
return -EBADF;
}
/*============================================================================*/
/* отработка драйвером fopen("/dev/can") файловой операции */
int can_open(struct inode *inode, struct file *filp)
{ struct can_buf *wrbuf, *rdbuf;
if(verbose >= 3) printk(KERN_ERR "%s> fopen(/dev/can);\r\n", chipset);
down_interruptible(&can_chdev->sem);
if (can_chdev->ports_usage > 0) {up(&can_chdev->sem); return -EBUSY;}
filp->private_data = can_chdev;
can_chdev->ports_usage++;
memset(wrbuf, 0, BUFSIZE); memset(rdbuf, 0, BUFSIZE);
wrbuf= wrbuf= &can_chdev->wrbuf;rdbuf= &can_chdev->rdbuf;
wrbuf->tail= wrbuf->head= wrbuf->buf;
rdbuf->tail= rdbuf->head= rdbuf->buf;
wrbuf->status= rdbuf->status= wrbuf->active= rdbuf->active = 0;
up(&can_chdev->sem);
return 0
/*============================================================================*/
/* the following does all the board specific things also memory remapping if necessary */
if( (lasterr = sja1000_init()) < 0 ){debug(); return lasterr;}
/* check if device is already open, should be used only by one process */
Can_WaitInit(minor); /* initialize wait queue for select() */
canfifo_init(minor);

if( sja1000_reset(minor) < 0 ) {debug(); return -EINVAL;}
SJA1000_StartChip(minor);
#if DEBUG
can_printstatus(minor);
#endif
/* sja1000_dump(minor); */
++can_isopen[minor];
debug();
return retval;
}
/*==================================================================================================*/
/* ф-ии, выполняющиеся при загрузке драйвера */
int can_init_module (void)
{dev_t can_ndev;
printk(" SJA1000 SJA1000 Driver " VERSION " (c) " __DATE__ "\n");
printk(" H.J. Oertel (oe@port.de)\n");
printk(" C.Schroeter (clausi@chemie.fu-berlin.de), H.D. Stich\n");
if (!io) {printk( KERN_ERR "%s> - please specify I/O address (e.g. insmod acc_can io=0x160\r\n", can_devname); return -EINVAL;}
if (io % 2) {printk( KERN_ERR "%s>- io must be on a 2-byte boundary, you've stuck it on %x\r\n", can_devname, io); return -EINVAL;}
can_ndev = MKDEV(SJA1000_MAJOR, SJA1000_MINOR);
if (request_region (io, 32, can_devname)==NULL) {printk( KERN_ERR "%s>- reagion %x already in use\r\n", can_devname, io); return -EINVAL;}
if (register_chrdev_region(can_ndev, 1, can_devname) < 0) { printk( KERN_ERR "%s> Couldn't register /dev/acc_can driver\r\n", can_devname); return -EINVAL;}
if ((can_chdev = kmalloc(sizeof(struct can_dev), GFP_KERNEL))==NULL)
{ printk( KERN_ERR "%s> - kalloc fault. \r\n", can_devname); unregister_chrdev_region(can_ndev, 1); release_region (can_chdev->iobase, 32); return -ENOMEM;}
memset(can_chdev, 0, sizeof(struct can_dev));
can_chdev->wrbuf.tail= can_chdev->wrbuf.head= can_chdev->wrbuf.buf;
can_chdev->rdbuf.tail= can_chdev->rdbuf.head= can_chdev->rdbuf.buf;
can_chdev->wrbuf.status= can_chdev->rdbuf.>status= can_chdev->wrbuf.active= can_chdev->rdbuf.active = 0;
cdev_init(&can_chdev->can_cdev, &can_fops);
can_chdev->can_cdev.owner = THIS_MODULE;
can_chdev->can_cdev.ops = &can_fops;
can_chdev->iobase = io;
can_chdev->baud= 125;
can_chdev->acc_code= can_chdev->acc_mask= 0xffffffff;
can_chdev->tmout[i]= 100;
init_MUTEX(&can_chdev->sem);
init_waitqueue_head(&(can_chdev->inq));
init_waitqueue_head(&(can_chdev->outq));
if(cdev_add (&can_chdev->can_cdev, can_ndev, 1))
{printk( KERN_ERR "%s> error adding acc_can driver\r\n", can_devname);
unregister_chrdev_region(can_ndev, 1); release_region (io, 32); cdev_del(&can_chdev->can_cdev); devfs_remove(can_devname);
kfree(can_chdev);can_chdev=NULL;
return -ENOMEM;
}
devfs_mk_cdev(can_ndev, S_IFCHR|S_IRUGO|S_IWUGO, can_devname);
if(verbose >= 2) printk( KERN_ERR "%s>%s\r\n", can_devname, _EOK);
return 0;
}
/*==================================================================================================*/
/* ф-ии, выполняющиеся при выгрузке драйвера */
void can_cleanup_module (void)
{dev_t can_ndev = MKDEV(SJA1000_MAJOR, SJA1000_MINOR);
can_chdev->ports_usage=0;
release_region (io, 32);
cdev_del(&can_chdev->can_cdev);
devfs_remove(can_devname);
unregister_chrdev_region(can_ndev, 1);
kfree(can_chdev);can_chdev=NULL;
if(verbose >= 2) printk( KERN_ERR "%s> Removed driver for can\r\n", can_devname);
}
/*==================================================================================================*/
module_init(can_init_module);
module_exit(can_cleanup_module);
MODULE_AUTHOR("H.-J.Oertel ");
MODULE_DESCRIPTION("SJA1000 fieldbus driver");
MODULE_LICENSE("GPL");



Составить ответ  |||  Конференция  |||  Архив

Ответы


Отправка ответа
Имя (обязательно): 
Пароль: 
E-mail: 

Тема (обязательно):
Сообщение:

Ссылка на URL: 
Название ссылки: 
URL изображения: 


Rambler's Top100 Рейтинг@Mail.ru
Перейти к списку ответов  |||  Конференция  |||  Архив  |||  Главная страница  |||  Содержание