mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2025-04-21 12:27:27 +03:00
Move files and patches to files-2.6.23 and patches-2.6.23
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@11843 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
## Makefile for the RB532 CF port
|
||||
|
||||
obj-y += bdev.o ata.o
|
||||
487
target/linux/rb532/files-2.6.23/drivers/block/rb500/ata.c
Normal file
487
target/linux/rb532/files-2.6.23/drivers/block/rb500/ata.c
Normal file
@@ -0,0 +1,487 @@
|
||||
/* CF-mips driver
|
||||
This is a block driver for the direct (mmaped) interface to the CF-slot,
|
||||
found in Routerboard.com's RB532 board
|
||||
See SDK provided from routerboard.com.
|
||||
|
||||
Module adapted By P.Christeas <p_christeas@yahoo.com>, 2005-6.
|
||||
Cleaned up and adapted to platform_device by Felix Fietkau <nbd@openwrt.org>
|
||||
|
||||
This work is redistributed under the terms of the GNU General Public License.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h> /* printk() */
|
||||
#include <linux/module.h> /* module to be loadable */
|
||||
#include <linux/delay.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ioport.h> /* request_mem_region() */
|
||||
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/unaligned.h> /* ioremap() */
|
||||
#include <asm/io.h> /* ioremap() */
|
||||
#include <asm/rc32434/rb.h>
|
||||
|
||||
#include "ata.h"
|
||||
|
||||
#define REQUEST_MEM_REGION 0
|
||||
#define DEBUG 1
|
||||
|
||||
#if DEBUG
|
||||
#define DEBUGP printk
|
||||
#else
|
||||
#define DEBUGP(format, args...)
|
||||
#endif
|
||||
|
||||
#define SECS 1000000 /* unit for wait_not_busy() is 1us */
|
||||
|
||||
unsigned cf_head = 0;
|
||||
unsigned cf_cyl = 0;
|
||||
unsigned cf_spt = 0;
|
||||
unsigned cf_sectors = 0;
|
||||
static unsigned cf_block_size = 1;
|
||||
static void *baddr = 0;
|
||||
|
||||
#define DBUF32 ((volatile u32 *)((unsigned long)dev->baddr | ATA_DBUF_OFFSET))
|
||||
|
||||
|
||||
static void cf_do_tasklet(unsigned long dev_l);
|
||||
|
||||
|
||||
static inline void wareg(u8 val, unsigned reg, struct cf_mips_dev* dev)
|
||||
{
|
||||
writeb(val, dev->baddr + ATA_REG_OFFSET + reg);
|
||||
}
|
||||
|
||||
static inline u8 rareg(unsigned reg, struct cf_mips_dev* dev)
|
||||
{
|
||||
return readb(dev->baddr + ATA_REG_OFFSET + reg);
|
||||
}
|
||||
|
||||
static inline int cfrdy(struct cf_mips_dev *dev)
|
||||
{
|
||||
return gpio_get_value(dev->pin);
|
||||
}
|
||||
|
||||
static inline void prepare_cf_irq(struct cf_mips_dev *dev)
|
||||
{
|
||||
rb500_gpio_set_int_level(1, dev->pin); /* interrupt on cf ready (not busy) */
|
||||
rb500_gpio_set_int_status(0, dev->pin); /* clear interrupt status */
|
||||
}
|
||||
|
||||
static inline int cf_present(struct cf_mips_dev* dev)
|
||||
{
|
||||
/* TODO: read and configure CIS into memory mapped mode
|
||||
* TODO: parse CISTPL_CONFIG on CF+ cards to get base address (0x200)
|
||||
* TODO: maybe adjust power saving setting for Hitachi Microdrive
|
||||
*/
|
||||
int i;
|
||||
|
||||
/* setup CFRDY GPIO as input */
|
||||
rb500_gpio_set_func(dev->pin, 0);
|
||||
gpio_direction_input(dev->pin);
|
||||
|
||||
for (i = 0; i < 0x10; ++i) {
|
||||
if (rareg(i,dev) != 0xff)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int is_busy(struct cf_mips_dev *dev)
|
||||
{
|
||||
return !cfrdy(dev);
|
||||
}
|
||||
|
||||
static int wait_not_busy(int to_us, int wait_for_busy,struct cf_mips_dev *dev)
|
||||
{
|
||||
int us_passed = 0;
|
||||
if (wait_for_busy && !is_busy(dev)) {
|
||||
/* busy must appear within 400ns,
|
||||
* but it may dissapear before we see it
|
||||
* => must not wait for busy in a loop
|
||||
*/
|
||||
ndelay(400);
|
||||
}
|
||||
|
||||
do {
|
||||
if (us_passed)
|
||||
udelay(1); /* never reached in async mode */
|
||||
if (!is_busy(dev)) {
|
||||
if (us_passed > 1 * SECS) {
|
||||
printk(KERN_WARNING "cf-mips: not busy ok (after %dus)"
|
||||
", status 0x%02x\n", us_passed, (unsigned) rareg(ATA_REG_ST,dev));
|
||||
}
|
||||
return CF_TRANS_OK;
|
||||
}
|
||||
if (us_passed == 1 * SECS) {
|
||||
printk(KERN_WARNING "cf-mips: wait not busy %dus..\n", to_us);
|
||||
}
|
||||
if (dev->async_mode) {
|
||||
dev->to_timer.expires = jiffies + (to_us * HZ / SECS);
|
||||
dev->irq_enable_time = jiffies;
|
||||
prepare_cf_irq(dev);
|
||||
if (is_busy(dev)) {
|
||||
add_timer(&dev->to_timer);
|
||||
enable_irq(dev->irq);
|
||||
return CF_TRANS_IN_PROGRESS;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
++us_passed;
|
||||
} while (us_passed < to_us);
|
||||
|
||||
printk(KERN_ERR "cf-mips: wait not busy timeout (%dus)"
|
||||
", status 0x%02x, state %d\n",
|
||||
to_us, (unsigned) rareg(ATA_REG_ST,dev), dev->tstate);
|
||||
return CF_TRANS_FAILED;
|
||||
}
|
||||
|
||||
static irqreturn_t cf_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
/* While tasklet has not disabled irq, irq will be retried all the time
|
||||
* because of ILEVEL matching GPIO pin status => deadlock.
|
||||
* To avoid this, we change ILEVEL to 0.
|
||||
*/
|
||||
struct cf_mips_dev *dev=dev_id;
|
||||
|
||||
rb500_gpio_set_int_level(0, dev->pin);
|
||||
rb500_gpio_set_int_status(0, dev->pin);
|
||||
|
||||
del_timer(&dev->to_timer);
|
||||
tasklet_schedule(&dev->tasklet);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int do_reset(struct cf_mips_dev *dev)
|
||||
{
|
||||
printk(KERN_INFO "cf-mips: resetting..\n");
|
||||
|
||||
wareg(ATA_REG_DC_SRST, ATA_REG_DC,dev);
|
||||
udelay(1); /* FIXME: how long should we wait here? */
|
||||
wareg(0, ATA_REG_DC,dev);
|
||||
|
||||
return wait_not_busy(30 * SECS, 1,dev);
|
||||
}
|
||||
|
||||
static int set_multiple(struct cf_mips_dev *dev)
|
||||
{
|
||||
if (dev->block_size <= 1)
|
||||
return CF_TRANS_OK;
|
||||
|
||||
wareg(dev->block_size, ATA_REG_SC,dev);
|
||||
wareg(ATA_REG_DH_BASE | ATA_REG_DH_LBA, ATA_REG_DH,dev);
|
||||
wareg(ATA_CMD_SET_MULTIPLE, ATA_REG_CMD,dev);
|
||||
|
||||
return wait_not_busy(10 * SECS, 1,dev);
|
||||
}
|
||||
|
||||
static int set_cmd(struct cf_mips_dev *dev)
|
||||
{
|
||||
//DEBUGP(KERN_INFO "cf-mips: ata cmd 0x%02x\n", dev->tcmd);
|
||||
// sector_count should be <=24 bits..
|
||||
BUG_ON(dev->tsect_start>=0x10000000);
|
||||
// This way, it addresses 2^24 * 512 = 128G
|
||||
|
||||
if (dev->tsector_count) {
|
||||
wareg(dev->tsector_count & 0xff, ATA_REG_SC,dev);
|
||||
wareg(dev->tsect_start & 0xff, ATA_REG_SN,dev);
|
||||
wareg((dev->tsect_start >> 8) & 0xff, ATA_REG_CL,dev);
|
||||
wareg((dev->tsect_start >> 16) & 0xff, ATA_REG_CH,dev);
|
||||
}
|
||||
wareg(((dev->tsect_start >> 24) & 0x0f) | ATA_REG_DH_BASE | ATA_REG_DH_LBA,
|
||||
ATA_REG_DH,dev); /* select drive on all commands */
|
||||
wareg(dev->tcmd, ATA_REG_CMD,dev);
|
||||
return wait_not_busy(10 * SECS, 1,dev);
|
||||
}
|
||||
|
||||
static int do_trans(struct cf_mips_dev *dev)
|
||||
{
|
||||
int res;
|
||||
unsigned st;
|
||||
int transfered;
|
||||
|
||||
//printk("do_trans: %d sectors left\n",dev->tsectors_left);
|
||||
while (dev->tsectors_left) {
|
||||
transfered = 0;
|
||||
|
||||
st = rareg(ATA_REG_ST,dev);
|
||||
if (!(st & ATA_REG_ST_DRQ)) {
|
||||
printk(KERN_ERR "cf-mips: do_trans without DRQ (status 0x%x)!\n", st);
|
||||
if (st & ATA_REG_ST_ERR) {
|
||||
int errId = rareg(ATA_REG_ERR,dev);
|
||||
printk(KERN_ERR "cf-mips: %s error, status 0x%x, errid 0x%x\n",
|
||||
(dev->tread ? "read" : "write"), st, errId);
|
||||
}
|
||||
return CF_TRANS_FAILED;
|
||||
}
|
||||
do { /* Fill/read the buffer one block */
|
||||
u32 *qbuf, *qend;
|
||||
qbuf = (u32 *)dev->tbuf;
|
||||
qend = qbuf + CF_SECT_SIZE / sizeof(u32);
|
||||
if (dev->tread) {
|
||||
while (qbuf!=qend)
|
||||
put_unaligned(*DBUF32,qbuf++);
|
||||
//*(qbuf++) = *DBUF32;
|
||||
}
|
||||
else {
|
||||
while(qbuf!=qend)
|
||||
*DBUF32 = get_unaligned(qbuf++);
|
||||
}
|
||||
|
||||
dev->tsectors_left--;
|
||||
dev->tbuf += CF_SECT_SIZE;
|
||||
dev->tbuf_size -= CF_SECT_SIZE;
|
||||
transfered++;
|
||||
} while (transfered != dev->block_size && dev->tsectors_left > 0);
|
||||
|
||||
res = wait_not_busy(10 * SECS, 1,dev);
|
||||
if (res != CF_TRANS_OK)
|
||||
return res;
|
||||
};
|
||||
|
||||
st = rareg(ATA_REG_ST,dev);
|
||||
if (st & (ATA_REG_ST_DRQ | ATA_REG_ST_DWF | ATA_REG_ST_ERR)) {
|
||||
if (st & ATA_REG_ST_DRQ) {
|
||||
printk(KERN_ERR "cf-mips: DRQ after all %d sectors are %s"
|
||||
", status 0x%x\n", dev->tsector_count, (dev->tread ? "read" : "written"), st);
|
||||
} else if (st & ATA_REG_ST_DWF) {
|
||||
printk(KERN_ERR "cf-mips: write fault, status 0x%x\n", st);
|
||||
} else {
|
||||
int errId = rareg(ATA_REG_ERR,dev);
|
||||
printk(KERN_ERR "cf-mips: %s error, status 0x%x, errid 0x%x\n",
|
||||
(dev->tread ? "read" : "write"), st, errId);
|
||||
}
|
||||
return CF_TRANS_FAILED;
|
||||
}
|
||||
return CF_TRANS_OK;
|
||||
}
|
||||
|
||||
static int cf_do_state(struct cf_mips_dev *dev)
|
||||
{
|
||||
int res;
|
||||
switch (dev->tstate) { /* fall through everywhere */
|
||||
case TS_IDLE:
|
||||
dev->tstate = TS_READY;
|
||||
if (is_busy(dev)) {
|
||||
dev->tstate = TS_AFTER_RESET;
|
||||
res = do_reset(dev);
|
||||
if (res != CF_TRANS_OK)
|
||||
break;
|
||||
}
|
||||
case TS_AFTER_RESET:
|
||||
if (dev->tstate == TS_AFTER_RESET) {
|
||||
dev->tstate = TS_READY;
|
||||
res = set_multiple(dev);
|
||||
if (res != CF_TRANS_OK)
|
||||
break;
|
||||
}
|
||||
case TS_READY:
|
||||
dev->tstate = TS_CMD;
|
||||
res = set_cmd(dev);
|
||||
if (res != CF_TRANS_OK)
|
||||
break;;
|
||||
case TS_CMD:
|
||||
dev->tstate = TS_TRANS;
|
||||
case TS_TRANS:
|
||||
res = do_trans(dev);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "cf-mips: BUG: unknown tstate %d\n", dev->tstate);
|
||||
return CF_TRANS_FAILED;
|
||||
}
|
||||
if (res != CF_TRANS_IN_PROGRESS)
|
||||
dev->tstate = TS_IDLE;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void cf_do_tasklet(unsigned long dev_l)
|
||||
{
|
||||
struct cf_mips_dev* dev=(struct cf_mips_dev*) dev_l;
|
||||
int res;
|
||||
|
||||
disable_irq(dev->irq);
|
||||
|
||||
if (dev->tstate == TS_IDLE)
|
||||
return; /* can happen when irq is first registered */
|
||||
|
||||
#if 0
|
||||
DEBUGP(KERN_WARNING "cf-mips: not busy ok (tasklet) status 0x%02x\n",
|
||||
(unsigned) rareg(ATA_REG_ST,dev));
|
||||
#endif
|
||||
|
||||
res = cf_do_state(dev);
|
||||
if (res == CF_TRANS_IN_PROGRESS)
|
||||
return;
|
||||
cf_async_trans_done(dev,res);
|
||||
}
|
||||
|
||||
static void cf_async_timeout(unsigned long dev_l)
|
||||
{
|
||||
struct cf_mips_dev* dev=(struct cf_mips_dev*) dev_l;
|
||||
disable_irq(dev->irq);
|
||||
/* Perhaps send abort to the device? */
|
||||
printk(KERN_ERR "cf-mips: wait not busy timeout (%lus)"
|
||||
", status 0x%02x, state %d\n",
|
||||
jiffies - dev->irq_enable_time, (unsigned) rareg(ATA_REG_ST,dev), dev->tstate);
|
||||
dev->tstate = TS_IDLE;
|
||||
cf_async_trans_done(dev,CF_TRANS_FAILED);
|
||||
}
|
||||
|
||||
int cf_do_transfer(struct cf_mips_dev* dev,sector_t sector, unsigned long nsect,
|
||||
char* buffer, int is_write)
|
||||
{
|
||||
BUG_ON(dev->tstate!=TS_IDLE);
|
||||
if (nsect > ATA_MAX_SECT_PER_CMD) {
|
||||
printk(KERN_WARNING "cf-mips: sector count %lu out of range\n",nsect);
|
||||
return CF_TRANS_FAILED;
|
||||
}
|
||||
if (sector + nsect > dev->sectors) {
|
||||
printk(KERN_WARNING "cf-mips: sector %lu out of range\n",sector);
|
||||
return CF_TRANS_FAILED;
|
||||
}
|
||||
dev->tbuf = buffer;
|
||||
dev->tbuf_size = nsect*512;
|
||||
dev->tsect_start = sector;
|
||||
dev->tsector_count = nsect;
|
||||
dev->tsectors_left = dev->tsector_count;
|
||||
dev->tread = (is_write)?0:1;
|
||||
|
||||
dev->tcmd = (dev->block_size == 1 ?
|
||||
(is_write ? ATA_CMD_WRITE_SECTORS : ATA_CMD_READ_SECTORS) :
|
||||
(is_write ? ATA_CMD_WRITE_MULTIPLE : ATA_CMD_READ_MULTIPLE));
|
||||
|
||||
return cf_do_state(dev);
|
||||
}
|
||||
|
||||
static int do_identify(struct cf_mips_dev *dev)
|
||||
{
|
||||
u16 sbuf[CF_SECT_SIZE >> 1];
|
||||
int res;
|
||||
char tstr[17]; //serial
|
||||
char tmp;
|
||||
int i;
|
||||
BUG_ON(dev->tstate!=TS_IDLE);
|
||||
dev->tbuf = (char *) sbuf;
|
||||
dev->tbuf_size = CF_SECT_SIZE;
|
||||
dev->tsect_start = 0;
|
||||
dev->tsector_count = 0;
|
||||
dev->tsectors_left = 1;
|
||||
dev->tread = 1;
|
||||
dev->tcmd = ATA_CMD_IDENTIFY_DRIVE;
|
||||
|
||||
DEBUGP(KERN_INFO "cf-mips: identify drive..\n");
|
||||
res = cf_do_state(dev);
|
||||
if (res == CF_TRANS_IN_PROGRESS) {
|
||||
printk(KERN_ERR "cf-mips: BUG: async identify cmd\n");
|
||||
return CF_TRANS_FAILED;
|
||||
}
|
||||
if (res != CF_TRANS_OK)
|
||||
return 0;
|
||||
|
||||
dev->head = sbuf[3];
|
||||
dev->cyl = sbuf[1];
|
||||
dev->spt = sbuf[6];
|
||||
dev->sectors = ((unsigned long) sbuf[7] << 16) | sbuf[8];
|
||||
dev->dtype=sbuf[0];
|
||||
memcpy(tstr, &sbuf[12], 16);
|
||||
tstr[16] = '\0';
|
||||
|
||||
/* Byte-swap the serial number */
|
||||
for (i = 0; i<8; i++) {
|
||||
tmp = tstr[i * 2];
|
||||
tstr[i * 2] = tstr[i * 2 +1];
|
||||
tstr[i * 2 + 1] = tmp;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "cf-mips: %s detected, C/H/S=%d/%d/%d sectors=%u (%uMB) Serial=%s\n",
|
||||
(sbuf[0] == 0x848A ? "CF card" : "ATA drive"), dev->cyl, dev->head,
|
||||
dev->spt, dev->sectors, dev->sectors >> 11, tstr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void init_multiple(struct cf_mips_dev * dev)
|
||||
{
|
||||
int res;
|
||||
DEBUGP(KERN_INFO "cf-mips: detecting block size\n");
|
||||
|
||||
dev->block_size = 128; /* max block size = 128 sectors (64KB) */
|
||||
do {
|
||||
wareg(dev->block_size, ATA_REG_SC,dev);
|
||||
wareg(ATA_REG_DH_BASE | ATA_REG_DH_LBA, ATA_REG_DH,dev);
|
||||
wareg(ATA_CMD_SET_MULTIPLE, ATA_REG_CMD,dev);
|
||||
|
||||
res = wait_not_busy(10 * SECS, 1,dev);
|
||||
if (res != CF_TRANS_OK) {
|
||||
printk(KERN_ERR "cf-mips: failed to detect block size: busy!\n");
|
||||
dev->block_size = 1;
|
||||
return;
|
||||
}
|
||||
if ((rareg(ATA_REG_ST,dev) & ATA_REG_ST_ERR) == 0)
|
||||
break;
|
||||
dev->block_size /= 2;
|
||||
} while (dev->block_size > 1);
|
||||
|
||||
printk(KERN_INFO "cf-mips: multiple sectors = %d\n", dev->block_size);
|
||||
}
|
||||
|
||||
int cf_init(struct cf_mips_dev *dev)
|
||||
{
|
||||
tasklet_init(&dev->tasklet,cf_do_tasklet,(unsigned long)dev);
|
||||
dev->baddr = ioremap_nocache((unsigned long)dev->base, CFDEV_BUF_SIZE);
|
||||
if (!dev->baddr) {
|
||||
printk(KERN_ERR "cf-mips: cf_init: ioremap for (%lx,%x) failed\n",
|
||||
(unsigned long) dev->base, CFDEV_BUF_SIZE);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (!cf_present(dev)) {
|
||||
printk(KERN_WARNING "cf-mips: cf card not present\n");
|
||||
iounmap(dev->baddr);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (do_reset(dev) != CF_TRANS_OK) {
|
||||
printk(KERN_ERR "cf-mips: cf reset failed\n");
|
||||
iounmap(dev->baddr);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (!do_identify(dev)) {
|
||||
printk(KERN_ERR "cf-mips: cf identify failed\n");
|
||||
iounmap(dev->baddr);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* set_apm_level(ATA_APM_WITH_STANDBY); */
|
||||
init_multiple(dev);
|
||||
|
||||
init_timer(&dev->to_timer);
|
||||
dev->to_timer.function = cf_async_timeout;
|
||||
dev->to_timer.data = (unsigned long)dev;
|
||||
|
||||
prepare_cf_irq(dev);
|
||||
if (request_irq(dev->irq, cf_irq_handler, 0, "CF Mips", dev)) {
|
||||
printk(KERN_ERR "cf-mips: failed to get irq\n");
|
||||
iounmap(dev->baddr);
|
||||
return -EBUSY;
|
||||
}
|
||||
/* Disable below would be odd, because request will enable, and the tasklet
|
||||
will disable it itself */
|
||||
//disable_irq(dev->irq);
|
||||
|
||||
dev->async_mode = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cf_cleanup(struct cf_mips_dev *dev)
|
||||
{
|
||||
iounmap(dev->baddr);
|
||||
free_irq(dev->irq, NULL);
|
||||
#if REQUEST_MEM_REGION
|
||||
release_mem_region((unsigned long)dev->base, CFDEV_BUF_SIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*eof*/
|
||||
143
target/linux/rb532/files-2.6.23/drivers/block/rb500/ata.h
Normal file
143
target/linux/rb532/files-2.6.23/drivers/block/rb500/ata.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/* CF-mips driver
|
||||
This is a block driver for the direct (mmaped) interface to the CF-slot,
|
||||
found in Routerboard.com's RB532 board
|
||||
See SDK provided from routerboard.com.
|
||||
|
||||
Module adapted By P.Christeas <p_christeas@yahoo.com>, 2005-6.
|
||||
Cleaned up and adapted to platform_device by Felix Fietkau <nbd@openwrt.org>
|
||||
|
||||
This work is redistributed under the terms of the GNU General Public License.
|
||||
*/
|
||||
|
||||
#ifndef __CFMIPS_ATA_H__
|
||||
#define __CFMIPS_ATA_H__
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#define CFG_DC_DEV1 (void*)0xb8010010
|
||||
#define CFG_DC_DEVBASE 0x0
|
||||
#define CFG_DC_DEVMASK 0x4
|
||||
#define CFG_DC_DEVC 0x8
|
||||
#define CFG_DC_DEVTC 0xC
|
||||
|
||||
#define CFDEV_BUF_SIZE 0x1000
|
||||
#define ATA_CIS_OFFSET 0x200
|
||||
#define ATA_REG_OFFSET 0x800
|
||||
#define ATA_DBUF_OFFSET 0xC00
|
||||
|
||||
#define ATA_REG_FEAT 0x1
|
||||
#define ATA_REG_SC 0x2
|
||||
#define ATA_REG_SN 0x3
|
||||
#define ATA_REG_CL 0x4
|
||||
#define ATA_REG_CH 0x5
|
||||
#define ATA_REG_DH 0x6
|
||||
#define ATA_REG_DH_BASE 0xa0
|
||||
#define ATA_REG_DH_LBA 0x40
|
||||
#define ATA_REG_DH_DRV 0x10
|
||||
#define ATA_REG_CMD 0x7
|
||||
#define ATA_REG_ST 0x7
|
||||
#define ATA_REG_ST_BUSY 0x80
|
||||
#define ATA_REG_ST_RDY 0x40
|
||||
#define ATA_REG_ST_DWF 0x20
|
||||
#define ATA_REG_ST_DSC 0x10
|
||||
#define ATA_REG_ST_DRQ 0x08
|
||||
#define ATA_REG_ST_CORR 0x04
|
||||
#define ATA_REG_ST_ERR 0x01
|
||||
#define ATA_REG_ERR 0xd
|
||||
#define ATA_REG_DC 0xe
|
||||
#define ATA_REG_DC_IEN 0x02
|
||||
#define ATA_REG_DC_SRST 0x04
|
||||
|
||||
#define ATA_CMD_READ_SECTORS 0x20
|
||||
#define ATA_CMD_WRITE_SECTORS 0x30
|
||||
#define ATA_CMD_EXEC_DRIVE_DIAG 0x90
|
||||
#define ATA_CMD_READ_MULTIPLE 0xC4
|
||||
#define ATA_CMD_WRITE_MULTIPLE 0xC5
|
||||
#define ATA_CMD_SET_MULTIPLE 0xC6
|
||||
#define ATA_CMD_IDENTIFY_DRIVE 0xEC
|
||||
#define ATA_CMD_SET_FEATURES 0xEF
|
||||
|
||||
#define ATA_FEATURE_ENABLE_APM 0x05
|
||||
#define ATA_FEATURE_DISABLE_APM 0x85
|
||||
#define ATA_APM_DISABLED 0x00
|
||||
#define ATA_APM_MIN_POWER 0x01
|
||||
#define ATA_APM_WITH_STANDBY 0x7f
|
||||
#define ATA_APM_WITHOUT_STANDBY 0x80
|
||||
#define ATA_APM_MAX_PERFORMANCE 0xfe
|
||||
|
||||
#define CF_SECT_SIZE 0x200
|
||||
/* That is the ratio CF_SECT_SIZE/512 (the kernel sector size) */
|
||||
#define CF_KERNEL_MUL 1
|
||||
#define ATA_MAX_SECT_PER_CMD 0x100
|
||||
|
||||
#define CF_TRANS_FAILED 0
|
||||
#define CF_TRANS_OK 1
|
||||
#define CF_TRANS_IN_PROGRESS 2
|
||||
|
||||
|
||||
enum trans_state {
|
||||
TS_IDLE = 0,
|
||||
TS_AFTER_RESET,
|
||||
TS_READY,
|
||||
TS_CMD,
|
||||
TS_TRANS
|
||||
};
|
||||
|
||||
//
|
||||
// #if DEBUG
|
||||
// static unsigned long busy_time;
|
||||
// #endif
|
||||
|
||||
/** Struct to hold the cfdev
|
||||
Actually, all the data here only has one instance. However, for
|
||||
reasons of programming conformity, it is passed around as a pointer
|
||||
*/
|
||||
struct cf_mips_dev {
|
||||
void *base; /* base address for I/O */
|
||||
void *baddr; /* remapped address */
|
||||
|
||||
int pin; /* gpio pin */
|
||||
int irq; /* gpio irq */
|
||||
|
||||
unsigned head;
|
||||
unsigned cyl;
|
||||
unsigned spt;
|
||||
unsigned sectors;
|
||||
|
||||
unsigned short block_size;
|
||||
unsigned dtype ; // ATA or CF
|
||||
struct request_queue *queue;
|
||||
struct gendisk *gd;
|
||||
|
||||
/* Transaction state */
|
||||
enum trans_state tstate;
|
||||
char *tbuf;
|
||||
unsigned long tbuf_size;
|
||||
sector_t tsect_start;
|
||||
unsigned tsector_count;
|
||||
unsigned tsectors_left;
|
||||
int tread;
|
||||
unsigned tcmd;
|
||||
int async_mode;
|
||||
unsigned long irq_enable_time;
|
||||
|
||||
struct request *active_req; /* A request is being carried out. Is that different from tstate? */
|
||||
int users;
|
||||
struct timer_list to_timer;
|
||||
struct tasklet_struct tasklet;
|
||||
|
||||
/** This lock ensures that the requests to this device are all done
|
||||
atomically. Transfers can run in parallel, requests are all queued
|
||||
one-by-one */
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
int cf_do_transfer(struct cf_mips_dev* dev,sector_t sector, unsigned long nsect,
|
||||
char* buffer, int is_write);
|
||||
int cf_init(struct cf_mips_dev* dev);
|
||||
void cf_cleanup(struct cf_mips_dev* dev);
|
||||
|
||||
void cf_async_trans_done(struct cf_mips_dev* dev, int result);
|
||||
// void *cf_get_next_buf(unsigned long *buf_size);
|
||||
|
||||
#endif
|
||||
340
target/linux/rb532/files-2.6.23/drivers/block/rb500/bdev.c
Normal file
340
target/linux/rb532/files-2.6.23/drivers/block/rb500/bdev.c
Normal file
@@ -0,0 +1,340 @@
|
||||
/* CF-mips driver
|
||||
This is a block driver for the direct (mmaped) interface to the CF-slot,
|
||||
found in Routerboard.com's RB532 board
|
||||
See SDK provided from routerboard.com.
|
||||
|
||||
Module adapted By P.Christeas <p_christeas@yahoo.com>, 2005-6.
|
||||
Cleaned up and adapted to platform_device by Felix Fietkau <nbd@openwrt.org>
|
||||
|
||||
This work is redistributed under the terms of the GNU General Public License.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/genhd.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/blkpg.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/gpio.h>
|
||||
|
||||
#include <asm/rc32434/rb.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUGP printk
|
||||
#define DLEVEL 1
|
||||
#else
|
||||
#define DEBUGP(format, args...)
|
||||
#define DLEVEL 0
|
||||
#endif
|
||||
|
||||
#define CF_MIPS_MAJOR 13
|
||||
#define MAJOR_NR CF_MIPS_MAJOR
|
||||
#define CF_MAX_PART 16 /* max 15 partitions */
|
||||
|
||||
#include "ata.h"
|
||||
|
||||
//extern struct block_device_operations cf_bdops;
|
||||
|
||||
// static struct hd_struct cf_parts[CF_MAX_PART];
|
||||
// static int cf_part_sizes[CF_MAX_PART];
|
||||
// static int cf_hsect_sizes[CF_MAX_PART];
|
||||
// static int cf_max_sectors[CF_MAX_PART];
|
||||
// static int cf_blksize_sizes[CF_MAX_PART];
|
||||
|
||||
// static spinlock_t lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
// volatile int cf_busy = 0;
|
||||
|
||||
static struct request *active_req = NULL;
|
||||
|
||||
static int cf_open (struct inode *, struct file *);
|
||||
static int cf_release (struct inode *, struct file *);
|
||||
static int cf_ioctl (struct inode *, struct file *, unsigned, unsigned long);
|
||||
|
||||
static void cf_request(request_queue_t * q);
|
||||
static int cf_transfer(const struct request *req);
|
||||
|
||||
/*long (*unlocked_ioctl) (struct file *, unsigned, unsigned long);
|
||||
long (*compat_ioctl) (struct file *, unsigned, unsigned long);*/
|
||||
// int (*direct_access) (struct block_device *, sector_t, unsigned long *);
|
||||
// int (*media_changed) (struct gendisk *);
|
||||
// int (*revalidate_disk) (struct gendisk *);
|
||||
|
||||
static struct block_device_operations cf_bdops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = cf_open,
|
||||
.release = cf_release,
|
||||
.ioctl = cf_ioctl,
|
||||
.media_changed = NULL,
|
||||
.unlocked_ioctl = NULL,
|
||||
.revalidate_disk = NULL,
|
||||
.compat_ioctl = NULL,
|
||||
.direct_access = NULL
|
||||
};
|
||||
|
||||
|
||||
int cf_mips_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gendisk* cf_gendisk=NULL;
|
||||
struct cf_device *cdev = (struct cf_device *) pdev->dev.platform_data;
|
||||
struct cf_mips_dev *dev;
|
||||
struct resource *r;
|
||||
int reg_result;
|
||||
|
||||
reg_result = register_blkdev(MAJOR_NR, "cf-mips");
|
||||
if (reg_result < 0) {
|
||||
printk(KERN_WARNING "cf-mips: can't get major %d\n", MAJOR_NR);
|
||||
return reg_result;
|
||||
}
|
||||
|
||||
dev = (struct cf_mips_dev *)kmalloc(sizeof(struct cf_mips_dev),GFP_KERNEL);
|
||||
if (!dev)
|
||||
goto out_err;
|
||||
memset(dev, 0, sizeof(struct cf_mips_dev));
|
||||
cdev->dev = dev;
|
||||
|
||||
dev->pin = cdev->gpio_pin;
|
||||
dev->irq = platform_get_irq_byname(pdev, "cf_irq");
|
||||
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cf_membase");
|
||||
dev->base = (void *) r->start;
|
||||
|
||||
if (cf_init(dev)) goto out_err;
|
||||
printk("init done");
|
||||
|
||||
spin_lock_init(&dev->lock);
|
||||
dev->queue = blk_init_queue(cf_request,&dev->lock);
|
||||
if (!dev->queue){
|
||||
printk(KERN_ERR "cf-mips: no mem for queue\n");
|
||||
goto out_err;
|
||||
}
|
||||
blk_queue_max_sectors(dev->queue,ATA_MAX_SECT_PER_CMD);
|
||||
|
||||
/* For memory devices, it is always better to avoid crossing segments
|
||||
inside the same request. */
|
||||
/* if (dev->dtype==0x848A){
|
||||
printk(KERN_INFO "Setting boundary for cf to 0x%x",(dev->block_size*512)-1);
|
||||
blk_queue_segment_boundary(dev->queue, (dev->block_size*512)-1);
|
||||
}*/
|
||||
|
||||
dev->gd = alloc_disk(CF_MAX_PART);
|
||||
cf_gendisk = dev->gd;
|
||||
cdev->gd = dev->gd;
|
||||
if (!cf_gendisk) goto out_err; /* Last of these goto's */
|
||||
|
||||
cf_gendisk->major = MAJOR_NR;
|
||||
cf_gendisk->first_minor = 0;
|
||||
cf_gendisk->queue=dev->queue;
|
||||
BUG_ON(cf_gendisk->minors != CF_MAX_PART);
|
||||
strcpy(cf_gendisk->disk_name,"cfa");
|
||||
cf_gendisk->fops = &cf_bdops;
|
||||
cf_gendisk->flags = 0 ; /* is not yet GENHD_FL_REMOVABLE */
|
||||
cf_gendisk->private_data=dev;
|
||||
|
||||
set_capacity(cf_gendisk,dev->sectors * CF_KERNEL_MUL);
|
||||
|
||||
/* Let the disk go live */
|
||||
add_disk(cf_gendisk);
|
||||
#if 0
|
||||
result = cf_init();
|
||||
|
||||
/* default cfg for all partitions */
|
||||
memset(cf_parts, 0, sizeof (cf_parts[0]) * CF_MAX_PART);
|
||||
memset(cf_part_sizes, 0, sizeof (cf_part_sizes[0]) * CF_MAX_PART);
|
||||
for (i = 0; i < CF_MAX_PART; ++i) {
|
||||
cf_hsect_sizes[i] = CF_SECT_SIZE;
|
||||
cf_max_sectors[i] = ATA_MAX_SECT_PER_CMD;
|
||||
cf_blksize_sizes[i] = BLOCK_SIZE;
|
||||
}
|
||||
|
||||
/* setup info for whole disk (partition 0) */
|
||||
cf_part_sizes[0] = cf_sectors / 2;
|
||||
cf_parts[0].nr_sects = cf_sectors;
|
||||
|
||||
blk_size[MAJOR_NR] = cf_part_sizes;
|
||||
blksize_size[MAJOR_NR] = cf_blksize_sizes;
|
||||
max_sectors[MAJOR_NR] = cf_max_sectors;
|
||||
hardsect_size[MAJOR_NR] = cf_hsect_sizes;
|
||||
read_ahead[MAJOR_NR] = 8; /* (4kB) */
|
||||
|
||||
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
|
||||
|
||||
add_gendisk(&cf_gendisk);
|
||||
#endif
|
||||
// printk(KERN_INFO "cf-mips partition check: \n");
|
||||
// register_disk(cf_gendisk, MKDEV(MAJOR_NR, 0), CF_MAX_PART,
|
||||
// &cf_bdops, dev->sectors);
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
if (dev->queue){
|
||||
blk_cleanup_queue(dev->queue);
|
||||
}
|
||||
if (reg_result) {
|
||||
unregister_blkdev(MAJOR_NR, "cf-mips");
|
||||
return reg_result;
|
||||
}
|
||||
if (dev){
|
||||
cf_cleanup(dev);
|
||||
kfree(dev);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
cf_mips_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct cf_device *cdev = (struct cf_device *) pdev->dev.platform_data;
|
||||
struct cf_mips_dev *dev = (struct cf_mips_dev *) cdev->dev;
|
||||
|
||||
unregister_blkdev(MAJOR_NR, "cf-mips");
|
||||
blk_cleanup_queue(dev->queue);
|
||||
|
||||
del_gendisk(dev->gd);
|
||||
cf_cleanup(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct platform_driver cf_driver = {
|
||||
.driver.name = "rb500-cf",
|
||||
.probe = cf_mips_probe,
|
||||
.remove = cf_mips_remove,
|
||||
};
|
||||
|
||||
static int __init cf_mips_init(void)
|
||||
{
|
||||
printk(KERN_INFO "cf-mips module loaded\n");
|
||||
return platform_driver_register(&cf_driver);
|
||||
}
|
||||
|
||||
static void cf_mips_cleanup(void)
|
||||
{
|
||||
platform_driver_unregister(&cf_driver);
|
||||
printk(KERN_INFO "cf-mips module removed\n");
|
||||
}
|
||||
|
||||
module_init(cf_mips_init);
|
||||
module_exit(cf_mips_cleanup);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_BLOCKDEV_MAJOR(CF_MIPS_MAJOR);
|
||||
|
||||
|
||||
static int cf_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct cf_mips_dev *dev=inode->i_bdev->bd_disk->private_data;
|
||||
int minor = MINOR(inode->i_rdev);
|
||||
|
||||
if (minor >= CF_MAX_PART)
|
||||
return -ENODEV;
|
||||
//DEBUGP(KERN_INFO "cf-mips module opened, minor %d\n", minor);
|
||||
spin_lock(&dev->lock);
|
||||
dev->users++;
|
||||
spin_unlock(&dev->lock);
|
||||
filp->private_data=dev;
|
||||
|
||||
/* dirty workaround to set CFRDY GPIO as an input when some other
|
||||
program sets it as an output */
|
||||
gpio_set_value(dev->pin, 0);
|
||||
return 0; /* success */
|
||||
}
|
||||
|
||||
static int cf_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
int minor = MINOR(inode->i_rdev);
|
||||
struct cf_mips_dev *dev=inode->i_bdev->bd_disk->private_data;
|
||||
spin_lock(&dev->lock);
|
||||
dev->users--;
|
||||
spin_unlock(&dev->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cf_ioctl(struct inode *inode, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
unsigned minor = MINOR(inode->i_rdev);
|
||||
struct cf_mips_dev *dev=inode->i_bdev->bd_disk->private_data;
|
||||
|
||||
DEBUGP(KERN_INFO "cf_ioctl cmd %u\n", cmd);
|
||||
switch (cmd) {
|
||||
case BLKRRPART: /* re-read partition table */
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EACCES;
|
||||
printk(KERN_INFO "cf-mips partition check: \n");
|
||||
register_disk(dev->gd);
|
||||
return 0;
|
||||
|
||||
case HDIO_GETGEO:
|
||||
{
|
||||
struct hd_geometry geo;
|
||||
geo.cylinders = dev->cyl;
|
||||
geo.heads = dev->head;
|
||||
geo.sectors = dev->spt;
|
||||
geo.start = (*dev->gd->part)[minor].start_sect;
|
||||
if (copy_to_user((void *) arg, &geo, sizeof (geo)))
|
||||
return -EFAULT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL; /* unknown command */
|
||||
}
|
||||
|
||||
static void cf_request(request_queue_t * q)
|
||||
{
|
||||
struct cf_mips_dev* dev;
|
||||
|
||||
struct request * req;
|
||||
int status;
|
||||
|
||||
/* We could have q->queuedata = dev , but haven't yet. */
|
||||
if (active_req)
|
||||
return;
|
||||
|
||||
while ((req=elv_next_request(q))!=NULL){
|
||||
dev=req->rq_disk->private_data;
|
||||
status=cf_transfer(req);
|
||||
if (status==CF_TRANS_IN_PROGRESS){
|
||||
active_req=req;
|
||||
return;
|
||||
}
|
||||
end_request(req,status);
|
||||
}
|
||||
}
|
||||
|
||||
static int cf_transfer(const struct request *req)
|
||||
{
|
||||
struct cf_mips_dev* dev=req->rq_disk->private_data;
|
||||
|
||||
if (!blk_fs_request(req)){
|
||||
if (printk_ratelimit())
|
||||
printk(KERN_WARNING "cf-mips: skipping non-fs request 0x%x\n",req->cmd[0]);
|
||||
return CF_TRANS_FAILED;
|
||||
}
|
||||
|
||||
return cf_do_transfer(dev,req->sector,req->current_nr_sectors,req->buffer,rq_data_dir(req));
|
||||
}
|
||||
|
||||
void cf_async_trans_done(struct cf_mips_dev * dev,int result)
|
||||
{
|
||||
struct request *req;
|
||||
|
||||
spin_lock(&dev->lock);
|
||||
req=active_req;
|
||||
active_req=NULL;
|
||||
end_request(req,result);
|
||||
spin_unlock(&dev->lock);
|
||||
|
||||
spin_lock(&dev->lock);
|
||||
cf_request(dev->queue);
|
||||
spin_unlock(&dev->lock);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* RC32434_WDT 0.01: IDT Interprise 79RC32434 watchdog driver
|
||||
* Copyright (c) Ondrej Zajicek <santiago@crfreenet.org>, 2006
|
||||
*
|
||||
* based on
|
||||
*
|
||||
* SoftDog 0.05: A Software Watchdog Device
|
||||
*
|
||||
* (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/watchdog.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/time.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/rc32434/integ.h>
|
||||
|
||||
#define DEFAULT_TIMEOUT 15 /* (secs) Default is 15 seconds */
|
||||
#define MAX_TIMEOUT 20
|
||||
/*
|
||||
* (secs) Max is 20 seconds
|
||||
* (max frequency of counter is ~200 MHz, counter is 32-bit unsigned int)
|
||||
*/
|
||||
|
||||
#define NAME "rc32434_wdt"
|
||||
#define VERSION "0.1"
|
||||
|
||||
static INTEG_t rc_wdt = (INTEG_t) INTEG_VirtualAddress;
|
||||
|
||||
static int expect_close = 0;
|
||||
static int access = 0;
|
||||
static int timeout = 0;
|
||||
|
||||
static int nowayout = WATCHDOG_NOWAYOUT;
|
||||
module_param(nowayout, int, 0);
|
||||
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
static inline void start_wdt(void)
|
||||
{
|
||||
rc_wdt -> wtcount = 0;
|
||||
rc_wdt -> errcs |= ERRCS_wre_m;
|
||||
rc_wdt -> wtc |= WTC_en_m;
|
||||
}
|
||||
|
||||
static inline void stop_wdt(void)
|
||||
{
|
||||
rc_wdt -> wtc &= ~WTC_en_m;
|
||||
rc_wdt -> errcs &= ~ERRCS_wre_m;
|
||||
}
|
||||
|
||||
static inline void set_wdt(int new_timeout)
|
||||
{
|
||||
u32 cmp = new_timeout * mips_hpt_frequency;
|
||||
u32 state;
|
||||
|
||||
timeout = new_timeout;
|
||||
/*
|
||||
* store and disable WTC
|
||||
*/
|
||||
state = rc_wdt -> wtc & WTC_en_m;
|
||||
rc_wdt -> wtc &= ~WTC_en_m;
|
||||
|
||||
rc_wdt -> wtcount = 0;
|
||||
rc_wdt -> wtcompare = cmp;
|
||||
|
||||
/*
|
||||
* restore WTC
|
||||
*/
|
||||
rc_wdt -> wtc |= state;
|
||||
}
|
||||
|
||||
static inline void update_wdt(void)
|
||||
{
|
||||
rc_wdt -> wtcount = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow only one person to hold it open
|
||||
*/
|
||||
|
||||
static int wdt_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
if (access)
|
||||
return -EBUSY;
|
||||
if (nowayout) {
|
||||
__module_get(THIS_MODULE);
|
||||
}
|
||||
/*
|
||||
* Activate timer
|
||||
*/
|
||||
start_wdt();
|
||||
printk(KERN_INFO NAME ": enabling watchdog timer\n");
|
||||
access = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wdt_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
/*
|
||||
* Shut off the timer.
|
||||
* Lock it in if it's a module and we set nowayout
|
||||
*/
|
||||
if (expect_close && nowayout == 0) {
|
||||
stop_wdt ();
|
||||
printk(KERN_INFO NAME ": disabling watchdog timer\n");
|
||||
module_put(THIS_MODULE);
|
||||
} else {
|
||||
printk (KERN_CRIT NAME ": device closed unexpectedly. WDT will not stop!\n");
|
||||
}
|
||||
access = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
|
||||
{
|
||||
/*
|
||||
* Refresh the timer.
|
||||
*/
|
||||
if (len) {
|
||||
if (!nowayout) {
|
||||
size_t i;
|
||||
|
||||
/* In case it was set long ago */
|
||||
expect_close = 0;
|
||||
|
||||
for (i = 0; i != len; i++) {
|
||||
char c;
|
||||
if (get_user(c, data + i))
|
||||
return -EFAULT;
|
||||
if (c == 'V')
|
||||
expect_close = 1;
|
||||
}
|
||||
}
|
||||
update_wdt ();
|
||||
return len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wdt_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int new_timeout;
|
||||
static struct watchdog_info ident = {
|
||||
.options = WDIOF_SETTIMEOUT |
|
||||
WDIOF_KEEPALIVEPING |
|
||||
WDIOF_MAGICCLOSE,
|
||||
.firmware_version = 0,
|
||||
.identity = "RC32434_WDT Watchdog",
|
||||
};
|
||||
switch (cmd) {
|
||||
default:
|
||||
return -ENOTTY;
|
||||
case WDIOC_GETSUPPORT:
|
||||
if(copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
case WDIOC_GETSTATUS:
|
||||
case WDIOC_GETBOOTSTATUS:
|
||||
return put_user(0,(int *)arg);
|
||||
case WDIOC_KEEPALIVE:
|
||||
update_wdt();
|
||||
return 0;
|
||||
case WDIOC_SETTIMEOUT:
|
||||
if (get_user(new_timeout, (int *)arg))
|
||||
return -EFAULT;
|
||||
if (new_timeout < 1)
|
||||
return -EINVAL;
|
||||
if (new_timeout > MAX_TIMEOUT)
|
||||
return -EINVAL;
|
||||
set_wdt(new_timeout);
|
||||
/* Fall */
|
||||
case WDIOC_GETTIMEOUT:
|
||||
return put_user(timeout, (int *)arg);
|
||||
}
|
||||
}
|
||||
|
||||
static struct file_operations wdt_fops = {
|
||||
owner: THIS_MODULE,
|
||||
llseek: no_llseek,
|
||||
write: wdt_write,
|
||||
ioctl: wdt_ioctl,
|
||||
open: wdt_open,
|
||||
release: wdt_release,
|
||||
};
|
||||
|
||||
static struct miscdevice wdt_miscdev = {
|
||||
minor: WATCHDOG_MINOR,
|
||||
name: "watchdog",
|
||||
fops: &wdt_fops,
|
||||
};
|
||||
|
||||
static char banner[] __initdata = KERN_INFO NAME ": Watchdog Timer version " VERSION ", timer margin: %d sec\n";
|
||||
|
||||
static int __init watchdog_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* There should be check for RC32434 SoC
|
||||
*/
|
||||
if (mips_machgroup != MACH_GROUP_MIKROTIK) return -1;
|
||||
|
||||
ret = misc_register(&wdt_miscdev);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
stop_wdt();
|
||||
set_wdt(DEFAULT_TIMEOUT);
|
||||
|
||||
printk(banner, timeout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit watchdog_exit(void)
|
||||
{
|
||||
misc_deregister(&wdt_miscdev);
|
||||
}
|
||||
|
||||
module_init(watchdog_init);
|
||||
module_exit(watchdog_exit);
|
||||
81
target/linux/rb532/files-2.6.23/drivers/leds/leds-rb500.c
Normal file
81
target/linux/rb532/files-2.6.23/drivers/leds/leds-rb500.c
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* linux/drivers/leds/leds-rb500.c
|
||||
*
|
||||
* Copyright (C) 2006
|
||||
* Twente Institute for Wireless and Mobile Communications BV
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details (see file GPLv2).
|
||||
*
|
||||
* Author: Tjalling Hattink <tjalling.hattink@ti-wmc.nl>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/leds.h>
|
||||
#include <asm/rc32434/rb.h>
|
||||
|
||||
static void rb500led_amber_set(struct led_classdev *led_cdev, enum led_brightness value)
|
||||
{
|
||||
if (value)
|
||||
changeLatchU5(LO_ULED, 0);
|
||||
else
|
||||
changeLatchU5(0, LO_ULED);
|
||||
}
|
||||
|
||||
static struct led_classdev rb500_amber_led = {
|
||||
.name = "rb500led:amber",
|
||||
.default_trigger = "ide-disk",
|
||||
.brightness_set = rb500led_amber_set,
|
||||
};
|
||||
|
||||
static int rb500led_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
changeLatchU5(0, LO_ULED);
|
||||
|
||||
ret = led_classdev_register(&pdev->dev, &rb500_amber_led);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rb500led_remove(struct platform_device *pdev)
|
||||
{
|
||||
led_classdev_unregister(&rb500_amber_led);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver rb500led_driver = {
|
||||
.probe = rb500led_probe,
|
||||
.remove = rb500led_remove,
|
||||
.driver = {
|
||||
.name = "rb500-led",
|
||||
},
|
||||
};
|
||||
|
||||
static int __init rb500led_init(void)
|
||||
{
|
||||
return platform_driver_register(&rb500led_driver);
|
||||
}
|
||||
|
||||
static void __exit rb500led_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&rb500led_driver);
|
||||
}
|
||||
|
||||
module_init(rb500led_init);
|
||||
module_exit(rb500led_exit);
|
||||
|
||||
MODULE_AUTHOR("tjalling.hattink@ti-wmc.nl");
|
||||
MODULE_DESCRIPTION("Mikrotik RB500 LED driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
1167
target/linux/rb532/files-2.6.23/drivers/net/korina.c
Normal file
1167
target/linux/rb532/files-2.6.23/drivers/net/korina.c
Normal file
File diff suppressed because it is too large
Load Diff
178
target/linux/rb532/files-2.6.23/drivers/net/rc32434_eth.h
Normal file
178
target/linux/rb532/files-2.6.23/drivers/net/rc32434_eth.h
Normal file
@@ -0,0 +1,178 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* BRIEF MODULE DESCRIPTION
|
||||
* Definitions for IDT RC32434 on-chip ethernet controller.
|
||||
*
|
||||
* Copyright 2004 IDT Inc. (rischelp@idt.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*
|
||||
**************************************************************************
|
||||
* May 2004 rkt, neb
|
||||
*
|
||||
* Initial Release
|
||||
*
|
||||
* Aug 2004
|
||||
*
|
||||
* Added NAPI
|
||||
*
|
||||
**************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
#include <asm/rc32434/rc32434.h>
|
||||
#include <asm/rc32434/dma_v.h>
|
||||
#include <asm/rc32434/eth_v.h>
|
||||
|
||||
#define CONFIG_IDT_USE_NAPI 1
|
||||
#define RC32434_DEBUG 2
|
||||
//#define RC32434_PROC_DEBUG
|
||||
#undef RC32434_DEBUG
|
||||
|
||||
#ifdef RC32434_DEBUG
|
||||
|
||||
/* use 0 for production, 1 for verification, >2 for debug */
|
||||
static int rc32434_debug = RC32434_DEBUG;
|
||||
#define ASSERT(expr) \
|
||||
if(!(expr)) { \
|
||||
printk( "Assertion failed! %s,%s,%s,line=%d\n", \
|
||||
#expr,__FILE__,__FUNCTION__,__LINE__); }
|
||||
#define DBG(lvl, format, arg...) if (rc32434_debug > lvl) printk(KERN_INFO "%s: " format, dev->name , ## arg)
|
||||
#else
|
||||
#define ASSERT(expr) do {} while (0)
|
||||
#define DBG(lvl, format, arg...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define INFO(format, arg...) printk(KERN_INFO "%s: " format, dev->name , ## arg)
|
||||
#define ERR(format, arg...) printk(KERN_ERR "%s: " format, dev->name , ## arg)
|
||||
#define WARN(format, arg...) printk(KERN_WARNING "%s: " format, dev->name , ## arg)
|
||||
|
||||
/* the following must be powers of two */
|
||||
#ifdef CONFIG_IDT_USE_NAPI
|
||||
#define RC32434_NUM_RDS 64 /* number of receive descriptors */
|
||||
#define RC32434_NUM_TDS 64 /* number of transmit descriptors */
|
||||
#else
|
||||
#define RC32434_NUM_RDS 128 /* number of receive descriptors */
|
||||
#define RC32434_NUM_TDS 128 /* number of transmit descriptors */
|
||||
#endif
|
||||
|
||||
#define RC32434_RBSIZE 1536 /* size of one resource buffer = Ether MTU */
|
||||
#define RC32434_RDS_MASK (RC32434_NUM_RDS-1)
|
||||
#define RC32434_TDS_MASK (RC32434_NUM_TDS-1)
|
||||
#define RD_RING_SIZE (RC32434_NUM_RDS * sizeof(struct DMAD_s))
|
||||
#define TD_RING_SIZE (RC32434_NUM_TDS * sizeof(struct DMAD_s))
|
||||
|
||||
#define RC32434_TX_TIMEOUT HZ * 100
|
||||
|
||||
#define rc32434_eth0_regs ((ETH_t)(ETH0_VirtualAddress))
|
||||
#define rc32434_eth1_regs ((ETH_t)(ETH1_VirtualAddress))
|
||||
|
||||
enum status { filled, empty};
|
||||
#define IS_DMA_FINISHED(X) (((X) & (DMAD_f_m)) != 0)
|
||||
#define IS_DMA_DONE(X) (((X) & (DMAD_d_m)) != 0)
|
||||
|
||||
|
||||
/* Information that need to be kept for each board. */
|
||||
struct rc32434_local {
|
||||
ETH_t eth_regs;
|
||||
DMA_Chan_t rx_dma_regs;
|
||||
DMA_Chan_t tx_dma_regs;
|
||||
volatile DMAD_t td_ring; /* transmit descriptor ring */
|
||||
volatile DMAD_t rd_ring; /* receive descriptor ring */
|
||||
|
||||
struct sk_buff* tx_skb[RC32434_NUM_TDS]; /* skbuffs for pkt to trans */
|
||||
struct sk_buff* rx_skb[RC32434_NUM_RDS]; /* skbuffs for pkt to trans */
|
||||
|
||||
#ifndef CONFIG_IDT_USE_NAPI
|
||||
struct tasklet_struct * rx_tasklet;
|
||||
#endif
|
||||
struct tasklet_struct * tx_tasklet;
|
||||
|
||||
int rx_next_done;
|
||||
int rx_chain_head;
|
||||
int rx_chain_tail;
|
||||
enum status rx_chain_status;
|
||||
|
||||
int tx_next_done;
|
||||
int tx_chain_head;
|
||||
int tx_chain_tail;
|
||||
enum status tx_chain_status;
|
||||
int tx_count;
|
||||
int tx_full;
|
||||
|
||||
struct timer_list mii_phy_timer;
|
||||
unsigned long duplex_mode;
|
||||
|
||||
int rx_irq;
|
||||
int tx_irq;
|
||||
int ovr_irq;
|
||||
int und_irq;
|
||||
|
||||
struct net_device_stats stats;
|
||||
spinlock_t lock;
|
||||
|
||||
/* debug /proc entry */
|
||||
struct proc_dir_entry *ps;
|
||||
int dma_halt_cnt; int dma_run_cnt;
|
||||
};
|
||||
|
||||
extern unsigned int idt_cpu_freq;
|
||||
|
||||
/* Index to functions, as function prototypes. */
|
||||
static int rc32434_open(struct net_device *dev);
|
||||
static int rc32434_send_packet(struct sk_buff *skb, struct net_device *dev);
|
||||
static void rc32434_mii_handler(unsigned long data);
|
||||
static irqreturn_t rc32434_und_interrupt(int irq, void *dev_id);
|
||||
static irqreturn_t rc32434_rx_dma_interrupt(int irq, void *dev_id);
|
||||
static irqreturn_t rc32434_tx_dma_interrupt(int irq, void *dev_id);
|
||||
#ifdef RC32434_REVISION
|
||||
static irqreturn_t rc32434_ovr_interrupt(int irq, void *dev_id);
|
||||
#endif
|
||||
static int rc32434_close(struct net_device *dev);
|
||||
static struct net_device_stats *rc32434_get_stats(struct net_device *dev);
|
||||
static void rc32434_multicast_list(struct net_device *dev);
|
||||
static int rc32434_init(struct net_device *dev);
|
||||
static void rc32434_tx_timeout(struct net_device *dev);
|
||||
|
||||
static void rc32434_tx_tasklet(unsigned long tx_data_dev);
|
||||
#ifdef CONFIG_IDT_USE_NAPI
|
||||
static int rc32434_poll(struct net_device *rx_data_dev, int *budget);
|
||||
#else
|
||||
static void rc32434_rx_tasklet(unsigned long rx_data_dev);
|
||||
#endif
|
||||
static void rc32434_cleanup_module(void);
|
||||
|
||||
|
||||
static inline void rc32434_abort_dma(struct net_device *dev, DMA_Chan_t ch)
|
||||
{
|
||||
if (__raw_readl(&ch->dmac) & DMAC_run_m) {
|
||||
__raw_writel(0x10, &ch->dmac);
|
||||
|
||||
while (!(__raw_readl(&ch->dmas) & DMAS_h_m))
|
||||
dev->trans_start = jiffies;
|
||||
|
||||
__raw_writel(0, &ch->dmas);
|
||||
}
|
||||
|
||||
__raw_writel(0, &ch->dmadptr);
|
||||
__raw_writel(0, &ch->dmandptr);
|
||||
}
|
||||
Reference in New Issue
Block a user