由于uClinux只能在A核运行,因此它以驱动的形式提供了对B核的支持。默认配置下此支持是打开的,可以通过Kernel Settings -> Blackfin Processor Options -> BF561 Specific Configurations -> Core B support进行关闭。估计没人会做这种事吧?呵呵!。
以下的所有代码来自于:linux-2.6.x/arch/blackfin/mach-bf561/coreb.c,也就是/dev/coreb驱动的实现文件。
1
、驱动状态查看
如果此驱动正确加载,在系统启动时有如下提示:
BF561 Core B driver v0.1 initialized.
通过以下命令可以看到此驱动的运行状态:
root:~> cat /sys/class/misc/coreb/coreb_status
Base Address:
0xff600000
Core B is stalled
SICA_SYSCR:
0022
SICB_SYSCR:
0020
IRQ Status:
Core A Core B
ISR0:
00000000 00000000
ISR1:
00000000 00000000
IMASK0:
30000000 00000000
IMASK1:
008a8000 00000000
2
、驱动实现的功能
下面看看这个驱动实现的功能。
static struct file_operations coreb_fops = {
.owner = THIS_MODULE,
.llseek = coreb_lseek,
.read = coreb_read,
.write = coreb_write,
.ioctl = coreb_ioctl,
.open = coreb_open,
.release = coreb_release
};
static struct miscdevice coreb_dev = {
COREB_MINOR,
"coreb",
&coreb_fops
};
在此模块加载时执行bf561_coreb_init函数,此函数中有一段代码:
misc_register(&coreb_dev);
if (class_device_create_file(coreb_dev.class, &class_device_attr_coreb_status))
goto release_dma_src;
这两行代码向kernel注册了这个驱动的信息,从这个信息可以看出我们将可以对此设备进行打开和关闭。可以使用fread和fwrite进行数据读写,可用fseek进行指针的定位,还可用ioctl进行输入输出的控制。
从上面可知对ioctl调用的处理是由coreb_ioctl函数完成的,如下所示:
//
定义
ioctl
调用中可用的命令
#define CMD_COREB_INDEX
1
#define CMD_COREB_START
2
#define CMD_COREB_STOP
3
#define CMD_COREB_RESET
4
static int coreb_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int retval = 0;
int coreb_index = 0;
switch (cmd) {
//
设置基址指针和可操作的空间大小,后面打开文件进行读写时将以此为基址。
case CMD_COREB_INDEX:
if (copy_from_user(&coreb_index, (int *)arg, sizeof(int))) {
retval = -EFAULT;
break;
}
spin_lock_irq(&coreb_lock);
switch (coreb_index) {
//
表示要对
0xff60 0000 ~ 0xff60 4000
这段
16K
的空间进行读写,也就是
Core B
中的
L1
指令缓存。当
CoreB
开始允许执行时,第一条指令也是从
0xFF60 0000
开始执行的。因此在允许
B
核运行之前,应当将可执行的代码写入到这里。
case 0:
coreb_base = 0xff600000;
coreb_size = 0x4000;
break;
//
表示要对
0xff61 0000 ~ 0xff61 4000
这段
16K
的地址空间进行操作,即
B
核中的
L1
指令缓存。
case 1:
coreb_base = 0xff610000;
coreb_size = 0x4000;
break;
//
表示要对
0xff50 0000 ~ 0xff50 8000
这段
32K
地址空间进行操作,这是
B
核中的数据缓存。
case 2:
coreb_base = 0xff500000;
coreb_size = 0x8000;
break;
//
表示要对
0xff40 0000 ~ 0xff40 8000
这段
32K
地址空间进行操作,这是
B
核中的另一段数据缓存。
case 3:
coreb_base = 0xff400000;
coreb_size = 0x8000;
break;
default:
retval = -EINVAL;
break;
}
spin_unlock_irq(&coreb_lock);
mutex_lock(&file->f_dentry->d_inode->i_mutex);
file->f_pos = 0;
mutex_unlock(&file->f_dentry->d_inode->i_mutex);
break;
//
要求
B
核从
0xff60 0000
这个位置开始执行代码
case CMD_COREB_START:
spin_lock_irq(&coreb_lock);
if (coreb_status & COREB_IS_RUNNING) {
retval = -EBUSY;
break;
}
printk(KERN_INFO "Starting Core B/n");
coreb_status |= COREB_IS_RUNNING;
//
将
SICA_SYSCR
中的
CoreB_SRAM_INIT
这位设置为
0
,也即允许
B
核开始执行
bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~0x0020);
SSYNC();
spin_lock_irq(&coreb_lock);
break;
#if defined(CONFIG_BF561_COREB_RESET)
//
要求
B
核停止运行
case CMD_COREB_STOP:
spin_lock_irq(&coreb_lock);
printk(KERN_INFO "Stopping Core B/n");
//
将
SICA_SYSCR
中的
CoreB_SRAM_INIT
位设置为
1
bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() | 0x0020);
//
将
SICB_SYSCR
中的
CB_supplement_int0
位写
1
,要求
B
核产生中断
1
进行复位,复位后由于
SICA_SYSCR
中的
CoreB_SRAM_INIT
为
1
,
B
核将不再运行。
bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
coreb_status &= ~COREB_IS_RUNNING;
spin_lock_irq(&coreb_lock);
break;
//
要求
B
核复位
case CMD_COREB_RESET:
printk(KERN_INFO "Resetting Core B/n");
bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
break;
#endif
}
return retval;
}
至于对read和write的处理则比较简单,主要要注意的就是:在读写时驱动程序将自动将FILE结构中的文件位置加上基地址后再进行读写,且读写不能超过每个块允许的大小,否则将读写失败,。如对0xff60 0000的读写就不能超过4K。