remove more redundant files and clone files-2.6.23 for 2.6.24 - fixes rdc build errors

SVN-Revision: 13022
lede-17.01
Felix Fietkau 2008-10-22 06:51:06 +00:00
parent 40b5e7a30d
commit 5065bb589a
165 changed files with 7767 additions and 45570 deletions

View File

@ -1,170 +0,0 @@
/*
* ADM6996 switch driver
*
* Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License v2 as published by the
* Free Software Foundation
*/
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/phy.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include "adm6996.h"
MODULE_DESCRIPTION("Infineon ADM6996 Switch");
MODULE_AUTHOR("Felix Fietkau");
MODULE_LICENSE("GPL");
struct adm6996_priv {
/* use abstraction for regops, we want to add gpio support in the future */
u16 (*read)(struct phy_device *phydev, enum admreg reg);
void (*write)(struct phy_device *phydev, enum admreg reg, u16 val);
};
#define to_adm(_phy) ((struct adm6996_priv *) (_phy)->priv)
static inline u16
r16(struct phy_device *pdev, enum admreg reg)
{
return to_adm(pdev)->read(pdev, reg);
}
static inline void
w16(struct phy_device *pdev, enum admreg reg, u16 val)
{
to_adm(pdev)->write(pdev, reg, val);
}
static u16
adm6996_read_mii_reg(struct phy_device *phydev, enum admreg reg)
{
return phydev->bus->read(phydev->bus, PHYADDR(reg));
}
static void
adm6996_write_mii_reg(struct phy_device *phydev, enum admreg reg, u16 val)
{
phydev->bus->write(phydev->bus, PHYADDR(reg), val);
}
static int adm6996_config_init(struct phy_device *pdev)
{
int i;
printk("%s: ADM6996 PHY driver attached.\n", pdev->attached_dev->name);
pdev->supported = ADVERTISED_100baseT_Full;
pdev->advertising = ADVERTISED_100baseT_Full;
/* initialize port and vlan settings */
for (i = 0; i < ADM_PHY_PORTS; i++) {
w16(pdev, adm_portcfg[i], ADM_PORTCFG_INIT |
ADM_PORTCFG_PVID((i == ADM_WAN_PORT) ? 1 : 0));
}
w16(pdev, adm_portcfg[5], ADM_PORTCFG_CPU);
/* reset all ports */
for (i = 0; i < ADM_PHY_PORTS; i++) {
w16(pdev, ADM_PHY_PORT(i), ADM_PHYCFG_INIT);
}
return 0;
}
static int adm6996_read_status(struct phy_device *phydev)
{
phydev->speed = SPEED_100;
phydev->duplex = DUPLEX_FULL;
phydev->state = PHY_UP;
return 0;
}
static int adm6996_config_aneg(struct phy_device *phydev)
{
return 0;
}
static int adm6996_probe(struct phy_device *pdev)
{
struct adm6996_priv *priv;
priv = kzalloc(sizeof(struct adm6996_priv), GFP_KERNEL);
if (priv == NULL)
return -ENOMEM;
priv->read = adm6996_read_mii_reg;
priv->write = adm6996_write_mii_reg;
pdev->priv = priv;
return 0;
}
static void adm6996_remove(struct phy_device *pdev)
{
kfree(pdev->priv);
}
static bool adm6996_detect(struct mii_bus *bus, int addr)
{
u16 reg;
/* we only attach to phy id 0 */
if (addr != 0)
return false;
/* look for the switch on the bus */
reg = bus->read(bus, PHYADDR(ADM_SIG0)) & ADM_SIG0_MASK;
if (reg != ADM_SIG0_VAL)
return false;
reg = bus->read(bus, PHYADDR(ADM_SIG1)) & ADM_SIG1_MASK;
if (reg != ADM_SIG1_VAL)
return false;
return true;
}
static struct phy_driver adm6996_driver = {
.name = "Infineon ADM6996",
.features = PHY_BASIC_FEATURES,
.detect = adm6996_detect,
.probe = adm6996_probe,
.remove = adm6996_remove,
.config_init = &adm6996_config_init,
.config_aneg = &adm6996_config_aneg,
.read_status = &adm6996_read_status,
.driver = { .owner = THIS_MODULE,},
};
static int __init adm6996_init(void)
{
return phy_driver_register(&adm6996_driver);
}
static void __exit adm6996_exit(void)
{
phy_driver_unregister(&adm6996_driver);
}
module_init(adm6996_init);
module_exit(adm6996_exit);

View File

@ -1,105 +0,0 @@
/*
* ADM6996 switch driver
*
* Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License v2 as published by the
* Free Software Foundation
*/
#ifndef __ADM6996_H
#define __ADM6996_H
#define ADM_PHY_PORTS 5
#define ADM_CPU_PORT 5
#define ADM_WAN_PORT 0 /* FIXME: dynamic ? */
enum admreg {
ADM_EEPROM_BASE = 0x0,
ADM_P0_CFG = ADM_EEPROM_BASE + 1,
ADM_P1_CFG = ADM_EEPROM_BASE + 3,
ADM_P2_CFG = ADM_EEPROM_BASE + 5,
ADM_P3_CFG = ADM_EEPROM_BASE + 7,
ADM_P4_CFG = ADM_EEPROM_BASE + 8,
ADM_P5_CFG = ADM_EEPROM_BASE + 9,
ADM_EEPROM_EXT_BASE = 0x40,
ADM_COUNTER_BASE = 0xa0,
ADM_SIG0 = ADM_COUNTER_BASE + 0,
ADM_SIG1 = ADM_COUNTER_BASE + 1,
ADM_PHY_BASE = 0x200,
#define ADM_PHY_PORT(n) (ADM_PHY_BASE + (0x20 * n))
};
/* Chip identification patterns */
#define ADM_SIG0_MASK 0xfff0
#define ADM_SIG0_VAL 0x1020
#define ADM_SIG1_MASK 0xffff
#define ADM_SIG1_VAL 0x0007
enum {
ADM_PHYCFG_COLTST = (1 << 7), /* Enable collision test */
ADM_PHYCFG_DPLX = (1 << 8), /* Enable full duplex */
ADM_PHYCFG_ANEN_RST = (1 << 9), /* Restart auto negotiation (self clear) */
ADM_PHYCFG_ISO = (1 << 10), /* Isolate PHY */
ADM_PHYCFG_PDN = (1 << 11), /* Power down PHY */
ADM_PHYCFG_ANEN = (1 << 12), /* Enable auto negotiation */
ADM_PHYCFG_SPEED_100 = (1 << 13), /* Enable 100 Mbit/s */
ADM_PHYCFG_LPBK = (1 << 14), /* Enable loopback operation */
ADM_PHYCFG_RST = (1 << 15), /* Reset the port (self clear) */
ADM_PHYCFG_INIT = (
ADM_PHYCFG_RST |
ADM_PHYCFG_SPEED_100 |
ADM_PHYCFG_ANEN |
ADM_PHYCFG_ANEN_RST
)
};
enum {
ADM_PORTCFG_FC = (1 << 0), /* Enable 802.x flow control */
ADM_PORTCFG_AN = (1 << 1), /* Enable auto-negotiation */
ADM_PORTCFG_SPEED_100 = (1 << 2), /* Enable 100 Mbit/s */
ADM_PORTCFG_DPLX = (1 << 3), /* Enable full duplex */
ADM_PORTCFG_OT = (1 << 4), /* Output tagged packets */
ADM_PORTCFG_PD = (1 << 5), /* Port disable */
ADM_PORTCFG_TV_PRIO = (1 << 6), /* 0 = VLAN based priority
* 1 = TOS based priority */
ADM_PORTCFG_PPE = (1 << 7), /* Port based priority enable */
ADM_PORTCFG_PP_S = (1 << 8), /* Port based priority, 2 bits */
ADM_PORTCFG_PVID_BASE = (1 << 10), /* Primary VLAN id, 4 bits */
ADM_PORTCFG_FSE = (1 << 14), /* Fx select enable */
ADM_PORTCFG_CAM = (1 << 15), /* Crossover Auto MDIX */
ADM_PORTCFG_INIT = (
ADM_PORTCFG_FC |
ADM_PORTCFG_AN |
ADM_PORTCFG_SPEED_100 |
ADM_PORTCFG_DPLX |
ADM_PORTCFG_CAM
),
ADM_PORTCFG_CPU = (
ADM_PORTCFG_FC |
ADM_PORTCFG_SPEED_100 |
ADM_PORTCFG_OT |
ADM_PORTCFG_DPLX
),
};
#define ADM_PORTCFG_PPID(N) ((n & 0x3) << 8)
#define ADM_PORTCFG_PVID(n) ((n & 0xf) << 10)
static const u8 adm_portcfg[] = {
[0] = ADM_P0_CFG,
[1] = ADM_P1_CFG,
[2] = ADM_P2_CFG,
[3] = ADM_P3_CFG,
[4] = ADM_P4_CFG,
[5] = ADM_P5_CFG,
};
/*
* Split the register address in phy id and register
* it will get combined again by the mdio bus op
*/
#define PHYADDR(_reg) ((_reg >> 5) & 0xff), (_reg & 0x1f)
#endif

View File

@ -1,474 +0,0 @@
/*
* Marvell 88E6060 switch driver
* Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License v2 as published by the
* Free Software Foundation
*/
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/phy.h>
#include <linux/if_vlan.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include "mvswitch.h"
/* Undefine this to use trailer mode instead.
* I don't know if header mode works with all chips */
#define HEADER_MODE 1
MODULE_DESCRIPTION("Marvell 88E6060 Switch driver");
MODULE_AUTHOR("Felix Fietkau");
MODULE_LICENSE("GPL");
struct mvswitch_priv {
/* the driver's tx function */
int (*hardstart)(struct sk_buff *skb, struct net_device *dev);
struct vlan_group *grp;
u8 vlans[16];
};
#define to_mvsw(_phy) ((struct mvswitch_priv *) (_phy)->priv)
static inline u16
r16(struct phy_device *phydev, int addr, int reg)
{
return phydev->bus->read(phydev->bus, addr, reg);
}
static inline void
w16(struct phy_device *phydev, int addr, int reg, u16 val)
{
phydev->bus->write(phydev->bus, addr, reg, val);
}
static int
mvswitch_mangle_tx(struct sk_buff *skb, struct net_device *dev)
{
struct mvswitch_priv *priv;
char *buf = NULL;
u16 vid;
priv = dev->phy_ptr;
if (unlikely(!priv))
goto error;
if (unlikely(skb->len < 16))
goto error;
#ifdef HEADER_MODE
if (__vlan_hwaccel_get_tag(skb, &vid))
goto error;
if (skb_cloned(skb) || (skb->len <= 62) || (skb_headroom(skb) < MV_HEADER_SIZE)) {
if (pskb_expand_head(skb, MV_HEADER_SIZE, (skb->len < 62 ? 62 - skb->len : 0), GFP_ATOMIC))
goto error_expand;
if (skb->len < 62)
skb->len = 62;
}
buf = skb_push(skb, MV_HEADER_SIZE);
#else
if (__vlan_get_tag(skb, &vid))
goto error;
if (unlikely((vid > 15 || !priv->vlans[vid])))
goto error;
if (skb->len <= 64) {
if (pskb_expand_head(skb, 0, 64 + MV_TRAILER_SIZE - skb->len, GFP_ATOMIC))
goto error_expand;
buf = skb->data + 64;
skb->len = 64 + MV_TRAILER_SIZE;
} else {
if (skb_cloned(skb) || unlikely(skb_tailroom(skb) < 4)) {
if (pskb_expand_head(skb, 0, 4, GFP_ATOMIC))
goto error_expand;
}
buf = skb_put(skb, 4);
}
/* move the ethernet header 4 bytes forward, overwriting the vlan tag */
memmove(skb->data + 4, skb->data, 12);
skb->data += 4;
skb->len -= 4;
skb->mac_header += 4;
#endif
if (!buf)
goto error;
#ifdef HEADER_MODE
/* prepend the tag */
*((__be16 *) buf) = cpu_to_be16(
((vid << MV_HEADER_VLAN_S) & MV_HEADER_VLAN_M) |
((priv->vlans[vid] << MV_HEADER_PORTS_S) & MV_HEADER_PORTS_M)
);
#else
/* append the tag */
*((__be32 *) buf) = cpu_to_be32((
(MV_TRAILER_OVERRIDE << MV_TRAILER_FLAGS_S) |
((priv->vlans[vid] & MV_TRAILER_PORTS_M) << MV_TRAILER_PORTS_S)
));
#endif
return priv->hardstart(skb, dev);
error_expand:
if (net_ratelimit())
printk("%s: failed to expand/update skb for the switch\n", dev->name);
error:
/* any errors? drop the packet! */
dev_kfree_skb_any(skb);
return 0;
}
static int
mvswitch_mangle_rx(struct sk_buff *skb, int napi)
{
struct mvswitch_priv *priv;
struct net_device *dev;
int vlan = -1;
unsigned char *buf;
int i;
dev = skb->dev;
if (!dev)
goto error;
priv = dev->phy_ptr;
if (!priv)
goto error;
if (!priv->grp)
goto error;
#ifdef HEADER_MODE
buf = skb->data;
skb_pull(skb, MV_HEADER_SIZE);
#else
buf = skb->data + skb->len - MV_TRAILER_SIZE;
if (buf[0] != 0x80)
goto error;
#endif
/* look for the vlan matching the incoming port */
for (i = 0; i < ARRAY_SIZE(priv->vlans); i++) {
if ((1 << buf[1]) & priv->vlans[i])
vlan = i;
}
if (vlan == -1)
goto error;
skb->protocol = eth_type_trans(skb, skb->dev);
if (napi)
return vlan_hwaccel_receive_skb(skb, priv->grp, vlan);
else
return vlan_hwaccel_rx(skb, priv->grp, vlan);
error:
/* no vlan? eat the packet! */
dev_kfree_skb_any(skb);
return 0;
}
static int
mvswitch_netif_rx(struct sk_buff *skb)
{
return mvswitch_mangle_rx(skb, 0);
}
static int
mvswitch_netif_receive_skb(struct sk_buff *skb)
{
return mvswitch_mangle_rx(skb, 1);
}
static void
mvswitch_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
{
struct mvswitch_priv *priv = dev->phy_ptr;
priv->grp = grp;
}
static int
mvswitch_wait_mask(struct phy_device *pdev, int addr, int reg, u16 mask, u16 val)
{
int i = 100;
u16 r;
do {
r = r16(pdev, addr, reg) & mask;
if (r == val)
return 0;
} while(--i > 0);
return -ETIMEDOUT;
}
static int
mvswitch_config_init(struct phy_device *pdev)
{
struct mvswitch_priv *priv = to_mvsw(pdev);
struct net_device *dev = pdev->attached_dev;
u8 vlmap = 0;
int i;
if (!dev)
return -EINVAL;
printk("%s: Marvell 88E6060 PHY driver attached.\n", dev->name);
pdev->supported = ADVERTISED_100baseT_Full;
pdev->advertising = ADVERTISED_100baseT_Full;
dev->phy_ptr = priv;
dev->irq = PHY_POLL;
/* initialize default vlans */
for (i = 0; i < MV_PORTS; i++)
priv->vlans[(i == MV_WANPORT ? 1 : 0)] |= (1 << i);
/* before entering reset, disable all ports */
for (i = 0; i < MV_PORTS; i++)
w16(pdev, MV_PORTREG(CONTROL, i), 0x00);
msleep(2); /* wait for the status change to settle in */
/* put the ATU in reset */
w16(pdev, MV_SWITCHREG(ATU_CTRL), MV_ATUCTL_RESET);
i = mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_CTRL), MV_ATUCTL_RESET, 0);
if (i < 0) {
printk("%s: Timeout waiting for the switch to reset.\n", dev->name);
return i;
}
/* set the ATU flags */
w16(pdev, MV_SWITCHREG(ATU_CTRL),
MV_ATUCTL_NO_LEARN |
MV_ATUCTL_ATU_1K |
MV_ATUCTL_AGETIME(MV_ATUCTL_AGETIME_MIN) /* minimum without disabling ageing */
);
/* initialize the cpu port */
w16(pdev, MV_PORTREG(CONTROL, MV_CPUPORT),
#ifdef HEADER_MODE
MV_PORTCTRL_HEADER |
#else
MV_PORTCTRL_RXTR |
MV_PORTCTRL_TXTR |
#endif
MV_PORTCTRL_ENABLED
);
/* wait for the phy change to settle in */
msleep(2);
for (i = 0; i < MV_PORTS; i++) {
u8 pvid = 0;
int j;
vlmap = 0;
/* look for the matching vlan */
for (j = 0; j < ARRAY_SIZE(priv->vlans); j++) {
if (priv->vlans[j] & (1 << i)) {
vlmap = priv->vlans[j];
pvid = j;
}
}
/* leave port unconfigured if it's not part of a vlan */
if (!vlmap)
continue;
/* add the cpu port to the allowed destinations list */
vlmap |= (1 << MV_CPUPORT);
/* take port out of its own vlan destination map */
vlmap &= ~(1 << i);
/* apply vlan settings */
w16(pdev, MV_PORTREG(VLANMAP, i),
MV_PORTVLAN_PORTS(vlmap) |
MV_PORTVLAN_ID(i)
);
/* re-enable port */
w16(pdev, MV_PORTREG(CONTROL, i),
MV_PORTCTRL_ENABLED
);
}
w16(pdev, MV_PORTREG(VLANMAP, MV_CPUPORT),
MV_PORTVLAN_ID(MV_CPUPORT)
);
/* set the port association vector */
for (i = 0; i <= MV_PORTS; i++) {
w16(pdev, MV_PORTREG(ASSOC, i),
MV_PORTASSOC_PORTS(1 << i)
);
}
/* init switch control */
w16(pdev, MV_SWITCHREG(CTRL),
MV_SWITCHCTL_MSIZE |
MV_SWITCHCTL_DROP
);
/* hook into the tx function */
priv->hardstart = dev->hard_start_xmit;
pdev->netif_receive_skb = mvswitch_netif_receive_skb;
pdev->netif_rx = mvswitch_netif_rx;
dev->hard_start_xmit = mvswitch_mangle_tx;
dev->vlan_rx_register = mvswitch_vlan_rx_register;
#ifdef HEADER_MODE
dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX;
#else
dev->features |= NETIF_F_HW_VLAN_RX;
#endif
return 0;
}
static int
mvswitch_read_status(struct phy_device *pdev)
{
pdev->speed = SPEED_100;
pdev->duplex = DUPLEX_FULL;
pdev->state = PHY_UP;
/* XXX ugly workaround: we can't force the switch
* to gracefully handle hosts moving from one port to another,
* so we have to regularly clear the ATU database */
/* wait for the ATU to become available */
mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_OP), MV_ATUOP_INPROGRESS, 0);
/* flush the ATU */
w16(pdev, MV_SWITCHREG(ATU_OP),
MV_ATUOP_INPROGRESS |
MV_ATUOP_FLUSH_ALL
);
/* wait for operation to complete */
mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_OP), MV_ATUOP_INPROGRESS, 0);
return 0;
}
static int
mvswitch_config_aneg(struct phy_device *phydev)
{
return 0;
}
static void
mvswitch_remove(struct phy_device *pdev)
{
struct mvswitch_priv *priv = to_mvsw(pdev);
struct net_device *dev = pdev->attached_dev;
/* restore old xmit handler */
if (priv->hardstart && dev)
dev->hard_start_xmit = priv->hardstart;
dev->vlan_rx_register = NULL;
dev->vlan_rx_kill_vid = NULL;
dev->phy_ptr = NULL;
dev->features &= ~NETIF_F_HW_VLAN_RX;
kfree(priv);
}
static bool
mvswitch_detect(struct mii_bus *bus, int addr)
{
u16 reg;
int i;
/* we attach to phy id 31 to make sure that the late probe works */
if (addr != 31)
return false;
/* look for the switch on the bus */
reg = bus->read(bus, MV_PORTREG(IDENT, 0)) & MV_IDENT_MASK;
if (reg != MV_IDENT_VALUE)
return false;
/*
* Now that we've established that the switch actually exists, let's
* get rid of the competition :)
*/
for (i = 0; i < 31; i++) {
if (!bus->phy_map[i])
continue;
device_unregister(&bus->phy_map[i]->dev);
kfree(bus->phy_map[i]);
bus->phy_map[i] = NULL;
}
return true;
}
static int
mvswitch_probe(struct phy_device *pdev)
{
struct mvswitch_priv *priv;
priv = kzalloc(sizeof(struct mvswitch_priv), GFP_KERNEL);
if (priv == NULL)
return -ENOMEM;
pdev->priv = priv;
return 0;
}
static struct phy_driver mvswitch_driver = {
.name = "Marvell 88E6060",
.features = PHY_BASIC_FEATURES,
.detect = &mvswitch_detect,
.probe = &mvswitch_probe,
.remove = &mvswitch_remove,
.config_init = &mvswitch_config_init,
.config_aneg = &mvswitch_config_aneg,
.read_status = &mvswitch_read_status,
.driver = { .owner = THIS_MODULE,},
};
static int __init
mvswitch_init(void)
{
return phy_driver_register(&mvswitch_driver);
}
static void __exit
mvswitch_exit(void)
{
phy_driver_unregister(&mvswitch_driver);
}
module_init(mvswitch_init);
module_exit(mvswitch_exit);

View File

@ -1,145 +0,0 @@
/*
* Marvell 88E6060 switch driver
* Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License v2 as published by the
* Free Software Foundation
*/
#ifndef __MVSWITCH_H
#define __MVSWITCH_H
#define MV_HEADER_SIZE 2
#define MV_HEADER_PORTS_M 0x001f
#define MV_HEADER_PORTS_S 0
#define MV_HEADER_VLAN_M 0xf000
#define MV_HEADER_VLAN_S 12
#define MV_TRAILER_SIZE 4
#define MV_TRAILER_PORTS_M 0x1f
#define MV_TRAILER_PORTS_S 16
#define MV_TRAILER_FLAGS_S 24
#define MV_TRAILER_OVERRIDE 0x80
#define MV_PORTS 5
#define MV_WANPORT 4
#define MV_CPUPORT 5
#define MV_BASE 0x10
#define MV_PHYPORT_BASE (MV_BASE + 0x0)
#define MV_PHYPORT(_n) (MV_PHYPORT_BASE + (_n))
#define MV_SWITCHPORT_BASE (MV_BASE + 0x8)
#define MV_SWITCHPORT(_n) (MV_SWITCHPORT_BASE + (_n))
#define MV_SWITCHREGS (MV_BASE + 0xf)
enum {
MV_PHY_CONTROL = 0x00,
MV_PHY_STATUS = 0x01,
MV_PHY_IDENT0 = 0x02,
MV_PHY_IDENT1 = 0x03,
MV_PHY_ANEG = 0x04,
MV_PHY_LINK_ABILITY = 0x05,
MV_PHY_ANEG_EXPAND = 0x06,
MV_PHY_XMIT_NEXTP = 0x07,
MV_PHY_LINK_NEXTP = 0x08,
MV_PHY_CONTROL1 = 0x10,
MV_PHY_STATUS1 = 0x11,
MV_PHY_INTR_EN = 0x12,
MV_PHY_INTR_STATUS = 0x13,
MV_PHY_INTR_PORT = 0x14,
MV_PHY_RECV_COUNTER = 0x16,
MV_PHY_LED_PARALLEL = 0x16,
MV_PHY_LED_STREAM = 0x17,
MV_PHY_LED_CTRL = 0x18,
MV_PHY_LED_OVERRIDE = 0x19,
MV_PHY_VCT_CTRL = 0x1a,
MV_PHY_VCT_STATUS = 0x1b,
MV_PHY_CONTROL2 = 0x1e
};
#define MV_PHYREG(_type, _port) MV_PHYPORT(_port), MV_PHY_##_type
enum {
MV_PORT_STATUS = 0x00,
MV_PORT_IDENT = 0x03,
MV_PORT_CONTROL = 0x04,
MV_PORT_VLANMAP = 0x06,
MV_PORT_ASSOC = 0x0b,
MV_PORT_RXCOUNT = 0x10,
MV_PORT_TXCOUNT = 0x11,
};
#define MV_PORTREG(_type, _port) MV_SWITCHPORT(_port), MV_PORT_##_type
enum {
MV_PORTCTRL_BLOCK = (1 << 0),
MV_PORTCTRL_LEARN = (2 << 0),
MV_PORTCTRL_ENABLED = (3 << 0),
MV_PORTCTRL_VLANTUN = (1 << 7), /* Enforce VLANs on packets */
MV_PORTCTRL_RXTR = (1 << 8), /* Enable Marvell packet trailer for ingress */
MV_PORTCTRL_HEADER = (1 << 11), /* Enable Marvell packet header mode for port */
MV_PORTCTRL_TXTR = (1 << 14), /* Enable Marvell packet trailer for egress */
MV_PORTCTRL_FORCEFL = (1 << 15), /* force flow control */
};
#define MV_PORTVLAN_ID(_n) (((_n) & 0xf) << 12)
#define MV_PORTVLAN_PORTS(_n) ((_n) & 0x3f)
#define MV_PORTASSOC_PORTS(_n) ((_n) & 0x1f)
#define MV_PORTASSOC_MONITOR (1 << 15)
enum {
MV_SWITCH_MAC0 = 0x01,
MV_SWITCH_MAC1 = 0x02,
MV_SWITCH_MAC2 = 0x03,
MV_SWITCH_CTRL = 0x04,
MV_SWITCH_ATU_CTRL = 0x0a,
MV_SWITCH_ATU_OP = 0x0b,
MV_SWITCH_ATU_DATA = 0x0c,
MV_SWITCH_ATU_MAC0 = 0x0d,
MV_SWITCH_ATU_MAC1 = 0x0e,
MV_SWITCH_ATU_MAC2 = 0x0f,
};
#define MV_SWITCHREG(_type) MV_SWITCHREGS, MV_SWITCH_##_type
enum {
MV_SWITCHCTL_EEIE = (1 << 0), /* EEPROM interrupt enable */
MV_SWITCHCTL_PHYIE = (1 << 1), /* PHY interrupt enable */
MV_SWITCHCTL_ATUDONE= (1 << 2), /* ATU done interrupt enable */
MV_SWITCHCTL_ATUIE = (1 << 3), /* ATU interrupt enable */
MV_SWITCHCTL_CTRMODE= (1 << 8), /* statistics for rx and tx errors */
MV_SWITCHCTL_RELOAD = (1 << 9), /* reload registers from eeprom */
MV_SWITCHCTL_MSIZE = (1 << 10), /* increase maximum frame size */
MV_SWITCHCTL_DROP = (1 << 13), /* discard frames with excessive collisions */
};
enum {
#define MV_ATUCTL_AGETIME_MIN 16
#define MV_ATUCTL_AGETIME_MAX 4080
#define MV_ATUCTL_AGETIME(_n) ((((_n) / 16) & 0xff) << 4)
MV_ATUCTL_ATU_256 = (0 << 12),
MV_ATUCTL_ATU_512 = (1 << 12),
MV_ATUCTL_ATU_1K = (2 << 12),
MV_ATUCTL_ATUMASK = (3 << 12),
MV_ATUCTL_NO_LEARN = (1 << 14),
MV_ATUCTL_RESET = (1 << 15),
};
enum {
#define MV_ATUOP_DBNUM(_n) ((_n) & 0x0f)
MV_ATUOP_NOOP = (0 << 12),
MV_ATUOP_FLUSH_ALL = (1 << 12),
MV_ATUOP_FLUSH_U = (2 << 12),
MV_ATUOP_LOAD_DB = (3 << 12),
MV_ATUOP_GET_NEXT = (4 << 12),
MV_ATUOP_FLUSH_DB = (5 << 12),
MV_ATUOP_FLUSH_DB_UU= (6 << 12),
MV_ATUOP_INPROGRESS = (1 << 15),
};
#define MV_IDENT_MASK 0xfff0
#define MV_IDENT_VALUE 0x0600
#endif

View File

@ -0,0 +1,201 @@
/*
* character device wrapper for generic gpio layer
*
* 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.
*
* 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., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
*
* Feedback, Bugs... blogic@openwrt.org
*
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/gpio.h>
#include <asm/atomic.h>
#include <linux/init.h>
#include <linux/genhd.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/gpio_dev.h>
#define DRVNAME "gpiodev"
#define DEVNAME "gpio"
static int dev_major;
static unsigned int gpio_access_mask;
static struct class *gpiodev_class;
/* Counter is 1, if the device is not opened and zero (or less) if opened. */
static atomic_t gpio_open_cnt = ATOMIC_INIT(1);
static int
gpio_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
{
int retval = 0;
if (((1 << arg) & gpio_access_mask) != (1 << arg))
{
retval = -EINVAL;
goto out;
}
switch (cmd)
{
case GPIO_GET:
retval = gpio_get_value(arg);
break;
case GPIO_SET:
gpio_set_value(arg, 1);
break;
case GPIO_CLEAR:
gpio_set_value(arg, 0);
break;
case GPIO_DIR_IN:
gpio_direction_input(arg);
break;
case GPIO_DIR_OUT:
gpio_direction_output(arg, 0);
break;
default:
retval = -EINVAL;
break;
}
out:
return retval;
}
static int
gpio_open(struct inode *inode, struct file *file)
{
int result = 0;
unsigned int dev_minor = MINOR(inode->i_rdev);
if (dev_minor != 0)
{
printk(KERN_ERR DRVNAME ": trying to access unknown minor device -> %d\n", dev_minor);
result = -ENODEV;
goto out;
}
/* FIXME: We should really allow multiple applications to open the device
* at the same time, as long as the apps access different IO pins.
* The generic gpio-registration functions can be used for that.
* Two new IOCTLs have to be introduced for that. Need to check userspace
* compatibility first. --mb */
if (!atomic_dec_and_test(&gpio_open_cnt)) {
atomic_inc(&gpio_open_cnt);
printk(KERN_ERR DRVNAME ": Device with minor ID %d already in use\n", dev_minor);
result = -EBUSY;
goto out;
}
out:
return result;
}
static int
gpio_close(struct inode * inode, struct file * file)
{
smp_mb__before_atomic_inc();
atomic_inc(&gpio_open_cnt);
return 0;
}
struct file_operations gpio_fops = {
ioctl: gpio_ioctl,
open: gpio_open,
release: gpio_close
};
static int
gpio_probe(struct platform_device *dev)
{
int result = 0;
dev_major = register_chrdev(0, DEVNAME, &gpio_fops);
if (!dev_major)
{
printk(KERN_ERR DRVNAME ": Error whilst opening %s \n", DEVNAME);
result = -ENODEV;
goto out;
}
gpiodev_class = class_create(THIS_MODULE, DRVNAME);
class_device_create(gpiodev_class, NULL, MKDEV(dev_major, 0), NULL, DEVNAME);
printk(KERN_INFO DRVNAME ": gpio device registered with major %d\n", dev_major);
if (dev->num_resources != 1)
{
printk(KERN_ERR DRVNAME ": device may only have 1 resource\n");
result = -ENODEV;
goto out;
}
gpio_access_mask = dev->resource[0].start;
printk(KERN_INFO DRVNAME ": gpio platform device registered with access mask %08X\n", gpio_access_mask);
out:
return result;
}
static int
gpio_remove(struct platform_device *dev)
{
unregister_chrdev(dev_major, DEVNAME);
return 0;
}
static struct
platform_driver gpio_driver = {
.probe = gpio_probe,
.remove = gpio_remove,
.driver = {
.name = "GPIODEV",
.owner = THIS_MODULE,
},
};
static int __init
gpio_mod_init(void)
{
int ret = platform_driver_register(&gpio_driver);
if (ret)
printk(KERN_INFO DRVNAME ": Error registering platfom driver!");
return ret;
}
static void __exit
gpio_mod_exit(void)
{
platform_driver_unregister(&gpio_driver);
}
module_init (gpio_mod_init);
module_exit (gpio_mod_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("John Crispin / OpenWrt");
MODULE_DESCRIPTION("Character device for for generic gpio api");

View File

@ -0,0 +1,209 @@
/*
* Driver for buttons on GPIO lines not capable of generating interrupts
*
* Copyright (C) 2007,2008 Gabor Juhos <juhosg at openwrt.org>
*
* This file was based on: /drivers/input/misc/cobalt_btns.c
* Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
*
* also was based on: /drivers/input/keyboard/gpio_keys.c
* Copyright 2005 Phil Blundell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/input-polldev.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/gpio_buttons.h>
#include <asm/gpio.h>
#define DRV_NAME "gpio-buttons"
#define DRV_VERSION "0.1.1"
#define PFX DRV_NAME ": "
struct gpio_buttons_dev {
struct input_polled_dev *poll_dev;
struct gpio_buttons_platform_data *pdata;
};
static void gpio_buttons_poll(struct input_polled_dev *dev)
{
struct gpio_buttons_dev *bdev = dev->private;
struct gpio_buttons_platform_data *pdata = bdev->pdata;
struct input_dev *input = dev->input;
int i;
for (i = 0; i < bdev->pdata->nbuttons; i++) {
struct gpio_button *button = &pdata->buttons[i];
unsigned int type = button->type ?: EV_KEY;
int state;
state = gpio_get_value(button->gpio) ? 1 : 0;
state ^= button->active_low;
if (state) {
button->count++;
} else {
if (button->count >= button->threshold) {
input_event(input, type, button->code, 1);
input_sync(input);
}
button->count = 0;
}
if (button->count == button->threshold) {
input_event(input, type, button->code, 0);
input_sync(input);
}
}
}
static int __devinit gpio_buttons_probe(struct platform_device *pdev)
{
struct gpio_buttons_platform_data *pdata = pdev->dev.platform_data;
struct gpio_buttons_dev *bdev;
struct input_polled_dev *poll_dev;
struct input_dev *input;
int error, i;
if (!pdata)
return -ENXIO;
bdev = kzalloc(sizeof(*bdev), GFP_KERNEL);
if (!bdev) {
printk(KERN_ERR DRV_NAME "no memory for device\n");
return -ENOMEM;
}
poll_dev = input_allocate_polled_device();
if (!poll_dev) {
printk(KERN_ERR DRV_NAME "no memory for polled device\n");
error = -ENOMEM;
goto err_free_bdev;
}
poll_dev->private = bdev;
poll_dev->poll = gpio_buttons_poll;
poll_dev->poll_interval = pdata->poll_interval;
input = poll_dev->input;
input->evbit[0] = BIT(EV_KEY);
input->name = pdev->name;
input->phys = "gpio-buttons/input0";
input->dev.parent = &pdev->dev;
input->id.bustype = BUS_HOST;
input->id.vendor = 0x0001;
input->id.product = 0x0001;
input->id.version = 0x0100;
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_button *button = &pdata->buttons[i];
unsigned int gpio = button->gpio;
unsigned int type = button->type ?: EV_KEY;
error = gpio_request(gpio, button->desc ?
button->desc : DRV_NAME);
if (error) {
printk(KERN_ERR PFX "unable to claim gpio %u, "
"error %d\n", gpio, error);
goto err_free_gpio;
}
error = gpio_direction_input(gpio);
if (error) {
printk(KERN_ERR PFX "unable to set direction on "
"gpio %u, error %d\n", gpio, error);
goto err_free_gpio;
}
input_set_capability(input, type, button->code);
button->count = 0;
}
bdev->poll_dev = poll_dev;
bdev->pdata = pdata;
platform_set_drvdata(pdev, bdev);
error = input_register_polled_device(poll_dev);
if (error) {
printk(KERN_ERR PFX "unable to register polled device, "
"error %d\n", error);
goto err_free_gpio;
}
return 0;
err_free_gpio:
for (i = i - 1; i >= 0; i--)
gpio_free(pdata->buttons[i].gpio);
input_free_polled_device(poll_dev);
err_free_bdev:
kfree(bdev);
platform_set_drvdata(pdev, NULL);
return error;
}
static int __devexit gpio_buttons_remove(struct platform_device *pdev)
{
struct gpio_buttons_dev *bdev = platform_get_drvdata(pdev);
struct gpio_buttons_platform_data *pdata = bdev->pdata;
int i;
input_unregister_polled_device(bdev->poll_dev);
for (i = 0; i < pdata->nbuttons; i++)
gpio_free(pdata->buttons[i].gpio);
input_free_polled_device(bdev->poll_dev);
kfree(bdev);
platform_set_drvdata(pdev, NULL);
return 0;
}
static struct platform_driver gpio_buttons_driver = {
.probe = gpio_buttons_probe,
.remove = __devexit_p(gpio_buttons_remove),
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
};
static int __init gpio_buttons_init(void)
{
printk(KERN_INFO DRV_NAME " driver version " DRV_VERSION "\n");
return platform_driver_register(&gpio_buttons_driver);
}
static void __exit gpio_buttons_exit(void)
{
platform_driver_unregister(&gpio_buttons_driver);
}
module_init(gpio_buttons_init);
module_exit(gpio_buttons_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
MODULE_VERSION(DRV_VERSION);
MODULE_DESCRIPTION("Polled buttons driver for CPU GPIOs");

View File

@ -0,0 +1,172 @@
/*
* LEDs driver for PCEngines ALIX 2/3 series
*
* Copyright (C) 2007 Petr Liebman
*
* Based on leds-wrap.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/leds.h>
#include <linux/err.h>
#include <asm/io.h>
#define DRVNAME "alix-led"
#define ALIX_LED1_PORT (0x6100)
#define ALIX_LED1_ON (1<<22)
#define ALIX_LED1_OFF (1<<6)
#define ALIX_LED2_PORT (0x6180)
#define ALIX_LED2_ON (1<<25)
#define ALIX_LED2_OFF (1<<9)
#define ALIX_LED3_PORT (0x6180)
#define ALIX_LED3_ON (1<<27)
#define ALIX_LED3_OFF (1<<11)
static struct platform_device *pdev;
static void alix_led_set_1(struct led_classdev *led_cdev,
enum led_brightness value)
{
if (value)
outl(ALIX_LED1_ON, ALIX_LED1_PORT);
else
outl(ALIX_LED1_OFF, ALIX_LED1_PORT);
}
static void alix_led_set_2(struct led_classdev *led_cdev,
enum led_brightness value)
{
if (value)
outl(ALIX_LED2_ON, ALIX_LED2_PORT);
else
outl(ALIX_LED2_OFF, ALIX_LED2_PORT);
}
static void alix_led_set_3(struct led_classdev *led_cdev,
enum led_brightness value)
{
if (value)
outl(ALIX_LED3_ON, ALIX_LED3_PORT);
else
outl(ALIX_LED3_OFF, ALIX_LED3_PORT);
}
static struct led_classdev alix_led_1 = {
.name = "alix:1",
.brightness_set = alix_led_set_1,
};
static struct led_classdev alix_led_2 = {
.name = "alix:2",
.brightness_set = alix_led_set_2,
};
static struct led_classdev alix_led_3 = {
.name = "alix:3",
.brightness_set = alix_led_set_3,
};
#ifdef CONFIG_PM
static int alix_led_suspend(struct platform_device *dev,
pm_message_t state)
{
led_classdev_suspend(&alix_led_1);
led_classdev_suspend(&alix_led_2);
led_classdev_suspend(&alix_led_3);
return 0;
}
static int alix_led_resume(struct platform_device *dev)
{
led_classdev_resume(&alix_led_1);
led_classdev_resume(&alix_led_2);
led_classdev_resume(&alix_led_3);
return 0;
}
#else
#define alix_led_suspend NULL
#define alix_led_resume NULL
#endif
static int alix_led_probe(struct platform_device *pdev)
{
int ret;
ret = led_classdev_register(&pdev->dev, &alix_led_1);
if (ret >= 0)
{
ret = led_classdev_register(&pdev->dev, &alix_led_2);
if (ret >= 0)
{
ret = led_classdev_register(&pdev->dev, &alix_led_3);
if (ret < 0)
led_classdev_unregister(&alix_led_2);
}
if (ret < 0)
led_classdev_unregister(&alix_led_1);
}
return ret;
}
static int alix_led_remove(struct platform_device *pdev)
{
led_classdev_unregister(&alix_led_1);
led_classdev_unregister(&alix_led_2);
led_classdev_unregister(&alix_led_3);
return 0;
}
static struct platform_driver alix_led_driver = {
.probe = alix_led_probe,
.remove = alix_led_remove,
.suspend = alix_led_suspend,
.resume = alix_led_resume,
.driver = {
.name = DRVNAME,
.owner = THIS_MODULE,
},
};
static int __init alix_led_init(void)
{
int ret;
ret = platform_driver_register(&alix_led_driver);
if (ret < 0)
goto out;
pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0);
if (IS_ERR(pdev)) {
ret = PTR_ERR(pdev);
platform_driver_unregister(&alix_led_driver);
goto out;
}
out:
return ret;
}
static void __exit alix_led_exit(void)
{
platform_device_unregister(pdev);
platform_driver_unregister(&alix_led_driver);
}
module_init(alix_led_init);
module_exit(alix_led_exit);
MODULE_AUTHOR("Petr Liebman");
MODULE_DESCRIPTION("PCEngines ALIX LED driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,45 @@
/*
* LED Kernel Default ON Trigger
*
* Copyright 2008 Nick Forbes <nick.forbes@incepta.com>
*
* Based on Richard Purdie's ledtrig-timer.c.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/leds.h>
#include "leds.h"
static void defon_trig_activate(struct led_classdev *led_cdev)
{
led_set_brightness(led_cdev, LED_FULL);
}
static struct led_trigger defon_led_trigger = {
.name = "default-on",
.activate = defon_trig_activate,
};
static int __init defon_trig_init(void)
{
return led_trigger_register(&defon_led_trigger);
}
static void __exit defon_trig_exit(void)
{
led_trigger_unregister(&defon_led_trigger);
}
module_init(defon_trig_init);
module_exit(defon_trig_exit);
MODULE_AUTHOR("Nick Forbes <nick.forbes@incepta.com>");
MODULE_DESCRIPTION("Default-ON LED trigger");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,365 @@
/*
* LED Morse Trigger
*
* Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
*
* This file was based on: drivers/led/ledtrig-timer.c
* Copyright 2005-2006 Openedhand Ltd.
* Author: Richard Purdie <rpurdie@openedhand.com>
*
* also based on the patch '[PATCH] 2.5.59 morse code panics' posted
* in the LKML by Tomas Szepe at Thu, 30 Jan 2003
* Copyright (C) 2002 Andrew Rodland <arodland@noln.com>
* Copyright (C) 2003 Tomas Szepe <szepe@pinerecords.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
*/
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/device.h>
#include <linux/sysdev.h>
#include <linux/timer.h>
#include <linux/ctype.h>
#include <linux/leds.h>
#include "leds.h"
#define MORSE_DELAY_BASE (HZ/2)
#define MORSE_STATE_BLINK_START 0
#define MORSE_STATE_BLINK_STOP 1
#define MORSE_DIT_LEN 1
#define MORSE_DAH_LEN 3
#define MORSE_SPACE_LEN 7
struct morse_trig_data {
unsigned long delay;
char *msg;
unsigned char morse;
unsigned char state;
char *msgpos;
struct timer_list timer;
};
const unsigned char morsetable[] = {
0122, 0, 0310, 0, 0, 0163, /* "#$%&' */
055, 0155, 0, 0, 0163, 0141, 0152, 0051, /* ()*+,-./ */
077, 076, 074, 070, 060, 040, 041, 043, 047, 057, /* 0-9 */
0107, 0125, 0, 0061, 0, 0114, 0, /* :;<=>?@ */
006, 021, 025, 011, 002, 024, 013, 020, 004, /* A-I */
036, 015, 022, 007, 005, 017, 026, 033, 012, /* J-R */
010, 003, 014, 030, 016, 031, 035, 023, /* S-Z */
0, 0, 0, 0, 0154 /* [\]^_ */
};
static inline unsigned char tomorse(char c) {
if (c >= 'a' && c <= 'z')
c = c - 'a' + 'A';
if (c >= '"' && c <= '_') {
return morsetable[c - '"'];
} else
return 0;
}
static inline unsigned long dit_len(struct morse_trig_data *morse_data)
{
return MORSE_DIT_LEN*morse_data->delay;
}
static inline unsigned long dah_len(struct morse_trig_data *morse_data)
{
return MORSE_DAH_LEN*morse_data->delay;
}
static inline unsigned long space_len(struct morse_trig_data *morse_data)
{
return MORSE_SPACE_LEN*morse_data->delay;
}
static void morse_timer_function(unsigned long data)
{
struct led_classdev *led_cdev = (struct led_classdev *)data;
struct morse_trig_data *morse_data = led_cdev->trigger_data;
unsigned long brightness = LED_OFF;
unsigned long delay = 0;
if (!morse_data->msg)
goto set_led;
switch (morse_data->state) {
case MORSE_STATE_BLINK_START:
/* Starting a new blink. We have a valid code in morse. */
delay = (morse_data->morse & 001) ? dah_len(morse_data):
dit_len(morse_data);
brightness = LED_FULL;
morse_data->state = MORSE_STATE_BLINK_STOP;
morse_data->morse >>= 1;
break;
case MORSE_STATE_BLINK_STOP:
/* Coming off of a blink. */
morse_data->state = MORSE_STATE_BLINK_START;
if (morse_data->morse > 1) {
/* Not done yet, just a one-dit pause. */
delay = dit_len(morse_data);
break;
}
/* Get a new char, figure out how much space. */
/* First time through */
if (!morse_data->msgpos)
morse_data->msgpos = (char *)morse_data->msg;
if (!*morse_data->msgpos) {
/* Repeating */
morse_data->msgpos = (char *)morse_data->msg;
delay = space_len(morse_data);
} else {
/* Inter-letter space */
delay = dah_len(morse_data);
}
if (!(morse_data->morse = tomorse(*morse_data->msgpos))) {
delay = space_len(morse_data);
/* And get us back here */
morse_data->state = MORSE_STATE_BLINK_STOP;
}
morse_data->msgpos++;
break;
}
mod_timer(&morse_data->timer, jiffies + msecs_to_jiffies(delay));
set_led:
led_set_brightness(led_cdev, brightness);
}
static ssize_t _morse_delay_show(struct led_classdev *led_cdev, char *buf)
{
struct morse_trig_data *morse_data = led_cdev->trigger_data;
sprintf(buf, "%lu\n", morse_data->delay);
return strlen(buf) + 1;
}
static ssize_t _morse_delay_store(struct led_classdev *led_cdev,
const char *buf, size_t size)
{
struct morse_trig_data *morse_data = led_cdev->trigger_data;
char *after;
unsigned long state = simple_strtoul(buf, &after, 10);
size_t count = after - buf;
int ret = -EINVAL;
if (*after && isspace(*after))
count++;
if (count == size) {
morse_data->delay = state;
mod_timer(&morse_data->timer, jiffies + 1);
ret = count;
}
return ret;
}
static ssize_t _morse_msg_show(struct led_classdev *led_cdev, char *buf)
{
struct morse_trig_data *morse_data = led_cdev->trigger_data;
if (!morse_data->msg)
sprintf(buf, "<none>\n");
else
sprintf(buf, "%s\n", morse_data->msg);
return strlen(buf) + 1;
}
static ssize_t _morse_msg_store(struct led_classdev *led_cdev,
const char *buf, size_t size)
{
struct morse_trig_data *morse_data = led_cdev->trigger_data;
char *m;
m = kmalloc(size, GFP_KERNEL);
if (!m)
return -ENOMEM;
memcpy(m,buf,size);
m[size]='\0';
if (morse_data->msg)
kfree(morse_data->msg);
morse_data->msg = m;
morse_data->msgpos = NULL;
morse_data->state = MORSE_STATE_BLINK_STOP;
mod_timer(&morse_data->timer, jiffies + 1);
return size;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
static ssize_t morse_delay_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
return _morse_delay_show(led_cdev, buf);
}
static ssize_t morse_delay_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
return _morse_delay_store(led_cdev, buf, size);
}
static ssize_t morse_msg_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
return _morse_msg_show(led_cdev, buf);
}
static ssize_t morse_msg_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
return _morse_msg_store(led_cdev, buf, size);
}
static DEVICE_ATTR(delay, 0644, morse_delay_show, morse_delay_store);
static DEVICE_ATTR(message, 0644, morse_msg_show, morse_msg_store);
#define led_device_create_file(leddev, attr) \
device_create_file(leddev->dev, &dev_attr_ ## attr)
#define led_device_remove_file(leddev, attr) \
device_remove_file(leddev->dev, &dev_attr_ ## attr)
#else
static ssize_t morse_delay_show(struct class_device *dev, char *buf)
{
struct led_classdev *led_cdev = class_get_devdata(dev);
return _morse_delay_show(led_cdev, buf);
}
static ssize_t morse_delay_store(struct class_device *dev, const char *buf,
size_t size)
{
struct led_classdev *led_cdev = class_get_devdata(dev);
return _morse_delay_store(led_cdev, buf, size);
}
static ssize_t morse_msg_show(struct class_device *dev, char *buf)
{
struct led_classdev *led_cdev = class_get_devdata(dev);
return _morse_msg_show(led_cdev, buf);
}
static ssize_t morse_msg_store(struct class_device *dev, const char *buf,
size_t size)
{
struct led_classdev *led_cdev = class_get_devdata(dev);
return _morse_msg_store(led_cdev, buf, size);
}
static CLASS_DEVICE_ATTR(delay, 0644, morse_delay_show, morse_delay_store);
static CLASS_DEVICE_ATTR(message, 0644, morse_msg_show, morse_msg_store);
#define led_device_create_file(leddev, attr) \
class_device_create_file(leddev->class_dev, &class_device_attr_ ## attr)
#define led_device_remove_file(leddev, attr) \
class_device_remove_file(leddev->class_dev, &class_device_attr_ ## attr)
#endif
static void morse_trig_activate(struct led_classdev *led_cdev)
{
struct morse_trig_data *morse_data;
int rc;
morse_data = kzalloc(sizeof(*morse_data), GFP_KERNEL);
if (!morse_data)
return;
morse_data->delay = MORSE_DELAY_BASE;
init_timer(&morse_data->timer);
morse_data->timer.function = morse_timer_function;
morse_data->timer.data = (unsigned long)led_cdev;
rc = led_device_create_file(led_cdev, delay);
if (rc) goto err;
rc = led_device_create_file(led_cdev, message);
if (rc) goto err_delay;
led_cdev->trigger_data = morse_data;
return;
err_delay:
led_device_remove_file(led_cdev, delay);
err:
kfree(morse_data);
}
static void morse_trig_deactivate(struct led_classdev *led_cdev)
{
struct morse_trig_data *morse_data = led_cdev->trigger_data;
if (!morse_data)
return;
led_device_remove_file(led_cdev, message);
led_device_remove_file(led_cdev, delay);
del_timer_sync(&morse_data->timer);
if (morse_data->msg)
kfree(morse_data->msg);
kfree(morse_data);
}
static struct led_trigger morse_led_trigger = {
.name = "morse",
.activate = morse_trig_activate,
.deactivate = morse_trig_deactivate,
};
static int __init morse_trig_init(void)
{
return led_trigger_register(&morse_led_trigger);
}
static void __exit morse_trig_exit(void)
{
led_trigger_unregister(&morse_led_trigger);
}
module_init(morse_trig_init);
module_exit(morse_trig_exit);
MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
MODULE_DESCRIPTION("Morse LED trigger");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,451 @@
/*
* LED Kernel Netdev Trigger
*
* Toggles the LED to reflect the link and traffic state of a named net device
*
* Copyright 2007 Oliver Jowett <oliver@opencloud.com>
*
* Derived from ledtrig-timer.c which is:
* Copyright 2005-2006 Openedhand Ltd.
* Author: Richard Purdie <rpurdie@openedhand.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/device.h>
#include <linux/sysdev.h>
#include <linux/netdevice.h>
#include <linux/timer.h>
#include <linux/ctype.h>
#include <linux/leds.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
#include <net/net_namespace.h>
#endif
#include "leds.h"
/*
* Configurable sysfs attributes:
*
* device_name - network device name to monitor
*
* interval - duration of LED blink, in milliseconds
*
* mode - either "none" (LED is off) or a space separated list of one or more of:
* link: LED's normal state reflects whether the link is up (has carrier) or not
* tx: LED blinks on transmitted data
* rx: LED blinks on receive data
*
* Some suggestions:
*
* Simple link status LED:
* $ echo netdev >someled/trigger
* $ echo eth0 >someled/device_name
* $ echo link >someled/mode
*
* Ethernet-style link/activity LED:
* $ echo netdev >someled/trigger
* $ echo eth0 >someled/device_name
* $ echo "link tx rx" >someled/mode
*
* Modem-style tx/rx LEDs:
* $ echo netdev >led1/trigger
* $ echo ppp0 >led1/device_name
* $ echo tx >led1/mode
* $ echo netdev >led2/trigger
* $ echo ppp0 >led2/device_name
* $ echo rx >led2/mode
*
*/
#define MODE_LINK 1
#define MODE_TX 2
#define MODE_RX 4
struct led_netdev_data {
rwlock_t lock;
struct timer_list timer;
struct notifier_block notifier;
struct led_classdev *led_cdev;
struct net_device *net_dev;
char device_name[IFNAMSIZ];
unsigned interval;
unsigned mode;
unsigned link_up;
unsigned last_activity;
};
static void set_baseline_state(struct led_netdev_data *trigger_data)
{
if ((trigger_data->mode & MODE_LINK) != 0 && trigger_data->link_up)
led_set_brightness(trigger_data->led_cdev, LED_FULL);
else
led_set_brightness(trigger_data->led_cdev, LED_OFF);
if ((trigger_data->mode & (MODE_TX | MODE_RX)) != 0 && trigger_data->link_up)
mod_timer(&trigger_data->timer, jiffies + trigger_data->interval);
else
del_timer(&trigger_data->timer);
}
static ssize_t led_device_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
read_lock(&trigger_data->lock);
sprintf(buf, "%s\n", trigger_data->device_name);
read_unlock(&trigger_data->lock);
return strlen(buf) + 1;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
extern struct net init_net;
#endif
static ssize_t led_device_name_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
if (size < 0 || size >= IFNAMSIZ)
return -EINVAL;
write_lock(&trigger_data->lock);
strcpy(trigger_data->device_name, buf);
if (size > 0 && trigger_data->device_name[size-1] == '\n')
trigger_data->device_name[size-1] = 0;
if (trigger_data->device_name[0] != 0) {
/* check for existing device to update from */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
trigger_data->net_dev = dev_get_by_name(&init_net, trigger_data->device_name);
#else
trigger_data->net_dev = dev_get_by_name(trigger_data->device_name);
#endif
if (trigger_data->net_dev != NULL)
trigger_data->link_up = (dev_get_flags(trigger_data->net_dev) & IFF_LOWER_UP) != 0;
set_baseline_state(trigger_data); /* updates LEDs, may start timers */
}
write_unlock(&trigger_data->lock);
return size;
}
static DEVICE_ATTR(device_name, 0644, led_device_name_show, led_device_name_store);
static ssize_t led_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
read_lock(&trigger_data->lock);
if (trigger_data->mode == 0) {
strcpy(buf, "none\n");
} else {
if (trigger_data->mode & MODE_LINK)
strcat(buf, "link ");
if (trigger_data->mode & MODE_TX)
strcat(buf, "tx ");
if (trigger_data->mode & MODE_RX)
strcat(buf, "rx ");
strcat(buf, "\n");
}
read_unlock(&trigger_data->lock);
return strlen(buf)+1;
}
static ssize_t led_mode_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
char copybuf[1024];
int new_mode = -1;
char *p, *token;
/* take a copy since we don't want to trash the inbound buffer when using strsep */
strncpy(copybuf, buf, sizeof(copybuf));
copybuf[1023] = 0;
p = copybuf;
while ((token = strsep(&p, " \t\n")) != NULL) {
if (!*token)
continue;
if (new_mode == -1)
new_mode = 0;
if (!strcmp(token, "none"))
new_mode = 0;
else if (!strcmp(token, "tx"))
new_mode |= MODE_TX;
else if (!strcmp(token, "rx"))
new_mode |= MODE_RX;
else if (!strcmp(token, "link"))
new_mode |= MODE_LINK;
else
return -EINVAL;
}
if (new_mode == -1)
return -EINVAL;
write_lock(&trigger_data->lock);
trigger_data->mode = new_mode;
set_baseline_state(trigger_data);
write_unlock(&trigger_data->lock);
return size;
}
static DEVICE_ATTR(mode, 0644, led_mode_show, led_mode_store);
static ssize_t led_interval_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
read_lock(&trigger_data->lock);
sprintf(buf, "%u\n", jiffies_to_msecs(trigger_data->interval));
read_unlock(&trigger_data->lock);
return strlen(buf) + 1;
}
static ssize_t led_interval_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
int ret = -EINVAL;
char *after;
unsigned long value = simple_strtoul(buf, &after, 10);
size_t count = after - buf;
if (*after && isspace(*after))
count++;
/* impose some basic bounds on the timer interval */
if (count == size && value >= 5 && value <= 10000) {
write_lock(&trigger_data->lock);
trigger_data->interval = msecs_to_jiffies(value);
set_baseline_state(trigger_data); // resets timer
write_unlock(&trigger_data->lock);
ret = count;
}
return ret;
}
static DEVICE_ATTR(interval, 0644, led_interval_show, led_interval_store);
static int netdev_trig_notify(struct notifier_block *nb,
unsigned long evt,
void *dv)
{
struct net_device *dev = dv;
struct led_netdev_data *trigger_data = container_of(nb, struct led_netdev_data, notifier);
if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER)
return NOTIFY_DONE;
write_lock(&trigger_data->lock);
if (strcmp(dev->name, trigger_data->device_name))
goto done;
if (evt == NETDEV_REGISTER) {
if (trigger_data->net_dev != NULL)
dev_put(trigger_data->net_dev);
dev_hold(dev);
trigger_data->net_dev = dev;
trigger_data->link_up = 0;
goto done;
}
if (evt == NETDEV_UNREGISTER && trigger_data->net_dev != NULL) {
dev_put(trigger_data->net_dev);
trigger_data->net_dev = NULL;
goto done;
}
/* UP / DOWN / CHANGE */
trigger_data->link_up = (evt != NETDEV_DOWN && netif_carrier_ok(dev));
set_baseline_state(trigger_data);
done:
write_unlock(&trigger_data->lock);
return NOTIFY_DONE;
}
/* here's the real work! */
static void netdev_trig_timer(unsigned long arg)
{
struct led_netdev_data *trigger_data = (struct led_netdev_data *)arg;
struct net_device_stats *dev_stats;
unsigned new_activity;
write_lock(&trigger_data->lock);
if (!trigger_data->link_up || !trigger_data->net_dev || (trigger_data->mode & (MODE_TX | MODE_RX)) == 0) {
/* we don't need to do timer work, just reflect link state. */
led_set_brightness(trigger_data->led_cdev, ((trigger_data->mode & MODE_LINK) != 0 && trigger_data->link_up) ? LED_FULL : LED_OFF);
goto no_restart;
}
dev_stats = trigger_data->net_dev->get_stats(trigger_data->net_dev);
new_activity =
((trigger_data->mode & MODE_TX) ? dev_stats->tx_packets : 0) +
((trigger_data->mode & MODE_RX) ? dev_stats->rx_packets : 0);
if (trigger_data->mode & MODE_LINK) {
/* base state is ON (link present) */
/* if there's no link, we don't get this far and the LED is off */
/* OFF -> ON always */
/* ON -> OFF on activity */
if (trigger_data->led_cdev->brightness == LED_OFF) {
led_set_brightness(trigger_data->led_cdev, LED_FULL);
} else if (trigger_data->last_activity != new_activity) {
led_set_brightness(trigger_data->led_cdev, LED_OFF);
}
} else {
/* base state is OFF */
/* ON -> OFF always */
/* OFF -> ON on activity */
if (trigger_data->led_cdev->brightness == LED_FULL) {
led_set_brightness(trigger_data->led_cdev, LED_OFF);
} else if (trigger_data->last_activity != new_activity) {
led_set_brightness(trigger_data->led_cdev, LED_FULL);
}
}
trigger_data->last_activity = new_activity;
mod_timer(&trigger_data->timer, jiffies + trigger_data->interval);
no_restart:
write_unlock(&trigger_data->lock);
}
static void netdev_trig_activate(struct led_classdev *led_cdev)
{
struct led_netdev_data *trigger_data;
int rc;
trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL);
if (!trigger_data)
return;
rwlock_init(&trigger_data->lock);
trigger_data->notifier.notifier_call = netdev_trig_notify;
trigger_data->notifier.priority = 10;
setup_timer(&trigger_data->timer, netdev_trig_timer, (unsigned long) trigger_data);
trigger_data->led_cdev = led_cdev;
trigger_data->net_dev = NULL;
trigger_data->device_name[0] = 0;
trigger_data->mode = 0;
trigger_data->interval = msecs_to_jiffies(50);
trigger_data->link_up = 0;
trigger_data->last_activity = 0;
led_cdev->trigger_data = trigger_data;
rc = device_create_file(led_cdev->dev, &dev_attr_device_name);
if (rc)
goto err_out;
rc = device_create_file(led_cdev->dev, &dev_attr_mode);
if (rc)
goto err_out_device_name;
rc = device_create_file(led_cdev->dev, &dev_attr_interval);
if (rc)
goto err_out_mode;
register_netdevice_notifier(&trigger_data->notifier);
return;
err_out_mode:
device_remove_file(led_cdev->dev, &dev_attr_mode);
err_out_device_name:
device_remove_file(led_cdev->dev, &dev_attr_device_name);
err_out:
led_cdev->trigger_data = NULL;
kfree(trigger_data);
}
static void netdev_trig_deactivate(struct led_classdev *led_cdev)
{
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
if (trigger_data) {
unregister_netdevice_notifier(&trigger_data->notifier);
device_remove_file(led_cdev->dev, &dev_attr_device_name);
device_remove_file(led_cdev->dev, &dev_attr_mode);
device_remove_file(led_cdev->dev, &dev_attr_interval);
write_lock(&trigger_data->lock);
if (trigger_data->net_dev) {
dev_put(trigger_data->net_dev);
trigger_data->net_dev = NULL;
}
write_unlock(&trigger_data->lock);
del_timer_sync(&trigger_data->timer);
kfree(trigger_data);
}
}
static struct led_trigger netdev_led_trigger = {
.name = "netdev",
.activate = netdev_trig_activate,
.deactivate = netdev_trig_deactivate,
};
static int __init netdev_trig_init(void)
{
return led_trigger_register(&netdev_led_trigger);
}
static void __exit netdev_trig_exit(void)
{
led_trigger_unregister(&netdev_led_trigger);
}
module_init(netdev_trig_init);
module_exit(netdev_trig_exit);
MODULE_AUTHOR("Oliver Jowett <oliver@opencloud.com>");
MODULE_DESCRIPTION("Netdev LED trigger");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,242 @@
/*
* Bitbanging SPI bus driver using GPIO API
*
* Copyright (c) 2008 Piotr Skamruk
* Copyright (c) 2008 Michael Buesch
*
* based on spi_s3c2410_gpio.c
* Copyright (c) 2006 Ben Dooks
* Copyright (c) 2006 Simtec Electronics
* and on i2c-gpio.c
* Copyright (C) 2007 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include "linux/spi/spi_gpio.h" //XXX
#include <asm/gpio.h>
struct spi_gpio {
struct spi_bitbang bitbang;
struct spi_gpio_platform_data *info;
struct platform_device *pdev;
struct spi_board_info bi;
};
static inline struct spi_gpio *spidev_to_sg(struct spi_device *dev)
{
return dev->controller_data;
}
static inline void setsck(struct spi_device *dev, int val)
{
struct spi_gpio *sp = spidev_to_sg(dev);
gpio_set_value(sp->info->pin_clk, val ? 1 : 0);
}
static inline void setmosi(struct spi_device *dev, int val )
{
struct spi_gpio *sp = spidev_to_sg(dev);
gpio_set_value(sp->info->pin_mosi, val ? 1 : 0);
}
static inline u32 getmiso(struct spi_device *dev)
{
struct spi_gpio *sp = spidev_to_sg(dev);
return gpio_get_value(sp->info->pin_miso) ? 1 : 0;
}
static inline void do_spidelay(struct spi_device *dev, unsigned nsecs)
{
struct spi_gpio *sp = spidev_to_sg(dev);
if (!sp->info->no_spi_delay)
ndelay(nsecs);
}
#define spidelay(nsecs) do { \
/* Steal the spi_device pointer from our caller. \
* The bitbang-API should probably get fixed here... */ \
do_spidelay(spi, nsecs); \
} while (0)
#define EXPAND_BITBANG_TXRX
#include <linux/spi/spi_bitbang.h>
static u32 spi_gpio_txrx_mode0(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits)
{
return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
}
static u32 spi_gpio_txrx_mode1(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits)
{
return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
}
static u32 spi_gpio_txrx_mode2(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits)
{
return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
}
static u32 spi_gpio_txrx_mode3(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits)
{
return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
}
static void spi_gpio_chipselect(struct spi_device *dev, int on)
{
struct spi_gpio *sp = spidev_to_sg(dev);
if (sp->info->cs_activelow)
on = !on;
gpio_set_value(sp->info->pin_cs, on ? 1 : 0);
}
static int spi_gpio_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct spi_gpio_platform_data *pdata;
struct spi_gpio *sp;
struct spi_device *spidev;
int err;
pdata = pdev->dev.platform_data;
if (!pdata)
return -ENXIO;
err = -ENOMEM;
master = spi_alloc_master(&pdev->dev, sizeof(struct spi_gpio));
if (!master)
goto err_alloc_master;
sp = spi_master_get_devdata(master);
platform_set_drvdata(pdev, sp);
sp->info = pdata;
err = gpio_request(pdata->pin_clk, "spi_clock");
if (err)
goto err_request_clk;
err = gpio_request(pdata->pin_mosi, "spi_mosi");
if (err)
goto err_request_mosi;
err = gpio_request(pdata->pin_miso, "spi_miso");
if (err)
goto err_request_miso;
err = gpio_request(pdata->pin_cs, "spi_cs");
if (err)
goto err_request_cs;
sp->bitbang.master = spi_master_get(master);
sp->bitbang.master->bus_num = -1;
sp->bitbang.master->num_chipselect = 1;
sp->bitbang.chipselect = spi_gpio_chipselect;
sp->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_mode0;
sp->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_mode1;
sp->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_mode2;
sp->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_mode3;
gpio_direction_output(pdata->pin_clk, 0);
gpio_direction_output(pdata->pin_mosi, 0);
gpio_direction_output(pdata->pin_cs,
pdata->cs_activelow ? 1 : 0);
gpio_direction_input(pdata->pin_miso);
err = spi_bitbang_start(&sp->bitbang);
if (err)
goto err_no_bitbang;
err = pdata->boardinfo_setup(&sp->bi, master,
pdata->boardinfo_setup_data);
if (err)
goto err_bi_setup;
sp->bi.controller_data = sp;
spidev = spi_new_device(master, &sp->bi);
if (!spidev)
goto err_new_dev;
return 0;
err_new_dev:
err_bi_setup:
spi_bitbang_stop(&sp->bitbang);
err_no_bitbang:
spi_master_put(sp->bitbang.master);
gpio_free(pdata->pin_cs);
err_request_cs:
gpio_free(pdata->pin_miso);
err_request_miso:
gpio_free(pdata->pin_mosi);
err_request_mosi:
gpio_free(pdata->pin_clk);
err_request_clk:
kfree(master);
err_alloc_master:
return err;
}
static int __devexit spi_gpio_remove(struct platform_device *pdev)
{
struct spi_gpio *sp;
struct spi_gpio_platform_data *pdata;
pdata = pdev->dev.platform_data;
sp = platform_get_drvdata(pdev);
gpio_free(pdata->pin_clk);
gpio_free(pdata->pin_mosi);
gpio_free(pdata->pin_miso);
gpio_free(pdata->pin_cs);
spi_bitbang_stop(&sp->bitbang);
spi_master_put(sp->bitbang.master);
return 0;
}
static struct platform_driver spi_gpio_driver = {
.driver = {
.name = "spi-gpio",
.owner = THIS_MODULE,
},
.probe = spi_gpio_probe,
.remove = __devexit_p(spi_gpio_remove),
};
static int __init spi_gpio_init(void)
{
int err;
err = platform_driver_register(&spi_gpio_driver);
if (err)
printk(KERN_ERR "spi-gpio: register failed: %d\n", err);
return err;
}
module_init(spi_gpio_init);
static void __exit spi_gpio_exit(void)
{
platform_driver_unregister(&spi_gpio_driver);
}
module_exit(spi_gpio_exit);
MODULE_AUTHOR("Piot Skamruk <piotr.skamruk at gmail.com>");
MODULE_AUTHOR("Michael Buesch");
MODULE_DESCRIPTION("Platform independent GPIO bitbangling SPI driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,117 @@
menu "Sonics Silicon Backplane"
config SSB_POSSIBLE
bool
depends on HAS_IOMEM
default y
config SSB
tristate "Sonics Silicon Backplane support"
depends on SSB_POSSIBLE
help
Support for the Sonics Silicon Backplane bus.
You only need to enable this option, if you are
configuring a kernel for an embedded system with
this bus.
It will be auto-selected if needed in other
environments.
The module will be called ssb.
If unsure, say N.
config SSB_PCIHOST_POSSIBLE
bool
depends on SSB && (PCI = y || PCI = SSB)
default y
config SSB_PCIHOST
bool "Support for SSB on PCI-bus host"
depends on SSB_PCIHOST_POSSIBLE
default y
help
Support for a Sonics Silicon Backplane on top
of a PCI device.
If unsure, say Y
config SSB_PCMCIAHOST_POSSIBLE
bool
depends on SSB && (PCMCIA = y || PCMCIA = SSB) && EXPERIMENTAL
default y
config SSB_PCMCIAHOST
bool "Support for SSB on PCMCIA-bus host (EXPERIMENTAL)"
depends on SSB_PCMCIAHOST_POSSIBLE
help
Support for a Sonics Silicon Backplane on top
of a PCMCIA device.
If unsure, say N
config SSB_SILENT
bool "No SSB kernel messages"
depends on SSB && EMBEDDED
help
This option turns off all Sonics Silicon Backplane printks.
Note that you won't be able to identify problems, once
messages are turned off.
This might only be desired for production kernels on
embedded devices to reduce the kernel size.
Say N
config SSB_DEBUG
bool "SSB debugging"
depends on SSB && !SSB_SILENT
help
This turns on additional runtime checks and debugging
messages. Turn this on for SSB troubleshooting.
If unsure, say N
config SSB_SERIAL
bool
depends on SSB
# ChipCommon and ExtIf serial support routines.
config SSB_DRIVER_PCICORE_POSSIBLE
bool
depends on SSB_PCIHOST
default y
config SSB_DRIVER_PCICORE
bool "SSB PCI core driver"
depends on SSB_DRIVER_PCICORE_POSSIBLE
help
Driver for the Sonics Silicon Backplane attached
Broadcom PCI core.
If unsure, say Y
config SSB_PCICORE_HOSTMODE
bool "Hostmode support for SSB PCI core (EXPERIMENTAL)"
depends on SSB_DRIVER_PCICORE && SSB_DRIVER_MIPS && EXPERIMENTAL
help
PCIcore hostmode operation (external PCI bus).
config SSB_DRIVER_MIPS
bool "SSB Broadcom MIPS core driver (EXPERIMENTAL)"
depends on SSB && MIPS && EXPERIMENTAL
select SSB_SERIAL
help
Driver for the Sonics Silicon Backplane attached
Broadcom MIPS core.
If unsure, say N
config SSB_DRIVER_EXTIF
bool "SSB Broadcom EXTIF core driver (EXPERIMENTAL)"
depends on SSB_DRIVER_MIPS && EXPERIMENTAL
help
Driver for the Sonics Silicon Backplane attached
Broadcom EXTIF core.
If unsure, say N
endmenu

View File

@ -0,0 +1,18 @@
# core
ssb-y += main.o scan.o
# host support
ssb-$(CONFIG_SSB_PCIHOST) += pci.o pcihost_wrapper.o
ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia.o
# built-in drivers
ssb-y += driver_chipcommon.o
ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o
ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o
ssb-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o
# b43 pci-ssb-bridge driver
# Not strictly a part of SSB, but kept here for convenience
ssb-$(CONFIG_SSB_PCIHOST) += b43_pci_bridge.o
obj-$(CONFIG_SSB) += ssb.o

View File

@ -0,0 +1,50 @@
/*
* Broadcom 43xx PCI-SSB bridge module
*
* This technically is a separate PCI driver module, but
* because of its small size we include it in the SSB core
* instead of creating a standalone module.
*
* Copyright 2007 Michael Buesch <mb@bu3sch.de>
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
#include <linux/pci.h>
#include <linux/ssb/ssb.h>
#include "ssb_private.h"
static const struct pci_device_id b43_pci_bridge_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4301) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4307) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4311) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4312) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4318) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4319) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4320) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4325) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4328) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4329) },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl);
static struct pci_driver b43_pci_bridge_driver = {
.name = "b43-pci-bridge",
.id_table = b43_pci_bridge_tbl,
};
int __init b43_pci_ssb_bridge_init(void)
{
return ssb_pcihost_register(&b43_pci_bridge_driver);
}
void __exit b43_pci_ssb_bridge_exit(void)
{
ssb_pcihost_unregister(&b43_pci_bridge_driver);
}

View File

@ -0,0 +1,445 @@
/*
* Sonics Silicon Backplane
* Broadcom ChipCommon core driver
*
* Copyright 2005, Broadcom Corporation
* Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
#include <linux/ssb/ssb.h>
#include <linux/ssb/ssb_regs.h>
#include <linux/pci.h>
#include "ssb_private.h"
/* Clock sources */
enum ssb_clksrc {
/* PCI clock */
SSB_CHIPCO_CLKSRC_PCI,
/* Crystal slow clock oscillator */
SSB_CHIPCO_CLKSRC_XTALOS,
/* Low power oscillator */
SSB_CHIPCO_CLKSRC_LOPWROS,
};
static inline u32 chipco_read32(struct ssb_chipcommon *cc,
u16 offset)
{
return ssb_read32(cc->dev, offset);
}
static inline void chipco_write32(struct ssb_chipcommon *cc,
u16 offset,
u32 value)
{
ssb_write32(cc->dev, offset, value);
}
static inline void chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset,
u32 mask, u32 value)
{
value &= mask;
value |= chipco_read32(cc, offset) & ~mask;
chipco_write32(cc, offset, value);
}
void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc,
enum ssb_clkmode mode)
{
struct ssb_device *ccdev = cc->dev;
struct ssb_bus *bus;
u32 tmp;
if (!ccdev)
return;
bus = ccdev->bus;
/* chipcommon cores prior to rev6 don't support dynamic clock control */
if (ccdev->id.revision < 6)
return;
/* chipcommon cores rev10 are a whole new ball game */
if (ccdev->id.revision >= 10)
return;
if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
return;
switch (mode) {
case SSB_CLKMODE_SLOW:
tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
tmp |= SSB_CHIPCO_SLOWCLKCTL_FSLOW;
chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
break;
case SSB_CLKMODE_FAST:
ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */
tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW;
tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL;
chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
break;
case SSB_CLKMODE_DYNAMIC:
tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW;
tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL;
tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL;
if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) != SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL)
tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL;
chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
/* for dynamic control, we have to release our xtal_pu "force on" */
if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL)
ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0);
break;
default:
SSB_WARN_ON(1);
}
}
/* Get the Slow Clock Source */
static enum ssb_clksrc chipco_pctl_get_slowclksrc(struct ssb_chipcommon *cc)
{
struct ssb_bus *bus = cc->dev->bus;
u32 uninitialized_var(tmp);
if (cc->dev->id.revision < 6) {
if (bus->bustype == SSB_BUSTYPE_SSB ||
bus->bustype == SSB_BUSTYPE_PCMCIA)
return SSB_CHIPCO_CLKSRC_XTALOS;
if (bus->bustype == SSB_BUSTYPE_PCI) {
pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &tmp);
if (tmp & 0x10)
return SSB_CHIPCO_CLKSRC_PCI;
return SSB_CHIPCO_CLKSRC_XTALOS;
}
}
if (cc->dev->id.revision < 10) {
tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
tmp &= 0x7;
if (tmp == 0)
return SSB_CHIPCO_CLKSRC_LOPWROS;
if (tmp == 1)
return SSB_CHIPCO_CLKSRC_XTALOS;
if (tmp == 2)
return SSB_CHIPCO_CLKSRC_PCI;
}
return SSB_CHIPCO_CLKSRC_XTALOS;
}
/* Get maximum or minimum (depending on get_max flag) slowclock frequency. */
static int chipco_pctl_clockfreqlimit(struct ssb_chipcommon *cc, int get_max)
{
int uninitialized_var(limit);
enum ssb_clksrc clocksrc;
int divisor = 1;
u32 tmp;
clocksrc = chipco_pctl_get_slowclksrc(cc);
if (cc->dev->id.revision < 6) {
switch (clocksrc) {
case SSB_CHIPCO_CLKSRC_PCI:
divisor = 64;
break;
case SSB_CHIPCO_CLKSRC_XTALOS:
divisor = 32;
break;
default:
SSB_WARN_ON(1);
}
} else if (cc->dev->id.revision < 10) {
switch (clocksrc) {
case SSB_CHIPCO_CLKSRC_LOPWROS:
break;
case SSB_CHIPCO_CLKSRC_XTALOS:
case SSB_CHIPCO_CLKSRC_PCI:
tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
divisor = (tmp >> 16) + 1;
divisor *= 4;
break;
}
} else {
tmp = chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL);
divisor = (tmp >> 16) + 1;
divisor *= 4;
}
switch (clocksrc) {
case SSB_CHIPCO_CLKSRC_LOPWROS:
if (get_max)
limit = 43000;
else
limit = 25000;
break;
case SSB_CHIPCO_CLKSRC_XTALOS:
if (get_max)
limit = 20200000;
else
limit = 19800000;
break;
case SSB_CHIPCO_CLKSRC_PCI:
if (get_max)
limit = 34000000;
else
limit = 25000000;
break;
}
limit /= divisor;
return limit;
}
static void chipco_powercontrol_init(struct ssb_chipcommon *cc)
{
struct ssb_bus *bus = cc->dev->bus;
if (bus->chip_id == 0x4321) {
if (bus->chip_rev == 0)
chipco_write32(cc, SSB_CHIPCO_CHIPCTL, 0x3A4);
else if (bus->chip_rev == 1)
chipco_write32(cc, SSB_CHIPCO_CHIPCTL, 0xA4);
}
if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
return;
if (cc->dev->id.revision >= 10) {
/* Set Idle Power clock rate to 1Mhz */
chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL,
(chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) &
0x0000FFFF) | 0x00040000);
} else {
int maxfreq;
maxfreq = chipco_pctl_clockfreqlimit(cc, 1);
chipco_write32(cc, SSB_CHIPCO_PLLONDELAY,
(maxfreq * 150 + 999999) / 1000000);
chipco_write32(cc, SSB_CHIPCO_FREFSELDELAY,
(maxfreq * 15 + 999999) / 1000000);
}
}
static void calc_fast_powerup_delay(struct ssb_chipcommon *cc)
{
struct ssb_bus *bus = cc->dev->bus;
int minfreq;
unsigned int tmp;
u32 pll_on_delay;
if (bus->bustype != SSB_BUSTYPE_PCI)
return;
if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
return;
minfreq = chipco_pctl_clockfreqlimit(cc, 0);
pll_on_delay = chipco_read32(cc, SSB_CHIPCO_PLLONDELAY);
tmp = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq;
SSB_WARN_ON(tmp & ~0xFFFF);
cc->fast_pwrup_delay = tmp;
}
void ssb_chipcommon_init(struct ssb_chipcommon *cc)
{
if (!cc->dev)
return; /* We don't have a ChipCommon */
chipco_powercontrol_init(cc);
ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
calc_fast_powerup_delay(cc);
}
void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state)
{
if (!cc->dev)
return;
ssb_chipco_set_clockmode(cc, SSB_CLKMODE_SLOW);
}
void ssb_chipco_resume(struct ssb_chipcommon *cc)
{
if (!cc->dev)
return;
chipco_powercontrol_init(cc);
ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
}
/* Get the processor clock */
void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc,
u32 *plltype, u32 *n, u32 *m)
{
*n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N);
*plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
switch (*plltype) {
case SSB_PLLTYPE_2:
case SSB_PLLTYPE_4:
case SSB_PLLTYPE_6:
case SSB_PLLTYPE_7:
*m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS);
break;
case SSB_PLLTYPE_3:
/* 5350 uses m2 to control mips */
*m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2);
break;
default:
*m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB);
break;
}
}
/* Get the bus clock */
void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc,
u32 *plltype, u32 *n, u32 *m)
{
*n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N);
*plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
switch (*plltype) {
case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */
*m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS);
break;
case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
if (cc->dev->bus->chip_id != 0x5365) {
*m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2);
break;
}
/* Fallthough */
default:
*m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB);
}
}
void ssb_chipco_timing_init(struct ssb_chipcommon *cc,
unsigned long ns)
{
struct ssb_device *dev = cc->dev;
struct ssb_bus *bus = dev->bus;
u32 tmp;
/* set register for external IO to control LED. */
chipco_write32(cc, SSB_CHIPCO_PROG_CFG, 0x11);
tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; /* Waitcount-3 = 10ns */
tmp |= DIV_ROUND_UP(40, ns) << SSB_PROG_WCNT_1_SHIFT; /* Waitcount-1 = 40ns */
tmp |= DIV_ROUND_UP(240, ns); /* Waitcount-0 = 240ns */
chipco_write32(cc, SSB_CHIPCO_PROG_WAITCNT, tmp); /* 0x01020a0c for a 100Mhz clock */
/* Set timing for the flash */
tmp = DIV_ROUND_UP(10, ns) << SSB_FLASH_WCNT_3_SHIFT; /* Waitcount-3 = 10nS */
tmp |= DIV_ROUND_UP(10, ns) << SSB_FLASH_WCNT_1_SHIFT; /* Waitcount-1 = 10nS */
tmp |= DIV_ROUND_UP(120, ns); /* Waitcount-0 = 120nS */
if ((bus->chip_id == 0x5365) ||
(dev->id.revision < 9))
chipco_write32(cc, SSB_CHIPCO_FLASH_WAITCNT, tmp);
if ((bus->chip_id == 0x5365) ||
(dev->id.revision < 9) ||
((bus->chip_id == 0x5350) && (bus->chip_rev == 0)))
chipco_write32(cc, SSB_CHIPCO_PCMCIA_MEMWAIT, tmp);
if (bus->chip_id == 0x5350) {
/* Enable EXTIF */
tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT; /* Waitcount-3 = 10ns */
tmp |= DIV_ROUND_UP(20, ns) << SSB_PROG_WCNT_2_SHIFT; /* Waitcount-2 = 20ns */
tmp |= DIV_ROUND_UP(100, ns) << SSB_PROG_WCNT_1_SHIFT; /* Waitcount-1 = 100ns */
tmp |= DIV_ROUND_UP(120, ns); /* Waitcount-0 = 120ns */
chipco_write32(cc, SSB_CHIPCO_PROG_WAITCNT, tmp); /* 0x01020a0c for a 100Mhz clock */
}
}
/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks)
{
/* instant NMI */
chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks);
}
u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask)
{
return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask;
}
void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value)
{
chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value);
}
void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value)
{
chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value);
}
#ifdef CONFIG_SSB_SERIAL
int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
struct ssb_serial_port *ports)
{
struct ssb_bus *bus = cc->dev->bus;
int nr_ports = 0;
u32 plltype;
unsigned int irq;
u32 baud_base, div;
u32 i, n;
plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
irq = ssb_mips_irq(cc->dev);
if (plltype == SSB_PLLTYPE_1) {
/* PLL clock */
baud_base = ssb_calc_clock_rate(plltype,
chipco_read32(cc, SSB_CHIPCO_CLOCK_N),
chipco_read32(cc, SSB_CHIPCO_CLOCK_M2));
div = 1;
} else {
if (cc->dev->id.revision >= 11) {
/* Fixed ALP clock */
baud_base = 20000000;
div = 1;
/* Set the override bit so we don't divide it */
chipco_write32(cc, SSB_CHIPCO_CORECTL,
SSB_CHIPCO_CORECTL_UARTCLK0);
} else if (cc->dev->id.revision >= 3) {
/* Internal backplane clock */
baud_base = ssb_clockspeed(bus);
div = chipco_read32(cc, SSB_CHIPCO_CLKDIV)
& SSB_CHIPCO_CLKDIV_UART;
} else {
/* Fixed internal backplane clock */
baud_base = 88000000;
div = 48;
}
/* Clock source depends on strapping if UartClkOverride is unset */
if ((cc->dev->id.revision > 0) &&
!(chipco_read32(cc, SSB_CHIPCO_CORECTL) & SSB_CHIPCO_CORECTL_UARTCLK0)) {
if ((cc->capabilities & SSB_CHIPCO_CAP_UARTCLK) ==
SSB_CHIPCO_CAP_UARTCLK_INT) {
/* Internal divided backplane clock */
baud_base /= div;
} else {
/* Assume external clock of 1.8432 MHz */
baud_base = 1843200;
}
}
}
/* Determine the registers of the UARTs */
n = (cc->capabilities & SSB_CHIPCO_CAP_NRUART);
for (i = 0; i < n; i++) {
void __iomem *cc_mmio;
void __iomem *uart_regs;
cc_mmio = cc->dev->bus->mmio + (cc->dev->core_index * SSB_CORE_SIZE);
uart_regs = cc_mmio + SSB_CHIPCO_UART0_DATA;
/* Offset changed at after rev 0 */
if (cc->dev->id.revision == 0)
uart_regs += (i * 8);
else
uart_regs += (i * 256);
nr_ports++;
ports[i].regs = uart_regs;
ports[i].irq = irq;
ports[i].baud_base = baud_base;
ports[i].reg_shift = 0;
}
return nr_ports;
}
#endif /* CONFIG_SSB_SERIAL */

View File

@ -0,0 +1,129 @@
/*
* Sonics Silicon Backplane
* Broadcom EXTIF core driver
*
* Copyright 2005, Broadcom Corporation
* Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
* Copyright 2006, 2007, Felix Fietkau <nbd@openwrt.org>
* Copyright 2007, Aurelien Jarno <aurelien@aurel32.net>
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include "ssb_private.h"
static inline u32 extif_read32(struct ssb_extif *extif, u16 offset)
{
return ssb_read32(extif->dev, offset);
}
static inline void extif_write32(struct ssb_extif *extif, u16 offset, u32 value)
{
ssb_write32(extif->dev, offset, value);
}
static inline void extif_write32_masked(struct ssb_extif *extif, u16 offset,
u32 mask, u32 value)
{
value &= mask;
value |= extif_read32(extif, offset) & ~mask;
extif_write32(extif, offset, value);
}
#ifdef CONFIG_SSB_SERIAL
static bool serial_exists(u8 *regs)
{
u8 save_mcr, msr = 0;
if (regs) {
save_mcr = regs[UART_MCR];
regs[UART_MCR] = (UART_MCR_LOOP | UART_MCR_OUT2 | UART_MCR_RTS);
msr = regs[UART_MSR] & (UART_MSR_DCD | UART_MSR_RI
| UART_MSR_CTS | UART_MSR_DSR);
regs[UART_MCR] = save_mcr;
}
return (msr == (UART_MSR_DCD | UART_MSR_CTS));
}
int ssb_extif_serial_init(struct ssb_extif *extif, struct ssb_serial_port *ports)
{
u32 i, nr_ports = 0;
/* Disable GPIO interrupt initially */
extif_write32(extif, SSB_EXTIF_GPIO_INTPOL, 0);
extif_write32(extif, SSB_EXTIF_GPIO_INTMASK, 0);
for (i = 0; i < 2; i++) {
void __iomem *uart_regs;
uart_regs = ioremap_nocache(SSB_EUART, 16);
if (uart_regs) {
uart_regs += (i * 8);
if (serial_exists(uart_regs) && ports) {
extif_write32(extif, SSB_EXTIF_GPIO_INTMASK, 2);
nr_ports++;
ports[i].regs = uart_regs;
ports[i].irq = 2;
ports[i].baud_base = 13500000;
ports[i].reg_shift = 0;
}
iounmap(uart_regs);
}
}
return nr_ports;
}
#endif /* CONFIG_SSB_SERIAL */
void ssb_extif_timing_init(struct ssb_extif *extif, unsigned long ns)
{
u32 tmp;
/* Initialize extif so we can get to the LEDs and external UART */
extif_write32(extif, SSB_EXTIF_PROG_CFG, SSB_EXTCFG_EN);
/* Set timing for the flash */
tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT;
tmp |= DIV_ROUND_UP(40, ns) << SSB_PROG_WCNT_1_SHIFT;
tmp |= DIV_ROUND_UP(120, ns);
extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp);
/* Set programmable interface timing for external uart */
tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT;
tmp |= DIV_ROUND_UP(20, ns) << SSB_PROG_WCNT_2_SHIFT;
tmp |= DIV_ROUND_UP(100, ns) << SSB_PROG_WCNT_1_SHIFT;
tmp |= DIV_ROUND_UP(120, ns);
extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp);
}
void ssb_extif_get_clockcontrol(struct ssb_extif *extif,
u32 *pll_type, u32 *n, u32 *m)
{
*pll_type = SSB_PLLTYPE_1;
*n = extif_read32(extif, SSB_EXTIF_CLOCK_N);
*m = extif_read32(extif, SSB_EXTIF_CLOCK_SB);
}
u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask)
{
return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask;
}
void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value)
{
return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0),
mask, value);
}
void ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value)
{
return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0),
mask, value);
}

View File

@ -0,0 +1,225 @@
/*
* Sonics Silicon Backplane
* Broadcom MIPS core driver
*
* Copyright 2005, Broadcom Corporation
* Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
#include <linux/ssb/ssb.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/time.h>
#include "ssb_private.h"
static inline u32 mips_read32(struct ssb_mipscore *mcore,
u16 offset)
{
return ssb_read32(mcore->dev, offset);
}
static inline void mips_write32(struct ssb_mipscore *mcore,
u16 offset,
u32 value)
{
ssb_write32(mcore->dev, offset, value);
}
static const u32 ipsflag_irq_mask[] = {
0,
SSB_IPSFLAG_IRQ1,
SSB_IPSFLAG_IRQ2,
SSB_IPSFLAG_IRQ3,
SSB_IPSFLAG_IRQ4,
};
static const u32 ipsflag_irq_shift[] = {
0,
SSB_IPSFLAG_IRQ1_SHIFT,
SSB_IPSFLAG_IRQ2_SHIFT,
SSB_IPSFLAG_IRQ3_SHIFT,
SSB_IPSFLAG_IRQ4_SHIFT,
};
static inline u32 ssb_irqflag(struct ssb_device *dev)
{
return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
}
/* Get the MIPS IRQ assignment for a specified device.
* If unassigned, 0 is returned.
*/
unsigned int ssb_mips_irq(struct ssb_device *dev)
{
struct ssb_bus *bus = dev->bus;
u32 irqflag;
u32 ipsflag;
u32 tmp;
unsigned int irq;
irqflag = ssb_irqflag(dev);
ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG);
for (irq = 1; irq <= 4; irq++) {
tmp = ((ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]);
if (tmp == irqflag)
break;
}
if (irq == 5)
irq = 0;
return irq;
}
static void clear_irq(struct ssb_bus *bus, unsigned int irq)
{
struct ssb_device *dev = bus->mipscore.dev;
/* Clear the IRQ in the MIPScore backplane registers */
if (irq == 0) {
ssb_write32(dev, SSB_INTVEC, 0);
} else {
ssb_write32(dev, SSB_IPSFLAG,
ssb_read32(dev, SSB_IPSFLAG) |
ipsflag_irq_mask[irq]);
}
}
static void set_irq(struct ssb_device *dev, unsigned int irq)
{
unsigned int oldirq = ssb_mips_irq(dev);
struct ssb_bus *bus = dev->bus;
struct ssb_device *mdev = bus->mipscore.dev;
u32 irqflag = ssb_irqflag(dev);
dev->irq = irq + 2;
ssb_dprintk(KERN_INFO PFX
"set_irq: core 0x%04x, irq %d => %d\n",
dev->id.coreid, oldirq, irq);
/* clear the old irq */
if (oldirq == 0)
ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) & ssb_read32(mdev, SSB_INTVEC)));
else
clear_irq(bus, oldirq);
/* assign the new one */
if (irq == 0) {
ssb_write32(mdev, SSB_INTVEC, ((1 << irqflag) | ssb_read32(mdev, SSB_INTVEC)));
} else {
irqflag <<= ipsflag_irq_shift[irq];
irqflag |= (ssb_read32(mdev, SSB_IPSFLAG) & ~ipsflag_irq_mask[irq]);
ssb_write32(mdev, SSB_IPSFLAG, irqflag);
}
}
static void ssb_mips_serial_init(struct ssb_mipscore *mcore)
{
struct ssb_bus *bus = mcore->dev->bus;
if (bus->extif.dev)
mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports);
else if (bus->chipco.dev)
mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports);
else
mcore->nr_serial_ports = 0;
}
static void ssb_mips_flash_detect(struct ssb_mipscore *mcore)
{
struct ssb_bus *bus = mcore->dev->bus;
mcore->flash_buswidth = 2;
if (bus->chipco.dev) {
mcore->flash_window = 0x1c000000;
mcore->flash_window_size = 0x02000000;
if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
& SSB_CHIPCO_CFG_DS16) == 0)
mcore->flash_buswidth = 1;
} else {
mcore->flash_window = 0x1fc00000;
mcore->flash_window_size = 0x00400000;
}
}
u32 ssb_cpu_clock(struct ssb_mipscore *mcore)
{
struct ssb_bus *bus = mcore->dev->bus;
u32 pll_type, n, m, rate = 0;
if (bus->extif.dev) {
ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m);
} else if (bus->chipco.dev) {
ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m);
} else
return 0;
if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) {
rate = 200000000;
} else {
rate = ssb_calc_clock_rate(pll_type, n, m);
}
if (pll_type == SSB_PLLTYPE_6) {
rate *= 2;
}
return rate;
}
void ssb_mipscore_init(struct ssb_mipscore *mcore)
{
struct ssb_bus *bus;
struct ssb_device *dev;
unsigned long hz, ns;
unsigned int irq, i;
if (!mcore->dev)
return; /* We don't have a MIPS core */
ssb_dprintk(KERN_INFO PFX "Initializing MIPS core...\n");
bus = mcore->dev->bus;
hz = ssb_clockspeed(bus);
if (!hz)
hz = 100000000;
ns = 1000000000 / hz;
if (bus->extif.dev)
ssb_extif_timing_init(&bus->extif, ns);
else if (bus->chipco.dev)
ssb_chipco_timing_init(&bus->chipco, ns);
/* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */
for (irq = 2, i = 0; i < bus->nr_devices; i++) {
dev = &(bus->devices[i]);
dev->irq = ssb_mips_irq(dev) + 2;
switch (dev->id.coreid) {
case SSB_DEV_USB11_HOST:
/* shouldn't need a separate irq line for non-4710, most of them have a proper
* external usb controller on the pci */
if ((bus->chip_id == 0x4710) && (irq <= 4)) {
set_irq(dev, irq++);
break;
}
/* fallthrough */
case SSB_DEV_PCI:
case SSB_DEV_ETHERNET:
case SSB_DEV_80211:
case SSB_DEV_USB20_HOST:
/* These devices get their own IRQ line if available, the rest goes on IRQ0 */
if (irq <= 4) {
set_irq(dev, irq++);
break;
}
}
}
ssb_mips_serial_init(mcore);
ssb_mips_flash_detect(mcore);
}

View File

@ -0,0 +1,576 @@
/*
* Sonics Silicon Backplane
* Broadcom PCI-core driver
*
* Copyright 2005, Broadcom Corporation
* Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
#include <linux/ssb/ssb.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include "ssb_private.h"
static inline
u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset)
{
return ssb_read32(pc->dev, offset);
}
static inline
void pcicore_write32(struct ssb_pcicore *pc, u16 offset, u32 value)
{
ssb_write32(pc->dev, offset, value);
}
/**************************************************
* Code for hostmode operation.
**************************************************/
#ifdef CONFIG_SSB_PCICORE_HOSTMODE
#include <asm/paccess.h>
/* Probe a 32bit value on the bus and catch bus exceptions.
* Returns nonzero on a bus exception.
* This is MIPS specific */
#define mips_busprobe32(val, addr) get_dbe((val), ((u32 *)(addr)))
/* Assume one-hot slot wiring */
#define SSB_PCI_SLOT_MAX 16
/* Global lock is OK, as we won't have more than one extpci anyway. */
static DEFINE_SPINLOCK(cfgspace_lock);
/* Core to access the external PCI config space. Can only have one. */
static struct ssb_pcicore *extpci_core;
static u32 ssb_pcicore_pcibus_iobase = 0x100;
static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA;
int pcibios_plat_dev_init(struct pci_dev *d)
{
struct resource *res;
int pos, size;
u32 *base;
ssb_printk(KERN_INFO "PCI: Fixing up device %s\n",
pci_name(d));
/* Fix up resource bases */
for (pos = 0; pos < 6; pos++) {
res = &d->resource[pos];
if (res->flags & IORESOURCE_IO)
base = &ssb_pcicore_pcibus_iobase;
else
base = &ssb_pcicore_pcibus_membase;
if (res->end) {
size = res->end - res->start + 1;
if (*base & (size - 1))
*base = (*base + size) & ~(size - 1);
res->start = *base;
res->end = res->start + size - 1;
*base += size;
pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start);
}
/* Fix up PCI bridge BAR0 only */
if (d->bus->number == 0 && PCI_SLOT(d->devfn) == 0)
break;
}
/* Fix up interrupt lines */
d->irq = ssb_mips_irq(extpci_core->dev) + 2;
pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
return 0;
}
static void __init ssb_fixup_pcibridge(struct pci_dev *dev)
{
if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0)
return;
ssb_printk(KERN_INFO "PCI: fixing up bridge\n");
/* Enable PCI bridge bus mastering and memory space */
pci_set_master(dev);
pcibios_enable_device(dev, ~0);
/* Enable PCI bridge BAR1 prefetch and burst */
pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
/* Make sure our latency is high enough to handle the devices behind us */
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xa8);
}
DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge);
int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
return ssb_mips_irq(extpci_core->dev) + 2;
}
static u32 get_cfgspace_addr(struct ssb_pcicore *pc,
unsigned int bus, unsigned int dev,
unsigned int func, unsigned int off)
{
u32 addr = 0;
u32 tmp;
if (unlikely(pc->cardbusmode && dev > 1))
goto out;
if (bus == 0) {
/* Type 0 transaction */
if (unlikely(dev >= SSB_PCI_SLOT_MAX))
goto out;
/* Slide the window */
tmp = SSB_PCICORE_SBTOPCI_CFG0;
tmp |= ((1 << (dev + 16)) & SSB_PCICORE_SBTOPCI1_MASK);
pcicore_write32(pc, SSB_PCICORE_SBTOPCI1, tmp);
/* Calculate the address */
addr = SSB_PCI_CFG;
addr |= ((1 << (dev + 16)) & ~SSB_PCICORE_SBTOPCI1_MASK);
addr |= (func << 8);
addr |= (off & ~3);
} else {
/* Type 1 transaction */
pcicore_write32(pc, SSB_PCICORE_SBTOPCI1,
SSB_PCICORE_SBTOPCI_CFG1);
/* Calculate the address */
addr = SSB_PCI_CFG;
addr |= (bus << 16);
addr |= (dev << 11);
addr |= (func << 8);
addr |= (off & ~3);
}
out:
return addr;
}
static int ssb_extpci_read_config(struct ssb_pcicore *pc,
unsigned int bus, unsigned int dev,
unsigned int func, unsigned int off,
void *buf, int len)
{
int err = -EINVAL;
u32 addr, val;
void __iomem *mmio;
SSB_WARN_ON(!pc->hostmode);
if (unlikely(len != 1 && len != 2 && len != 4))
goto out;
addr = get_cfgspace_addr(pc, bus, dev, func, off);
if (unlikely(!addr))
goto out;
err = -ENOMEM;
mmio = ioremap_nocache(addr, len);
if (!mmio)
goto out;
if (mips_busprobe32(val, mmio)) {
val = 0xffffffff;
goto unmap;
}
val = readl(mmio);
val >>= (8 * (off & 3));
switch (len) {
case 1:
*((u8 *)buf) = (u8)val;
break;
case 2:
*((u16 *)buf) = (u16)val;
break;
case 4:
*((u32 *)buf) = (u32)val;
break;
}
err = 0;
unmap:
iounmap(mmio);
out:
return err;
}
static int ssb_extpci_write_config(struct ssb_pcicore *pc,
unsigned int bus, unsigned int dev,
unsigned int func, unsigned int off,
const void *buf, int len)
{
int err = -EINVAL;
u32 addr, val = 0;
void __iomem *mmio;
SSB_WARN_ON(!pc->hostmode);
if (unlikely(len != 1 && len != 2 && len != 4))
goto out;
addr = get_cfgspace_addr(pc, bus, dev, func, off);
if (unlikely(!addr))
goto out;
err = -ENOMEM;
mmio = ioremap_nocache(addr, len);
if (!mmio)
goto out;
if (mips_busprobe32(val, mmio)) {
val = 0xffffffff;
goto unmap;
}
switch (len) {
case 1:
val = readl(mmio);
val &= ~(0xFF << (8 * (off & 3)));
val |= *((const u8 *)buf) << (8 * (off & 3));
break;
case 2:
val = readl(mmio);
val &= ~(0xFFFF << (8 * (off & 3)));
val |= *((const u16 *)buf) << (8 * (off & 3));
break;
case 4:
val = *((const u32 *)buf);
break;
}
writel(val, mmio);
err = 0;
unmap:
iounmap(mmio);
out:
return err;
}
static int ssb_pcicore_read_config(struct pci_bus *bus, unsigned int devfn,
int reg, int size, u32 *val)
{
unsigned long flags;
int err;
spin_lock_irqsave(&cfgspace_lock, flags);
err = ssb_extpci_read_config(extpci_core, bus->number, PCI_SLOT(devfn),
PCI_FUNC(devfn), reg, val, size);
spin_unlock_irqrestore(&cfgspace_lock, flags);
return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
}
static int ssb_pcicore_write_config(struct pci_bus *bus, unsigned int devfn,
int reg, int size, u32 val)
{
unsigned long flags;
int err;
spin_lock_irqsave(&cfgspace_lock, flags);
err = ssb_extpci_write_config(extpci_core, bus->number, PCI_SLOT(devfn),
PCI_FUNC(devfn), reg, &val, size);
spin_unlock_irqrestore(&cfgspace_lock, flags);
return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
}
static struct pci_ops ssb_pcicore_pciops = {
.read = ssb_pcicore_read_config,
.write = ssb_pcicore_write_config,
};
static struct resource ssb_pcicore_mem_resource = {
.name = "SSB PCIcore external memory",
.start = SSB_PCI_DMA,
.end = SSB_PCI_DMA + SSB_PCI_DMA_SZ - 1,
.flags = IORESOURCE_MEM,
};
static struct resource ssb_pcicore_io_resource = {
.name = "SSB PCIcore external I/O",
.start = 0x100,
.end = 0x7FF,
.flags = IORESOURCE_IO,
};
static struct pci_controller ssb_pcicore_controller = {
.pci_ops = &ssb_pcicore_pciops,
.io_resource = &ssb_pcicore_io_resource,
.mem_resource = &ssb_pcicore_mem_resource,
.mem_offset = 0x24000000,
};
static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
{
u32 val;
if (WARN_ON(extpci_core))
return;
extpci_core = pc;
ssb_dprintk(KERN_INFO PFX "PCIcore in host mode found\n");
/* Reset devices on the external PCI bus */
val = SSB_PCICORE_CTL_RST_OE;
val |= SSB_PCICORE_CTL_CLK_OE;
pcicore_write32(pc, SSB_PCICORE_CTL, val);
val |= SSB_PCICORE_CTL_CLK; /* Clock on */
pcicore_write32(pc, SSB_PCICORE_CTL, val);
udelay(150); /* Assertion time demanded by the PCI standard */
val |= SSB_PCICORE_CTL_RST; /* Deassert RST# */
pcicore_write32(pc, SSB_PCICORE_CTL, val);
val = SSB_PCICORE_ARBCTL_INTERN;
pcicore_write32(pc, SSB_PCICORE_ARBCTL, val);
udelay(1); /* Assertion time demanded by the PCI standard */
/*TODO cardbus mode */
/* 64MB I/O window */
pcicore_write32(pc, SSB_PCICORE_SBTOPCI0,
SSB_PCICORE_SBTOPCI_IO);
/* 64MB config space */
pcicore_write32(pc, SSB_PCICORE_SBTOPCI1,
SSB_PCICORE_SBTOPCI_CFG0);
/* 1GB memory window */
pcicore_write32(pc, SSB_PCICORE_SBTOPCI2,
SSB_PCICORE_SBTOPCI_MEM | SSB_PCI_DMA);
/* Enable PCI bridge BAR0 prefetch and burst */
val = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
ssb_extpci_write_config(pc, 0, 0, 0, PCI_COMMAND, &val, 2);
/* Clear error conditions */
val = 0;
ssb_extpci_write_config(pc, 0, 0, 0, PCI_STATUS, &val, 2);
/* Enable PCI interrupts */
pcicore_write32(pc, SSB_PCICORE_IMASK,
SSB_PCICORE_IMASK_INTA);
/* Ok, ready to run, register it to the system.
* The following needs change, if we want to port hostmode
* to non-MIPS platform. */
set_io_port_base((unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000));
/* Give some time to the PCI controller to configure itself with the new
* values. Not waiting at this point causes crashes of the machine. */
mdelay(10);
register_pci_controller(&ssb_pcicore_controller);
}
static int pcicore_is_in_hostmode(struct ssb_pcicore *pc)
{
struct ssb_bus *bus = pc->dev->bus;
u16 chipid_top;
u32 tmp;
chipid_top = (bus->chip_id & 0xFF00);
if (chipid_top != 0x4700 &&
chipid_top != 0x5300)
return 0;
if (bus->sprom.r1.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
return 0;
/* The 200-pin BCM4712 package does not bond out PCI. Even when
* PCI is bonded out, some boards may leave the pins floating. */
if (bus->chip_id == 0x4712) {
if (bus->chip_package == SSB_CHIPPACK_BCM4712S)
return 0;
if (bus->chip_package == SSB_CHIPPACK_BCM4712M)
return 0;
}
if (bus->chip_id == 0x5350)
return 0;
return !mips_busprobe32(tmp, (bus->mmio + (pc->dev->core_index * SSB_CORE_SIZE)));
}
#endif /* CONFIG_SSB_PCICORE_HOSTMODE */
/**************************************************
* Generic and Clientmode operation code.
**************************************************/
static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
{
/* Disable PCI interrupts. */
ssb_write32(pc->dev, SSB_INTVEC, 0);
}
void ssb_pcicore_init(struct ssb_pcicore *pc)
{
struct ssb_device *dev = pc->dev;
struct ssb_bus *bus;
if (!dev)
return;
bus = dev->bus;
if (!ssb_device_is_enabled(dev))
ssb_device_enable(dev, 0);
#ifdef CONFIG_SSB_PCICORE_HOSTMODE
pc->hostmode = pcicore_is_in_hostmode(pc);
if (pc->hostmode)
ssb_pcicore_init_hostmode(pc);
#endif /* CONFIG_SSB_PCICORE_HOSTMODE */
if (!pc->hostmode)
ssb_pcicore_init_clientmode(pc);
}
static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address)
{
pcicore_write32(pc, 0x130, address);
return pcicore_read32(pc, 0x134);
}
static void ssb_pcie_write(struct ssb_pcicore *pc, u32 address, u32 data)
{
pcicore_write32(pc, 0x130, address);
pcicore_write32(pc, 0x134, data);
}
static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device,
u8 address, u16 data)
{
const u16 mdio_control = 0x128;
const u16 mdio_data = 0x12C;
u32 v;
int i;
v = 0x80; /* Enable Preamble Sequence */
v |= 0x2; /* MDIO Clock Divisor */
pcicore_write32(pc, mdio_control, v);
v = (1 << 30); /* Start of Transaction */
v |= (1 << 28); /* Write Transaction */
v |= (1 << 17); /* Turnaround */
v |= (u32)device << 22;
v |= (u32)address << 18;
v |= data;
pcicore_write32(pc, mdio_data, v);
/* Wait for the device to complete the transaction */
udelay(10);
for (i = 0; i < 10; i++) {
v = pcicore_read32(pc, mdio_control);
if (v & 0x100 /* Trans complete */)
break;
msleep(1);
}
pcicore_write32(pc, mdio_control, 0);
}
static void ssb_broadcast_value(struct ssb_device *dev,
u32 address, u32 data)
{
/* This is used for both, PCI and ChipCommon core, so be careful. */
BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR);
BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA);
ssb_write32(dev, SSB_PCICORE_BCAST_ADDR, address);
ssb_read32(dev, SSB_PCICORE_BCAST_ADDR); /* flush */
ssb_write32(dev, SSB_PCICORE_BCAST_DATA, data);
ssb_read32(dev, SSB_PCICORE_BCAST_DATA); /* flush */
}
static void ssb_commit_settings(struct ssb_bus *bus)
{
struct ssb_device *dev;
dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev;
if (WARN_ON(!dev))
return;
/* This forces an update of the cached registers. */
ssb_broadcast_value(dev, 0xFD8, 0);
}
int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
struct ssb_device *dev)
{
struct ssb_device *pdev = pc->dev;
struct ssb_bus *bus;
int err = 0;
u32 tmp;
might_sleep();
if (!pdev)
goto out;
bus = pdev->bus;
/* Enable interrupts for this device. */
if (bus->host_pci &&
((pdev->id.revision >= 6) || (pdev->id.coreid == SSB_DEV_PCIE))) {
u32 coremask;
/* Calculate the "coremask" for the device. */
coremask = (1 << dev->core_index);
err = pci_read_config_dword(bus->host_pci, SSB_PCI_IRQMASK, &tmp);
if (err)
goto out;
tmp |= coremask << 8;
err = pci_write_config_dword(bus->host_pci, SSB_PCI_IRQMASK, tmp);
if (err)
goto out;
} else {
u32 intvec;
intvec = ssb_read32(pdev, SSB_INTVEC);
if ((bus->chip_id & 0xFF00) == 0x4400) {
/* Workaround: On the BCM44XX the BPFLAG routing
* bit is wrong. Use a hardcoded constant. */
intvec |= 0x00000002;
} else {
tmp = ssb_read32(dev, SSB_TPSFLAG);
tmp &= SSB_TPSFLAG_BPFLAG;
intvec |= tmp;
}
ssb_write32(pdev, SSB_INTVEC, intvec);
}
/* Setup PCIcore operation. */
if (pc->setup_done)
goto out;
if (pdev->id.coreid == SSB_DEV_PCI) {
tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
tmp |= SSB_PCICORE_SBTOPCI_PREF;
tmp |= SSB_PCICORE_SBTOPCI_BURST;
pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
if (pdev->id.revision < 5) {
tmp = ssb_read32(pdev, SSB_IMCFGLO);
tmp &= ~SSB_IMCFGLO_SERTO;
tmp |= 2;
tmp &= ~SSB_IMCFGLO_REQTO;
tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT;
ssb_write32(pdev, SSB_IMCFGLO, tmp);
ssb_commit_settings(bus);
} else if (pdev->id.revision >= 11) {
tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
tmp |= SSB_PCICORE_SBTOPCI_MRM;
pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
}
} else {
WARN_ON(pdev->id.coreid != SSB_DEV_PCIE);
//TODO: Better make defines for all these magic PCIE values.
if ((pdev->id.revision == 0) || (pdev->id.revision == 1)) {
/* TLP Workaround register. */
tmp = ssb_pcie_read(pc, 0x4);
tmp |= 0x8;
ssb_pcie_write(pc, 0x4, tmp);
}
if (pdev->id.revision == 0) {
const u8 serdes_rx_device = 0x1F;
ssb_pcie_mdio_write(pc, serdes_rx_device,
2 /* Timer */, 0x8128);
ssb_pcie_mdio_write(pc, serdes_rx_device,
6 /* CDR */, 0x0100);
ssb_pcie_mdio_write(pc, serdes_rx_device,
7 /* CDR BW */, 0x1466);
} else if (pdev->id.revision == 1) {
/* DLLP Link Control register. */
tmp = ssb_pcie_read(pc, 0x100);
tmp |= 0x40;
ssb_pcie_write(pc, 0x100, tmp);
}
}
pc->setup_done = 1;
out:
return err;
}
EXPORT_SYMBOL(ssb_pcicore_dev_irqvecs_enable);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,790 @@
/*
* Sonics Silicon Backplane PCI-Hostbus related functions.
*
* Copyright (C) 2005-2006 Michael Buesch <mb@bu3sch.de>
* Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
* Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
* Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
* Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
*
* Derived from the Broadcom 4400 device driver.
* Copyright (C) 2002 David S. Miller (davem@redhat.com)
* Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
* Copyright (C) 2006 Broadcom Corporation.
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
#include <linux/ssb/ssb.h>
#include <linux/ssb/ssb_regs.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include "ssb_private.h"
/* Define the following to 1 to enable a printk on each coreswitch. */
#define SSB_VERBOSE_PCICORESWITCH_DEBUG 0
/* Lowlevel coreswitching */
int ssb_pci_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
{
int err;
int attempts = 0;
u32 cur_core;
while (1) {
err = pci_write_config_dword(bus->host_pci, SSB_BAR0_WIN,
(coreidx * SSB_CORE_SIZE)
+ SSB_ENUM_BASE);
if (err)
goto error;
err = pci_read_config_dword(bus->host_pci, SSB_BAR0_WIN,
&cur_core);
if (err)
goto error;
cur_core = (cur_core - SSB_ENUM_BASE)
/ SSB_CORE_SIZE;
if (cur_core == coreidx)
break;
if (attempts++ > SSB_BAR0_MAX_RETRIES)
goto error;
udelay(10);
}
return 0;
error:
ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
return -ENODEV;
}
int ssb_pci_switch_core(struct ssb_bus *bus,
struct ssb_device *dev)
{
int err;
unsigned long flags;
#if SSB_VERBOSE_PCICORESWITCH_DEBUG
ssb_printk(KERN_INFO PFX
"Switching to %s core, index %d\n",
ssb_core_name(dev->id.coreid),
dev->core_index);
#endif
spin_lock_irqsave(&bus->bar_lock, flags);
err = ssb_pci_switch_coreidx(bus, dev->core_index);
if (!err)
bus->mapped_device = dev;
spin_unlock_irqrestore(&bus->bar_lock, flags);
return err;
}
/* Enable/disable the on board crystal oscillator and/or PLL. */
int ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on)
{
int err;
u32 in, out, outenable;
u16 pci_status;
if (bus->bustype != SSB_BUSTYPE_PCI)
return 0;
err = pci_read_config_dword(bus->host_pci, SSB_GPIO_IN, &in);
if (err)
goto err_pci;
err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &out);
if (err)
goto err_pci;
err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, &outenable);
if (err)
goto err_pci;
outenable |= what;
if (turn_on) {
/* Avoid glitching the clock if GPRS is already using it.
* We can't actually read the state of the PLLPD so we infer it
* by the value of XTAL_PU which *is* readable via gpioin.
*/
if (!(in & SSB_GPIO_XTAL)) {
if (what & SSB_GPIO_XTAL) {
/* Turn the crystal on */
out |= SSB_GPIO_XTAL;
if (what & SSB_GPIO_PLL)
out |= SSB_GPIO_PLL;
err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
if (err)
goto err_pci;
err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE,
outenable);
if (err)
goto err_pci;
msleep(1);
}
if (what & SSB_GPIO_PLL) {
/* Turn the PLL on */
out &= ~SSB_GPIO_PLL;
err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
if (err)
goto err_pci;
msleep(5);
}
}
err = pci_read_config_word(bus->host_pci, PCI_STATUS, &pci_status);
if (err)
goto err_pci;
pci_status &= ~PCI_STATUS_SIG_TARGET_ABORT;
err = pci_write_config_word(bus->host_pci, PCI_STATUS, pci_status);
if (err)
goto err_pci;
} else {
if (what & SSB_GPIO_XTAL) {
/* Turn the crystal off */
out &= ~SSB_GPIO_XTAL;
}
if (what & SSB_GPIO_PLL) {
/* Turn the PLL off */
out |= SSB_GPIO_PLL;
}
err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
if (err)
goto err_pci;
err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, outenable);
if (err)
goto err_pci;
}
out:
return err;
err_pci:
printk(KERN_ERR PFX "Error: ssb_pci_xtal() could not access PCI config space!\n");
err = -EBUSY;
goto out;
}
/* Get the word-offset for a SSB_SPROM_XXX define. */
#define SPOFF(offset) (((offset) - SSB_SPROM_BASE) / sizeof(u16))
/* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */
#define SPEX(_outvar, _offset, _mask, _shift) \
out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
static inline u8 ssb_crc8(u8 crc, u8 data)
{
/* Polynomial: x^8 + x^7 + x^6 + x^4 + x^2 + 1 */
static const u8 t[] = {
0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
};
return t[crc ^ data];
}
static u8 ssb_sprom_crc(const u16 *sprom, u16 size)
{
int word;
u8 crc = 0xFF;
for (word = 0; word < size - 1; word++) {
crc = ssb_crc8(crc, sprom[word] & 0x00FF);
crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8);
}
crc = ssb_crc8(crc, sprom[size - 1] & 0x00FF);
crc ^= 0xFF;
return crc;
}
static int sprom_check_crc(const u16 *sprom, u16 size)
{
u8 crc;
u8 expected_crc;
u16 tmp;
crc = ssb_sprom_crc(sprom, size);
tmp = sprom[size - 1] & SSB_SPROM_REVISION_CRC;
expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
if (crc != expected_crc)
return -EPROTO;
return 0;
}
static void sprom_do_read(struct ssb_bus *bus, u16 *sprom)
{
int i;
for (i = 0; i < bus->sprom_size; i++)
sprom[i] = ioread16(bus->mmio + SSB_SPROM_BASE + (i * 2));
}
static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
{
struct pci_dev *pdev = bus->host_pci;
int i, err;
u32 spromctl;
u16 size = bus->sprom_size;
ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
if (err)
goto err_ctlreg;
spromctl |= SSB_SPROMCTL_WE;
err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
if (err)
goto err_ctlreg;
ssb_printk(KERN_NOTICE PFX "[ 0%%");
msleep(500);
for (i = 0; i < size; i++) {
if (i == size / 4)
ssb_printk("25%%");
else if (i == size / 2)
ssb_printk("50%%");
else if (i == (size * 3) / 4)
ssb_printk("75%%");
else if (i % 2)
ssb_printk(".");
writew(sprom[i], bus->mmio + SSB_SPROM_BASE + (i * 2));
mmiowb();
msleep(20);
}
err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
if (err)
goto err_ctlreg;
spromctl &= ~SSB_SPROMCTL_WE;
err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
if (err)
goto err_ctlreg;
msleep(500);
ssb_printk("100%% ]\n");
ssb_printk(KERN_NOTICE PFX "SPROM written.\n");
return 0;
err_ctlreg:
ssb_printk(KERN_ERR PFX "Could not access SPROM control register.\n");
return err;
}
static s8 r123_extract_antgain(u8 sprom_revision, const u16 *in,
u16 mask, u16 shift)
{
u16 v;
u8 gain;
v = in[SPOFF(SSB_SPROM1_AGAIN)];
gain = (v & mask) >> shift;
if (gain == 0xFF)
gain = 2; /* If unset use 2dBm */
if (sprom_revision == 1) {
/* Convert to Q5.2 */
gain <<= 2;
} else {
/* Q5.2 Fractional part is stored in 0xC0 */
gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2);
}
return (s8)gain;
}
static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
{
int i;
u16 v;
s8 gain;
u16 loc[3];
if (out->revision == 3) { /* rev 3 moved MAC */
loc[0] = SSB_SPROM3_IL0MAC;
loc[1] = SSB_SPROM3_ET0MAC;
loc[2] = SSB_SPROM3_ET1MAC;
} else {
loc[0] = SSB_SPROM1_IL0MAC;
loc[1] = SSB_SPROM1_ET0MAC;
loc[2] = SSB_SPROM1_ET1MAC;
}
for (i = 0; i < 3; i++) {
v = in[SPOFF(loc[0]) + i];
*(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
}
for (i = 0; i < 3; i++) {
v = in[SPOFF(loc[1]) + i];
*(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
}
for (i = 0; i < 3; i++) {
v = in[SPOFF(loc[2]) + i];
*(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
}
SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
SSB_SPROM1_ETHPHY_ET1A_SHIFT);
SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
SSB_SPROM1_BINF_CCODE_SHIFT);
SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
SSB_SPROM1_BINF_ANTA_SHIFT);
SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
SSB_SPROM1_BINF_ANTBG_SHIFT);
SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0);
SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0);
SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0);
SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0);
SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0);
SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1,
SSB_SPROM1_GPIOA_P1_SHIFT);
SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0);
SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3,
SSB_SPROM1_GPIOB_P3_SHIFT);
SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A,
SSB_SPROM1_MAXPWR_A_SHIFT);
SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0);
SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A,
SSB_SPROM1_ITSSI_A_SHIFT);
SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
if (out->revision >= 2)
SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
/* Extract the antenna gain values. */
gain = r123_extract_antgain(out->revision, in,
SSB_SPROM1_AGAIN_BG,
SSB_SPROM1_AGAIN_BG_SHIFT);
out->antenna_gain.ghz24.a0 = gain;
out->antenna_gain.ghz24.a1 = gain;
out->antenna_gain.ghz24.a2 = gain;
out->antenna_gain.ghz24.a3 = gain;
gain = r123_extract_antgain(out->revision, in,
SSB_SPROM1_AGAIN_A,
SSB_SPROM1_AGAIN_A_SHIFT);
out->antenna_gain.ghz5.a0 = gain;
out->antenna_gain.ghz5.a1 = gain;
out->antenna_gain.ghz5.a2 = gain;
out->antenna_gain.ghz5.a3 = gain;
}
static void sprom_extract_r4(struct ssb_sprom *out, const u16 *in)
{
int i;
u16 v;
/* extract the equivalent of the r1 variables */
for (i = 0; i < 3; i++) {
v = in[SPOFF(SSB_SPROM4_IL0MAC) + i];
*(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
}
for (i = 0; i < 3; i++) {
v = in[SPOFF(SSB_SPROM4_ET0MAC) + i];
*(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
}
for (i = 0; i < 3; i++) {
v = in[SPOFF(SSB_SPROM4_ET1MAC) + i];
*(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
}
SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);
SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
SSB_SPROM4_ETHPHY_ET1A_SHIFT);
SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A,
SSB_SPROM4_ANTAVAIL_A_SHIFT);
SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG,
SSB_SPROM4_ANTAVAIL_BG_SHIFT);
SPEX(maxpwr_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_MAXP_BG_MASK, 0);
SPEX(itssi_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_ITSSI_BG,
SSB_SPROM4_ITSSI_BG_SHIFT);
SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0);
SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A,
SSB_SPROM4_ITSSI_A_SHIFT);
SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0);
SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1,
SSB_SPROM4_GPIOA_P1_SHIFT);
SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0);
SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3,
SSB_SPROM4_GPIOB_P3_SHIFT);
/* Extract the antenna gain values. */
SPEX(antenna_gain.ghz24.a0, SSB_SPROM4_AGAIN01,
SSB_SPROM4_AGAIN0, SSB_SPROM4_AGAIN0_SHIFT);
SPEX(antenna_gain.ghz24.a1, SSB_SPROM4_AGAIN01,
SSB_SPROM4_AGAIN1, SSB_SPROM4_AGAIN1_SHIFT);
SPEX(antenna_gain.ghz24.a2, SSB_SPROM4_AGAIN23,
SSB_SPROM4_AGAIN2, SSB_SPROM4_AGAIN2_SHIFT);
SPEX(antenna_gain.ghz24.a3, SSB_SPROM4_AGAIN23,
SSB_SPROM4_AGAIN3, SSB_SPROM4_AGAIN3_SHIFT);
memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
sizeof(out->antenna_gain.ghz5));
/* TODO - get remaining rev 4 stuff needed */
}
static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
const u16 *in, u16 size)
{
memset(out, 0, sizeof(*out));
out->revision = in[size - 1] & 0x00FF;
ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision);
if ((bus->chip_id & 0xFF00) == 0x4400) {
/* Workaround: The BCM44XX chip has a stupid revision
* number stored in the SPROM.
* Always extract r1. */
out->revision = 1;
sprom_extract_r123(out, in);
} else if (bus->chip_id == 0x4321) {
/* the BCM4328 has a chipid == 0x4321 and a rev 4 SPROM */
out->revision = 4;
sprom_extract_r4(out, in);
} else {
if (out->revision == 0)
goto unsupported;
if (out->revision >= 1 && out->revision <= 3) {
sprom_extract_r123(out, in);
}
if (out->revision == 4)
sprom_extract_r4(out, in);
if (out->revision >= 5)
goto unsupported;
}
return 0;
unsupported:
ssb_printk(KERN_WARNING PFX "Unsupported SPROM revision %d "
"detected. Will extract v1\n", out->revision);
sprom_extract_r123(out, in);
return 0;
}
static int ssb_pci_sprom_get(struct ssb_bus *bus,
struct ssb_sprom *sprom)
{
int err = -ENOMEM;
u16 *buf;
buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
if (!buf)
goto out;
bus->sprom_size = SSB_SPROMSIZE_WORDS_R123;
sprom_do_read(bus, buf);
err = sprom_check_crc(buf, bus->sprom_size);
if (err) {
/* check for rev 4 sprom - has special signature */
if (buf[32] == 0x5372) {
kfree(buf);
buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
GFP_KERNEL);
if (!buf)
goto out;
bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
sprom_do_read(bus, buf);
err = sprom_check_crc(buf, bus->sprom_size);
}
if (err)
ssb_printk(KERN_WARNING PFX "WARNING: Invalid"
" SPROM CRC (corrupt SPROM)\n");
}
err = sprom_extract(bus, sprom, buf, bus->sprom_size);
kfree(buf);
out:
return err;
}
static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
struct ssb_boardinfo *bi)
{
pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_VENDOR_ID,
&bi->vendor);
pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_ID,
&bi->type);
pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
&bi->rev);
}
int ssb_pci_get_invariants(struct ssb_bus *bus,
struct ssb_init_invariants *iv)
{
int err;
err = ssb_pci_sprom_get(bus, &iv->sprom);
if (err)
goto out;
ssb_pci_get_boardinfo(bus, &iv->boardinfo);
out:
return err;
}
#ifdef CONFIG_SSB_DEBUG
static int ssb_pci_assert_buspower(struct ssb_bus *bus)
{
if (likely(bus->powered_up))
return 0;
printk(KERN_ERR PFX "FATAL ERROR: Bus powered down "
"while accessing PCI MMIO space\n");
if (bus->power_warn_count <= 10) {
bus->power_warn_count++;
dump_stack();
}
return -ENODEV;
}
#else /* DEBUG */
static inline int ssb_pci_assert_buspower(struct ssb_bus *bus)
{
return 0;
}
#endif /* DEBUG */
static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
{
struct ssb_bus *bus = dev->bus;
if (unlikely(ssb_pci_assert_buspower(bus)))
return 0xFFFF;
if (unlikely(bus->mapped_device != dev)) {
if (unlikely(ssb_pci_switch_core(bus, dev)))
return 0xFFFF;
}
return ioread16(bus->mmio + offset);
}
static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset)
{
struct ssb_bus *bus = dev->bus;
if (unlikely(ssb_pci_assert_buspower(bus)))
return 0xFFFFFFFF;
if (unlikely(bus->mapped_device != dev)) {
if (unlikely(ssb_pci_switch_core(bus, dev)))
return 0xFFFFFFFF;
}
return ioread32(bus->mmio + offset);
}
static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
{
struct ssb_bus *bus = dev->bus;
if (unlikely(ssb_pci_assert_buspower(bus)))
return;
if (unlikely(bus->mapped_device != dev)) {
if (unlikely(ssb_pci_switch_core(bus, dev)))
return;
}
iowrite16(value, bus->mmio + offset);
}
static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value)
{
struct ssb_bus *bus = dev->bus;
if (unlikely(ssb_pci_assert_buspower(bus)))
return;
if (unlikely(bus->mapped_device != dev)) {
if (unlikely(ssb_pci_switch_core(bus, dev)))
return;
}
iowrite32(value, bus->mmio + offset);
}
/* Not "static", as it's used in main.c */
const struct ssb_bus_ops ssb_pci_ops = {
.read16 = ssb_pci_read16,
.read32 = ssb_pci_read32,
.write16 = ssb_pci_write16,
.write32 = ssb_pci_write32,
};
static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len, u16 size)
{
int i, pos = 0;
for (i = 0; i < size; i++)
pos += snprintf(buf + pos, buf_len - pos - 1,
"%04X", swab16(sprom[i]) & 0xFFFF);
pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
return pos + 1;
}
static int hex2sprom(u16 *sprom, const char *dump, size_t len, u16 size)
{
char tmp[5] = { 0 };
int cnt = 0;
unsigned long parsed;
if (len < size * 2)
return -EINVAL;
while (cnt < size) {
memcpy(tmp, dump, 4);
dump += 4;
parsed = simple_strtoul(tmp, NULL, 16);
sprom[cnt++] = swab16((u16)parsed);
}
return 0;
}
static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
struct device_attribute *attr,
char *buf)
{
struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
struct ssb_bus *bus;
u16 *sprom;
int err = -ENODEV;
ssize_t count = 0;
bus = ssb_pci_dev_to_bus(pdev);
if (!bus)
goto out;
err = -ENOMEM;
sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
if (!sprom)
goto out;
/* Use interruptible locking, as the SPROM write might
* be holding the lock for several seconds. So allow userspace
* to cancel operation. */
err = -ERESTARTSYS;
if (mutex_lock_interruptible(&bus->pci_sprom_mutex))
goto out_kfree;
sprom_do_read(bus, sprom);
mutex_unlock(&bus->pci_sprom_mutex);
count = sprom2hex(sprom, buf, PAGE_SIZE, bus->sprom_size);
err = 0;
out_kfree:
kfree(sprom);
out:
return err ? err : count;
}
static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
struct ssb_bus *bus;
u16 *sprom;
int res = 0, err = -ENODEV;
bus = ssb_pci_dev_to_bus(pdev);
if (!bus)
goto out;
err = -ENOMEM;
sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
if (!sprom)
goto out;
err = hex2sprom(sprom, buf, count, bus->sprom_size);
if (err) {
err = -EINVAL;
goto out_kfree;
}
err = sprom_check_crc(sprom, bus->sprom_size);
if (err) {
err = -EINVAL;
goto out_kfree;
}
/* Use interruptible locking, as the SPROM write might
* be holding the lock for several seconds. So allow userspace
* to cancel operation. */
err = -ERESTARTSYS;
if (mutex_lock_interruptible(&bus->pci_sprom_mutex))
goto out_kfree;
err = ssb_devices_freeze(bus);
if (err == -EOPNOTSUPP) {
ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. "
"No suspend support. Is CONFIG_PM enabled?\n");
goto out_unlock;
}
if (err) {
ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");
goto out_unlock;
}
res = sprom_do_write(bus, sprom);
err = ssb_devices_thaw(bus);
if (err)
ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");
out_unlock:
mutex_unlock(&bus->pci_sprom_mutex);
out_kfree:
kfree(sprom);
out:
if (res)
return res;
return err ? err : count;
}
static DEVICE_ATTR(ssb_sprom, 0600,
ssb_pci_attr_sprom_show,
ssb_pci_attr_sprom_store);
void ssb_pci_exit(struct ssb_bus *bus)
{
struct pci_dev *pdev;
if (bus->bustype != SSB_BUSTYPE_PCI)
return;
pdev = bus->host_pci;
device_remove_file(&pdev->dev, &dev_attr_ssb_sprom);
}
int ssb_pci_init(struct ssb_bus *bus)
{
struct pci_dev *pdev;
int err;
if (bus->bustype != SSB_BUSTYPE_PCI)
return 0;
pdev = bus->host_pci;
mutex_init(&bus->pci_sprom_mutex);
err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom);
if (err)
goto out;
out:
return err;
}

View File

@ -0,0 +1,104 @@
/*
* Sonics Silicon Backplane
* PCI Hostdevice wrapper
*
* Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
* Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
* Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
* Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
* Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de>
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
#include <linux/pci.h>
#include <linux/ssb/ssb.h>
#ifdef CONFIG_PM
static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state)
{
pci_save_state(dev);
pci_disable_device(dev);
pci_set_power_state(dev, pci_choose_state(dev, state));
return 0;
}
static int ssb_pcihost_resume(struct pci_dev *dev)
{
int err;
pci_set_power_state(dev, 0);
err = pci_enable_device(dev);
if (err)
return err;
pci_restore_state(dev);
return 0;
}
#else /* CONFIG_PM */
# define ssb_pcihost_suspend NULL
# define ssb_pcihost_resume NULL
#endif /* CONFIG_PM */
static int ssb_pcihost_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
struct ssb_bus *ssb;
int err = -ENOMEM;
const char *name;
ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
if (!ssb)
goto out;
err = pci_enable_device(dev);
if (err)
goto err_kfree_ssb;
name = dev->dev.bus_id;
if (dev->driver && dev->driver->name)
name = dev->driver->name;
err = pci_request_regions(dev, name);
if (err)
goto err_pci_disable;
pci_set_master(dev);
err = ssb_bus_pcibus_register(ssb, dev);
if (err)
goto err_pci_release_regions;
pci_set_drvdata(dev, ssb);
out:
return err;
err_pci_release_regions:
pci_release_regions(dev);
err_pci_disable:
pci_disable_device(dev);
err_kfree_ssb:
kfree(ssb);
return err;
}
static void ssb_pcihost_remove(struct pci_dev *dev)
{
struct ssb_bus *ssb = pci_get_drvdata(dev);
ssb_bus_unregister(ssb);
pci_release_regions(dev);
pci_disable_device(dev);
kfree(ssb);
pci_set_drvdata(dev, NULL);
}
int ssb_pcihost_register(struct pci_driver *driver)
{
driver->probe = ssb_pcihost_probe;
driver->remove = ssb_pcihost_remove;
driver->suspend = ssb_pcihost_suspend;
driver->resume = ssb_pcihost_resume;
return pci_register_driver(driver);
}
EXPORT_SYMBOL(ssb_pcihost_register);

View File

@ -0,0 +1,287 @@
/*
* Sonics Silicon Backplane
* PCMCIA-Hostbus related functions
*
* Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2007 Michael Buesch <mb@bu3sch.de>
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
#include <linux/ssb/ssb.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
#include <pcmcia/ds.h>
#include <pcmcia/cisreg.h>
#include "ssb_private.h"
/* Define the following to 1 to enable a printk on each coreswitch. */
#define SSB_VERBOSE_PCMCIACORESWITCH_DEBUG 0
int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
u8 coreidx)
{
struct pcmcia_device *pdev = bus->host_pcmcia;
int err;
int attempts = 0;
u32 cur_core;
conf_reg_t reg;
u32 addr;
u32 read_addr;
addr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE;
while (1) {
reg.Action = CS_WRITE;
reg.Offset = 0x2E;
reg.Value = (addr & 0x0000F000) >> 12;
err = pcmcia_access_configuration_register(pdev, &reg);
if (err != CS_SUCCESS)
goto error;
reg.Offset = 0x30;
reg.Value = (addr & 0x00FF0000) >> 16;
err = pcmcia_access_configuration_register(pdev, &reg);
if (err != CS_SUCCESS)
goto error;
reg.Offset = 0x32;
reg.Value = (addr & 0xFF000000) >> 24;
err = pcmcia_access_configuration_register(pdev, &reg);
if (err != CS_SUCCESS)
goto error;
read_addr = 0;
reg.Action = CS_READ;
reg.Offset = 0x2E;
err = pcmcia_access_configuration_register(pdev, &reg);
if (err != CS_SUCCESS)
goto error;
read_addr |= ((u32)(reg.Value & 0x0F)) << 12;
reg.Offset = 0x30;
err = pcmcia_access_configuration_register(pdev, &reg);
if (err != CS_SUCCESS)
goto error;
read_addr |= ((u32)reg.Value) << 16;
reg.Offset = 0x32;
err = pcmcia_access_configuration_register(pdev, &reg);
if (err != CS_SUCCESS)
goto error;
read_addr |= ((u32)reg.Value) << 24;
cur_core = (read_addr - SSB_ENUM_BASE) / SSB_CORE_SIZE;
if (cur_core == coreidx)
break;
if (attempts++ > SSB_BAR0_MAX_RETRIES)
goto error;
udelay(10);
}
return 0;
error:
ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
return -ENODEV;
}
int ssb_pcmcia_switch_core(struct ssb_bus *bus,
struct ssb_device *dev)
{
int err;
#if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG
ssb_printk(KERN_INFO PFX
"Switching to %s core, index %d\n",
ssb_core_name(dev->id.coreid),
dev->core_index);
#endif
err = ssb_pcmcia_switch_coreidx(bus, dev->core_index);
if (!err)
bus->mapped_device = dev;
return err;
}
int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)
{
int attempts = 0;
conf_reg_t reg;
int res;
SSB_WARN_ON((seg != 0) && (seg != 1));
reg.Offset = 0x34;
reg.Function = 0;
while (1) {
reg.Action = CS_WRITE;
reg.Value = seg;
res = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
if (unlikely(res != CS_SUCCESS))
goto error;
reg.Value = 0xFF;
reg.Action = CS_READ;
res = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
if (unlikely(res != CS_SUCCESS))
goto error;
if (reg.Value == seg)
break;
if (unlikely(attempts++ > SSB_BAR0_MAX_RETRIES))
goto error;
udelay(10);
}
bus->mapped_pcmcia_seg = seg;
return 0;
error:
ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n");
return -ENODEV;
}
static int select_core_and_segment(struct ssb_device *dev,
u16 *offset)
{
struct ssb_bus *bus = dev->bus;
int err;
u8 need_segment;
if (*offset >= 0x800) {
*offset -= 0x800;
need_segment = 1;
} else
need_segment = 0;
if (unlikely(dev != bus->mapped_device)) {
err = ssb_pcmcia_switch_core(bus, dev);
if (unlikely(err))
return err;
}
if (unlikely(need_segment != bus->mapped_pcmcia_seg)) {
err = ssb_pcmcia_switch_segment(bus, need_segment);
if (unlikely(err))
return err;
}
return 0;
}
static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset)
{
struct ssb_bus *bus = dev->bus;
unsigned long flags;
int err;
u16 value = 0xFFFF;
spin_lock_irqsave(&bus->bar_lock, flags);
err = select_core_and_segment(dev, &offset);
if (likely(!err))
value = readw(bus->mmio + offset);
spin_unlock_irqrestore(&bus->bar_lock, flags);
return value;
}
static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset)
{
struct ssb_bus *bus = dev->bus;
unsigned long flags;
int err;
u32 lo = 0xFFFFFFFF, hi = 0xFFFFFFFF;
spin_lock_irqsave(&bus->bar_lock, flags);
err = select_core_and_segment(dev, &offset);
if (likely(!err)) {
lo = readw(bus->mmio + offset);
hi = readw(bus->mmio + offset + 2);
}
spin_unlock_irqrestore(&bus->bar_lock, flags);
return (lo | (hi << 16));
}
static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value)
{
struct ssb_bus *bus = dev->bus;
unsigned long flags;
int err;
spin_lock_irqsave(&bus->bar_lock, flags);
err = select_core_and_segment(dev, &offset);
if (likely(!err))
writew(value, bus->mmio + offset);
mmiowb();
spin_unlock_irqrestore(&bus->bar_lock, flags);
}
static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value)
{
struct ssb_bus *bus = dev->bus;
unsigned long flags;
int err;
spin_lock_irqsave(&bus->bar_lock, flags);
err = select_core_and_segment(dev, &offset);
if (likely(!err)) {
writew((value & 0x0000FFFF), bus->mmio + offset);
writew(((value & 0xFFFF0000) >> 16), bus->mmio + offset + 2);
}
mmiowb();
spin_unlock_irqrestore(&bus->bar_lock, flags);
}
/* Not "static", as it's used in main.c */
const struct ssb_bus_ops ssb_pcmcia_ops = {
.read16 = ssb_pcmcia_read16,
.read32 = ssb_pcmcia_read32,
.write16 = ssb_pcmcia_write16,
.write32 = ssb_pcmcia_write32,
};
#include <linux/etherdevice.h>
int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
struct ssb_init_invariants *iv)
{
//TODO
random_ether_addr(iv->sprom.il0mac);
return 0;
}
int ssb_pcmcia_init(struct ssb_bus *bus)
{
conf_reg_t reg;
int err;
if (bus->bustype != SSB_BUSTYPE_PCMCIA)
return 0;
/* Switch segment to a known state and sync
* bus->mapped_pcmcia_seg with hardware state. */
ssb_pcmcia_switch_segment(bus, 0);
/* Init IRQ routing */
reg.Action = CS_READ;
reg.Function = 0;
if (bus->chip_id == 0x4306)
reg.Offset = 0x00;
else
reg.Offset = 0x80;
err = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
if (err != CS_SUCCESS)
goto error;
reg.Action = CS_WRITE;
reg.Value |= 0x04 | 0x01;
err = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
if (err != CS_SUCCESS)
goto error;
return 0;
error:
return -ENODEV;
}

View File

@ -0,0 +1,424 @@
/*
* Sonics Silicon Backplane
* Bus scanning
*
* Copyright (C) 2005-2007 Michael Buesch <mb@bu3sch.de>
* Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
* Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
* Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
* Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
* Copyright (C) 2006 Broadcom Corporation.
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
#include <linux/ssb/ssb.h>
#include <linux/ssb/ssb_regs.h>
#include <linux/pci.h>
#include <linux/io.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#include "ssb_private.h"
const char *ssb_core_name(u16 coreid)
{
switch (coreid) {
case SSB_DEV_CHIPCOMMON:
return "ChipCommon";
case SSB_DEV_ILINE20:
return "ILine 20";
case SSB_DEV_SDRAM:
return "SDRAM";
case SSB_DEV_PCI:
return "PCI";
case SSB_DEV_MIPS:
return "MIPS";
case SSB_DEV_ETHERNET:
return "Fast Ethernet";
case SSB_DEV_V90:
return "V90";
case SSB_DEV_USB11_HOSTDEV:
return "USB 1.1 Hostdev";
case SSB_DEV_ADSL:
return "ADSL";
case SSB_DEV_ILINE100:
return "ILine 100";
case SSB_DEV_IPSEC:
return "IPSEC";
case SSB_DEV_PCMCIA:
return "PCMCIA";
case SSB_DEV_INTERNAL_MEM:
return "Internal Memory";
case SSB_DEV_MEMC_SDRAM:
return "MEMC SDRAM";
case SSB_DEV_EXTIF:
return "EXTIF";
case SSB_DEV_80211:
return "IEEE 802.11";
case SSB_DEV_MIPS_3302:
return "MIPS 3302";
case SSB_DEV_USB11_HOST:
return "USB 1.1 Host";
case SSB_DEV_USB11_DEV:
return "USB 1.1 Device";
case SSB_DEV_USB20_HOST:
return "USB 2.0 Host";
case SSB_DEV_USB20_DEV:
return "USB 2.0 Device";
case SSB_DEV_SDIO_HOST:
return "SDIO Host";
case SSB_DEV_ROBOSWITCH:
return "Roboswitch";
case SSB_DEV_PARA_ATA:
return "PATA";
case SSB_DEV_SATA_XORDMA:
return "SATA XOR-DMA";
case SSB_DEV_ETHERNET_GBIT:
return "GBit Ethernet";
case SSB_DEV_PCIE:
return "PCI-E";
case SSB_DEV_MIMO_PHY:
return "MIMO PHY";
case SSB_DEV_SRAM_CTRLR:
return "SRAM Controller";
case SSB_DEV_MINI_MACPHY:
return "Mini MACPHY";
case SSB_DEV_ARM_1176:
return "ARM 1176";
case SSB_DEV_ARM_7TDMI:
return "ARM 7TDMI";
}
return "UNKNOWN";
}
static u16 pcidev_to_chipid(struct pci_dev *pci_dev)
{
u16 chipid_fallback = 0;
switch (pci_dev->device) {
case 0x4301:
chipid_fallback = 0x4301;
break;
case 0x4305 ... 0x4307:
chipid_fallback = 0x4307;
break;
case 0x4403:
chipid_fallback = 0x4402;
break;
case 0x4610 ... 0x4615:
chipid_fallback = 0x4610;
break;
case 0x4710 ... 0x4715:
chipid_fallback = 0x4710;
break;
case 0x4320 ... 0x4325:
chipid_fallback = 0x4309;
break;
case PCI_DEVICE_ID_BCM4401:
case PCI_DEVICE_ID_BCM4401B0:
case PCI_DEVICE_ID_BCM4401B1:
chipid_fallback = 0x4401;
break;
default:
ssb_printk(KERN_ERR PFX
"PCI-ID not in fallback list\n");
}
return chipid_fallback;
}
static u8 chipid_to_nrcores(u16 chipid)
{
switch (chipid) {
case 0x5365:
return 7;
case 0x4306:
return 6;
case 0x4310:
return 8;
case 0x4307:
case 0x4301:
return 5;
case 0x4401:
case 0x4402:
return 3;
case 0x4710:
case 0x4610:
case 0x4704:
return 9;
default:
ssb_printk(KERN_ERR PFX
"CHIPID not in nrcores fallback list\n");
}
return 1;
}
static u32 scan_read32(struct ssb_bus *bus, u8 current_coreidx,
u16 offset)
{
switch (bus->bustype) {
case SSB_BUSTYPE_SSB:
offset += current_coreidx * SSB_CORE_SIZE;
break;
case SSB_BUSTYPE_PCI:
break;
case SSB_BUSTYPE_PCMCIA:
if (offset >= 0x800) {
ssb_pcmcia_switch_segment(bus, 1);
offset -= 0x800;
} else
ssb_pcmcia_switch_segment(bus, 0);
break;
}
return readl(bus->mmio + offset);
}
static int scan_switchcore(struct ssb_bus *bus, u8 coreidx)
{
switch (bus->bustype) {
case SSB_BUSTYPE_SSB:
break;
case SSB_BUSTYPE_PCI:
return ssb_pci_switch_coreidx(bus, coreidx);
case SSB_BUSTYPE_PCMCIA:
return ssb_pcmcia_switch_coreidx(bus, coreidx);
}
return 0;
}
void ssb_iounmap(struct ssb_bus *bus)
{
switch (bus->bustype) {
case SSB_BUSTYPE_SSB:
case SSB_BUSTYPE_PCMCIA:
iounmap(bus->mmio);
break;
case SSB_BUSTYPE_PCI:
#ifdef CONFIG_SSB_PCIHOST
pci_iounmap(bus->host_pci, bus->mmio);
#else
SSB_BUG_ON(1); /* Can't reach this code. */
#endif
break;
}
bus->mmio = NULL;
bus->mapped_device = NULL;
}
static void __iomem *ssb_ioremap(struct ssb_bus *bus,
unsigned long baseaddr)
{
void __iomem *mmio = NULL;
switch (bus->bustype) {
case SSB_BUSTYPE_SSB:
/* Only map the first core for now. */
/* fallthrough... */
case SSB_BUSTYPE_PCMCIA:
mmio = ioremap(baseaddr, SSB_CORE_SIZE);
break;
case SSB_BUSTYPE_PCI:
#ifdef CONFIG_SSB_PCIHOST
mmio = pci_iomap(bus->host_pci, 0, ~0UL);
#else
SSB_BUG_ON(1); /* Can't reach this code. */
#endif
break;
}
return mmio;
}
static int we_support_multiple_80211_cores(struct ssb_bus *bus)
{
/* More than one 802.11 core is only supported by special chips.
* There are chips with two 802.11 cores, but with dangling
* pins on the second core. Be careful and reject them here.
*/
#ifdef CONFIG_SSB_PCIHOST
if (bus->bustype == SSB_BUSTYPE_PCI) {
if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
bus->host_pci->device == 0x4324)
return 1;
}
#endif /* CONFIG_SSB_PCIHOST */
return 0;
}
int ssb_bus_scan(struct ssb_bus *bus,
unsigned long baseaddr)
{
int err = -ENOMEM;
void __iomem *mmio;
u32 idhi, cc, rev, tmp;
int dev_i, i;
struct ssb_device *dev;
int nr_80211_cores = 0;
mmio = ssb_ioremap(bus, baseaddr);
if (!mmio)
goto out;
bus->mmio = mmio;
err = scan_switchcore(bus, 0); /* Switch to first core */
if (err)
goto err_unmap;
idhi = scan_read32(bus, 0, SSB_IDHIGH);
cc = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
rev = (idhi & SSB_IDHIGH_RCLO);
rev |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT;
bus->nr_devices = 0;
if (cc == SSB_DEV_CHIPCOMMON) {
tmp = scan_read32(bus, 0, SSB_CHIPCO_CHIPID);
bus->chip_id = (tmp & SSB_CHIPCO_IDMASK);
bus->chip_rev = (tmp & SSB_CHIPCO_REVMASK) >>
SSB_CHIPCO_REVSHIFT;
bus->chip_package = (tmp & SSB_CHIPCO_PACKMASK) >>
SSB_CHIPCO_PACKSHIFT;
if (rev >= 4) {
bus->nr_devices = (tmp & SSB_CHIPCO_NRCORESMASK) >>
SSB_CHIPCO_NRCORESSHIFT;
}
tmp = scan_read32(bus, 0, SSB_CHIPCO_CAP);
bus->chipco.capabilities = tmp;
} else {
if (bus->bustype == SSB_BUSTYPE_PCI) {
bus->chip_id = pcidev_to_chipid(bus->host_pci);
pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
&bus->chip_rev);
bus->chip_package = 0;
} else {
bus->chip_id = 0x4710;
bus->chip_rev = 0;
bus->chip_package = 0;
}
}
if (!bus->nr_devices)
bus->nr_devices = chipid_to_nrcores(bus->chip_id);
if (bus->nr_devices > ARRAY_SIZE(bus->devices)) {
ssb_printk(KERN_ERR PFX
"More than %d ssb cores found (%d)\n",
SSB_MAX_NR_CORES, bus->nr_devices);
goto err_unmap;
}
if (bus->bustype == SSB_BUSTYPE_SSB) {
/* Now that we know the number of cores,
* remap the whole IO space for all cores.
*/
err = -ENOMEM;
iounmap(mmio);
mmio = ioremap(baseaddr, SSB_CORE_SIZE * bus->nr_devices);
if (!mmio)
goto out;
bus->mmio = mmio;
}
/* Fetch basic information about each core/device */
for (i = 0, dev_i = 0; i < bus->nr_devices; i++) {
err = scan_switchcore(bus, i);
if (err)
goto err_unmap;
dev = &(bus->devices[dev_i]);
idhi = scan_read32(bus, i, SSB_IDHIGH);
dev->id.coreid = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
dev->id.revision = (idhi & SSB_IDHIGH_RCLO);
dev->id.revision |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT;
dev->id.vendor = (idhi & SSB_IDHIGH_VC) >> SSB_IDHIGH_VC_SHIFT;
dev->core_index = i;
dev->bus = bus;
dev->ops = bus->ops;
ssb_dprintk(KERN_INFO PFX
"Core %d found: %s "
"(cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n",
i, ssb_core_name(dev->id.coreid),
dev->id.coreid, dev->id.revision, dev->id.vendor);
switch (dev->id.coreid) {
case SSB_DEV_80211:
nr_80211_cores++;
if (nr_80211_cores > 1) {
if (!we_support_multiple_80211_cores(bus)) {
ssb_dprintk(KERN_INFO PFX "Ignoring additional "
"802.11 core\n");
continue;
}
}
break;
case SSB_DEV_EXTIF:
#ifdef CONFIG_SSB_DRIVER_EXTIF
if (bus->extif.dev) {
ssb_printk(KERN_WARNING PFX
"WARNING: Multiple EXTIFs found\n");
break;
}
bus->extif.dev = dev;
#endif /* CONFIG_SSB_DRIVER_EXTIF */
break;
case SSB_DEV_CHIPCOMMON:
if (bus->chipco.dev) {
ssb_printk(KERN_WARNING PFX
"WARNING: Multiple ChipCommon found\n");
break;
}
bus->chipco.dev = dev;
break;
case SSB_DEV_MIPS:
case SSB_DEV_MIPS_3302:
#ifdef CONFIG_SSB_DRIVER_MIPS
if (bus->mipscore.dev) {
ssb_printk(KERN_WARNING PFX
"WARNING: Multiple MIPS cores found\n");
break;
}
bus->mipscore.dev = dev;
#endif /* CONFIG_SSB_DRIVER_MIPS */
break;
case SSB_DEV_PCI:
case SSB_DEV_PCIE:
#ifdef CONFIG_SSB_DRIVER_PCICORE
if (bus->bustype == SSB_BUSTYPE_PCI) {
/* Ignore PCI cores on PCI-E cards.
* Ignore PCI-E cores on PCI cards. */
if (dev->id.coreid == SSB_DEV_PCI) {
if (bus->host_pci->is_pcie)
continue;
} else {
if (!bus->host_pci->is_pcie)
continue;
}
}
if (bus->pcicore.dev) {
ssb_printk(KERN_WARNING PFX
"WARNING: Multiple PCI(E) cores found\n");
break;
}
bus->pcicore.dev = dev;
#endif /* CONFIG_SSB_DRIVER_PCICORE */
break;
default:
break;
}
dev_i++;
}
bus->nr_devices = dev_i;
err = 0;
out:
return err;
err_unmap:
ssb_iounmap(bus);
goto out;
}

View File

@ -0,0 +1,136 @@
#ifndef LINUX_SSB_PRIVATE_H_
#define LINUX_SSB_PRIVATE_H_
#include <linux/ssb/ssb.h>
#include <linux/types.h>
#define PFX "ssb: "
#ifdef CONFIG_SSB_SILENT
# define ssb_printk(fmt, x...) do { /* nothing */ } while (0)
#else
# define ssb_printk printk
#endif /* CONFIG_SSB_SILENT */
/* dprintk: Debugging printk; vanishes for non-debug compilation */
#ifdef CONFIG_SSB_DEBUG
# define ssb_dprintk(fmt, x...) ssb_printk(fmt , ##x)
#else
# define ssb_dprintk(fmt, x...) do { /* nothing */ } while (0)
#endif
#ifdef CONFIG_SSB_DEBUG
# define SSB_WARN_ON(x) WARN_ON(x)
# define SSB_BUG_ON(x) BUG_ON(x)
#else
static inline int __ssb_do_nothing(int x) { return x; }
# define SSB_WARN_ON(x) __ssb_do_nothing(unlikely(!!(x)))
# define SSB_BUG_ON(x) __ssb_do_nothing(unlikely(!!(x)))
#endif
/* pci.c */
#ifdef CONFIG_SSB_PCIHOST
extern int ssb_pci_switch_core(struct ssb_bus *bus,
struct ssb_device *dev);
extern int ssb_pci_switch_coreidx(struct ssb_bus *bus,
u8 coreidx);
extern int ssb_pci_xtal(struct ssb_bus *bus, u32 what,
int turn_on);
extern int ssb_pci_get_invariants(struct ssb_bus *bus,
struct ssb_init_invariants *iv);
extern void ssb_pci_exit(struct ssb_bus *bus);
extern int ssb_pci_init(struct ssb_bus *bus);
extern const struct ssb_bus_ops ssb_pci_ops;
#else /* CONFIG_SSB_PCIHOST */
static inline int ssb_pci_switch_core(struct ssb_bus *bus,
struct ssb_device *dev)
{
return 0;
}
static inline int ssb_pci_switch_coreidx(struct ssb_bus *bus,
u8 coreidx)
{
return 0;
}
static inline int ssb_pci_xtal(struct ssb_bus *bus, u32 what,
int turn_on)
{
return 0;
}
static inline void ssb_pci_exit(struct ssb_bus *bus)
{
}
static inline int ssb_pci_init(struct ssb_bus *bus)
{
return 0;
}
#endif /* CONFIG_SSB_PCIHOST */
/* pcmcia.c */
#ifdef CONFIG_SSB_PCMCIAHOST
extern int ssb_pcmcia_switch_core(struct ssb_bus *bus,
struct ssb_device *dev);
extern int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
u8 coreidx);
extern int ssb_pcmcia_switch_segment(struct ssb_bus *bus,
u8 seg);
extern int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
struct ssb_init_invariants *iv);
extern int ssb_pcmcia_init(struct ssb_bus *bus);
extern const struct ssb_bus_ops ssb_pcmcia_ops;
#else /* CONFIG_SSB_PCMCIAHOST */
static inline int ssb_pcmcia_switch_core(struct ssb_bus *bus,
struct ssb_device *dev)
{
return 0;
}
static inline int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
u8 coreidx)
{
return 0;
}
static inline int ssb_pcmcia_switch_segment(struct ssb_bus *bus,
u8 seg)
{
return 0;
}
static inline int ssb_pcmcia_init(struct ssb_bus *bus)
{
return 0;
}
#endif /* CONFIG_SSB_PCMCIAHOST */
/* scan.c */
extern const char *ssb_core_name(u16 coreid);
extern int ssb_bus_scan(struct ssb_bus *bus,
unsigned long baseaddr);
extern void ssb_iounmap(struct ssb_bus *ssb);
/* core.c */
extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m);
extern int ssb_devices_freeze(struct ssb_bus *bus);
extern int ssb_devices_thaw(struct ssb_bus *bus);
extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev);
/* b43_pci_bridge.c */
#ifdef CONFIG_SSB_PCIHOST
extern int __init b43_pci_ssb_bridge_init(void);
extern void __exit b43_pci_ssb_bridge_exit(void);
#else /* CONFIG_SSB_PCIHOST */
static inline int b43_pci_ssb_bridge_init(void)
{
return 0;
}
static inline void b43_pci_ssb_bridge_exit(void)
{
}
#endif /* CONFIG_SSB_PCIHOST */
#endif /* LINUX_SSB_PRIVATE_H_ */

View File

@ -0,0 +1,35 @@
/*
* Definitions for the GPIO buttons interface driver
*
* Copyright (C) 2007,2008 Gabor Juhos <juhosg at openwrt.org>
*
* This file was based on: /include/linux/gpio_keys.h
* The original gpio_keys.h seems not to have a license.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef _GPIO_BUTTONS_H_
#define _GPIO_BUTTONS_H_
struct gpio_button {
int gpio; /* GPIO line number */
int active_low;
char *desc; /* button description */
int type; /* input event type (EV_KEY, EV_SW) */
int code; /* input event code (KEY_*, SW_*) */
int count;
int threshold; /* count threshold */
};
struct gpio_buttons_platform_data {
struct gpio_button *buttons;
int nbuttons; /* number of buttons */
int poll_interval; /* polling interval */
};
#endif /* _GPIO_BUTTONS_H_ */

View File

@ -0,0 +1,11 @@
#ifndef _GPIODEV_H__
#define _GPIODEV_H__
#define IOC_GPIODEV_MAGIC 'B'
#define GPIO_GET _IO(IOC_GPIODEV_MAGIC, 10)
#define GPIO_SET _IO(IOC_GPIODEV_MAGIC, 11)
#define GPIO_CLEAR _IO(IOC_GPIODEV_MAGIC, 12)
#define GPIO_DIR_IN _IO(IOC_GPIODEV_MAGIC, 13)
#define GPIO_DIR_OUT _IO(IOC_GPIODEV_MAGIC, 14)
#endif

View File

@ -0,0 +1,53 @@
/*
* spi_gpio interface to platform code
*
* Copyright (c) 2008 Piotr Skamruk
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _LINUX_SPI_SPI_GPIO
#define _LINUX_SPI_SPI_GPIO
#include <linux/types.h>
#include <linux/spi/spi.h>
/** struct spi_gpio_platform_data - Data definitions for a SPI-GPIO device.
* This structure holds information about a GPIO-based SPI device.
*
* @pin_clk: The GPIO pin number of the CLOCK pin.
*
* @pin_miso: The GPIO pin number of the MISO pin.
*
* @pin_mosi: The GPIO pin number of the MOSI pin.
*
* @pin_cs: The GPIO pin number of the CHIPSELECT pin.
*
* @cs_activelow: If true, the chip is selected when the CS line is low.
*
* @no_spi_delay: If true, no delay is done in the lowlevel bitbanging.
* Note that doing no delay is not standards compliant,
* but it might be needed to speed up transfers on some
* slow embedded machines.
*
* @boardinfo_setup: This callback is called after the
* SPI master device was registered, but before the
* device is registered.
* @boardinfo_setup_data: Data argument passed to boardinfo_setup().
*/
struct spi_gpio_platform_data {
unsigned int pin_clk;
unsigned int pin_miso;
unsigned int pin_mosi;
unsigned int pin_cs;
bool cs_activelow;
bool no_spi_delay;
int (*boardinfo_setup)(struct spi_board_info *bi,
struct spi_master *master,
void *data);
void *boardinfo_setup_data;
};
#endif /* _LINUX_SPI_SPI_GPIO */

View File

@ -0,0 +1,404 @@
#ifndef LINUX_SSB_H_
#define LINUX_SSB_H_
#include <linux/device.h>
#include <linux/list.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/pci.h>
#include <linux/mod_devicetable.h>
#include <linux/ssb/ssb_regs.h>
struct pcmcia_device;
struct ssb_bus;
struct ssb_driver;
struct ssb_sprom {
u8 revision;
u8 il0mac[6]; /* MAC address for 802.11b/g */
u8 et0mac[6]; /* MAC address for Ethernet */
u8 et1mac[6]; /* MAC address for 802.11a */
u8 et0phyaddr; /* MII address for enet0 */
u8 et1phyaddr; /* MII address for enet1 */
u8 et0mdcport; /* MDIO for enet0 */
u8 et1mdcport; /* MDIO for enet1 */
u8 board_rev; /* Board revision number from SPROM. */
u8 country_code; /* Country Code */
u8 ant_available_a; /* A-PHY antenna available bits (up to 4) */
u8 ant_available_bg; /* B/G-PHY antenna available bits (up to 4) */
u16 pa0b0;
u16 pa0b1;
u16 pa0b2;
u16 pa1b0;
u16 pa1b1;
u16 pa1b2;
u8 gpio0; /* GPIO pin 0 */
u8 gpio1; /* GPIO pin 1 */
u8 gpio2; /* GPIO pin 2 */
u8 gpio3; /* GPIO pin 3 */
u16 maxpwr_a; /* A-PHY Amplifier Max Power (in dBm Q5.2) */
u16 maxpwr_bg; /* B/G-PHY Amplifier Max Power (in dBm Q5.2) */
u8 itssi_a; /* Idle TSSI Target for A-PHY */
u8 itssi_bg; /* Idle TSSI Target for B/G-PHY */
u16 boardflags_lo; /* Boardflags (low 16 bits) */
u16 boardflags_hi; /* Boardflags (high 16 bits) */
/* Antenna gain values for up to 4 antennas
* on each band. Values in dBm/4 (Q5.2). Negative gain means the
* loss in the connectors is bigger than the gain. */
struct {
struct {
s8 a0, a1, a2, a3;
} ghz24; /* 2.4GHz band */
struct {
s8 a0, a1, a2, a3;
} ghz5; /* 5GHz band */
} antenna_gain;
/* TODO - add any parameters needed from rev 2, 3, or 4 SPROMs */
};
/* Information about the PCB the circuitry is soldered on. */
struct ssb_boardinfo {
u16 vendor;
u16 type;
u16 rev;
};
struct ssb_device;
/* Lowlevel read/write operations on the device MMIO.
* Internal, don't use that outside of ssb. */
struct ssb_bus_ops {
u16 (*read16)(struct ssb_device *dev, u16 offset);
u32 (*read32)(struct ssb_device *dev, u16 offset);
void (*write16)(struct ssb_device *dev, u16 offset, u16 value);
void (*write32)(struct ssb_device *dev, u16 offset, u32 value);
};
/* Core-ID values. */
#define SSB_DEV_CHIPCOMMON 0x800
#define SSB_DEV_ILINE20 0x801
#define SSB_DEV_SDRAM 0x803
#define SSB_DEV_PCI 0x804
#define SSB_DEV_MIPS 0x805
#define SSB_DEV_ETHERNET 0x806
#define SSB_DEV_V90 0x807
#define SSB_DEV_USB11_HOSTDEV 0x808
#define SSB_DEV_ADSL 0x809
#define SSB_DEV_ILINE100 0x80A
#define SSB_DEV_IPSEC 0x80B
#define SSB_DEV_PCMCIA 0x80D
#define SSB_DEV_INTERNAL_MEM 0x80E
#define SSB_DEV_MEMC_SDRAM 0x80F
#define SSB_DEV_EXTIF 0x811
#define SSB_DEV_80211 0x812
#define SSB_DEV_MIPS_3302 0x816
#define SSB_DEV_USB11_HOST 0x817
#define SSB_DEV_USB11_DEV 0x818
#define SSB_DEV_USB20_HOST 0x819
#define SSB_DEV_USB20_DEV 0x81A
#define SSB_DEV_SDIO_HOST 0x81B
#define SSB_DEV_ROBOSWITCH 0x81C
#define SSB_DEV_PARA_ATA 0x81D
#define SSB_DEV_SATA_XORDMA 0x81E
#define SSB_DEV_ETHERNET_GBIT 0x81F
#define SSB_DEV_PCIE 0x820
#define SSB_DEV_MIMO_PHY 0x821
#define SSB_DEV_SRAM_CTRLR 0x822
#define SSB_DEV_MINI_MACPHY 0x823
#define SSB_DEV_ARM_1176 0x824
#define SSB_DEV_ARM_7TDMI 0x825
/* Vendor-ID values */
#define SSB_VENDOR_BROADCOM 0x4243
/* Some kernel subsystems poke with dev->drvdata, so we must use the
* following ugly workaround to get from struct device to struct ssb_device */
struct __ssb_dev_wrapper {
struct device dev;
struct ssb_device *sdev;
};
struct ssb_device {
/* Having a copy of the ops pointer in each dev struct
* is an optimization. */
const struct ssb_bus_ops *ops;
struct device *dev;
struct ssb_bus *bus;
struct ssb_device_id id;
u8 core_index;
unsigned int irq;
/* Internal-only stuff follows. */
void *drvdata; /* Per-device data */
void *devtypedata; /* Per-devicetype (eg 802.11) data */
};
/* Go from struct device to struct ssb_device. */
static inline
struct ssb_device * dev_to_ssb_dev(struct device *dev)
{
struct __ssb_dev_wrapper *wrap;
wrap = container_of(dev, struct __ssb_dev_wrapper, dev);
return wrap->sdev;
}
/* Device specific user data */
static inline
void ssb_set_drvdata(struct ssb_device *dev, void *data)
{
dev->drvdata = data;
}
static inline
void * ssb_get_drvdata(struct ssb_device *dev)
{
return dev->drvdata;
}
/* Devicetype specific user data. This is per device-type (not per device) */
void ssb_set_devtypedata(struct ssb_device *dev, void *data);
static inline
void * ssb_get_devtypedata(struct ssb_device *dev)
{
return dev->devtypedata;
}
struct ssb_driver {
const char *name;
const struct ssb_device_id *id_table;
int (*probe)(struct ssb_device *dev, const struct ssb_device_id *id);
void (*remove)(struct ssb_device *dev);
int (*suspend)(struct ssb_device *dev, pm_message_t state);
int (*resume)(struct ssb_device *dev);
void (*shutdown)(struct ssb_device *dev);
struct device_driver drv;
};
#define drv_to_ssb_drv(_drv) container_of(_drv, struct ssb_driver, drv)
extern int __ssb_driver_register(struct ssb_driver *drv, struct module *owner);
static inline int ssb_driver_register(struct ssb_driver *drv)
{
return __ssb_driver_register(drv, THIS_MODULE);
}
extern void ssb_driver_unregister(struct ssb_driver *drv);
enum ssb_bustype {
SSB_BUSTYPE_SSB, /* This SSB bus is the system bus */
SSB_BUSTYPE_PCI, /* SSB is connected to PCI bus */
SSB_BUSTYPE_PCMCIA, /* SSB is connected to PCMCIA bus */
};
/* board_vendor */
#define SSB_BOARDVENDOR_BCM 0x14E4 /* Broadcom */
#define SSB_BOARDVENDOR_DELL 0x1028 /* Dell */
#define SSB_BOARDVENDOR_HP 0x0E11 /* HP */
/* board_type */
#define SSB_BOARD_BCM94306MP 0x0418
#define SSB_BOARD_BCM4309G 0x0421
#define SSB_BOARD_BCM4306CB 0x0417
#define SSB_BOARD_BCM4309MP 0x040C
#define SSB_BOARD_MP4318 0x044A
#define SSB_BOARD_BU4306 0x0416
#define SSB_BOARD_BU4309 0x040A
/* chip_package */
#define SSB_CHIPPACK_BCM4712S 1 /* Small 200pin 4712 */
#define SSB_CHIPPACK_BCM4712M 2 /* Medium 225pin 4712 */
#define SSB_CHIPPACK_BCM4712L 0 /* Large 340pin 4712 */
#include <linux/ssb/ssb_driver_chipcommon.h>
#include <linux/ssb/ssb_driver_mips.h>
#include <linux/ssb/ssb_driver_extif.h>
#include <linux/ssb/ssb_driver_pci.h>
struct ssb_bus {
/* The MMIO area. */
void __iomem *mmio;
const struct ssb_bus_ops *ops;
/* The core in the basic address register window. (PCI bus only) */
struct ssb_device *mapped_device;
/* Currently mapped PCMCIA segment. (bustype == SSB_BUSTYPE_PCMCIA only) */
u8 mapped_pcmcia_seg;
/* Lock for core and segment switching.
* On PCMCIA-host busses this is used to protect the whole MMIO access. */
spinlock_t bar_lock;
/* The bus this backplane is running on. */
enum ssb_bustype bustype;
/* Pointer to the PCI bus (only valid if bustype == SSB_BUSTYPE_PCI). */
struct pci_dev *host_pci;
/* Pointer to the PCMCIA device (only if bustype == SSB_BUSTYPE_PCMCIA). */
struct pcmcia_device *host_pcmcia;
#ifdef CONFIG_SSB_PCIHOST
/* Mutex to protect the SPROM writing. */
struct mutex pci_sprom_mutex;
#endif
/* ID information about the Chip. */
u16 chip_id;
u16 chip_rev;
u16 sprom_size; /* number of words in sprom */
u8 chip_package;
/* List of devices (cores) on the backplane. */
struct ssb_device devices[SSB_MAX_NR_CORES];
u8 nr_devices;
/* Reference count. Number of suspended devices. */
u8 suspend_cnt;
/* Software ID number for this bus. */
unsigned int busnumber;
/* The ChipCommon device (if available). */
struct ssb_chipcommon chipco;
/* The PCI-core device (if available). */
struct ssb_pcicore pcicore;
/* The MIPS-core device (if available). */
struct ssb_mipscore mipscore;
/* The EXTif-core device (if available). */
struct ssb_extif extif;
/* The following structure elements are not available in early
* SSB initialization. Though, they are available for regular
* registered drivers at any stage. So be careful when
* using them in the ssb core code. */
/* ID information about the PCB. */
struct ssb_boardinfo boardinfo;
/* Contents of the SPROM. */
struct ssb_sprom sprom;
/* Internal-only stuff follows. Do not touch. */
struct list_head list;
#ifdef CONFIG_SSB_DEBUG
/* Is the bus already powered up? */
bool powered_up;
int power_warn_count;
#endif /* DEBUG */
};
/* The initialization-invariants. */
struct ssb_init_invariants {
struct ssb_boardinfo boardinfo;
struct ssb_sprom sprom;
};
/* Type of function to fetch the invariants. */
typedef int (*ssb_invariants_func_t)(struct ssb_bus *bus,
struct ssb_init_invariants *iv);
/* Register a SSB system bus. get_invariants() is called after the
* basic system devices are initialized.
* The invariants are usually fetched from some NVRAM.
* Put the invariants into the struct pointed to by iv. */
extern int ssb_bus_ssbbus_register(struct ssb_bus *bus,
unsigned long baseaddr,
ssb_invariants_func_t get_invariants);
#ifdef CONFIG_SSB_PCIHOST
extern int ssb_bus_pcibus_register(struct ssb_bus *bus,
struct pci_dev *host_pci);
#endif /* CONFIG_SSB_PCIHOST */
#ifdef CONFIG_SSB_PCMCIAHOST
extern int ssb_bus_pcmciabus_register(struct ssb_bus *bus,
struct pcmcia_device *pcmcia_dev,
unsigned long baseaddr);
#endif /* CONFIG_SSB_PCMCIAHOST */
extern void ssb_bus_unregister(struct ssb_bus *bus);
extern u32 ssb_clockspeed(struct ssb_bus *bus);
/* Is the device enabled in hardware? */
int ssb_device_is_enabled(struct ssb_device *dev);
/* Enable a device and pass device-specific SSB_TMSLOW flags.
* If no device-specific flags are available, use 0. */
void ssb_device_enable(struct ssb_device *dev, u32 core_specific_flags);
/* Disable a device in hardware and pass SSB_TMSLOW flags (if any). */
void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags);
/* Device MMIO register read/write functions. */
static inline u16 ssb_read16(struct ssb_device *dev, u16 offset)
{
return dev->ops->read16(dev, offset);
}
static inline u32 ssb_read32(struct ssb_device *dev, u16 offset)
{
return dev->ops->read32(dev, offset);
}
static inline void ssb_write16(struct ssb_device *dev, u16 offset, u16 value)
{
dev->ops->write16(dev, offset, value);
}
static inline void ssb_write32(struct ssb_device *dev, u16 offset, u32 value)
{
dev->ops->write32(dev, offset, value);
}
/* Translation (routing) bits that need to be ORed to DMA
* addresses before they are given to a device. */
extern u32 ssb_dma_translation(struct ssb_device *dev);
#define SSB_DMA_TRANSLATION_MASK 0xC0000000
#define SSB_DMA_TRANSLATION_SHIFT 30
extern int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask);
#ifdef CONFIG_SSB_PCIHOST
/* PCI-host wrapper driver */
extern int ssb_pcihost_register(struct pci_driver *driver);
static inline void ssb_pcihost_unregister(struct pci_driver *driver)
{
pci_unregister_driver(driver);
}
static inline
void ssb_pcihost_set_power_state(struct ssb_device *sdev, pci_power_t state)
{
if (sdev->bus->bustype == SSB_BUSTYPE_PCI)
pci_set_power_state(sdev->bus->host_pci, state);
}
#else
static inline void ssb_pcihost_unregister(struct pci_driver *driver)
{
}
static inline
void ssb_pcihost_set_power_state(struct ssb_device *sdev, pci_power_t state)
{
}
#endif /* CONFIG_SSB_PCIHOST */
/* If a driver is shutdown or suspended, call this to signal
* that the bus may be completely powered down. SSB will decide,
* if it's really time to power down the bus, based on if there
* are other devices that want to run. */
extern int ssb_bus_may_powerdown(struct ssb_bus *bus);
/* Before initializing and enabling a device, call this to power-up the bus.
* If you want to allow use of dynamic-power-control, pass the flag.
* Otherwise static always-on powercontrol will be used. */
extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl);
/* Various helper functions */
extern u32 ssb_admatch_base(u32 adm);
extern u32 ssb_admatch_size(u32 adm);
#endif /* LINUX_SSB_H_ */

View File

@ -0,0 +1,396 @@
#ifndef LINUX_SSB_CHIPCO_H_
#define LINUX_SSB_CHIPCO_H_
/* SonicsSiliconBackplane CHIPCOMMON core hardware definitions
*
* The chipcommon core provides chip identification, SB control,
* jtag, 0/1/2 uarts, clock frequency control, a watchdog interrupt timer,
* gpio interface, extbus, and support for serial and parallel flashes.
*
* Copyright 2005, Broadcom Corporation
* Copyright 2006, Michael Buesch <mb@bu3sch.de>
*
* Licensed under the GPL version 2. See COPYING for details.
*/
/** ChipCommon core registers. **/
#define SSB_CHIPCO_CHIPID 0x0000
#define SSB_CHIPCO_IDMASK 0x0000FFFF
#define SSB_CHIPCO_REVMASK 0x000F0000
#define SSB_CHIPCO_REVSHIFT 16
#define SSB_CHIPCO_PACKMASK 0x00F00000
#define SSB_CHIPCO_PACKSHIFT 20
#define SSB_CHIPCO_NRCORESMASK 0x0F000000
#define SSB_CHIPCO_NRCORESSHIFT 24
#define SSB_CHIPCO_CAP 0x0004 /* Capabilities */
#define SSB_CHIPCO_CAP_NRUART 0x00000003 /* # of UARTs */
#define SSB_CHIPCO_CAP_MIPSEB 0x00000004 /* MIPS in BigEndian Mode */
#define SSB_CHIPCO_CAP_UARTCLK 0x00000018 /* UART clock select */
#define SSB_CHIPCO_CAP_UARTCLK_INT 0x00000008 /* UARTs are driven by internal divided clock */
#define SSB_CHIPCO_CAP_UARTGPIO 0x00000020 /* UARTs on GPIO 15-12 */
#define SSB_CHIPCO_CAP_EXTBUS 0x000000C0 /* External buses present */
#define SSB_CHIPCO_CAP_FLASHT 0x00000700 /* Flash Type */
#define SSB_CHIPCO_FLASHT_NONE 0x00000000 /* No flash */
#define SSB_CHIPCO_FLASHT_STSER 0x00000100 /* ST serial flash */
#define SSB_CHIPCO_FLASHT_ATSER 0x00000200 /* Atmel serial flash */
#define SSB_CHIPCO_FLASHT_PARA 0x00000700 /* Parallel flash */
#define SSB_CHIPCO_CAP_PLLT 0x00038000 /* PLL Type */
#define SSB_PLLTYPE_NONE 0x00000000
#define SSB_PLLTYPE_1 0x00010000 /* 48Mhz base, 3 dividers */
#define SSB_PLLTYPE_2 0x00020000 /* 48Mhz, 4 dividers */
#define SSB_PLLTYPE_3 0x00030000 /* 25Mhz, 2 dividers */
#define SSB_PLLTYPE_4 0x00008000 /* 48Mhz, 4 dividers */
#define SSB_PLLTYPE_5 0x00018000 /* 25Mhz, 4 dividers */
#define SSB_PLLTYPE_6 0x00028000 /* 100/200 or 120/240 only */
#define SSB_PLLTYPE_7 0x00038000 /* 25Mhz, 4 dividers */
#define SSB_CHIPCO_CAP_PCTL 0x00040000 /* Power Control */
#define SSB_CHIPCO_CAP_OTPS 0x00380000 /* OTP size */
#define SSB_CHIPCO_CAP_OTPS_SHIFT 19
#define SSB_CHIPCO_CAP_OTPS_BASE 5
#define SSB_CHIPCO_CAP_JTAGM 0x00400000 /* JTAG master present */
#define SSB_CHIPCO_CAP_BROM 0x00800000 /* Internal boot ROM active */
#define SSB_CHIPCO_CAP_64BIT 0x08000000 /* 64-bit Backplane */
#define SSB_CHIPCO_CORECTL 0x0008
#define SSB_CHIPCO_CORECTL_UARTCLK0 0x00000001 /* Drive UART with internal clock */
#define SSB_CHIPCO_CORECTL_SE 0x00000002 /* sync clk out enable (corerev >= 3) */
#define SSB_CHIPCO_BIST 0x000C
#define SSB_CHIPCO_OTPS 0x0010 /* OTP status */
#define SSB_CHIPCO_OTPS_PROGFAIL 0x80000000
#define SSB_CHIPCO_OTPS_PROTECT 0x00000007
#define SSB_CHIPCO_OTPS_HW_PROTECT 0x00000001
#define SSB_CHIPCO_OTPS_SW_PROTECT 0x00000002
#define SSB_CHIPCO_OTPS_CID_PROTECT 0x00000004
#define SSB_CHIPCO_OTPC 0x0014 /* OTP control */
#define SSB_CHIPCO_OTPC_RECWAIT 0xFF000000
#define SSB_CHIPCO_OTPC_PROGWAIT 0x00FFFF00
#define SSB_CHIPCO_OTPC_PRW_SHIFT 8
#define SSB_CHIPCO_OTPC_MAXFAIL 0x00000038
#define SSB_CHIPCO_OTPC_VSEL 0x00000006
#define SSB_CHIPCO_OTPC_SELVL 0x00000001
#define SSB_CHIPCO_OTPP 0x0018 /* OTP prog */
#define SSB_CHIPCO_OTPP_COL 0x000000FF
#define SSB_CHIPCO_OTPP_ROW 0x0000FF00
#define SSB_CHIPCO_OTPP_ROW_SHIFT 8
#define SSB_CHIPCO_OTPP_READERR 0x10000000
#define SSB_CHIPCO_OTPP_VALUE 0x20000000
#define SSB_CHIPCO_OTPP_READ 0x40000000
#define SSB_CHIPCO_OTPP_START 0x80000000
#define SSB_CHIPCO_OTPP_BUSY 0x80000000
#define SSB_CHIPCO_IRQSTAT 0x0020
#define SSB_CHIPCO_IRQMASK 0x0024
#define SSB_CHIPCO_IRQ_GPIO 0x00000001 /* gpio intr */
#define SSB_CHIPCO_IRQ_EXT 0x00000002 /* ro: ext intr pin (corerev >= 3) */
#define SSB_CHIPCO_IRQ_WDRESET 0x80000000 /* watchdog reset occurred */
#define SSB_CHIPCO_CHIPCTL 0x0028 /* Rev >= 11 only */
#define SSB_CHIPCO_CHIPSTAT 0x002C /* Rev >= 11 only */
#define SSB_CHIPCO_JCMD 0x0030 /* Rev >= 10 only */
#define SSB_CHIPCO_JCMD_START 0x80000000
#define SSB_CHIPCO_JCMD_BUSY 0x80000000
#define SSB_CHIPCO_JCMD_PAUSE 0x40000000
#define SSB_CHIPCO_JCMD0_ACC_MASK 0x0000F000
#define SSB_CHIPCO_JCMD0_ACC_IRDR 0x00000000
#define SSB_CHIPCO_JCMD0_ACC_DR 0x00001000
#define SSB_CHIPCO_JCMD0_ACC_IR 0x00002000
#define SSB_CHIPCO_JCMD0_ACC_RESET 0x00003000
#define SSB_CHIPCO_JCMD0_ACC_IRPDR 0x00004000
#define SSB_CHIPCO_JCMD0_ACC_PDR 0x00005000
#define SSB_CHIPCO_JCMD0_IRW_MASK 0x00000F00
#define SSB_CHIPCO_JCMD_ACC_MASK 0x000F0000 /* Changes for corerev 11 */
#define SSB_CHIPCO_JCMD_ACC_IRDR 0x00000000
#define SSB_CHIPCO_JCMD_ACC_DR 0x00010000
#define SSB_CHIPCO_JCMD_ACC_IR 0x00020000
#define SSB_CHIPCO_JCMD_ACC_RESET 0x00030000
#define SSB_CHIPCO_JCMD_ACC_IRPDR 0x00040000
#define SSB_CHIPCO_JCMD_ACC_PDR 0x00050000
#define SSB_CHIPCO_JCMD_IRW_MASK 0x00001F00
#define SSB_CHIPCO_JCMD_IRW_SHIFT 8
#define SSB_CHIPCO_JCMD_DRW_MASK 0x0000003F
#define SSB_CHIPCO_JIR 0x0034 /* Rev >= 10 only */
#define SSB_CHIPCO_JDR 0x0038 /* Rev >= 10 only */
#define SSB_CHIPCO_JCTL 0x003C /* Rev >= 10 only */
#define SSB_CHIPCO_JCTL_FORCE_CLK 4 /* Force clock */
#define SSB_CHIPCO_JCTL_EXT_EN 2 /* Enable external targets */
#define SSB_CHIPCO_JCTL_EN 1 /* Enable Jtag master */
#define SSB_CHIPCO_FLASHCTL 0x0040
#define SSB_CHIPCO_FLASHCTL_START 0x80000000
#define SSB_CHIPCO_FLASHCTL_BUSY SSB_CHIPCO_FLASHCTL_START
#define SSB_CHIPCO_FLASHADDR 0x0044
#define SSB_CHIPCO_FLASHDATA 0x0048
#define SSB_CHIPCO_BCAST_ADDR 0x0050
#define SSB_CHIPCO_BCAST_DATA 0x0054
#define SSB_CHIPCO_GPIOIN 0x0060
#define SSB_CHIPCO_GPIOOUT 0x0064
#define SSB_CHIPCO_GPIOOUTEN 0x0068
#define SSB_CHIPCO_GPIOCTL 0x006C
#define SSB_CHIPCO_GPIOPOL 0x0070
#define SSB_CHIPCO_GPIOIRQ 0x0074
#define SSB_CHIPCO_WATCHDOG 0x0080
#define SSB_CHIPCO_GPIOTIMER 0x0088 /* LED powersave (corerev >= 16) */
#define SSB_CHIPCO_GPIOTIMER_ONTIME_SHIFT 16
#define SSB_CHIPCO_GPIOTOUTM 0x008C /* LED powersave (corerev >= 16) */
#define SSB_CHIPCO_CLOCK_N 0x0090
#define SSB_CHIPCO_CLOCK_SB 0x0094
#define SSB_CHIPCO_CLOCK_PCI 0x0098
#define SSB_CHIPCO_CLOCK_M2 0x009C
#define SSB_CHIPCO_CLOCK_MIPS 0x00A0
#define SSB_CHIPCO_CLKDIV 0x00A4 /* Rev >= 3 only */
#define SSB_CHIPCO_CLKDIV_SFLASH 0x0F000000
#define SSB_CHIPCO_CLKDIV_SFLASH_SHIFT 24
#define SSB_CHIPCO_CLKDIV_OTP 0x000F0000
#define SSB_CHIPCO_CLKDIV_OTP_SHIFT 16
#define SSB_CHIPCO_CLKDIV_JTAG 0x00000F00
#define SSB_CHIPCO_CLKDIV_JTAG_SHIFT 8
#define SSB_CHIPCO_CLKDIV_UART 0x000000FF
#define SSB_CHIPCO_PLLONDELAY 0x00B0 /* Rev >= 4 only */
#define SSB_CHIPCO_FREFSELDELAY 0x00B4 /* Rev >= 4 only */
#define SSB_CHIPCO_SLOWCLKCTL 0x00B8 /* 6 <= Rev <= 9 only */
#define SSB_CHIPCO_SLOWCLKCTL_SRC 0x00000007 /* slow clock source mask */
#define SSB_CHIPCO_SLOWCLKCTL_SRC_LPO 0x00000000 /* source of slow clock is LPO */
#define SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL 0x00000001 /* source of slow clock is crystal */
#define SSB_CHIPCO_SLOECLKCTL_SRC_PCI 0x00000002 /* source of slow clock is PCI */
#define SSB_CHIPCO_SLOWCLKCTL_LPOFREQ 0x00000200 /* LPOFreqSel, 1: 160Khz, 0: 32KHz */
#define SSB_CHIPCO_SLOWCLKCTL_LPOPD 0x00000400 /* LPOPowerDown, 1: LPO is disabled, 0: LPO is enabled */
#define SSB_CHIPCO_SLOWCLKCTL_FSLOW 0x00000800 /* ForceSlowClk, 1: sb/cores running on slow clock, 0: power logic control */
#define SSB_CHIPCO_SLOWCLKCTL_IPLL 0x00001000 /* IgnorePllOffReq, 1/0: power logic ignores/honors PLL clock disable requests from core */
#define SSB_CHIPCO_SLOWCLKCTL_ENXTAL 0x00002000 /* XtalControlEn, 1/0: power logic does/doesn't disable crystal when appropriate */
#define SSB_CHIPCO_SLOWCLKCTL_XTALPU 0x00004000 /* XtalPU (RO), 1/0: crystal running/disabled */
#define SSB_CHIPCO_SLOWCLKCTL_CLKDIV 0xFFFF0000 /* ClockDivider (SlowClk = 1/(4+divisor)) */
#define SSB_CHIPCO_SLOWCLKCTL_CLKDIV_SHIFT 16
#define SSB_CHIPCO_SYSCLKCTL 0x00C0 /* Rev >= 3 only */
#define SSB_CHIPCO_SYSCLKCTL_IDLPEN 0x00000001 /* ILPen: Enable Idle Low Power */
#define SSB_CHIPCO_SYSCLKCTL_ALPEN 0x00000002 /* ALPen: Enable Active Low Power */
#define SSB_CHIPCO_SYSCLKCTL_PLLEN 0x00000004 /* ForcePLLOn */
#define SSB_CHIPCO_SYSCLKCTL_FORCEALP 0x00000008 /* Force ALP (or HT if ALPen is not set */
#define SSB_CHIPCO_SYSCLKCTL_FORCEHT 0x00000010 /* Force HT */
#define SSB_CHIPCO_SYSCLKCTL_CLKDIV 0xFFFF0000 /* ClkDiv (ILP = 1/(4+divisor)) */
#define SSB_CHIPCO_SYSCLKCTL_CLKDIV_SHIFT 16
#define SSB_CHIPCO_CLKSTSTR 0x00C4 /* Rev >= 3 only */
#define SSB_CHIPCO_PCMCIA_CFG 0x0100
#define SSB_CHIPCO_PCMCIA_MEMWAIT 0x0104
#define SSB_CHIPCO_PCMCIA_ATTRWAIT 0x0108
#define SSB_CHIPCO_PCMCIA_IOWAIT 0x010C
#define SSB_CHIPCO_IDE_CFG 0x0110
#define SSB_CHIPCO_IDE_MEMWAIT 0x0114
#define SSB_CHIPCO_IDE_ATTRWAIT 0x0118
#define SSB_CHIPCO_IDE_IOWAIT 0x011C
#define SSB_CHIPCO_PROG_CFG 0x0120
#define SSB_CHIPCO_PROG_WAITCNT 0x0124
#define SSB_CHIPCO_FLASH_CFG 0x0128
#define SSB_CHIPCO_FLASH_WAITCNT 0x012C
#define SSB_CHIPCO_UART0_DATA 0x0300
#define SSB_CHIPCO_UART0_IMR 0x0304
#define SSB_CHIPCO_UART0_FCR 0x0308
#define SSB_CHIPCO_UART0_LCR 0x030C
#define SSB_CHIPCO_UART0_MCR 0x0310
#define SSB_CHIPCO_UART0_LSR 0x0314
#define SSB_CHIPCO_UART0_MSR 0x0318
#define SSB_CHIPCO_UART0_SCRATCH 0x031C
#define SSB_CHIPCO_UART1_DATA 0x0400
#define SSB_CHIPCO_UART1_IMR 0x0404
#define SSB_CHIPCO_UART1_FCR 0x0408
#define SSB_CHIPCO_UART1_LCR 0x040C
#define SSB_CHIPCO_UART1_MCR 0x0410
#define SSB_CHIPCO_UART1_LSR 0x0414
#define SSB_CHIPCO_UART1_MSR 0x0418
#define SSB_CHIPCO_UART1_SCRATCH 0x041C
/** Clockcontrol masks and values **/
/* SSB_CHIPCO_CLOCK_N */
#define SSB_CHIPCO_CLK_N1 0x0000003F /* n1 control */
#define SSB_CHIPCO_CLK_N2 0x00003F00 /* n2 control */
#define SSB_CHIPCO_CLK_N2_SHIFT 8
#define SSB_CHIPCO_CLK_PLLC 0x000F0000 /* pll control */
#define SSB_CHIPCO_CLK_PLLC_SHIFT 16
/* SSB_CHIPCO_CLOCK_SB/PCI/UART */
#define SSB_CHIPCO_CLK_M1 0x0000003F /* m1 control */
#define SSB_CHIPCO_CLK_M2 0x00003F00 /* m2 control */
#define SSB_CHIPCO_CLK_M2_SHIFT 8
#define SSB_CHIPCO_CLK_M3 0x003F0000 /* m3 control */
#define SSB_CHIPCO_CLK_M3_SHIFT 16
#define SSB_CHIPCO_CLK_MC 0x1F000000 /* mux control */
#define SSB_CHIPCO_CLK_MC_SHIFT 24
/* N3M Clock control magic field values */
#define SSB_CHIPCO_CLK_F6_2 0x02 /* A factor of 2 in */
#define SSB_CHIPCO_CLK_F6_3 0x03 /* 6-bit fields like */
#define SSB_CHIPCO_CLK_F6_4 0x05 /* N1, M1 or M3 */
#define SSB_CHIPCO_CLK_F6_5 0x09
#define SSB_CHIPCO_CLK_F6_6 0x11
#define SSB_CHIPCO_CLK_F6_7 0x21
#define SSB_CHIPCO_CLK_F5_BIAS 5 /* 5-bit fields get this added */
#define SSB_CHIPCO_CLK_MC_BYPASS 0x08
#define SSB_CHIPCO_CLK_MC_M1 0x04
#define SSB_CHIPCO_CLK_MC_M1M2 0x02
#define SSB_CHIPCO_CLK_MC_M1M2M3 0x01
#define SSB_CHIPCO_CLK_MC_M1M3 0x11
/* Type 2 Clock control magic field values */
#define SSB_CHIPCO_CLK_T2_BIAS 2 /* n1, n2, m1 & m3 bias */
#define SSB_CHIPCO_CLK_T2M2_BIAS 3 /* m2 bias */
#define SSB_CHIPCO_CLK_T2MC_M1BYP 1
#define SSB_CHIPCO_CLK_T2MC_M2BYP 2
#define SSB_CHIPCO_CLK_T2MC_M3BYP 4
/* Type 6 Clock control magic field values */
#define SSB_CHIPCO_CLK_T6_MMASK 1 /* bits of interest in m */
#define SSB_CHIPCO_CLK_T6_M0 120000000 /* sb clock for m = 0 */
#define SSB_CHIPCO_CLK_T6_M1 100000000 /* sb clock for m = 1 */
#define SSB_CHIPCO_CLK_SB2MIPS_T6(sb) (2 * (sb))
/* Common clock base */
#define SSB_CHIPCO_CLK_BASE1 24000000 /* Half the clock freq */
#define SSB_CHIPCO_CLK_BASE2 12500000 /* Alternate crystal on some PLL's */
/* Clock control values for 200Mhz in 5350 */
#define SSB_CHIPCO_CLK_5350_N 0x0311
#define SSB_CHIPCO_CLK_5350_M 0x04020009
/** Bits in the config registers **/
#define SSB_CHIPCO_CFG_EN 0x0001 /* Enable */
#define SSB_CHIPCO_CFG_EXTM 0x000E /* Extif Mode */
#define SSB_CHIPCO_CFG_EXTM_ASYNC 0x0002 /* Async/Parallel flash */
#define SSB_CHIPCO_CFG_EXTM_SYNC 0x0004 /* Synchronous */
#define SSB_CHIPCO_CFG_EXTM_PCMCIA 0x0008 /* PCMCIA */
#define SSB_CHIPCO_CFG_EXTM_IDE 0x000A /* IDE */
#define SSB_CHIPCO_CFG_DS16 0x0010 /* Data size, 0=8bit, 1=16bit */
#define SSB_CHIPCO_CFG_CLKDIV 0x0060 /* Sync: Clock divisor */
#define SSB_CHIPCO_CFG_CLKEN 0x0080 /* Sync: Clock enable */
#define SSB_CHIPCO_CFG_BSTRO 0x0100 /* Sync: Size/Bytestrobe */
/** Flash-specific control/status values */
/* flashcontrol opcodes for ST flashes */
#define SSB_CHIPCO_FLASHCTL_ST_WREN 0x0006 /* Write Enable */
#define SSB_CHIPCO_FLASHCTL_ST_WRDIS 0x0004 /* Write Disable */
#define SSB_CHIPCO_FLASHCTL_ST_RDSR 0x0105 /* Read Status Register */
#define SSB_CHIPCO_FLASHCTL_ST_WRSR 0x0101 /* Write Status Register */
#define SSB_CHIPCO_FLASHCTL_ST_READ 0x0303 /* Read Data Bytes */
#define SSB_CHIPCO_FLASHCTL_ST_PP 0x0302 /* Page Program */
#define SSB_CHIPCO_FLASHCTL_ST_SE 0x02D8 /* Sector Erase */
#define SSB_CHIPCO_FLASHCTL_ST_BE 0x00C7 /* Bulk Erase */
#define SSB_CHIPCO_FLASHCTL_ST_DP 0x00B9 /* Deep Power-down */
#define SSB_CHIPCO_FLASHCTL_ST_RSIG 0x03AB /* Read Electronic Signature */
/* Status register bits for ST flashes */
#define SSB_CHIPCO_FLASHSTA_ST_WIP 0x01 /* Write In Progress */
#define SSB_CHIPCO_FLASHSTA_ST_WEL 0x02 /* Write Enable Latch */
#define SSB_CHIPCO_FLASHSTA_ST_BP 0x1C /* Block Protect */
#define SSB_CHIPCO_FLASHSTA_ST_BP_SHIFT 2
#define SSB_CHIPCO_FLASHSTA_ST_SRWD 0x80 /* Status Register Write Disable */
/* flashcontrol opcodes for Atmel flashes */
#define SSB_CHIPCO_FLASHCTL_AT_READ 0x07E8
#define SSB_CHIPCO_FLASHCTL_AT_PAGE_READ 0x07D2
#define SSB_CHIPCO_FLASHCTL_AT_BUF1_READ /* FIXME */
#define SSB_CHIPCO_FLASHCTL_AT_BUF2_READ /* FIXME */
#define SSB_CHIPCO_FLASHCTL_AT_STATUS 0x01D7
#define SSB_CHIPCO_FLASHCTL_AT_BUF1_WRITE 0x0384
#define SSB_CHIPCO_FLASHCTL_AT_BUF2_WRITE 0x0387
#define SSB_CHIPCO_FLASHCTL_AT_BUF1_ERASE_PRGM 0x0283 /* Erase program */
#define SSB_CHIPCO_FLASHCTL_AT_BUF2_ERASE_PRGM 0x0286 /* Erase program */
#define SSB_CHIPCO_FLASHCTL_AT_BUF1_PROGRAM 0x0288
#define SSB_CHIPCO_FLASHCTL_AT_BUF2_PROGRAM 0x0289
#define SSB_CHIPCO_FLASHCTL_AT_PAGE_ERASE 0x0281
#define SSB_CHIPCO_FLASHCTL_AT_BLOCK_ERASE 0x0250
#define SSB_CHIPCO_FLASHCTL_AT_BUF1_WRER_PRGM 0x0382 /* Write erase program */
#define SSB_CHIPCO_FLASHCTL_AT_BUF2_WRER_PRGM 0x0385 /* Write erase program */
#define SSB_CHIPCO_FLASHCTL_AT_BUF1_LOAD 0x0253
#define SSB_CHIPCO_FLASHCTL_AT_BUF2_LOAD 0x0255
#define SSB_CHIPCO_FLASHCTL_AT_BUF1_COMPARE 0x0260
#define SSB_CHIPCO_FLASHCTL_AT_BUF2_COMPARE 0x0261
#define SSB_CHIPCO_FLASHCTL_AT_BUF1_REPROGRAM 0x0258
#define SSB_CHIPCO_FLASHCTL_AT_BUF2_REPROGRAM 0x0259
/* Status register bits for Atmel flashes */
#define SSB_CHIPCO_FLASHSTA_AT_READY 0x80
#define SSB_CHIPCO_FLASHSTA_AT_MISMATCH 0x40
#define SSB_CHIPCO_FLASHSTA_AT_ID 0x38
#define SSB_CHIPCO_FLASHSTA_AT_ID_SHIFT 3
/** OTP **/
/* OTP regions */
#define SSB_CHIPCO_OTP_HW_REGION SSB_CHIPCO_OTPS_HW_PROTECT
#define SSB_CHIPCO_OTP_SW_REGION SSB_CHIPCO_OTPS_SW_PROTECT
#define SSB_CHIPCO_OTP_CID_REGION SSB_CHIPCO_OTPS_CID_PROTECT
/* OTP regions (Byte offsets from otp size) */
#define SSB_CHIPCO_OTP_SWLIM_OFF (-8)
#define SSB_CHIPCO_OTP_CIDBASE_OFF 0
#define SSB_CHIPCO_OTP_CIDLIM_OFF 8
/* Predefined OTP words (Word offset from otp size) */
#define SSB_CHIPCO_OTP_BOUNDARY_OFF (-4)
#define SSB_CHIPCO_OTP_HWSIGN_OFF (-3)
#define SSB_CHIPCO_OTP_SWSIGN_OFF (-2)
#define SSB_CHIPCO_OTP_CIDSIGN_OFF (-1)
#define SSB_CHIPCO_OTP_CID_OFF 0
#define SSB_CHIPCO_OTP_PKG_OFF 1
#define SSB_CHIPCO_OTP_FID_OFF 2
#define SSB_CHIPCO_OTP_RSV_OFF 3
#define SSB_CHIPCO_OTP_LIM_OFF 4
#define SSB_CHIPCO_OTP_SIGNATURE 0x578A
#define SSB_CHIPCO_OTP_MAGIC 0x4E56
struct ssb_device;
struct ssb_serial_port;
struct ssb_chipcommon {
struct ssb_device *dev;
u32 capabilities;
/* Fast Powerup Delay constant */
u16 fast_pwrup_delay;
};
extern void ssb_chipcommon_init(struct ssb_chipcommon *cc);
#include <linux/pm.h>
extern void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state);
extern void ssb_chipco_resume(struct ssb_chipcommon *cc);
extern void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc,
u32 *plltype, u32 *n, u32 *m);
extern void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc,
u32 *plltype, u32 *n, u32 *m);
extern void ssb_chipco_timing_init(struct ssb_chipcommon *cc,
unsigned long ns_per_cycle);
enum ssb_clkmode {
SSB_CLKMODE_SLOW,
SSB_CLKMODE_FAST,
SSB_CLKMODE_DYNAMIC,
};
extern void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc,
enum ssb_clkmode mode);
extern void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc,
u32 ticks);
u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask);
void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value);
void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value);
#ifdef CONFIG_SSB_SERIAL
extern int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
struct ssb_serial_port *ports);
#endif /* CONFIG_SSB_SERIAL */
#endif /* LINUX_SSB_CHIPCO_H_ */

View File

@ -0,0 +1,204 @@
/*
* Hardware-specific External Interface I/O core definitions
* for the BCM47xx family of SiliconBackplane-based chips.
*
* The External Interface core supports a total of three external chip selects
* supporting external interfaces. One of the external chip selects is
* used for Flash, one is used for PCMCIA, and the other may be
* programmed to support either a synchronous interface or an
* asynchronous interface. The asynchronous interface can be used to
* support external devices such as UARTs and the BCM2019 Bluetooth
* baseband processor.
* The external interface core also contains 2 on-chip 16550 UARTs, clock
* frequency control, a watchdog interrupt timer, and a GPIO interface.
*
* Copyright 2005, Broadcom Corporation
* Copyright 2006, Michael Buesch
*
* Licensed under the GPL version 2. See COPYING for details.
*/
#ifndef LINUX_SSB_EXTIFCORE_H_
#define LINUX_SSB_EXTIFCORE_H_
/* external interface address space */
#define SSB_EXTIF_PCMCIA_MEMBASE(x) (x)
#define SSB_EXTIF_PCMCIA_IOBASE(x) ((x) + 0x100000)
#define SSB_EXTIF_PCMCIA_CFGBASE(x) ((x) + 0x200000)
#define SSB_EXTIF_CFGIF_BASE(x) ((x) + 0x800000)
#define SSB_EXTIF_FLASH_BASE(x) ((x) + 0xc00000)
#define SSB_EXTIF_NR_GPIOOUT 5
/* GPIO NOTE:
* The multiple instances of output and output enable registers
* are present to allow driver software for multiple cores to control
* gpio outputs without needing to share a single register pair.
* Use the following helper macro to get a register offset value.
*/
#define SSB_EXTIF_GPIO_OUT(index) ({ \
BUILD_BUG_ON(index >= SSB_EXTIF_NR_GPIOOUT); \
SSB_EXTIF_GPIO_OUT_BASE + ((index) * 8); \
})
#define SSB_EXTIF_GPIO_OUTEN(index) ({ \
BUILD_BUG_ON(index >= SSB_EXTIF_NR_GPIOOUT); \
SSB_EXTIF_GPIO_OUTEN_BASE + ((index) * 8); \
})
/** EXTIF core registers **/
#define SSB_EXTIF_CTL 0x0000
#define SSB_EXTIF_CTL_UARTEN (1 << 0) /* UART enable */
#define SSB_EXTIF_EXTSTAT 0x0004
#define SSB_EXTIF_EXTSTAT_EMODE (1 << 0) /* Endian mode (ro) */
#define SSB_EXTIF_EXTSTAT_EIRQPIN (1 << 1) /* External interrupt pin (ro) */
#define SSB_EXTIF_EXTSTAT_GPIOIRQPIN (1 << 2) /* GPIO interrupt pin (ro) */
#define SSB_EXTIF_PCMCIA_CFG 0x0010
#define SSB_EXTIF_PCMCIA_MEMWAIT 0x0014
#define SSB_EXTIF_PCMCIA_ATTRWAIT 0x0018
#define SSB_EXTIF_PCMCIA_IOWAIT 0x001C
#define SSB_EXTIF_PROG_CFG 0x0020
#define SSB_EXTIF_PROG_WAITCNT 0x0024
#define SSB_EXTIF_FLASH_CFG 0x0028
#define SSB_EXTIF_FLASH_WAITCNT 0x002C
#define SSB_EXTIF_WATCHDOG 0x0040
#define SSB_EXTIF_CLOCK_N 0x0044
#define SSB_EXTIF_CLOCK_SB 0x0048
#define SSB_EXTIF_CLOCK_PCI 0x004C
#define SSB_EXTIF_CLOCK_MII 0x0050
#define SSB_EXTIF_GPIO_IN 0x0060
#define SSB_EXTIF_GPIO_OUT_BASE 0x0064
#define SSB_EXTIF_GPIO_OUTEN_BASE 0x0068
#define SSB_EXTIF_EJTAG_OUTEN 0x0090
#define SSB_EXTIF_GPIO_INTPOL 0x0094
#define SSB_EXTIF_GPIO_INTMASK 0x0098
#define SSB_EXTIF_UART_DATA 0x0300
#define SSB_EXTIF_UART_TIMER 0x0310
#define SSB_EXTIF_UART_FCR 0x0320
#define SSB_EXTIF_UART_LCR 0x0330
#define SSB_EXTIF_UART_MCR 0x0340
#define SSB_EXTIF_UART_LSR 0x0350
#define SSB_EXTIF_UART_MSR 0x0360
#define SSB_EXTIF_UART_SCRATCH 0x0370
/* pcmcia/prog/flash_config */
#define SSB_EXTCFG_EN (1 << 0) /* enable */
#define SSB_EXTCFG_MODE 0xE /* mode */
#define SSB_EXTCFG_MODE_SHIFT 1
#define SSB_EXTCFG_MODE_FLASH 0x0 /* flash/asynchronous mode */
#define SSB_EXTCFG_MODE_SYNC 0x2 /* synchronous mode */
#define SSB_EXTCFG_MODE_PCMCIA 0x4 /* pcmcia mode */
#define SSB_EXTCFG_DS16 (1 << 4) /* destsize: 0=8bit, 1=16bit */
#define SSB_EXTCFG_BSWAP (1 << 5) /* byteswap */
#define SSB_EXTCFG_CLKDIV 0xC0 /* clock divider */
#define SSB_EXTCFG_CLKDIV_SHIFT 6
#define SSB_EXTCFG_CLKDIV_2 0x0 /* backplane/2 */
#define SSB_EXTCFG_CLKDIV_3 0x40 /* backplane/3 */
#define SSB_EXTCFG_CLKDIV_4 0x80 /* backplane/4 */
#define SSB_EXTCFG_CLKEN (1 << 8) /* clock enable */
#define SSB_EXTCFG_STROBE (1 << 9) /* size/bytestrobe (synch only) */
/* pcmcia_memwait */
#define SSB_PCMCIA_MEMW_0 0x0000003F /* waitcount0 */
#define SSB_PCMCIA_MEMW_1 0x00001F00 /* waitcount1 */
#define SSB_PCMCIA_MEMW_1_SHIFT 8
#define SSB_PCMCIA_MEMW_2 0x001F0000 /* waitcount2 */
#define SSB_PCMCIA_MEMW_2_SHIFT 16
#define SSB_PCMCIA_MEMW_3 0x1F000000 /* waitcount3 */
#define SSB_PCMCIA_MEMW_3_SHIFT 24
/* pcmcia_attrwait */
#define SSB_PCMCIA_ATTW_0 0x0000003F /* waitcount0 */
#define SSB_PCMCIA_ATTW_1 0x00001F00 /* waitcount1 */
#define SSB_PCMCIA_ATTW_1_SHIFT 8
#define SSB_PCMCIA_ATTW_2 0x001F0000 /* waitcount2 */
#define SSB_PCMCIA_ATTW_2_SHIFT 16
#define SSB_PCMCIA_ATTW_3 0x1F000000 /* waitcount3 */
#define SSB_PCMCIA_ATTW_3_SHIFT 24
/* pcmcia_iowait */
#define SSB_PCMCIA_IOW_0 0x0000003F /* waitcount0 */
#define SSB_PCMCIA_IOW_1 0x00001F00 /* waitcount1 */
#define SSB_PCMCIA_IOW_1_SHIFT 8
#define SSB_PCMCIA_IOW_2 0x001F0000 /* waitcount2 */
#define SSB_PCMCIA_IOW_2_SHIFT 16
#define SSB_PCMCIA_IOW_3 0x1F000000 /* waitcount3 */
#define SSB_PCMCIA_IOW_3_SHIFT 24
/* prog_waitcount */
#define SSB_PROG_WCNT_0 0x0000001F /* waitcount0 */
#define SSB_PROG_WCNT_1 0x00001F00 /* waitcount1 */
#define SSB_PROG_WCNT_1_SHIFT 8
#define SSB_PROG_WCNT_2 0x001F0000 /* waitcount2 */
#define SSB_PROG_WCNT_2_SHIFT 16
#define SSB_PROG_WCNT_3 0x1F000000 /* waitcount3 */
#define SSB_PROG_WCNT_3_SHIFT 24
#define SSB_PROG_W0 0x0000000C
#define SSB_PROG_W1 0x00000A00
#define SSB_PROG_W2 0x00020000
#define SSB_PROG_W3 0x01000000
/* flash_waitcount */
#define SSB_FLASH_WCNT_0 0x0000001F /* waitcount0 */
#define SSB_FLASH_WCNT_1 0x00001F00 /* waitcount1 */
#define SSB_FLASH_WCNT_1_SHIFT 8
#define SSB_FLASH_WCNT_2 0x001F0000 /* waitcount2 */
#define SSB_FLASH_WCNT_2_SHIFT 16
#define SSB_FLASH_WCNT_3 0x1F000000 /* waitcount3 */
#define SSB_FLASH_WCNT_3_SHIFT 24
/* watchdog */
#define SSB_EXTIF_WATCHDOG_CLK 48000000 /* Hz */
#ifdef CONFIG_SSB_DRIVER_EXTIF
struct ssb_extif {
struct ssb_device *dev;
};
static inline bool ssb_extif_available(struct ssb_extif *extif)
{
return (extif->dev != NULL);
}
extern void ssb_extif_get_clockcontrol(struct ssb_extif *extif,
u32 *plltype, u32 *n, u32 *m);
extern void ssb_extif_timing_init(struct ssb_extif *extif,
unsigned long ns);
u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask);
void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value);
void ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value);
#ifdef CONFIG_SSB_SERIAL
extern int ssb_extif_serial_init(struct ssb_extif *extif,
struct ssb_serial_port *ports);
#endif /* CONFIG_SSB_SERIAL */
#else /* CONFIG_SSB_DRIVER_EXTIF */
/* extif disabled */
struct ssb_extif {
};
static inline bool ssb_extif_available(struct ssb_extif *extif)
{
return 0;
}
static inline
void ssb_extif_get_clockcontrol(struct ssb_extif *extif,
u32 *plltype, u32 *n, u32 *m)
{
}
#endif /* CONFIG_SSB_DRIVER_EXTIF */
#endif /* LINUX_SSB_EXTIFCORE_H_ */

View File

@ -0,0 +1,46 @@
#ifndef LINUX_SSB_MIPSCORE_H_
#define LINUX_SSB_MIPSCORE_H_
#ifdef CONFIG_SSB_DRIVER_MIPS
struct ssb_device;
struct ssb_serial_port {
void *regs;
unsigned long clockspeed;
unsigned int irq;
unsigned int baud_base;
unsigned int reg_shift;
};
struct ssb_mipscore {
struct ssb_device *dev;
int nr_serial_ports;
struct ssb_serial_port serial_ports[4];
u8 flash_buswidth;
u32 flash_window;
u32 flash_window_size;
};
extern void ssb_mipscore_init(struct ssb_mipscore *mcore);
extern u32 ssb_cpu_clock(struct ssb_mipscore *mcore);
extern unsigned int ssb_mips_irq(struct ssb_device *dev);
#else /* CONFIG_SSB_DRIVER_MIPS */
struct ssb_mipscore {
};
static inline
void ssb_mipscore_init(struct ssb_mipscore *mcore)
{
}
#endif /* CONFIG_SSB_DRIVER_MIPS */
#endif /* LINUX_SSB_MIPSCORE_H_ */

View File

@ -0,0 +1,106 @@
#ifndef LINUX_SSB_PCICORE_H_
#define LINUX_SSB_PCICORE_H_
#ifdef CONFIG_SSB_DRIVER_PCICORE
/* PCI core registers. */
#define SSB_PCICORE_CTL 0x0000 /* PCI Control */
#define SSB_PCICORE_CTL_RST_OE 0x00000001 /* PCI_RESET Output Enable */
#define SSB_PCICORE_CTL_RST 0x00000002 /* PCI_RESET driven out to pin */
#define SSB_PCICORE_CTL_CLK_OE 0x00000004 /* Clock gate Output Enable */
#define SSB_PCICORE_CTL_CLK 0x00000008 /* Gate for clock driven out to pin */
#define SSB_PCICORE_ARBCTL 0x0010 /* PCI Arbiter Control */
#define SSB_PCICORE_ARBCTL_INTERN 0x00000001 /* Use internal arbiter */
#define SSB_PCICORE_ARBCTL_EXTERN 0x00000002 /* Use external arbiter */
#define SSB_PCICORE_ARBCTL_PARKID 0x00000006 /* Mask, selects which agent is parked on an idle bus */
#define SSB_PCICORE_ARBCTL_PARKID_LAST 0x00000000 /* Last requestor */
#define SSB_PCICORE_ARBCTL_PARKID_4710 0x00000002 /* 4710 */
#define SSB_PCICORE_ARBCTL_PARKID_EXT0 0x00000004 /* External requestor 0 */
#define SSB_PCICORE_ARBCTL_PARKID_EXT1 0x00000006 /* External requestor 1 */
#define SSB_PCICORE_ISTAT 0x0020 /* Interrupt status */
#define SSB_PCICORE_ISTAT_INTA 0x00000001 /* PCI INTA# */
#define SSB_PCICORE_ISTAT_INTB 0x00000002 /* PCI INTB# */
#define SSB_PCICORE_ISTAT_SERR 0x00000004 /* PCI SERR# (write to clear) */
#define SSB_PCICORE_ISTAT_PERR 0x00000008 /* PCI PERR# (write to clear) */
#define SSB_PCICORE_ISTAT_PME 0x00000010 /* PCI PME# */
#define SSB_PCICORE_IMASK 0x0024 /* Interrupt mask */
#define SSB_PCICORE_IMASK_INTA 0x00000001 /* PCI INTA# */
#define SSB_PCICORE_IMASK_INTB 0x00000002 /* PCI INTB# */
#define SSB_PCICORE_IMASK_SERR 0x00000004 /* PCI SERR# */
#define SSB_PCICORE_IMASK_PERR 0x00000008 /* PCI PERR# */
#define SSB_PCICORE_IMASK_PME 0x00000010 /* PCI PME# */
#define SSB_PCICORE_MBOX 0x0028 /* Backplane to PCI Mailbox */
#define SSB_PCICORE_MBOX_F0_0 0x00000100 /* PCI function 0, INT 0 */
#define SSB_PCICORE_MBOX_F0_1 0x00000200 /* PCI function 0, INT 1 */
#define SSB_PCICORE_MBOX_F1_0 0x00000400 /* PCI function 1, INT 0 */
#define SSB_PCICORE_MBOX_F1_1 0x00000800 /* PCI function 1, INT 1 */
#define SSB_PCICORE_MBOX_F2_0 0x00001000 /* PCI function 2, INT 0 */
#define SSB_PCICORE_MBOX_F2_1 0x00002000 /* PCI function 2, INT 1 */
#define SSB_PCICORE_MBOX_F3_0 0x00004000 /* PCI function 3, INT 0 */
#define SSB_PCICORE_MBOX_F3_1 0x00008000 /* PCI function 3, INT 1 */
#define SSB_PCICORE_BCAST_ADDR 0x0050 /* Backplane Broadcast Address */
#define SSB_PCICORE_BCAST_ADDR_MASK 0x000000FF
#define SSB_PCICORE_BCAST_DATA 0x0054 /* Backplane Broadcast Data */
#define SSB_PCICORE_GPIO_IN 0x0060 /* rev >= 2 only */
#define SSB_PCICORE_GPIO_OUT 0x0064 /* rev >= 2 only */
#define SSB_PCICORE_GPIO_ENABLE 0x0068 /* rev >= 2 only */
#define SSB_PCICORE_GPIO_CTL 0x006C /* rev >= 2 only */
#define SSB_PCICORE_SBTOPCI0 0x0100 /* Backplane to PCI translation 0 (sbtopci0) */
#define SSB_PCICORE_SBTOPCI0_MASK 0xFC000000
#define SSB_PCICORE_SBTOPCI1 0x0104 /* Backplane to PCI translation 1 (sbtopci1) */
#define SSB_PCICORE_SBTOPCI1_MASK 0xFC000000
#define SSB_PCICORE_SBTOPCI2 0x0108 /* Backplane to PCI translation 2 (sbtopci2) */
#define SSB_PCICORE_SBTOPCI2_MASK 0xC0000000
/* SBtoPCIx */
#define SSB_PCICORE_SBTOPCI_MEM 0x00000000
#define SSB_PCICORE_SBTOPCI_IO 0x00000001
#define SSB_PCICORE_SBTOPCI_CFG0 0x00000002
#define SSB_PCICORE_SBTOPCI_CFG1 0x00000003
#define SSB_PCICORE_SBTOPCI_PREF 0x00000004 /* Prefetch enable */
#define SSB_PCICORE_SBTOPCI_BURST 0x00000008 /* Burst enable */
#define SSB_PCICORE_SBTOPCI_MRM 0x00000020 /* Memory Read Multiple */
#define SSB_PCICORE_SBTOPCI_RC 0x00000030 /* Read Command mask (rev >= 11) */
#define SSB_PCICORE_SBTOPCI_RC_READ 0x00000000 /* Memory read */
#define SSB_PCICORE_SBTOPCI_RC_READL 0x00000010 /* Memory read line */
#define SSB_PCICORE_SBTOPCI_RC_READM 0x00000020 /* Memory read multiple */
/* PCIcore specific boardflags */
#define SSB_PCICORE_BFL_NOPCI 0x00000400 /* Board leaves PCI floating */
struct ssb_pcicore {
struct ssb_device *dev;
u8 setup_done:1;
u8 hostmode:1;
u8 cardbusmode:1;
};
extern void ssb_pcicore_init(struct ssb_pcicore *pc);
/* Enable IRQ routing for a specific device */
extern int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
struct ssb_device *dev);
#else /* CONFIG_SSB_DRIVER_PCICORE */
struct ssb_pcicore {
};
static inline
void ssb_pcicore_init(struct ssb_pcicore *pc)
{
}
static inline
int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
struct ssb_device *dev)
{
return 0;
}
#endif /* CONFIG_SSB_DRIVER_PCICORE */
#endif /* LINUX_SSB_PCICORE_H_ */

View File

@ -0,0 +1,357 @@
#ifndef LINUX_SSB_REGS_H_
#define LINUX_SSB_REGS_H_
/* SiliconBackplane Address Map.
* All regions may not exist on all chips.
*/
#define SSB_SDRAM_BASE 0x00000000U /* Physical SDRAM */
#define SSB_PCI_MEM 0x08000000U /* Host Mode sb2pcitranslation0 (64 MB) */
#define SSB_PCI_CFG 0x0c000000U /* Host Mode sb2pcitranslation1 (64 MB) */
#define SSB_SDRAM_SWAPPED 0x10000000U /* Byteswapped Physical SDRAM */
#define SSB_ENUM_BASE 0x18000000U /* Enumeration space base */
#define SSB_ENUM_LIMIT 0x18010000U /* Enumeration space limit */
#define SSB_FLASH2 0x1c000000U /* Flash Region 2 (region 1 shadowed here) */
#define SSB_FLASH2_SZ 0x02000000U /* Size of Flash Region 2 */
#define SSB_EXTIF_BASE 0x1f000000U /* External Interface region base address */
#define SSB_FLASH1 0x1fc00000U /* Flash Region 1 */
#define SSB_FLASH1_SZ 0x00400000U /* Size of Flash Region 1 */
#define SSB_PCI_DMA 0x40000000U /* Client Mode sb2pcitranslation2 (1 GB) */
#define SSB_PCI_DMA_SZ 0x40000000U /* Client Mode sb2pcitranslation2 size in bytes */
#define SSB_PCIE_DMA_L32 0x00000000U /* PCIE Client Mode sb2pcitranslation2 (2 ZettaBytes), low 32 bits */
#define SSB_PCIE_DMA_H32 0x80000000U /* PCIE Client Mode sb2pcitranslation2 (2 ZettaBytes), high 32 bits */
#define SSB_EUART (SSB_EXTIF_BASE + 0x00800000)
#define SSB_LED (SSB_EXTIF_BASE + 0x00900000)
/* Enumeration space constants */
#define SSB_CORE_SIZE 0x1000 /* Size of a core MMIO area */
#define SSB_MAX_NR_CORES ((SSB_ENUM_LIMIT - SSB_ENUM_BASE) / SSB_CORE_SIZE)
/* mips address */
#define SSB_EJTAG 0xff200000 /* MIPS EJTAG space (2M) */
/* SSB PCI config space registers. */
#define SSB_PMCSR 0x44
#define SSB_PE 0x100
#define SSB_BAR0_WIN 0x80 /* Backplane address space 0 */
#define SSB_BAR1_WIN 0x84 /* Backplane address space 1 */
#define SSB_SPROMCTL 0x88 /* SPROM control */
#define SSB_SPROMCTL_WE 0x10 /* SPROM write enable */
#define SSB_BAR1_CONTROL 0x8c /* Address space 1 burst control */
#define SSB_PCI_IRQS 0x90 /* PCI interrupts */
#define SSB_PCI_IRQMASK 0x94 /* PCI IRQ control and mask (pcirev >= 6 only) */
#define SSB_BACKPLANE_IRQS 0x98 /* Backplane Interrupts */
#define SSB_GPIO_IN 0xB0 /* GPIO Input (pcirev >= 3 only) */
#define SSB_GPIO_OUT 0xB4 /* GPIO Output (pcirev >= 3 only) */
#define SSB_GPIO_OUT_ENABLE 0xB8 /* GPIO Output Enable/Disable (pcirev >= 3 only) */
#define SSB_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */
#define SSB_GPIO_HWRAD 0x20 /* PCI config space GPIO 13 for hw radio disable */
#define SSB_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal powerup */
#define SSB_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL powerdown */
#define SSB_BAR0_MAX_RETRIES 50
/* Silicon backplane configuration register definitions */
#define SSB_IPSFLAG 0x0F08
#define SSB_IPSFLAG_IRQ1 0x0000003F /* which sbflags get routed to mips interrupt 1 */
#define SSB_IPSFLAG_IRQ1_SHIFT 0
#define SSB_IPSFLAG_IRQ2 0x00003F00 /* which sbflags get routed to mips interrupt 2 */
#define SSB_IPSFLAG_IRQ2_SHIFT 8
#define SSB_IPSFLAG_IRQ3 0x003F0000 /* which sbflags get routed to mips interrupt 3 */
#define SSB_IPSFLAG_IRQ3_SHIFT 16
#define SSB_IPSFLAG_IRQ4 0x3F000000 /* which sbflags get routed to mips interrupt 4 */
#define SSB_IPSFLAG_IRQ4_SHIFT 24
#define SSB_TPSFLAG 0x0F18
#define SSB_TPSFLAG_BPFLAG 0x0000003F /* Backplane flag # */
#define SSB_TPSFLAG_ALWAYSIRQ 0x00000040 /* IRQ is always sent on the Backplane */
#define SSB_TMERRLOGA 0x0F48
#define SSB_TMERRLOG 0x0F50
#define SSB_ADMATCH3 0x0F60
#define SSB_ADMATCH2 0x0F68
#define SSB_ADMATCH1 0x0F70
#define SSB_IMSTATE 0x0F90 /* SB Initiator Agent State */
#define SSB_IMSTATE_PC 0x0000000f /* Pipe Count */
#define SSB_IMSTATE_AP_MASK 0x00000030 /* Arbitration Priority */
#define SSB_IMSTATE_AP_BOTH 0x00000000 /* Use both timeslices and token */
#define SSB_IMSTATE_AP_TS 0x00000010 /* Use timeslices only */
#define SSB_IMSTATE_AP_TK 0x00000020 /* Use token only */
#define SSB_IMSTATE_AP_RSV 0x00000030 /* Reserved */
#define SSB_IMSTATE_IBE 0x00020000 /* In Band Error */
#define SSB_IMSTATE_TO 0x00040000 /* Timeout */
#define SSB_INTVEC 0x0F94 /* SB Interrupt Mask */
#define SSB_INTVEC_PCI 0x00000001 /* Enable interrupts for PCI */
#define SSB_INTVEC_ENET0 0x00000002 /* Enable interrupts for enet 0 */
#define SSB_INTVEC_ILINE20 0x00000004 /* Enable interrupts for iline20 */
#define SSB_INTVEC_CODEC 0x00000008 /* Enable interrupts for v90 codec */
#define SSB_INTVEC_USB 0x00000010 /* Enable interrupts for usb */
#define SSB_INTVEC_EXTIF 0x00000020 /* Enable interrupts for external i/f */
#define SSB_INTVEC_ENET1 0x00000040 /* Enable interrupts for enet 1 */
#define SSB_TMSLOW 0x0F98 /* SB Target State Low */
#define SSB_TMSLOW_RESET 0x00000001 /* Reset */
#define SSB_TMSLOW_REJECT_22 0x00000002 /* Reject (Backplane rev 2.2) */
#define SSB_TMSLOW_REJECT_23 0x00000004 /* Reject (Backplane rev 2.3) */
#define SSB_TMSLOW_CLOCK 0x00010000 /* Clock Enable */
#define SSB_TMSLOW_FGC 0x00020000 /* Force Gated Clocks On */
#define SSB_TMSLOW_PE 0x40000000 /* Power Management Enable */
#define SSB_TMSLOW_BE 0x80000000 /* BIST Enable */
#define SSB_TMSHIGH 0x0F9C /* SB Target State High */
#define SSB_TMSHIGH_SERR 0x00000001 /* S-error */
#define SSB_TMSHIGH_INT 0x00000002 /* Interrupt */
#define SSB_TMSHIGH_BUSY 0x00000004 /* Busy */
#define SSB_TMSHIGH_TO 0x00000020 /* Timeout. Backplane rev >= 2.3 only */
#define SSB_TMSHIGH_COREFL 0x1FFF0000 /* Core specific flags */
#define SSB_TMSHIGH_COREFL_SHIFT 16
#define SSB_TMSHIGH_DMA64 0x10000000 /* 64bit DMA supported */
#define SSB_TMSHIGH_GCR 0x20000000 /* Gated Clock Request */
#define SSB_TMSHIGH_BISTF 0x40000000 /* BIST Failed */
#define SSB_TMSHIGH_BISTD 0x80000000 /* BIST Done */
#define SSB_BWA0 0x0FA0
#define SSB_IMCFGLO 0x0FA8
#define SSB_IMCFGLO_SERTO 0x00000007 /* Service timeout */
#define SSB_IMCFGLO_REQTO 0x00000070 /* Request timeout */
#define SSB_IMCFGLO_REQTO_SHIFT 4
#define SSB_IMCFGLO_CONNID 0x00FF0000 /* Connection ID */
#define SSB_IMCFGLO_CONNID_SHIFT 16
#define SSB_IMCFGHI 0x0FAC
#define SSB_ADMATCH0 0x0FB0
#define SSB_TMCFGLO 0x0FB8
#define SSB_TMCFGHI 0x0FBC
#define SSB_BCONFIG 0x0FC0
#define SSB_BSTATE 0x0FC8
#define SSB_ACTCFG 0x0FD8
#define SSB_FLAGST 0x0FE8
#define SSB_IDLOW 0x0FF8
#define SSB_IDLOW_CFGSP 0x00000003 /* Config Space */
#define SSB_IDLOW_ADDRNGE 0x00000038 /* Address Ranges supported */
#define SSB_IDLOW_ADDRNGE_SHIFT 3
#define SSB_IDLOW_SYNC 0x00000040
#define SSB_IDLOW_INITIATOR 0x00000080
#define SSB_IDLOW_MIBL 0x00000F00 /* Minimum Backplane latency */
#define SSB_IDLOW_MIBL_SHIFT 8
#define SSB_IDLOW_MABL 0x0000F000 /* Maximum Backplane latency */
#define SSB_IDLOW_MABL_SHIFT 12
#define SSB_IDLOW_TIF 0x00010000 /* This Initiator is first */
#define SSB_IDLOW_CCW 0x000C0000 /* Cycle counter width */
#define SSB_IDLOW_CCW_SHIFT 18
#define SSB_IDLOW_TPT 0x00F00000 /* Target ports */
#define SSB_IDLOW_TPT_SHIFT 20
#define SSB_IDLOW_INITP 0x0F000000 /* Initiator ports */
#define SSB_IDLOW_INITP_SHIFT 24
#define SSB_IDLOW_SSBREV 0xF0000000 /* Sonics Backplane Revision code */
#define SSB_IDLOW_SSBREV_22 0x00000000 /* <= 2.2 */
#define SSB_IDLOW_SSBREV_23 0x10000000 /* 2.3 */
#define SSB_IDLOW_SSBREV_24 0x40000000 /* ?? Found in BCM4328 */
#define SSB_IDLOW_SSBREV_25 0x50000000 /* ?? Not Found yet */
#define SSB_IDLOW_SSBREV_26 0x60000000 /* ?? Found in some BCM4311/2 */
#define SSB_IDLOW_SSBREV_27 0x70000000 /* ?? Found in some BCM4311/2 */
#define SSB_IDHIGH 0x0FFC /* SB Identification High */
#define SSB_IDHIGH_RCLO 0x0000000F /* Revision Code (low part) */
#define SSB_IDHIGH_CC 0x00008FF0 /* Core Code */
#define SSB_IDHIGH_CC_SHIFT 4
#define SSB_IDHIGH_RCHI 0x00007000 /* Revision Code (high part) */
#define SSB_IDHIGH_RCHI_SHIFT 8 /* yes, shift 8 is right */
#define SSB_IDHIGH_VC 0xFFFF0000 /* Vendor Code */
#define SSB_IDHIGH_VC_SHIFT 16
/* SPROM shadow area. If not otherwise noted, fields are
* two bytes wide. Note that the SPROM can _only_ be read
* in two-byte quantinies.
*/
#define SSB_SPROMSIZE_WORDS 64
#define SSB_SPROMSIZE_BYTES (SSB_SPROMSIZE_WORDS * sizeof(u16))
#define SSB_SPROMSIZE_WORDS_R123 64
#define SSB_SPROMSIZE_WORDS_R4 220
#define SSB_SPROMSIZE_BYTES_R123 (SSB_SPROMSIZE_WORDS_R123 * sizeof(u16))
#define SSB_SPROMSIZE_BYTES_R4 (SSB_SPROMSIZE_WORDS_R4 * sizeof(u16))
#define SSB_SPROM_BASE 0x1000
#define SSB_SPROM_REVISION 0x107E
#define SSB_SPROM_REVISION_REV 0x00FF /* SPROM Revision number */
#define SSB_SPROM_REVISION_CRC 0xFF00 /* SPROM CRC8 value */
#define SSB_SPROM_REVISION_CRC_SHIFT 8
/* SPROM Revision 1 */
#define SSB_SPROM1_SPID 0x1004 /* Subsystem Product ID for PCI */
#define SSB_SPROM1_SVID 0x1006 /* Subsystem Vendor ID for PCI */
#define SSB_SPROM1_PID 0x1008 /* Product ID for PCI */
#define SSB_SPROM1_IL0MAC 0x1048 /* 6 bytes MAC address for 802.11b/g */
#define SSB_SPROM1_ET0MAC 0x104E /* 6 bytes MAC address for Ethernet */
#define SSB_SPROM1_ET1MAC 0x1054 /* 6 bytes MAC address for 802.11a */
#define SSB_SPROM1_ETHPHY 0x105A /* Ethernet PHY settings */
#define SSB_SPROM1_ETHPHY_ET0A 0x001F /* MII Address for enet0 */
#define SSB_SPROM1_ETHPHY_ET1A 0x03E0 /* MII Address for enet1 */
#define SSB_SPROM1_ETHPHY_ET1A_SHIFT 5
#define SSB_SPROM1_ETHPHY_ET0M (1<<14) /* MDIO for enet0 */
#define SSB_SPROM1_ETHPHY_ET1M (1<<15) /* MDIO for enet1 */
#define SSB_SPROM1_BINF 0x105C /* Board info */
#define SSB_SPROM1_BINF_BREV 0x00FF /* Board Revision */
#define SSB_SPROM1_BINF_CCODE 0x0F00 /* Country Code */
#define SSB_SPROM1_BINF_CCODE_SHIFT 8
#define SSB_SPROM1_BINF_ANTBG 0x3000 /* Available B-PHY and G-PHY antennas */
#define SSB_SPROM1_BINF_ANTBG_SHIFT 12
#define SSB_SPROM1_BINF_ANTA 0xC000 /* Available A-PHY antennas */
#define SSB_SPROM1_BINF_ANTA_SHIFT 14
#define SSB_SPROM1_PA0B0 0x105E
#define SSB_SPROM1_PA0B1 0x1060
#define SSB_SPROM1_PA0B2 0x1062
#define SSB_SPROM1_GPIOA 0x1064 /* General Purpose IO pins 0 and 1 */
#define SSB_SPROM1_GPIOA_P0 0x00FF /* Pin 0 */
#define SSB_SPROM1_GPIOA_P1 0xFF00 /* Pin 1 */
#define SSB_SPROM1_GPIOA_P1_SHIFT 8
#define SSB_SPROM1_GPIOB 0x1066 /* General Purpuse IO pins 2 and 3 */
#define SSB_SPROM1_GPIOB_P2 0x00FF /* Pin 2 */
#define SSB_SPROM1_GPIOB_P3 0xFF00 /* Pin 3 */
#define SSB_SPROM1_GPIOB_P3_SHIFT 8
#define SSB_SPROM1_MAXPWR 0x1068 /* Power Amplifier Max Power */
#define SSB_SPROM1_MAXPWR_BG 0x00FF /* B-PHY and G-PHY (in dBm Q5.2) */
#define SSB_SPROM1_MAXPWR_A 0xFF00 /* A-PHY (in dBm Q5.2) */
#define SSB_SPROM1_MAXPWR_A_SHIFT 8
#define SSB_SPROM1_PA1B0 0x106A
#define SSB_SPROM1_PA1B1 0x106C
#define SSB_SPROM1_PA1B2 0x106E
#define SSB_SPROM1_ITSSI 0x1070 /* Idle TSSI Target */
#define SSB_SPROM1_ITSSI_BG 0x00FF /* B-PHY and G-PHY*/
#define SSB_SPROM1_ITSSI_A 0xFF00 /* A-PHY */
#define SSB_SPROM1_ITSSI_A_SHIFT 8
#define SSB_SPROM1_BFLLO 0x1072 /* Boardflags (low 16 bits) */
#define SSB_SPROM1_AGAIN 0x1074 /* Antenna Gain (in dBm Q5.2) */
#define SSB_SPROM1_AGAIN_BG 0x00FF /* B-PHY and G-PHY */
#define SSB_SPROM1_AGAIN_BG_SHIFT 0
#define SSB_SPROM1_AGAIN_A 0xFF00 /* A-PHY */
#define SSB_SPROM1_AGAIN_A_SHIFT 8
/* SPROM Revision 2 (inherits from rev 1) */
#define SSB_SPROM2_BFLHI 0x1038 /* Boardflags (high 16 bits) */
#define SSB_SPROM2_MAXP_A 0x103A /* A-PHY Max Power */
#define SSB_SPROM2_MAXP_A_HI 0x00FF /* Max Power High */
#define SSB_SPROM2_MAXP_A_LO 0xFF00 /* Max Power Low */
#define SSB_SPROM2_MAXP_A_LO_SHIFT 8
#define SSB_SPROM2_PA1LOB0 0x103C /* A-PHY PowerAmplifier Low Settings */
#define SSB_SPROM2_PA1LOB1 0x103E /* A-PHY PowerAmplifier Low Settings */
#define SSB_SPROM2_PA1LOB2 0x1040 /* A-PHY PowerAmplifier Low Settings */
#define SSB_SPROM2_PA1HIB0 0x1042 /* A-PHY PowerAmplifier High Settings */
#define SSB_SPROM2_PA1HIB1 0x1044 /* A-PHY PowerAmplifier High Settings */
#define SSB_SPROM2_PA1HIB2 0x1046 /* A-PHY PowerAmplifier High Settings */
#define SSB_SPROM2_OPO 0x1078 /* OFDM Power Offset from CCK Level */
#define SSB_SPROM2_OPO_VALUE 0x00FF
#define SSB_SPROM2_OPO_UNUSED 0xFF00
#define SSB_SPROM2_CCODE 0x107C /* Two char Country Code */
/* SPROM Revision 3 (inherits most data from rev 2) */
#define SSB_SPROM3_IL0MAC 0x104A /* 6 bytes MAC address for 802.11b/g */
#define SSB_SPROM3_ET0MAC 0x1050 /* 6 bytes MAC address for Ethernet ?? */
#define SSB_SPROM3_ET1MAC 0x1050 /* 6 bytes MAC address for 802.11a ?? */
#define SSB_SPROM3_OFDMAPO 0x102C /* A-PHY OFDM Mid Power Offset (4 bytes, BigEndian) */
#define SSB_SPROM3_OFDMALPO 0x1030 /* A-PHY OFDM Low Power Offset (4 bytes, BigEndian) */
#define SSB_SPROM3_OFDMAHPO 0x1034 /* A-PHY OFDM High Power Offset (4 bytes, BigEndian) */
#define SSB_SPROM3_GPIOLDC 0x1042 /* GPIO LED Powersave Duty Cycle (4 bytes, BigEndian) */
#define SSB_SPROM3_GPIOLDC_OFF 0x0000FF00 /* Off Count */
#define SSB_SPROM3_GPIOLDC_OFF_SHIFT 8
#define SSB_SPROM3_GPIOLDC_ON 0x00FF0000 /* On Count */
#define SSB_SPROM3_GPIOLDC_ON_SHIFT 16
#define SSB_SPROM3_CCKPO 0x1078 /* CCK Power Offset */
#define SSB_SPROM3_CCKPO_1M 0x000F /* 1M Rate PO */
#define SSB_SPROM3_CCKPO_2M 0x00F0 /* 2M Rate PO */
#define SSB_SPROM3_CCKPO_2M_SHIFT 4
#define SSB_SPROM3_CCKPO_55M 0x0F00 /* 5.5M Rate PO */
#define SSB_SPROM3_CCKPO_55M_SHIFT 8
#define SSB_SPROM3_CCKPO_11M 0xF000 /* 11M Rate PO */
#define SSB_SPROM3_CCKPO_11M_SHIFT 12
#define SSB_SPROM3_OFDMGPO 0x107A /* G-PHY OFDM Power Offset (4 bytes, BigEndian) */
/* SPROM Revision 4 */
#define SSB_SPROM4_IL0MAC 0x104C /* 6 byte MAC address for a/b/g/n */
#define SSB_SPROM4_ET0MAC 0x1018 /* 6 bytes MAC address for Ethernet ?? */
#define SSB_SPROM4_ET1MAC 0x1018 /* 6 bytes MAC address for 802.11a ?? */
#define SSB_SPROM4_ETHPHY 0x105A /* Ethernet PHY settings ?? */
#define SSB_SPROM4_ETHPHY_ET0A 0x001F /* MII Address for enet0 */
#define SSB_SPROM4_ETHPHY_ET1A 0x03E0 /* MII Address for enet1 */
#define SSB_SPROM4_ETHPHY_ET1A_SHIFT 5
#define SSB_SPROM4_ETHPHY_ET0M (1<<14) /* MDIO for enet0 */
#define SSB_SPROM4_ETHPHY_ET1M (1<<15) /* MDIO for enet1 */
#define SSB_SPROM4_CCODE 0x1052 /* Country Code (2 bytes) */
#define SSB_SPROM4_ANTAVAIL 0x105D /* Antenna available bitfields */
#define SSB_SPROM4_ANTAVAIL_A 0x00FF /* A-PHY bitfield */
#define SSB_SPROM4_ANTAVAIL_A_SHIFT 0
#define SSB_SPROM4_ANTAVAIL_BG 0xFF00 /* B-PHY and G-PHY bitfield */
#define SSB_SPROM4_ANTAVAIL_BG_SHIFT 8
#define SSB_SPROM4_BFLLO 0x1044 /* Boardflags (low 16 bits) */
#define SSB_SPROM4_AGAIN01 0x105E /* Antenna Gain (in dBm Q5.2) */
#define SSB_SPROM4_AGAIN0 0x00FF /* Antenna 0 */
#define SSB_SPROM4_AGAIN0_SHIFT 0
#define SSB_SPROM4_AGAIN1 0xFF00 /* Antenna 1 */
#define SSB_SPROM4_AGAIN1_SHIFT 8
#define SSB_SPROM4_AGAIN23 0x1060
#define SSB_SPROM4_AGAIN2 0x00FF /* Antenna 2 */
#define SSB_SPROM4_AGAIN2_SHIFT 0
#define SSB_SPROM4_AGAIN3 0xFF00 /* Antenna 3 */
#define SSB_SPROM4_AGAIN3_SHIFT 8
#define SSB_SPROM4_BFLHI 0x1046 /* Board Flags Hi */
#define SSB_SPROM4_MAXP_BG 0x1080 /* Max Power BG in path 1 */
#define SSB_SPROM4_MAXP_BG_MASK 0x00FF /* Mask for Max Power BG */
#define SSB_SPROM4_ITSSI_BG 0xFF00 /* Mask for path 1 itssi_bg */
#define SSB_SPROM4_ITSSI_BG_SHIFT 8
#define SSB_SPROM4_MAXP_A 0x108A /* Max Power A in path 1 */
#define SSB_SPROM4_MAXP_A_MASK 0x00FF /* Mask for Max Power A */
#define SSB_SPROM4_ITSSI_A 0xFF00 /* Mask for path 1 itssi_a */
#define SSB_SPROM4_ITSSI_A_SHIFT 8
#define SSB_SPROM4_GPIOA 0x1056 /* Gen. Purpose IO # 0 and 1 */
#define SSB_SPROM4_GPIOA_P0 0x00FF /* Pin 0 */
#define SSB_SPROM4_GPIOA_P1 0xFF00 /* Pin 1 */
#define SSB_SPROM4_GPIOA_P1_SHIFT 8
#define SSB_SPROM4_GPIOB 0x1058 /* Gen. Purpose IO # 2 and 3 */
#define SSB_SPROM4_GPIOB_P2 0x00FF /* Pin 2 */
#define SSB_SPROM4_GPIOB_P3 0xFF00 /* Pin 3 */
#define SSB_SPROM4_GPIOB_P3_SHIFT 8
#define SSB_SPROM4_PA0B0 0x1082 /* The paXbY locations are */
#define SSB_SPROM4_PA0B1 0x1084 /* only guesses */
#define SSB_SPROM4_PA0B2 0x1086
#define SSB_SPROM4_PA1B0 0x108E
#define SSB_SPROM4_PA1B1 0x1090
#define SSB_SPROM4_PA1B2 0x1092
/* Values for SSB_SPROM1_BINF_CCODE */
enum {
SSB_SPROM1CCODE_WORLD = 0,
SSB_SPROM1CCODE_THAILAND,
SSB_SPROM1CCODE_ISRAEL,
SSB_SPROM1CCODE_JORDAN,
SSB_SPROM1CCODE_CHINA,
SSB_SPROM1CCODE_JAPAN,
SSB_SPROM1CCODE_USA_CANADA_ANZ,
SSB_SPROM1CCODE_EUROPE,
SSB_SPROM1CCODE_USA_LOW,
SSB_SPROM1CCODE_JAPAN_HIGH,
SSB_SPROM1CCODE_ALL,
SSB_SPROM1CCODE_NONE,
};
/* Address-Match values and masks (SSB_ADMATCHxxx) */
#define SSB_ADM_TYPE 0x00000003 /* Address type */
#define SSB_ADM_TYPE0 0
#define SSB_ADM_TYPE1 1
#define SSB_ADM_TYPE2 2
#define SSB_ADM_AD64 0x00000004
#define SSB_ADM_SZ0 0x000000F8 /* Type0 size */
#define SSB_ADM_SZ0_SHIFT 3
#define SSB_ADM_SZ1 0x000001F8 /* Type1 size */
#define SSB_ADM_SZ1_SHIFT 3
#define SSB_ADM_SZ2 0x000001F8 /* Type2 size */
#define SSB_ADM_SZ2_SHIFT 3
#define SSB_ADM_EN 0x00000400 /* Enable */
#define SSB_ADM_NEG 0x00000800 /* Negative decode */
#define SSB_ADM_BASE0 0xFFFFFF00 /* Type0 base address */
#define SSB_ADM_BASE0_SHIFT 8
#define SSB_ADM_BASE1 0xFFFFF000 /* Type1 base address for the core */
#define SSB_ADM_BASE1_SHIFT 12
#define SSB_ADM_BASE2 0xFFFF0000 /* Type2 base address for the core */
#define SSB_ADM_BASE2_SHIFT 16
#endif /* LINUX_SSB_REGS_H_ */

View File

@ -1,175 +0,0 @@
#
# YAFFS file system configurations
#
config YAFFS_FS
tristate "YAFFS2 file system support"
default n
depends on MTD
select YAFFS_YAFFS1
select YAFFS_YAFFS2
help
YAFFS2, or Yet Another Flash Filing System, is a filing system
optimised for NAND Flash chips.
To compile the YAFFS2 file system support as a module, choose M
here: the module will be called yaffs2.
If unsure, say N.
Further information on YAFFS2 is available at
<http://www.aleph1.co.uk/yaffs/>.
config YAFFS_YAFFS1
bool "512 byte / page devices"
depends on YAFFS_FS
default y
help
Enable YAFFS1 support -- yaffs for 512 byte / page devices
Not needed for 2K-page devices.
If unsure, say Y.
config YAFFS_9BYTE_TAGS
bool "Use older-style on-NAND data format with pageStatus byte"
depends on YAFFS_YAFFS1
default n
help
Older-style on-NAND data format has a "pageStatus" byte to record
chunk/page state. This byte is zero when the page is discarded.
Choose this option if you have existing on-NAND data using this
format that you need to continue to support. New data written
also uses the older-style format. Note: Use of this option
generally requires that MTD's oob layout be adjusted to use the
older-style format. See notes on tags formats and MTD versions.
If unsure, say N.
config YAFFS_DOES_ECC
bool "Lets Yaffs do its own ECC"
depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS
default n
help
This enables Yaffs to use its own ECC functions instead of using
the ones from the generic MTD-NAND driver.
If unsure, say N.
config YAFFS_ECC_WRONG_ORDER
bool "Use the same ecc byte order as Steven Hill's nand_ecc.c"
depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS
default n
help
This makes yaffs_ecc.c use the same ecc byte order as Steven
Hill's nand_ecc.c. If not set, then you get the same ecc byte
order as SmartMedia.
If unsure, say N.
config YAFFS_YAFFS2
bool "2048 byte (or larger) / page devices"
depends on YAFFS_FS
default y
help
Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices
If unsure, say Y.
config YAFFS_AUTO_YAFFS2
bool "Autoselect yaffs2 format"
depends on YAFFS_YAFFS2
default y
help
Without this, you need to explicitely use yaffs2 as the file
system type. With this, you can say "yaffs" and yaffs or yaffs2
will be used depending on the device page size (yaffs on
512-byte page devices, yaffs2 on 2K page devices).
If unsure, say Y.
config YAFFS_DISABLE_LAZY_LOAD
bool "Disable lazy loading"
depends on YAFFS_YAFFS2
default n
help
"Lazy loading" defers loading file details until they are
required. This saves mount time, but makes the first look-up
a bit longer.
Lazy loading will only happen if enabled by this option being 'n'
and if the appropriate tags are available, else yaffs2 will
automatically fall back to immediate loading and do the right
thing.
Lazy laoding will be required by checkpointing.
Setting this to 'y' will disable lazy loading.
If unsure, say N.
config YAFFS_CHECKPOINT_RESERVED_BLOCKS
int "Reserved blocks for checkpointing"
depends on YAFFS_YAFFS2
default 10
help
Give the number of Blocks to reserve for checkpointing.
Checkpointing saves the state at unmount so that mounting is
much faster as a scan of all the flash to regenerate this state
is not needed. These Blocks are reserved per partition, so if
you have very small partitions the default (10) may be a mess
for you. You can set this value to 0, but that does not mean
checkpointing is disabled at all. There only won't be any
specially reserved blocks for checkpointing, so if there is
enough free space on the filesystem, it will be used for
checkpointing.
If unsure, leave at default (10), but don't wonder if there are
always 2MB used on your large page device partition (10 x 2k
pagesize). When using small partitions or when being very small
on space, you probably want to set this to zero.
config YAFFS_DISABLE_WIDE_TNODES
bool "Turn off wide tnodes"
depends on YAFFS_FS
default n
help
Wide tnodes are only used for NAND arrays >=32MB for 512-byte
page devices and >=128MB for 2k page devices. They use slightly
more RAM but are faster since they eliminate chunk group
searching.
Setting this to 'y' will force tnode width to 16 bits and save
memory but make large arrays slower.
If unsure, say N.
config YAFFS_ALWAYS_CHECK_CHUNK_ERASED
bool "Force chunk erase check"
depends on YAFFS_FS
default n
help
Normally YAFFS only checks chunks before writing until an erased
chunk is found. This helps to detect any partially written
chunks that might have happened due to power loss.
Enabling this forces on the test that chunks are erased in flash
before writing to them. This takes more time but is potentially
a bit more secure.
Suggest setting Y during development and ironing out driver
issues etc. Suggest setting to N if you want faster writing.
If unsure, say Y.
config YAFFS_SHORT_NAMES_IN_RAM
bool "Cache short names in RAM"
depends on YAFFS_FS
default y
help
If this config is set, then short names are stored with the
yaffs_Object. This costs an extra 16 bytes of RAM per object,
but makes look-ups faster.
If unsure, say Y.

View File

@ -1,11 +0,0 @@
#
# Makefile for the linux YAFFS filesystem routines.
#
obj-$(CONFIG_YAFFS_FS) += yaffs.o
yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o
yaffs-y += yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
yaffs-y += yaffs_mtdif1.o yaffs_packedtags1.o
yaffs-y += yaffs_mtdif.o yaffs_mtdif2.o

View File

@ -1,264 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/*
* This file is just holds extra declarations used during development.
* Most of these are from kernel includes placed here so we can use them in
* applications.
*
*/
#ifndef __EXTRAS_H__
#define __EXTRAS_H__
#if defined WIN32
#define __inline__ __inline
#define new newHack
#endif
#if !(defined __KERNEL__) || (defined WIN32)
/* User space defines */
typedef unsigned char __u8;
typedef unsigned short __u16;
typedef unsigned __u32;
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
#define prefetch(x) 1
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static __inline__ void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static __inline__ void list_add_tail(struct list_head *new,
struct list_head *head)
{
__list_add(new, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_del(struct list_head *prev,
struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is
* in an undefined state.
*/
static __inline__ void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static __inline__ void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static __inline__ int list_empty(struct list_head *head)
{
return head->next == head;
}
/**
* list_splice - join two lists
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static __inline__ void list_splice(struct list_head *list,
struct list_head *head)
{
struct list_head *first = list->next;
if (first != list) {
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
}
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next, prefetch(pos->next); pos != (head); \
pos = pos->next, prefetch(pos->next))
/**
* list_for_each_safe - iterate over a list safe against removal
* of list entry
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/*
* File types
*/
#define DT_UNKNOWN 0
#define DT_FIFO 1
#define DT_CHR 2
#define DT_DIR 4
#define DT_BLK 6
#define DT_REG 8
#define DT_LNK 10
#define DT_SOCK 12
#define DT_WHT 14
#ifndef WIN32
#include <sys/stat.h>
#endif
/*
* Attribute flags. These should be or-ed together to figure out what
* has been changed!
*/
#define ATTR_MODE 1
#define ATTR_UID 2
#define ATTR_GID 4
#define ATTR_SIZE 8
#define ATTR_ATIME 16
#define ATTR_MTIME 32
#define ATTR_CTIME 64
#define ATTR_ATIME_SET 128
#define ATTR_MTIME_SET 256
#define ATTR_FORCE 512 /* Not a change, but a change it */
#define ATTR_ATTR_FLAG 1024
struct iattr {
unsigned int ia_valid;
unsigned ia_mode;
unsigned ia_uid;
unsigned ia_gid;
unsigned ia_size;
unsigned ia_atime;
unsigned ia_mtime;
unsigned ia_ctime;
unsigned int ia_attr_flags;
};
#define KERN_DEBUG
#else
#ifndef WIN32
#include <linux/types.h>
#include <linux/list.h>
#include <linux/fs.h>
#include <linux/stat.h>
#endif
#endif
#if defined WIN32
#undef new
#endif
#endif

View File

@ -1,65 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Martin Fouts <Martin.Fouts@palmsource.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_CONFIG_H__
#define __YAFFS_CONFIG_H__
#ifdef YAFFS_OUT_OF_TREE
/* DO NOT UNSET THESE THREE. YAFFS2 will not compile if you do. */
#define CONFIG_YAFFS_FS
#define CONFIG_YAFFS_YAFFS1
#define CONFIG_YAFFS_YAFFS2
/* These options are independent of each other. Select those that matter. */
/* Default: Not selected */
/* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
//#define CONFIG_YAFFS_DOES_ECC
/* Default: Not selected */
/* Meaning: ECC byte order is 'wrong'. Only meaningful if */
/* CONFIG_YAFFS_DOES_ECC is set */
//#define CONFIG_YAFFS_ECC_WRONG_ORDER
/* Default: Selected */
/* Meaning: Disables testing whether chunks are erased before writing to them*/
#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
/* Default: Selected */
/* Meaning: Cache short names, taking more RAM, but faster look-ups */
#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
/* Default: 10 */
/* Meaning: set the count of blocks to reserve for checkpointing */
#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10
/*
Older-style on-NAND data format has a "pageStatus" byte to record
chunk/page state. This byte is zeroed when the page is discarded.
Choose this option if you have existing on-NAND data in this format
that you need to continue to support. New data written also uses the
older-style format.
Note: Use of this option generally requires that MTD's oob layout be
adjusted to use the older-style format. See notes on tags formats and
MTD versions.
*/
/* Default: Not selected */
/* Meaning: Use older-style on-NAND data format with pageStatus byte */
#define CONFIG_YAFFS_9BYTE_TAGS
#endif /* YAFFS_OUT_OF_TREE */
#endif /* __YAFFS_CONFIG_H__ */

View File

@ -1,404 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
const char *yaffs_checkptrw_c_version =
"$Id: yaffs_checkptrw.c,v 1.14 2007-05-15 20:07:40 charles Exp $";
#include "yaffs_checkptrw.h"
static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
{
int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
T(YAFFS_TRACE_CHECKPOINT,
(TSTR("checkpt blocks available = %d" TENDSTR),
blocksAvailable));
return (blocksAvailable <= 0) ? 0 : 1;
}
static int yaffs_CheckpointErase(yaffs_Device *dev)
{
int i;
if(!dev->eraseBlockInNAND)
return 0;
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checking blocks %d to %d"TENDSTR),
dev->internalStartBlock,dev->internalEndBlock));
for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
if(bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT){
T(YAFFS_TRACE_CHECKPOINT,(TSTR("erasing checkpt block %d"TENDSTR),i));
if(dev->eraseBlockInNAND(dev,i- dev->blockOffset /* realign */)){
bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
dev->nErasedBlocks++;
dev->nFreeChunks += dev->nChunksPerBlock;
}
else {
dev->markNANDBlockBad(dev,i);
bi->blockState = YAFFS_BLOCK_STATE_DEAD;
}
}
}
dev->blocksInCheckpoint = 0;
return 1;
}
static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
{
int i;
int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
T(YAFFS_TRACE_CHECKPOINT,
(TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),
dev->nErasedBlocks,dev->nReservedBlocks,blocksAvailable,dev->checkpointNextBlock));
if(dev->checkpointNextBlock >= 0 &&
dev->checkpointNextBlock <= dev->internalEndBlock &&
blocksAvailable > 0){
for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY){
dev->checkpointNextBlock = i + 1;
dev->checkpointCurrentBlock = i;
T(YAFFS_TRACE_CHECKPOINT,(TSTR("allocating checkpt block %d"TENDSTR),i));
return;
}
}
}
T(YAFFS_TRACE_CHECKPOINT,(TSTR("out of checkpt blocks"TENDSTR)));
dev->checkpointNextBlock = -1;
dev->checkpointCurrentBlock = -1;
}
static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
{
int i;
yaffs_ExtendedTags tags;
T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR),
dev->blocksInCheckpoint, dev->checkpointNextBlock));
if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){
int chunk = i * dev->nChunksPerBlock;
int realignedChunk = chunk - dev->chunkOffset;
dev->readChunkWithTagsFromNAND(dev,realignedChunk,NULL,&tags);
T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
i, tags.objectId,tags.sequenceNumber,tags.eccResult));
if(tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA){
/* Right kind of block */
dev->checkpointNextBlock = tags.objectId;
dev->checkpointCurrentBlock = i;
dev->checkpointBlockList[dev->blocksInCheckpoint] = i;
dev->blocksInCheckpoint++;
T(YAFFS_TRACE_CHECKPOINT,(TSTR("found checkpt block %d"TENDSTR),i));
return;
}
}
T(YAFFS_TRACE_CHECKPOINT,(TSTR("found no more checkpt blocks"TENDSTR)));
dev->checkpointNextBlock = -1;
dev->checkpointCurrentBlock = -1;
}
int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
{
/* Got the functions we need? */
if (!dev->writeChunkWithTagsToNAND ||
!dev->readChunkWithTagsFromNAND ||
!dev->eraseBlockInNAND ||
!dev->markNANDBlockBad)
return 0;
if(forWriting && !yaffs_CheckpointSpaceOk(dev))
return 0;
if(!dev->checkpointBuffer)
dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk);
if(!dev->checkpointBuffer)
return 0;
dev->checkpointPageSequence = 0;
dev->checkpointOpenForWrite = forWriting;
dev->checkpointByteCount = 0;
dev->checkpointSum = 0;
dev->checkpointXor = 0;
dev->checkpointCurrentBlock = -1;
dev->checkpointCurrentChunk = -1;
dev->checkpointNextBlock = dev->internalStartBlock;
/* Erase all the blocks in the checkpoint area */
if(forWriting){
memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
dev->checkpointByteOffset = 0;
return yaffs_CheckpointErase(dev);
} else {
int i;
/* Set to a value that will kick off a read */
dev->checkpointByteOffset = dev->nDataBytesPerChunk;
/* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
* going to be way more than we need */
dev->blocksInCheckpoint = 0;
dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
for(i = 0; i < dev->checkpointMaxBlocks; i++)
dev->checkpointBlockList[i] = -1;
}
return 1;
}
int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
{
__u32 compositeSum;
compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
*sum = compositeSum;
return 1;
}
static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
{
int chunk;
int realignedChunk;
yaffs_ExtendedTags tags;
if(dev->checkpointCurrentBlock < 0){
yaffs_CheckpointFindNextErasedBlock(dev);
dev->checkpointCurrentChunk = 0;
}
if(dev->checkpointCurrentBlock < 0)
return 0;
tags.chunkDeleted = 0;
tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */
tags.chunkId = dev->checkpointPageSequence + 1;
tags.sequenceNumber = YAFFS_SEQUENCE_CHECKPOINT_DATA;
tags.byteCount = dev->nDataBytesPerChunk;
if(dev->checkpointCurrentChunk == 0){
/* First chunk we write for the block? Set block state to
checkpoint */
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointCurrentBlock);
bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
dev->blocksInCheckpoint++;
}
chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk,tags.objectId,tags.chunkId));
realignedChunk = chunk - dev->chunkOffset;
dev->writeChunkWithTagsToNAND(dev,realignedChunk,dev->checkpointBuffer,&tags);
dev->checkpointByteOffset = 0;
dev->checkpointPageSequence++;
dev->checkpointCurrentChunk++;
if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock){
dev->checkpointCurrentChunk = 0;
dev->checkpointCurrentBlock = -1;
}
memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
return 1;
}
int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes)
{
int i=0;
int ok = 1;
__u8 * dataBytes = (__u8 *)data;
if(!dev->checkpointBuffer)
return 0;
if(!dev->checkpointOpenForWrite)
return -1;
while(i < nBytes && ok) {
dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ;
dev->checkpointSum += *dataBytes;
dev->checkpointXor ^= *dataBytes;
dev->checkpointByteOffset++;
i++;
dataBytes++;
dev->checkpointByteCount++;
if(dev->checkpointByteOffset < 0 ||
dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
ok = yaffs_CheckpointFlushBuffer(dev);
}
return i;
}
int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
{
int i=0;
int ok = 1;
yaffs_ExtendedTags tags;
int chunk;
int realignedChunk;
__u8 *dataBytes = (__u8 *)data;
if(!dev->checkpointBuffer)
return 0;
if(dev->checkpointOpenForWrite)
return -1;
while(i < nBytes && ok) {
if(dev->checkpointByteOffset < 0 ||
dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
if(dev->checkpointCurrentBlock < 0){
yaffs_CheckpointFindNextCheckpointBlock(dev);
dev->checkpointCurrentChunk = 0;
}
if(dev->checkpointCurrentBlock < 0)
ok = 0;
else {
chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock +
dev->checkpointCurrentChunk;
realignedChunk = chunk - dev->chunkOffset;
/* read in the next chunk */
/* printf("read checkpoint page %d\n",dev->checkpointPage); */
dev->readChunkWithTagsFromNAND(dev, realignedChunk,
dev->checkpointBuffer,
&tags);
if(tags.chunkId != (dev->checkpointPageSequence + 1) ||
tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
ok = 0;
dev->checkpointByteOffset = 0;
dev->checkpointPageSequence++;
dev->checkpointCurrentChunk++;
if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
dev->checkpointCurrentBlock = -1;
}
}
if(ok){
*dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
dev->checkpointSum += *dataBytes;
dev->checkpointXor ^= *dataBytes;
dev->checkpointByteOffset++;
i++;
dataBytes++;
dev->checkpointByteCount++;
}
}
return i;
}
int yaffs_CheckpointClose(yaffs_Device *dev)
{
if(dev->checkpointOpenForWrite){
if(dev->checkpointByteOffset != 0)
yaffs_CheckpointFlushBuffer(dev);
} else {
int i;
for(i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++){
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointBlockList[i]);
if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
else {
// Todo this looks odd...
}
}
YFREE(dev->checkpointBlockList);
dev->checkpointBlockList = NULL;
}
dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
dev->nErasedBlocks -= dev->blocksInCheckpoint;
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint byte count %d" TENDSTR),
dev->checkpointByteCount));
if(dev->checkpointBuffer){
/* free the buffer */
YFREE(dev->checkpointBuffer);
dev->checkpointBuffer = NULL;
return 1;
}
else
return 0;
}
int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
{
/* Erase the first checksum block */
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint invalidate"TENDSTR)));
if(!yaffs_CheckpointSpaceOk(dev))
return 0;
return yaffs_CheckpointErase(dev);
}

View File

@ -1,35 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_CHECKPTRW_H__
#define __YAFFS_CHECKPTRW_H__
#include "yaffs_guts.h"
int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting);
int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes);
int yaffs_CheckpointRead(yaffs_Device *dev,void *data, int nBytes);
int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
int yaffs_CheckpointClose(yaffs_Device *dev);
int yaffs_CheckpointInvalidateStream(yaffs_Device *dev);
#endif

View File

@ -1,331 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* This code implements the ECC algorithm used in SmartMedia.
*
* The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
* The two unused bit are set to 1.
* The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
* blocks are used on a 512-byte NAND page.
*
*/
/* Table generated by gen-ecc.c
* Using a table means we do not have to calculate p1..p4 and p1'..p4'
* for each byte of data. These are instead provided in a table in bits7..2.
* Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore
* this bytes influence on the line parity.
*/
const char *yaffs_ecc_c_version =
"$Id: yaffs_ecc.c,v 1.9 2007-02-14 01:09:06 wookey Exp $";
#include "yportenv.h"
#include "yaffs_ecc.h"
static const unsigned char column_parity_table[] = {
0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
};
/* Count the bits in an unsigned char or a U32 */
static int yaffs_CountBits(unsigned char x)
{
int r = 0;
while (x) {
if (x & 1)
r++;
x >>= 1;
}
return r;
}
static int yaffs_CountBits32(unsigned x)
{
int r = 0;
while (x) {
if (x & 1)
r++;
x >>= 1;
}
return r;
}
/* Calculate the ECC for a 256-byte block of data */
void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)
{
unsigned int i;
unsigned char col_parity = 0;
unsigned char line_parity = 0;
unsigned char line_parity_prime = 0;
unsigned char t;
unsigned char b;
for (i = 0; i < 256; i++) {
b = column_parity_table[*data++];
col_parity ^= b;
if (b & 0x01) // odd number of bits in the byte
{
line_parity ^= i;
line_parity_prime ^= ~i;
}
}
ecc[2] = (~col_parity) | 0x03;
t = 0;
if (line_parity & 0x80)
t |= 0x80;
if (line_parity_prime & 0x80)
t |= 0x40;
if (line_parity & 0x40)
t |= 0x20;
if (line_parity_prime & 0x40)
t |= 0x10;
if (line_parity & 0x20)
t |= 0x08;
if (line_parity_prime & 0x20)
t |= 0x04;
if (line_parity & 0x10)
t |= 0x02;
if (line_parity_prime & 0x10)
t |= 0x01;
ecc[1] = ~t;
t = 0;
if (line_parity & 0x08)
t |= 0x80;
if (line_parity_prime & 0x08)
t |= 0x40;
if (line_parity & 0x04)
t |= 0x20;
if (line_parity_prime & 0x04)
t |= 0x10;
if (line_parity & 0x02)
t |= 0x08;
if (line_parity_prime & 0x02)
t |= 0x04;
if (line_parity & 0x01)
t |= 0x02;
if (line_parity_prime & 0x01)
t |= 0x01;
ecc[0] = ~t;
#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
// Swap the bytes into the wrong order
t = ecc[0];
ecc[0] = ecc[1];
ecc[1] = t;
#endif
}
/* Correct the ECC on a 256 byte block of data */
int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
const unsigned char *test_ecc)
{
unsigned char d0, d1, d2; /* deltas */
d0 = read_ecc[0] ^ test_ecc[0];
d1 = read_ecc[1] ^ test_ecc[1];
d2 = read_ecc[2] ^ test_ecc[2];
if ((d0 | d1 | d2) == 0)
return 0; /* no error */
if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
/* Single bit (recoverable) error in data */
unsigned byte;
unsigned bit;
#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
// swap the bytes to correct for the wrong order
unsigned char t;
t = d0;
d0 = d1;
d1 = t;
#endif
bit = byte = 0;
if (d1 & 0x80)
byte |= 0x80;
if (d1 & 0x20)
byte |= 0x40;
if (d1 & 0x08)
byte |= 0x20;
if (d1 & 0x02)
byte |= 0x10;
if (d0 & 0x80)
byte |= 0x08;
if (d0 & 0x20)
byte |= 0x04;
if (d0 & 0x08)
byte |= 0x02;
if (d0 & 0x02)
byte |= 0x01;
if (d2 & 0x80)
bit |= 0x04;
if (d2 & 0x20)
bit |= 0x02;
if (d2 & 0x08)
bit |= 0x01;
data[byte] ^= (1 << bit);
return 1; /* Corrected the error */
}
if ((yaffs_CountBits(d0) +
yaffs_CountBits(d1) +
yaffs_CountBits(d2)) == 1) {
/* Reccoverable error in ecc */
read_ecc[0] = test_ecc[0];
read_ecc[1] = test_ecc[1];
read_ecc[2] = test_ecc[2];
return 1; /* Corrected the error */
}
/* Unrecoverable error */
return -1;
}
/*
* ECCxxxOther does ECC calcs on arbitrary n bytes of data
*/
void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
yaffs_ECCOther * eccOther)
{
unsigned int i;
unsigned char col_parity = 0;
unsigned line_parity = 0;
unsigned line_parity_prime = 0;
unsigned char b;
for (i = 0; i < nBytes; i++) {
b = column_parity_table[*data++];
col_parity ^= b;
if (b & 0x01) {
/* odd number of bits in the byte */
line_parity ^= i;
line_parity_prime ^= ~i;
}
}
eccOther->colParity = (col_parity >> 2) & 0x3f;
eccOther->lineParity = line_parity;
eccOther->lineParityPrime = line_parity_prime;
}
int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
yaffs_ECCOther * read_ecc,
const yaffs_ECCOther * test_ecc)
{
unsigned char cDelta; /* column parity delta */
unsigned lDelta; /* line parity delta */
unsigned lDeltaPrime; /* line parity delta */
unsigned bit;
cDelta = read_ecc->colParity ^ test_ecc->colParity;
lDelta = read_ecc->lineParity ^ test_ecc->lineParity;
lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime;
if ((cDelta | lDelta | lDeltaPrime) == 0)
return 0; /* no error */
if (lDelta == ~lDeltaPrime &&
(((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15))
{
/* Single bit (recoverable) error in data */
bit = 0;
if (cDelta & 0x20)
bit |= 0x04;
if (cDelta & 0x08)
bit |= 0x02;
if (cDelta & 0x02)
bit |= 0x01;
if(lDelta >= nBytes)
return -1;
data[lDelta] ^= (1 << bit);
return 1; /* corrected */
}
if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) +
yaffs_CountBits(cDelta)) == 1) {
/* Reccoverable error in ecc */
*read_ecc = *test_ecc;
return 1; /* corrected */
}
/* Unrecoverable error */
return -1;
}

View File

@ -1,44 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/*
* This code implements the ECC algorithm used in SmartMedia.
*
* The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
* The two unused bit are set to 1.
* The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
* blocks are used on a 512-byte NAND page.
*
*/
#ifndef __YAFFS_ECC_H__
#define __YAFFS_ECC_H__
typedef struct {
unsigned char colParity;
unsigned lineParity;
unsigned lineParityPrime;
} yaffs_ECCOther;
void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc);
int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
const unsigned char *test_ecc);
void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
yaffs_ECCOther * ecc);
int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
yaffs_ECCOther * read_ecc,
const yaffs_ECCOther * test_ecc);
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,902 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_GUTS_H__
#define __YAFFS_GUTS_H__
#include "devextras.h"
#include "yportenv.h"
#define YAFFS_OK 1
#define YAFFS_FAIL 0
/* Give us a Y=0x59,
* Give us an A=0x41,
* Give us an FF=0xFF
* Give us an S=0x53
* And what have we got...
*/
#define YAFFS_MAGIC 0x5941FF53
#define YAFFS_NTNODES_LEVEL0 16
#define YAFFS_TNODES_LEVEL0_BITS 4
#define YAFFS_TNODES_LEVEL0_MASK 0xf
#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2)
#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1)
#define YAFFS_TNODES_INTERNAL_MASK 0x7
#define YAFFS_TNODES_MAX_LEVEL 6
#ifndef CONFIG_YAFFS_NO_YAFFS1
#define YAFFS_BYTES_PER_SPARE 16
#define YAFFS_BYTES_PER_CHUNK 512
#define YAFFS_CHUNK_SIZE_SHIFT 9
#define YAFFS_CHUNKS_PER_BLOCK 32
#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
#endif
#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024
#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32
#define YAFFS_MAX_CHUNK_ID 0x000FFFFF
#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF
#define YAFFS_ALLOCATION_NOBJECTS 100
#define YAFFS_ALLOCATION_NTNODES 100
#define YAFFS_ALLOCATION_NLINKS 100
#define YAFFS_NOBJECT_BUCKETS 256
#define YAFFS_OBJECT_SPACE 0x40000
#define YAFFS_CHECKPOINT_VERSION 3
#ifdef CONFIG_YAFFS_UNICODE
#define YAFFS_MAX_NAME_LENGTH 127
#define YAFFS_MAX_ALIAS_LENGTH 79
#else
#define YAFFS_MAX_NAME_LENGTH 255
#define YAFFS_MAX_ALIAS_LENGTH 159
#endif
#define YAFFS_SHORT_NAME_LENGTH 15
/* Some special object ids for pseudo objects */
#define YAFFS_OBJECTID_ROOT 1
#define YAFFS_OBJECTID_LOSTNFOUND 2
#define YAFFS_OBJECTID_UNLINKED 3
#define YAFFS_OBJECTID_DELETED 4
/* Sseudo object ids for checkpointing */
#define YAFFS_OBJECTID_SB_HEADER 0x10
#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
/* */
#define YAFFS_MAX_SHORT_OP_CACHES 20
#define YAFFS_N_TEMP_BUFFERS 4
/* We limit the number attempts at sucessfully saving a chunk of data.
* Small-page devices have 32 pages per block; large-page devices have 64.
* Default to something in the order of 5 to 10 blocks worth of chunks.
*/
#define YAFFS_WR_ATTEMPTS (5*64)
/* Sequence numbers are used in YAFFS2 to determine block allocation order.
* The range is limited slightly to help distinguish bad numbers from good.
* This also allows us to perhaps in the future use special numbers for
* special purposes.
* EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years,
* and is a larger number than the lifetime of a 2GB device.
*/
#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000
#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xEFFFFF00
/* ChunkCache is used for short read/write operations.*/
typedef struct {
struct yaffs_ObjectStruct *object;
int chunkId;
int lastUse;
int dirty;
int nBytes; /* Only valid if the cache is dirty */
int locked; /* Can't push out or flush while locked. */
#ifdef CONFIG_YAFFS_YAFFS2
__u8 *data;
#else
__u8 data[YAFFS_BYTES_PER_CHUNK];
#endif
} yaffs_ChunkCache;
/* Tags structures in RAM
* NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise
* the structure size will get blown out.
*/
#ifndef CONFIG_YAFFS_NO_YAFFS1
typedef struct {
unsigned chunkId:20;
unsigned serialNumber:2;
unsigned byteCount:10;
unsigned objectId:18;
unsigned ecc:12;
unsigned unusedStuff:2;
} yaffs_Tags;
typedef union {
yaffs_Tags asTags;
__u8 asBytes[8];
} yaffs_TagsUnion;
#endif
/* Stuff used for extended tags in YAFFS2 */
typedef enum {
YAFFS_ECC_RESULT_UNKNOWN,
YAFFS_ECC_RESULT_NO_ERROR,
YAFFS_ECC_RESULT_FIXED,
YAFFS_ECC_RESULT_UNFIXED
} yaffs_ECCResult;
typedef enum {
YAFFS_OBJECT_TYPE_UNKNOWN,
YAFFS_OBJECT_TYPE_FILE,
YAFFS_OBJECT_TYPE_SYMLINK,
YAFFS_OBJECT_TYPE_DIRECTORY,
YAFFS_OBJECT_TYPE_HARDLINK,
YAFFS_OBJECT_TYPE_SPECIAL
} yaffs_ObjectType;
#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
typedef struct {
unsigned validMarker0;
unsigned chunkUsed; /* Status of the chunk: used or unused */
unsigned objectId; /* If 0 then this is not part of an object (unused) */
unsigned chunkId; /* If 0 then this is a header, else a data chunk */
unsigned byteCount; /* Only valid for data chunks */
/* The following stuff only has meaning when we read */
yaffs_ECCResult eccResult;
unsigned blockBad;
/* YAFFS 1 stuff */
unsigned chunkDeleted; /* The chunk is marked deleted */
unsigned serialNumber; /* Yaffs1 2-bit serial number */
/* YAFFS2 stuff */
unsigned sequenceNumber; /* The sequence number of this block */
/* Extra info if this is an object header (YAFFS2 only) */
unsigned extraHeaderInfoAvailable; /* There is extra info available if this is not zero */
unsigned extraParentObjectId; /* The parent object */
unsigned extraIsShrinkHeader; /* Is it a shrink header? */
unsigned extraShadows; /* Does this shadow another object? */
yaffs_ObjectType extraObjectType; /* What object type? */
unsigned extraFileLength; /* Length if it is a file */
unsigned extraEquivalentObjectId; /* Equivalent object Id if it is a hard link */
unsigned validMarker1;
} yaffs_ExtendedTags;
/* Spare structure for YAFFS1 */
typedef struct {
__u8 tagByte0;
__u8 tagByte1;
__u8 tagByte2;
__u8 tagByte3;
__u8 pageStatus; /* set to 0 to delete the chunk */
__u8 blockStatus;
__u8 tagByte4;
__u8 tagByte5;
__u8 ecc1[3];
__u8 tagByte6;
__u8 tagByte7;
__u8 ecc2[3];
} yaffs_Spare;
/*Special structure for passing through to mtd */
struct yaffs_NANDSpare {
yaffs_Spare spare;
int eccres1;
int eccres2;
};
/* Block data in RAM */
typedef enum {
YAFFS_BLOCK_STATE_UNKNOWN = 0,
YAFFS_BLOCK_STATE_SCANNING,
YAFFS_BLOCK_STATE_NEEDS_SCANNING,
/* The block might have something on it (ie it is allocating or full, perhaps empty)
* but it needs to be scanned to determine its true state.
* This state is only valid during yaffs_Scan.
* NB We tolerate empty because the pre-scanner might be incapable of deciding
* However, if this state is returned on a YAFFS2 device, then we expect a sequence number
*/
YAFFS_BLOCK_STATE_EMPTY,
/* This block is empty */
YAFFS_BLOCK_STATE_ALLOCATING,
/* This block is partially allocated.
* At least one page holds valid data.
* This is the one currently being used for page
* allocation. Should never be more than one of these
*/
YAFFS_BLOCK_STATE_FULL,
/* All the pages in this block have been allocated.
*/
YAFFS_BLOCK_STATE_DIRTY,
/* All pages have been allocated and deleted.
* Erase me, reuse me.
*/
YAFFS_BLOCK_STATE_CHECKPOINT,
/* This block is assigned to holding checkpoint data.
*/
YAFFS_BLOCK_STATE_COLLECTING,
/* This block is being garbage collected */
YAFFS_BLOCK_STATE_DEAD
/* This block has failed and is not in use */
} yaffs_BlockState;
#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
typedef struct {
int softDeletions:10; /* number of soft deleted pages */
int pagesInUse:10; /* number of pages in use */
yaffs_BlockState blockState:4; /* One of the above block states */
__u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */
/* and retire the block. */
__u32 skipErasedCheck: 1; /* If this is set we can skip the erased check on this block */
__u32 gcPrioritise: 1; /* An ECC check or blank check has failed on this block.
It should be prioritised for GC */
__u32 chunkErrorStrikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */
#ifdef CONFIG_YAFFS_YAFFS2
__u32 hasShrinkHeader:1; /* This block has at least one shrink object header */
__u32 sequenceNumber; /* block sequence number for yaffs2 */
#endif
} yaffs_BlockInfo;
/* -------------------------- Object structure -------------------------------*/
/* This is the object structure as stored on NAND */
typedef struct {
yaffs_ObjectType type;
/* Apply to everything */
int parentObjectId;
__u16 sum__NoLongerUsed; /* checksum of name. No longer used */
YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
/* Thes following apply to directories, files, symlinks - not hard links */
__u32 yst_mode; /* protection */
#ifdef CONFIG_YAFFS_WINCE
__u32 notForWinCE[5];
#else
__u32 yst_uid;
__u32 yst_gid;
__u32 yst_atime;
__u32 yst_mtime;
__u32 yst_ctime;
#endif
/* File size applies to files only */
int fileSize;
/* Equivalent object id applies to hard links only. */
int equivalentObjectId;
/* Alias is for symlinks only. */
YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
__u32 yst_rdev; /* device stuff for block and char devices (major/min) */
#ifdef CONFIG_YAFFS_WINCE
__u32 win_ctime[2];
__u32 win_atime[2];
__u32 win_mtime[2];
__u32 roomToGrow[4];
#else
__u32 roomToGrow[10];
#endif
int shadowsObject; /* This object header shadows the specified object if > 0 */
/* isShrink applies to object headers written when we shrink the file (ie resize) */
__u32 isShrink;
} yaffs_ObjectHeader;
/*--------------------------- Tnode -------------------------- */
union yaffs_Tnode_union {
#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1];
#else
union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL];
#endif
/* __u16 level0[YAFFS_NTNODES_LEVEL0]; */
};
typedef union yaffs_Tnode_union yaffs_Tnode;
struct yaffs_TnodeList_struct {
struct yaffs_TnodeList_struct *next;
yaffs_Tnode *tnodes;
};
typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
/*------------------------ Object -----------------------------*/
/* An object can be one of:
* - a directory (no data, has children links
* - a regular file (data.... not prunes :->).
* - a symlink [symbolic link] (the alias).
* - a hard link
*/
typedef struct {
__u32 fileSize;
__u32 scannedFileSize;
__u32 shrinkSize;
int topLevel;
yaffs_Tnode *top;
} yaffs_FileStructure;
typedef struct {
struct list_head children; /* list of child links */
} yaffs_DirectoryStructure;
typedef struct {
YCHAR *alias;
} yaffs_SymLinkStructure;
typedef struct {
struct yaffs_ObjectStruct *equivalentObject;
__u32 equivalentObjectId;
} yaffs_HardLinkStructure;
typedef union {
yaffs_FileStructure fileVariant;
yaffs_DirectoryStructure directoryVariant;
yaffs_SymLinkStructure symLinkVariant;
yaffs_HardLinkStructure hardLinkVariant;
} yaffs_ObjectVariant;
struct yaffs_ObjectStruct {
__u8 deleted:1; /* This should only apply to unlinked files. */
__u8 softDeleted:1; /* it has also been soft deleted */
__u8 unlinked:1; /* An unlinked file. The file should be in the unlinked directory.*/
__u8 fake:1; /* A fake object has no presence on NAND. */
__u8 renameAllowed:1; /* Some objects are not allowed to be renamed. */
__u8 unlinkAllowed:1;
__u8 dirty:1; /* the object needs to be written to flash */
__u8 valid:1; /* When the file system is being loaded up, this
* object might be created before the data
* is available (ie. file data records appear before the header).
*/
__u8 lazyLoaded:1; /* This object has been lazy loaded and is missing some detail */
__u8 deferedFree:1; /* For Linux kernel. Object is removed from NAND, but is
* still in the inode cache. Free of object is defered.
* until the inode is released.
*/
__u8 serial; /* serial number of chunk in NAND. Cached here */
__u16 sum; /* sum of the name to speed searching */
struct yaffs_DeviceStruct *myDev; /* The device I'm on */
struct list_head hashLink; /* list of objects in this hash bucket */
struct list_head hardLinks; /* all the equivalent hard linked objects */
/* directory structure stuff */
/* also used for linking up the free list */
struct yaffs_ObjectStruct *parent;
struct list_head siblings;
/* Where's my object header in NAND? */
int chunkId;
int nDataChunks; /* Number of data chunks attached to the file. */
__u32 objectId; /* the object id value */
__u32 yst_mode;
#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1];
#endif
#ifndef __KERNEL__
__u32 inUse;
#endif
#ifdef CONFIG_YAFFS_WINCE
__u32 win_ctime[2];
__u32 win_mtime[2];
__u32 win_atime[2];
#else
__u32 yst_uid;
__u32 yst_gid;
__u32 yst_atime;
__u32 yst_mtime;
__u32 yst_ctime;
#endif
__u32 yst_rdev;
#ifdef __KERNEL__
struct inode *myInode;
#endif
yaffs_ObjectType variantType;
yaffs_ObjectVariant variant;
};
typedef struct yaffs_ObjectStruct yaffs_Object;
struct yaffs_ObjectList_struct {
yaffs_Object *objects;
struct yaffs_ObjectList_struct *next;
};
typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
typedef struct {
struct list_head list;
int count;
} yaffs_ObjectBucket;
/* yaffs_CheckpointObject holds the definition of an object as dumped
* by checkpointing.
*/
typedef struct {
int structType;
__u32 objectId;
__u32 parentId;
int chunkId;
yaffs_ObjectType variantType:3;
__u8 deleted:1;
__u8 softDeleted:1;
__u8 unlinked:1;
__u8 fake:1;
__u8 renameAllowed:1;
__u8 unlinkAllowed:1;
__u8 serial;
int nDataChunks;
__u32 fileSizeOrEquivalentObjectId;
}yaffs_CheckpointObject;
/*--------------------- Temporary buffers ----------------
*
* These are chunk-sized working buffers. Each device has a few
*/
typedef struct {
__u8 *buffer;
int line; /* track from whence this buffer was allocated */
int maxLine;
} yaffs_TempBuffer;
/*----------------- Device ---------------------------------*/
struct yaffs_DeviceStruct {
struct list_head devList;
const char *name;
/* Entry parameters set up way early. Yaffs sets up the rest.*/
int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */
int nChunksPerBlock; /* does not need to be a power of 2 */
int nBytesPerSpare; /* spare area size */
int startBlock; /* Start block we're allowed to use */
int endBlock; /* End block we're allowed to use */
int nReservedBlocks; /* We want this tuneable so that we can reduce */
/* reserved blocks on NOR and RAM. */
/* Stuff used by the shared space checkpointing mechanism */
/* If this value is zero, then this mechanism is disabled */
int nCheckpointReservedBlocks; /* Blocks to reserve for checkpoint data */
int nShortOpCaches; /* If <= 0, then short op caching is disabled, else
* the number of short op caches (don't use too many)
*/
int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */
int useNANDECC; /* Flag to decide whether or not to use NANDECC */
void *genericDevice; /* Pointer to device context
* On an mtd this holds the mtd pointer.
*/
void *superBlock;
/* NAND access functions (Must be set before calling YAFFS)*/
int (*writeChunkToNAND) (struct yaffs_DeviceStruct * dev,
int chunkInNAND, const __u8 * data,
const yaffs_Spare * spare);
int (*readChunkFromNAND) (struct yaffs_DeviceStruct * dev,
int chunkInNAND, __u8 * data,
yaffs_Spare * spare);
int (*eraseBlockInNAND) (struct yaffs_DeviceStruct * dev,
int blockInNAND);
int (*initialiseNAND) (struct yaffs_DeviceStruct * dev);
#ifdef CONFIG_YAFFS_YAFFS2
int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct * dev,
int chunkInNAND, const __u8 * data,
const yaffs_ExtendedTags * tags);
int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct * dev,
int chunkInNAND, __u8 * data,
yaffs_ExtendedTags * tags);
int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo);
int (*queryNANDBlock) (struct yaffs_DeviceStruct * dev, int blockNo,
yaffs_BlockState * state, int *sequenceNumber);
#endif
int isYaffs2;
/* The removeObjectCallback function must be supplied by OS flavours that
* need it. The Linux kernel does not use this, but yaffs direct does use
* it to implement the faster readdir
*/
void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj);
/* Callback to mark the superblock dirsty */
void (*markSuperBlockDirty)(void * superblock);
int wideTnodesDisabled; /* Set to disable wide tnodes */
/* End of stuff that must be set before initialisation. */
/* Checkpoint control. Can be set before or after initialisation */
__u8 skipCheckpointRead;
__u8 skipCheckpointWrite;
/* Runtime parameters. Set up by YAFFS. */
__u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */
__u16 chunkGroupSize; /* == 2^^chunkGroupBits */
/* Stuff to support wide tnodes */
__u32 tnodeWidth;
__u32 tnodeMask;
/* Stuff to support various file offses to chunk/offset translations */
/* "Crumbs" for nDataBytesPerChunk not being a power of 2 */
__u32 crumbMask;
__u32 crumbShift;
__u32 crumbsPerChunk;
/* Straight shifting for nDataBytesPerChunk being a power of 2 */
__u32 chunkShift;
__u32 chunkMask;
#ifdef __KERNEL__
struct semaphore sem; /* Semaphore for waiting on erasure.*/
struct semaphore grossLock; /* Gross locking semaphore */
__u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
* at compile time so we have to allocate it.
*/
void (*putSuperFunc) (struct super_block * sb);
#endif
int isMounted;
int isCheckpointed;
/* Stuff to support block offsetting to support start block zero */
int internalStartBlock;
int internalEndBlock;
int blockOffset;
int chunkOffset;
/* Runtime checkpointing stuff */
int checkpointPageSequence; /* running sequence number of checkpoint pages */
int checkpointByteCount;
int checkpointByteOffset;
__u8 *checkpointBuffer;
int checkpointOpenForWrite;
int blocksInCheckpoint;
int checkpointCurrentChunk;
int checkpointCurrentBlock;
int checkpointNextBlock;
int *checkpointBlockList;
int checkpointMaxBlocks;
__u32 checkpointSum;
__u32 checkpointXor;
/* Block Info */
yaffs_BlockInfo *blockInfo;
__u8 *chunkBits; /* bitmap of chunks in use */
unsigned blockInfoAlt:1; /* was allocated using alternative strategy */
unsigned chunkBitsAlt:1; /* was allocated using alternative strategy */
int chunkBitmapStride; /* Number of bytes of chunkBits per block.
* Must be consistent with nChunksPerBlock.
*/
int nErasedBlocks;
int allocationBlock; /* Current block being allocated off */
__u32 allocationPage;
int allocationBlockFinder; /* Used to search for next allocation block */
/* Runtime state */
int nTnodesCreated;
yaffs_Tnode *freeTnodes;
int nFreeTnodes;
yaffs_TnodeList *allocatedTnodeList;
int isDoingGC;
int nObjectsCreated;
yaffs_Object *freeObjects;
int nFreeObjects;
yaffs_ObjectList *allocatedObjectList;
yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS];
int nFreeChunks;
int currentDirtyChecker; /* Used to find current dirtiest block */
__u32 *gcCleanupList; /* objects to delete at the end of a GC. */
int nonAggressiveSkip; /* GC state/mode */
/* Statistcs */
int nPageWrites;
int nPageReads;
int nBlockErasures;
int nErasureFailures;
int nGCCopies;
int garbageCollections;
int passiveGarbageCollections;
int nRetriedWrites;
int nRetiredBlocks;
int eccFixed;
int eccUnfixed;
int tagsEccFixed;
int tagsEccUnfixed;
int nDeletions;
int nUnmarkedDeletions;
int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */
/* Special directories */
yaffs_Object *rootDir;
yaffs_Object *lostNFoundDir;
/* Buffer areas for storing data to recover from write failures TODO
* __u8 bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK];
* yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK];
*/
int bufferedBlock; /* Which block is buffered here? */
int doingBufferedBlockRewrite;
yaffs_ChunkCache *srCache;
int srLastUse;
int cacheHits;
/* Stuff for background deletion and unlinked files.*/
yaffs_Object *unlinkedDir; /* Directory where unlinked and deleted files live. */
yaffs_Object *deletedDir; /* Directory where deleted objects are sent to disappear. */
yaffs_Object *unlinkedDeletion; /* Current file being background deleted.*/
int nDeletedFiles; /* Count of files awaiting deletion;*/
int nUnlinkedFiles; /* Count of unlinked files. */
int nBackgroundDeletions; /* Count of background deletions. */
yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
int maxTemp;
int unmanagedTempAllocations;
int unmanagedTempDeallocations;
/* yaffs2 runtime stuff */
unsigned sequenceNumber; /* Sequence number of currently allocating block */
unsigned oldestDirtySequence;
};
typedef struct yaffs_DeviceStruct yaffs_Device;
/* The static layout of bllock usage etc is stored in the super block header */
typedef struct {
int StructType;
int version;
int checkpointStartBlock;
int checkpointEndBlock;
int startBlock;
int endBlock;
int rfu[100];
} yaffs_SuperBlockHeader;
/* The CheckpointDevice structure holds the device information that changes at runtime and
* must be preserved over unmount/mount cycles.
*/
typedef struct {
int structType;
int nErasedBlocks;
int allocationBlock; /* Current block being allocated off */
__u32 allocationPage;
int nFreeChunks;
int nDeletedFiles; /* Count of files awaiting deletion;*/
int nUnlinkedFiles; /* Count of unlinked files. */
int nBackgroundDeletions; /* Count of background deletions. */
/* yaffs2 runtime stuff */
unsigned sequenceNumber; /* Sequence number of currently allocating block */
unsigned oldestDirtySequence;
} yaffs_CheckpointDevice;
typedef struct {
int structType;
__u32 magic;
__u32 version;
__u32 head;
} yaffs_CheckpointValidity;
/* Function to manipulate block info */
static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
{
if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
blk));
YBUG();
}
return &dev->blockInfo[blk - dev->internalStartBlock];
}
/*----------------------- YAFFS Functions -----------------------*/
int yaffs_GutsInitialise(yaffs_Device * dev);
void yaffs_Deinitialise(yaffs_Device * dev);
int yaffs_GetNumberOfFreeChunks(yaffs_Device * dev);
int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName,
yaffs_Object * newDir, const YCHAR * newName);
int yaffs_Unlink(yaffs_Object * dir, const YCHAR * name);
int yaffs_DeleteFile(yaffs_Object * obj);
int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize);
int yaffs_GetObjectFileLength(yaffs_Object * obj);
int yaffs_GetObjectInode(yaffs_Object * obj);
unsigned yaffs_GetObjectType(yaffs_Object * obj);
int yaffs_GetObjectLinkCount(yaffs_Object * obj);
int yaffs_SetAttributes(yaffs_Object * obj, struct iattr *attr);
int yaffs_GetAttributes(yaffs_Object * obj, struct iattr *attr);
/* File operations */
int yaffs_ReadDataFromFile(yaffs_Object * obj, __u8 * buffer, loff_t offset,
int nBytes);
int yaffs_WriteDataToFile(yaffs_Object * obj, const __u8 * buffer, loff_t offset,
int nBytes, int writeThrough);
int yaffs_ResizeFile(yaffs_Object * obj, loff_t newSize);
yaffs_Object *yaffs_MknodFile(yaffs_Object * parent, const YCHAR * name,
__u32 mode, __u32 uid, __u32 gid);
int yaffs_FlushFile(yaffs_Object * obj, int updateTime);
/* Flushing and checkpointing */
void yaffs_FlushEntireDeviceCache(yaffs_Device *dev);
int yaffs_CheckpointSave(yaffs_Device *dev);
int yaffs_CheckpointRestore(yaffs_Device *dev);
/* Directory operations */
yaffs_Object *yaffs_MknodDirectory(yaffs_Object * parent, const YCHAR * name,
__u32 mode, __u32 uid, __u32 gid);
yaffs_Object *yaffs_FindObjectByName(yaffs_Object * theDir, const YCHAR * name);
int yaffs_ApplyToDirectoryChildren(yaffs_Object * theDir,
int (*fn) (yaffs_Object *));
yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device * dev, __u32 number);
/* Link operations */
yaffs_Object *yaffs_Link(yaffs_Object * parent, const YCHAR * name,
yaffs_Object * equivalentObject);
yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object * obj);
/* Symlink operations */
yaffs_Object *yaffs_MknodSymLink(yaffs_Object * parent, const YCHAR * name,
__u32 mode, __u32 uid, __u32 gid,
const YCHAR * alias);
YCHAR *yaffs_GetSymlinkAlias(yaffs_Object * obj);
/* Special inodes (fifos, sockets and devices) */
yaffs_Object *yaffs_MknodSpecial(yaffs_Object * parent, const YCHAR * name,
__u32 mode, __u32 uid, __u32 gid, __u32 rdev);
/* Special directories */
yaffs_Object *yaffs_Root(yaffs_Device * dev);
yaffs_Object *yaffs_LostNFound(yaffs_Device * dev);
#ifdef CONFIG_YAFFS_WINCE
/* CONFIG_YAFFS_WINCE special stuff */
void yfsd_WinFileTimeNow(__u32 target[2]);
#endif
#ifdef __KERNEL__
void yaffs_HandleDeferedFree(yaffs_Object * obj);
#endif
/* Debug dump */
int yaffs_DumpObject(yaffs_Object * obj);
void yaffs_GutsTest(yaffs_Device * dev);
/* A few useful functions */
void yaffs_InitialiseTags(yaffs_ExtendedTags * tags);
void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn);
int yaffs_CheckFF(__u8 * buffer, int nBytes);
void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi);
#endif

View File

@ -1,241 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
const char *yaffs_mtdif_c_version =
"$Id: yaffs_mtdif.c,v 1.19 2007-02-14 01:09:06 wookey Exp $";
#include "yportenv.h"
#include "yaffs_mtdif.h"
#include "linux/mtd/mtd.h"
#include "linux/types.h"
#include "linux/time.h"
#include "linux/mtd/nand.h"
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
static struct nand_oobinfo yaffs_oobinfo = {
.useecc = 1,
.eccbytes = 6,
.eccpos = {8, 9, 10, 13, 14, 15}
};
static struct nand_oobinfo yaffs_noeccinfo = {
.useecc = 0,
};
#endif
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
{
oob[0] = spare->tagByte0;
oob[1] = spare->tagByte1;
oob[2] = spare->tagByte2;
oob[3] = spare->tagByte3;
oob[4] = spare->tagByte4;
oob[5] = spare->tagByte5 & 0x3f;
oob[5] |= spare->blockStatus == 'Y' ? 0: 0x80;
oob[5] |= spare->pageStatus == 0 ? 0: 0x40;
oob[6] = spare->tagByte6;
oob[7] = spare->tagByte7;
}
static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob)
{
struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare;
spare->tagByte0 = oob[0];
spare->tagByte1 = oob[1];
spare->tagByte2 = oob[2];
spare->tagByte3 = oob[3];
spare->tagByte4 = oob[4];
spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y';
spare->pageStatus = oob[5] & 0x40 ? 0xff : 0;
spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff;
spare->tagByte6 = oob[6];
spare->tagByte7 = oob[7];
spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff;
nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */
}
#endif
int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data, const yaffs_Spare * spare)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
struct mtd_oob_ops ops;
#endif
size_t dummy;
int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
__u8 spareAsBytes[8]; /* OOB */
if (data && !spare)
retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data);
else if (spare) {
if (dev->useNANDECC) {
translate_spare2oob(spare, spareAsBytes);
ops.mode = MTD_OOB_AUTO;
ops.ooblen = 8; /* temp hack */
} else {
ops.mode = MTD_OOB_RAW;
ops.ooblen = YAFFS_BYTES_PER_SPARE;
}
ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
ops.datbuf = (u8 *)data;
ops.ooboffs = 0;
ops.oobbuf = spareAsBytes;
retval = mtd->write_oob(mtd, addr, &ops);
}
#else
__u8 *spareAsBytes = (__u8 *) spare;
if (data && spare) {
if (dev->useNANDECC)
retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, spareAsBytes,
&yaffs_oobinfo);
else
retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, spareAsBytes,
&yaffs_noeccinfo);
} else {
if (data)
retval =
mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
data);
if (spare)
retval =
mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
&dummy, spareAsBytes);
}
#endif
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
yaffs_Spare * spare)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
struct mtd_oob_ops ops;
#endif
size_t dummy;
int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
__u8 spareAsBytes[8]; /* OOB */
if (data && !spare)
retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data);
else if (spare) {
if (dev->useNANDECC) {
ops.mode = MTD_OOB_AUTO;
ops.ooblen = 8; /* temp hack */
} else {
ops.mode = MTD_OOB_RAW;
ops.ooblen = YAFFS_BYTES_PER_SPARE;
}
ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
ops.datbuf = data;
ops.ooboffs = 0;
ops.oobbuf = spareAsBytes;
retval = mtd->read_oob(mtd, addr, &ops);
if (dev->useNANDECC)
translate_oob2spare(spare, spareAsBytes);
}
#else
__u8 *spareAsBytes = (__u8 *) spare;
if (data && spare) {
if (dev->useNANDECC) {
/* Careful, this call adds 2 ints */
/* to the end of the spare data. Calling function */
/* should allocate enough memory for spare, */
/* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */
retval =
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, spareAsBytes,
&yaffs_oobinfo);
} else {
retval =
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, spareAsBytes,
&yaffs_noeccinfo);
}
} else {
if (data)
retval =
mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
data);
if (spare)
retval =
mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
&dummy, spareAsBytes);
}
#endif
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
__u32 addr =
((loff_t) blockNumber) * dev->nDataBytesPerChunk
* dev->nChunksPerBlock;
struct erase_info ei;
int retval = 0;
ei.mtd = mtd;
ei.addr = addr;
ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;
ei.time = 1000;
ei.retries = 2;
ei.callback = NULL;
ei.priv = (u_long) dev;
/* Todo finish off the ei if required */
sema_init(&dev->sem, 0);
retval = mtd->erase(mtd, &ei);
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd_InitialiseNAND(yaffs_Device * dev)
{
return YAFFS_OK;
}

View File

@ -1,27 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_MTDIF_H__
#define __YAFFS_MTDIF_H__
#include "yaffs_guts.h"
int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data, const yaffs_Spare * spare);
int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
yaffs_Spare * spare);
int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber);
int nandmtd_InitialiseNAND(yaffs_Device * dev);
#endif

View File

@ -1,434 +0,0 @@
From ian@brightstareng.com Fri May 18 15:06:49 2007
From ian@brightstareng.com Fri May 18 15:08:21 2007
Received: from 206.173.66.57.ptr.us.xo.net ([206.173.66.57] helo=zebra.brightstareng.com)
by apollo.linkchoose.co.uk with esmtp (Exim 4.60)
(envelope-from <ian@brightstareng.com>)
id 1Hp380-00011e-T6
for david.goodenough@linkchoose.co.uk; Fri, 18 May 2007 15:08:21 +0100
Received: from localhost (localhost.localdomain [127.0.0.1])
by zebra.brightstareng.com (Postfix) with ESMTP
id 4819F28C004; Fri, 18 May 2007 10:07:49 -0400 (EDT)
Received: from zebra.brightstareng.com ([127.0.0.1])
by localhost (zebra [127.0.0.1]) (amavisd-new, port 10024) with ESMTP
id 05328-06; Fri, 18 May 2007 10:07:16 -0400 (EDT)
Received: from pippin (unknown [192.168.1.25])
by zebra.brightstareng.com (Postfix) with ESMTP
id 8BEF528C1BC; Fri, 18 May 2007 10:06:53 -0400 (EDT)
From: Ian McDonnell <ian@brightstareng.com>
To: David Goodenough <david.goodenough@linkchoose.co.uk>
Subject: Re: something tested this time -- yaffs_mtdif1-compat.c
Date: Fri, 18 May 2007 10:06:49 -0400
User-Agent: KMail/1.9.1
References: <200705142207.06909.ian@brightstareng.com> <200705171131.53536.ian@brightstareng.com> <200705181334.32166.david.goodenough@linkchoose.co.uk>
In-Reply-To: <200705181334.32166.david.goodenough@linkchoose.co.uk>
Cc: Andrea Conti <alyf@alyf.net>,
Charles Manning <manningc2@actrix.gen.nz>
MIME-Version: 1.0
Content-Type: Multipart/Mixed;
boundary="Boundary-00=_5LbTGmt62YoutxM"
Message-Id: <200705181006.49860.ian@brightstareng.com>
X-Virus-Scanned: by amavisd-new at brightstareng.com
Status: R
X-Status: NT
X-KMail-EncryptionState:
X-KMail-SignatureState:
X-KMail-MDN-Sent:
--Boundary-00=_5LbTGmt62YoutxM
Content-Type: text/plain;
charset="iso-8859-15"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
David, Andrea,
On Friday 18 May 2007 08:34, you wrote:
> Yea team. With this fix in place (I put it in the wrong place
> at first) I can now mount and ls the Yaffs partition without
> an error messages!
Good news!
Attached is a newer yaffs_mtdif1.c with a bandaid to help the
2.6.18 and 2.6.19 versions of MTD not trip on the oob read.
See the LINUX_VERSION_CODE conditional in
nandmtd1_ReadChunkWithTagsFromNAND.
-imcd
--Boundary-00=_5LbTGmt62YoutxM
Content-Type: text/x-csrc;
charset="iso-8859-15";
name="yaffs_mtdif1.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="yaffs_mtdif1.c"
/*
* YAFFS: Yet another FFS. A NAND-flash specific file system.
* yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
*
* Copyright (C) 2002 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* This module provides the interface between yaffs_nand.c and the
* MTD API. This version is used when the MTD interface supports the
* 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
* and we have small-page NAND device.
*
* These functions are invoked via function pointers in yaffs_nand.c.
* This replaces functionality provided by functions in yaffs_mtdif.c
* and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
* called in yaffs_mtdif.c when the function pointers are NULL.
* We assume the MTD layer is performing ECC (useNANDECC is true).
*/
#include "yportenv.h"
#include "yaffs_guts.h"
#include "yaffs_packedtags1.h"
#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC
#include "linux/kernel.h"
#include "linux/version.h"
#include "linux/types.h"
#include "linux/mtd/mtd.h"
/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
const char *yaffs_mtdif1_c_version = "$Id$";
#ifndef CONFIG_YAFFS_9BYTE_TAGS
# define YTAG1_SIZE 8
#else
# define YTAG1_SIZE 9
#endif
#if 0
/* Use the following nand_ecclayout with MTD when using
* CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout.
* If you have existing Yaffs images and the byte order differs from this,
* adjust 'oobfree' to match your existing Yaffs data.
*
* This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
* pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
* the 9th byte.
*
* Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
* We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
* where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
* byte and B is the small-page bad-block indicator byte.
*/
static struct nand_ecclayout nand_oob_16 = {
.eccbytes = 6,
.eccpos = { 8, 9, 10, 13, 14, 15 },
.oobavail = 9,
.oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
};
#endif
/* Write a chunk (page) of data to NAND.
*
* Caller always provides ExtendedTags data which are converted to a more
* compact (packed) form for storage in NAND. A mini-ECC runs over the
* contents of the tags meta-data; used to valid the tags when read.
*
* - Pack ExtendedTags to PackedTags1 form
* - Compute mini-ECC for PackedTags1
* - Write data and packed tags to NAND.
*
* Note: Due to the use of the PackedTags1 meta-data which does not include
* a full sequence number (as found in the larger PackedTags2 form) it is
* necessary for Yaffs to re-write a chunk/page (just once) to mark it as
* discarded and dirty. This is not ideal: newer NAND parts are supposed
* to be written just once. When Yaffs performs this operation, this
* function is called with a NULL data pointer -- calling MTD write_oob
* without data is valid usage (2.6.17).
*
* Any underlying MTD error results in YAFFS_FAIL.
* Returns YAFFS_OK or YAFFS_FAIL.
*/
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags)
{
struct mtd_info * mtd = dev->genericDevice;
int chunkBytes = dev->nDataBytesPerChunk;
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
struct mtd_oob_ops ops;
yaffs_PackedTags1 pt1;
int retval;
/* we assume that PackedTags1 and yaffs_Tags are compatible */
compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
compile_time_assertion(sizeof(yaffs_Tags) == 8);
yaffs_PackTags1(&pt1, etags);
yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
/* When deleting a chunk, the upper layer provides only skeletal
* etags, one with chunkDeleted set. However, we need to update the
* tags, not erase them completely. So we use the NAND write property
* that only zeroed-bits stick and set tag bytes to all-ones and
* zero just the (not) deleted bit.
*/
#ifndef CONFIG_YAFFS_9BYTE_TAGS
if (etags->chunkDeleted) {
memset(&pt1, 0xff, 8);
/* clear delete status bit to indicate deleted */
pt1.deleted = 0;
}
#else
((__u8 *)&pt1)[8] = 0xff;
if (etags->chunkDeleted) {
memset(&pt1, 0xff, 8);
/* zero pageStatus byte to indicate deleted */
((__u8 *)&pt1)[8] = 0;
}
#endif
memset(&ops, 0, sizeof(ops));
ops.mode = MTD_OOB_AUTO;
ops.len = (data) ? chunkBytes : 0;
ops.ooblen = YTAG1_SIZE;
ops.datbuf = (__u8 *)data;
ops.oobbuf = (__u8 *)&pt1;
retval = mtd->write_oob(mtd, addr, &ops);
if (retval) {
yaffs_trace(YAFFS_TRACE_MTD,
"write_oob failed, chunk %d, mtd error %d\n",
chunkInNAND, retval);
}
return retval ? YAFFS_FAIL : YAFFS_OK;
}
/* Return with empty ExtendedTags but add eccResult.
*/
static int rettags(yaffs_ExtendedTags * etags, int eccResult, int retval)
{
if (etags) {
memset(etags, 0, sizeof(*etags));
etags->eccResult = eccResult;
}
return retval;
}
/* Read a chunk (page) from NAND.
*
* Caller expects ExtendedTags data to be usable even on error; that is,
* all members except eccResult and blockBad are zeroed.
*
* - Check ECC results for data (if applicable)
* - Check for blank/erased block (return empty ExtendedTags if blank)
* - Check the PackedTags1 mini-ECC (correct if necessary/possible)
* - Convert PackedTags1 to ExtendedTags
* - Update eccResult and blockBad members to refect state.
*
* Returns YAFFS_OK or YAFFS_FAIL.
*/
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
int chunkInNAND, __u8 * data, yaffs_ExtendedTags * etags)
{
struct mtd_info * mtd = dev->genericDevice;
int chunkBytes = dev->nDataBytesPerChunk;
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
int eccres = YAFFS_ECC_RESULT_NO_ERROR;
struct mtd_oob_ops ops;
yaffs_PackedTags1 pt1;
int retval;
int deleted;
memset(&ops, 0, sizeof(ops));
ops.mode = MTD_OOB_AUTO;
ops.len = (data) ? chunkBytes : 0;
ops.ooblen = YTAG1_SIZE;
ops.datbuf = data;
ops.oobbuf = (__u8 *)&pt1;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
/* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
* help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
*/
ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
#endif
/* Read page and oob using MTD.
* Check status and determine ECC result.
*/
retval = mtd->read_oob(mtd, addr, &ops);
if (retval) {
yaffs_trace(YAFFS_TRACE_MTD,
"read_oob failed, chunk %d, mtd error %d\n",
chunkInNAND, retval);
}
switch (retval) {
case 0:
/* no error */
break;
case -EUCLEAN:
/* MTD's ECC fixed the data */
eccres = YAFFS_ECC_RESULT_FIXED;
dev->eccFixed++;
break;
case -EBADMSG:
/* MTD's ECC could not fix the data */
dev->eccUnfixed++;
/* fall into... */
default:
rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
etags->blockBad = (mtd->block_isbad)(mtd, addr);
return YAFFS_FAIL;
}
/* Check for a blank/erased chunk.
*/
if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
/* when blank, upper layers want eccResult to be <= NO_ERROR */
return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
}
#ifndef CONFIG_YAFFS_9BYTE_TAGS
/* Read deleted status (bit) then return it to it's non-deleted
* state before performing tags mini-ECC check. pt1.deleted is
* inverted.
*/
deleted = !pt1.deleted;
pt1.deleted = 1;
#else
(void) deleted; /* not used */
#endif
/* Check the packed tags mini-ECC and correct if necessary/possible.
*/
retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
switch (retval) {
case 0:
/* no tags error, use MTD result */
break;
case 1:
/* recovered tags-ECC error */
dev->tagsEccFixed++;
eccres = YAFFS_ECC_RESULT_FIXED;
break;
default:
/* unrecovered tags-ECC error */
dev->tagsEccUnfixed++;
return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
}
/* Unpack the tags to extended form and set ECC result.
* [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
*/
pt1.shouldBeFF = 0xFFFFFFFF;
yaffs_UnpackTags1(etags, &pt1);
etags->eccResult = eccres;
/* Set deleted state.
*/
#ifndef CONFIG_YAFFS_9BYTE_TAGS
etags->chunkDeleted = deleted;
#else
etags->chunkDeleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
#endif
return YAFFS_OK;
}
/* Mark a block bad.
*
* This is a persistant state.
* Use of this function should be rare.
*
* Returns YAFFS_OK or YAFFS_FAIL.
*/
int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
{
struct mtd_info * mtd = dev->genericDevice;
int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
int retval;
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo);
retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
return (retval) ? YAFFS_FAIL : YAFFS_OK;
}
/* Check any MTD prerequists.
*
* Returns YAFFS_OK or YAFFS_FAIL.
*/
static int nandmtd1_TestPrerequists(struct mtd_info * mtd)
{
/* 2.6.18 has mtd->ecclayout->oobavail */
/* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
int oobavail = mtd->ecclayout->oobavail;
if (oobavail < YTAG1_SIZE) {
yaffs_trace(YAFFS_TRACE_ERROR,
"mtd device has only %d bytes for tags, need %d",
oobavail, YTAG1_SIZE);
return YAFFS_FAIL;
}
return YAFFS_OK;
}
/* Query for the current state of a specific block.
*
* Examine the tags of the first chunk of the block and return the state:
* - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
* - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
* - YAFFS_BLOCK_STATE_EMPTY, the block is clean
*
* Always returns YAFFS_OK.
*/
int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState * pState, int *pSequenceNumber)
{
struct mtd_info * mtd = dev->genericDevice;
int chunkNo = blockNo * dev->nChunksPerBlock;
yaffs_ExtendedTags etags;
int state = YAFFS_BLOCK_STATE_DEAD;
int seqnum = 0;
int retval;
/* We don't yet have a good place to test for MTD config prerequists.
* Do it here as we are called during the initial scan.
*/
if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) {
return YAFFS_FAIL;
}
retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
if (etags.blockBad) {
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
"block %d is marked bad", blockNo);
state = YAFFS_BLOCK_STATE_DEAD;
}
else if (etags.chunkUsed) {
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
seqnum = etags.sequenceNumber;
}
else {
state = YAFFS_BLOCK_STATE_EMPTY;
}
*pState = state;
*pSequenceNumber = seqnum;
/* query always succeeds */
return YAFFS_OK;
}
#endif /*KERNEL_VERSION*/
--Boundary-00=_5LbTGmt62YoutxM--

View File

@ -1,363 +0,0 @@
/*
* YAFFS: Yet another FFS. A NAND-flash specific file system.
* yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
*
* Copyright (C) 2002 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* This module provides the interface between yaffs_nand.c and the
* MTD API. This version is used when the MTD interface supports the
* 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
* and we have small-page NAND device.
*
* These functions are invoked via function pointers in yaffs_nand.c.
* This replaces functionality provided by functions in yaffs_mtdif.c
* and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
* called in yaffs_mtdif.c when the function pointers are NULL.
* We assume the MTD layer is performing ECC (useNANDECC is true).
*/
#include "yportenv.h"
#include "yaffs_guts.h"
#include "yaffs_packedtags1.h"
#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC
#include "linux/kernel.h"
#include "linux/version.h"
#include "linux/types.h"
#include "linux/mtd/mtd.h"
/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.3 2007/05/15 20:16:11 ian Exp $";
#ifndef CONFIG_YAFFS_9BYTE_TAGS
# define YTAG1_SIZE 8
#else
# define YTAG1_SIZE 9
#endif
#if 0
/* Use the following nand_ecclayout with MTD when using
* CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout.
* If you have existing Yaffs images and the byte order differs from this,
* adjust 'oobfree' to match your existing Yaffs data.
*
* This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
* pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
* the 9th byte.
*
* Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
* We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
* where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
* byte and B is the small-page bad-block indicator byte.
*/
static struct nand_ecclayout nand_oob_16 = {
.eccbytes = 6,
.eccpos = { 8, 9, 10, 13, 14, 15 },
.oobavail = 9,
.oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
};
#endif
/* Write a chunk (page) of data to NAND.
*
* Caller always provides ExtendedTags data which are converted to a more
* compact (packed) form for storage in NAND. A mini-ECC runs over the
* contents of the tags meta-data; used to valid the tags when read.
*
* - Pack ExtendedTags to PackedTags1 form
* - Compute mini-ECC for PackedTags1
* - Write data and packed tags to NAND.
*
* Note: Due to the use of the PackedTags1 meta-data which does not include
* a full sequence number (as found in the larger PackedTags2 form) it is
* necessary for Yaffs to re-write a chunk/page (just once) to mark it as
* discarded and dirty. This is not ideal: newer NAND parts are supposed
* to be written just once. When Yaffs performs this operation, this
* function is called with a NULL data pointer -- calling MTD write_oob
* without data is valid usage (2.6.17).
*
* Any underlying MTD error results in YAFFS_FAIL.
* Returns YAFFS_OK or YAFFS_FAIL.
*/
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags)
{
struct mtd_info * mtd = dev->genericDevice;
int chunkBytes = dev->nDataBytesPerChunk;
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
struct mtd_oob_ops ops;
yaffs_PackedTags1 pt1;
int retval;
/* we assume that PackedTags1 and yaffs_Tags are compatible */
compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
compile_time_assertion(sizeof(yaffs_Tags) == 8);
dev->nPageWrites++;
yaffs_PackTags1(&pt1, etags);
yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
/* When deleting a chunk, the upper layer provides only skeletal
* etags, one with chunkDeleted set. However, we need to update the
* tags, not erase them completely. So we use the NAND write property
* that only zeroed-bits stick and set tag bytes to all-ones and
* zero just the (not) deleted bit.
*/
#ifndef CONFIG_YAFFS_9BYTE_TAGS
if (etags->chunkDeleted) {
memset(&pt1, 0xff, 8);
/* clear delete status bit to indicate deleted */
pt1.deleted = 0;
}
#else
((__u8 *)&pt1)[8] = 0xff;
if (etags->chunkDeleted) {
memset(&pt1, 0xff, 8);
/* zero pageStatus byte to indicate deleted */
((__u8 *)&pt1)[8] = 0;
}
#endif
memset(&ops, 0, sizeof(ops));
ops.mode = MTD_OOB_AUTO;
ops.len = (data) ? chunkBytes : 0;
ops.ooblen = YTAG1_SIZE;
ops.datbuf = (__u8 *)data;
ops.oobbuf = (__u8 *)&pt1;
retval = mtd->write_oob(mtd, addr, &ops);
if (retval) {
yaffs_trace(YAFFS_TRACE_MTD,
"write_oob failed, chunk %d, mtd error %d\n",
chunkInNAND, retval);
}
return retval ? YAFFS_FAIL : YAFFS_OK;
}
/* Return with empty ExtendedTags but add eccResult.
*/
static int rettags(yaffs_ExtendedTags * etags, int eccResult, int retval)
{
if (etags) {
memset(etags, 0, sizeof(*etags));
etags->eccResult = eccResult;
}
return retval;
}
/* Read a chunk (page) from NAND.
*
* Caller expects ExtendedTags data to be usable even on error; that is,
* all members except eccResult and blockBad are zeroed.
*
* - Check ECC results for data (if applicable)
* - Check for blank/erased block (return empty ExtendedTags if blank)
* - Check the PackedTags1 mini-ECC (correct if necessary/possible)
* - Convert PackedTags1 to ExtendedTags
* - Update eccResult and blockBad members to refect state.
*
* Returns YAFFS_OK or YAFFS_FAIL.
*/
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
int chunkInNAND, __u8 * data, yaffs_ExtendedTags * etags)
{
struct mtd_info * mtd = dev->genericDevice;
int chunkBytes = dev->nDataBytesPerChunk;
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
int eccres = YAFFS_ECC_RESULT_NO_ERROR;
struct mtd_oob_ops ops;
yaffs_PackedTags1 pt1;
int retval;
int deleted;
dev->nPageReads++;
memset(&ops, 0, sizeof(ops));
ops.mode = MTD_OOB_AUTO;
ops.len = (data) ? chunkBytes : 0;
ops.ooblen = YTAG1_SIZE;
ops.datbuf = data;
ops.oobbuf = (__u8 *)&pt1;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
/* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
* help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
*/
ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
#endif
/* Read page and oob using MTD.
* Check status and determine ECC result.
*/
retval = mtd->read_oob(mtd, addr, &ops);
if (retval) {
yaffs_trace(YAFFS_TRACE_MTD,
"read_oob failed, chunk %d, mtd error %d\n",
chunkInNAND, retval);
}
switch (retval) {
case 0:
/* no error */
break;
case -EUCLEAN:
/* MTD's ECC fixed the data */
eccres = YAFFS_ECC_RESULT_FIXED;
dev->eccFixed++;
break;
case -EBADMSG:
/* MTD's ECC could not fix the data */
dev->eccUnfixed++;
/* fall into... */
default:
rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
etags->blockBad = (mtd->block_isbad)(mtd, addr);
return YAFFS_FAIL;
}
/* Check for a blank/erased chunk.
*/
if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
/* when blank, upper layers want eccResult to be <= NO_ERROR */
return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
}
#ifndef CONFIG_YAFFS_9BYTE_TAGS
/* Read deleted status (bit) then return it to it's non-deleted
* state before performing tags mini-ECC check. pt1.deleted is
* inverted.
*/
deleted = !pt1.deleted;
pt1.deleted = 1;
#else
deleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
#endif
/* Check the packed tags mini-ECC and correct if necessary/possible.
*/
retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
switch (retval) {
case 0:
/* no tags error, use MTD result */
break;
case 1:
/* recovered tags-ECC error */
dev->tagsEccFixed++;
if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
eccres = YAFFS_ECC_RESULT_FIXED;
break;
default:
/* unrecovered tags-ECC error */
dev->tagsEccUnfixed++;
return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
}
/* Unpack the tags to extended form and set ECC result.
* [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
*/
pt1.shouldBeFF = 0xFFFFFFFF;
yaffs_UnpackTags1(etags, &pt1);
etags->eccResult = eccres;
/* Set deleted state */
etags->chunkDeleted = deleted;
return YAFFS_OK;
}
/* Mark a block bad.
*
* This is a persistant state.
* Use of this function should be rare.
*
* Returns YAFFS_OK or YAFFS_FAIL.
*/
int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
{
struct mtd_info * mtd = dev->genericDevice;
int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
int retval;
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo);
retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
return (retval) ? YAFFS_FAIL : YAFFS_OK;
}
/* Check any MTD prerequists.
*
* Returns YAFFS_OK or YAFFS_FAIL.
*/
static int nandmtd1_TestPrerequists(struct mtd_info * mtd)
{
/* 2.6.18 has mtd->ecclayout->oobavail */
/* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
int oobavail = mtd->ecclayout->oobavail;
if (oobavail < YTAG1_SIZE) {
yaffs_trace(YAFFS_TRACE_ERROR,
"mtd device has only %d bytes for tags, need %d\n",
oobavail, YTAG1_SIZE);
return YAFFS_FAIL;
}
return YAFFS_OK;
}
/* Query for the current state of a specific block.
*
* Examine the tags of the first chunk of the block and return the state:
* - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
* - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
* - YAFFS_BLOCK_STATE_EMPTY, the block is clean
*
* Always returns YAFFS_OK.
*/
int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState * pState, int *pSequenceNumber)
{
struct mtd_info * mtd = dev->genericDevice;
int chunkNo = blockNo * dev->nChunksPerBlock;
yaffs_ExtendedTags etags;
int state = YAFFS_BLOCK_STATE_DEAD;
int seqnum = 0;
int retval;
/* We don't yet have a good place to test for MTD config prerequists.
* Do it here as we are called during the initial scan.
*/
if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) {
return YAFFS_FAIL;
}
retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
if (etags.blockBad) {
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
"block %d is marked bad", blockNo);
state = YAFFS_BLOCK_STATE_DEAD;
}
else if (etags.chunkUsed) {
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
seqnum = etags.sequenceNumber;
}
else {
state = YAFFS_BLOCK_STATE_EMPTY;
}
*pState = state;
*pSequenceNumber = seqnum;
/* query always succeeds */
return YAFFS_OK;
}
#endif /*KERNEL_VERSION*/

View File

@ -1,28 +0,0 @@
/*
* YAFFS: Yet another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_MTDIF1_H__
#define __YAFFS_MTDIF1_H__
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data, const yaffs_ExtendedTags * tags);
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * data, yaffs_ExtendedTags * tags);
int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState * state, int *sequenceNumber);
#endif

View File

@ -1,232 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/* mtd interface for YAFFS2 */
const char *yaffs_mtdif2_c_version =
"$Id: yaffs_mtdif2.c,v 1.17 2007-02-14 01:09:06 wookey Exp $";
#include "yportenv.h"
#include "yaffs_mtdif2.h"
#include "linux/mtd/mtd.h"
#include "linux/types.h"
#include "linux/time.h"
#include "yaffs_packedtags2.h"
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data,
const yaffs_ExtendedTags * tags)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
struct mtd_oob_ops ops;
#else
size_t dummy;
#endif
int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
yaffs_PackedTags2 pt;
T(YAFFS_TRACE_MTD,
(TSTR
("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
TENDSTR), chunkInNAND, data, tags));
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
if (tags)
yaffs_PackTags2(&pt, tags);
else
BUG(); /* both tags and data should always be present */
if (data) {
ops.mode = MTD_OOB_AUTO;
ops.ooblen = sizeof(pt);
ops.len = dev->nDataBytesPerChunk;
ops.ooboffs = 0;
ops.datbuf = (__u8 *)data;
ops.oobbuf = (void *)&pt;
retval = mtd->write_oob(mtd, addr, &ops);
} else
BUG(); /* both tags and data should always be present */
#else
if (tags) {
yaffs_PackTags2(&pt, tags);
}
if (data && tags) {
if (dev->useNANDECC)
retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, (__u8 *) & pt, NULL);
else
retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, (__u8 *) & pt, NULL);
} else {
if (data)
retval =
mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
data);
if (tags)
retval =
mtd->write_oob(mtd, addr, mtd->oobsize, &dummy,
(__u8 *) & pt);
}
#endif
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * data, yaffs_ExtendedTags * tags)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
struct mtd_oob_ops ops;
#endif
size_t dummy;
int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
yaffs_PackedTags2 pt;
T(YAFFS_TRACE_MTD,
(TSTR
("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
TENDSTR), chunkInNAND, data, tags));
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
if (data && !tags)
retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data);
else if (tags) {
ops.mode = MTD_OOB_AUTO;
ops.ooblen = sizeof(pt);
ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
ops.ooboffs = 0;
ops.datbuf = data;
ops.oobbuf = dev->spareBuffer;
retval = mtd->read_oob(mtd, addr, &ops);
}
#else
if (data && tags) {
if (dev->useNANDECC) {
retval =
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, dev->spareBuffer,
NULL);
} else {
retval =
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, dev->spareBuffer,
NULL);
}
} else {
if (data)
retval =
mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
data);
if (tags)
retval =
mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
dev->spareBuffer);
}
#endif
memcpy(&pt, dev->spareBuffer, sizeof(pt));
if (tags)
yaffs_UnpackTags2(tags, &pt);
if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
int retval;
T(YAFFS_TRACE_MTD,
(TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
retval =
mtd->block_markbad(mtd,
blockNo * dev->nChunksPerBlock *
dev->nDataBytesPerChunk);
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState * state, int *sequenceNumber)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
int retval;
T(YAFFS_TRACE_MTD,
(TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
retval =
mtd->block_isbad(mtd,
blockNo * dev->nChunksPerBlock *
dev->nDataBytesPerChunk);
if (retval) {
T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
*state = YAFFS_BLOCK_STATE_DEAD;
*sequenceNumber = 0;
} else {
yaffs_ExtendedTags t;
nandmtd2_ReadChunkWithTagsFromNAND(dev,
blockNo *
dev->nChunksPerBlock, NULL,
&t);
if (t.chunkUsed) {
*sequenceNumber = t.sequenceNumber;
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
} else {
*sequenceNumber = 0;
*state = YAFFS_BLOCK_STATE_EMPTY;
}
}
T(YAFFS_TRACE_MTD,
(TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
*state));
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}

View File

@ -1,29 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_MTDIF2_H__
#define __YAFFS_MTDIF2_H__
#include "yaffs_guts.h"
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data,
const yaffs_ExtendedTags * tags);
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * data, yaffs_ExtendedTags * tags);
int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState * state, int *sequenceNumber);
#endif

View File

@ -1,134 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
const char *yaffs_nand_c_version =
"$Id: yaffs_nand.c,v 1.7 2007-02-14 01:09:06 wookey Exp $";
#include "yaffs_nand.h"
#include "yaffs_tagscompat.h"
#include "yaffs_tagsvalidity.h"
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * buffer,
yaffs_ExtendedTags * tags)
{
int result;
yaffs_ExtendedTags localTags;
int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
/* If there are no tags provided, use local tags to get prioritised gc working */
if(!tags)
tags = &localTags;
if (dev->readChunkWithTagsFromNAND)
result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
tags);
else
result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
realignedChunkInNAND,
buffer,
tags);
if(tags &&
tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR){
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock);
yaffs_HandleChunkError(dev,bi);
}
return result;
}
int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev,
int chunkInNAND,
const __u8 * buffer,
yaffs_ExtendedTags * tags)
{
chunkInNAND -= dev->chunkOffset;
if (tags) {
tags->sequenceNumber = dev->sequenceNumber;
tags->chunkUsed = 1;
if (!yaffs_ValidateTags(tags)) {
T(YAFFS_TRACE_ERROR,
(TSTR("Writing uninitialised tags" TENDSTR)));
YBUG();
}
T(YAFFS_TRACE_WRITE,
(TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND,
tags->objectId, tags->chunkId));
} else {
T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));
YBUG();
}
if (dev->writeChunkWithTagsToNAND)
return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
tags);
else
return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
chunkInNAND,
buffer,
tags);
}
int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo)
{
blockNo -= dev->blockOffset;
;
if (dev->markNANDBlockBad)
return dev->markNANDBlockBad(dev, blockNo);
else
return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);
}
int yaffs_QueryInitialBlockState(yaffs_Device * dev,
int blockNo,
yaffs_BlockState * state,
unsigned *sequenceNumber)
{
blockNo -= dev->blockOffset;
if (dev->queryNANDBlock)
return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber);
else
return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,
state,
sequenceNumber);
}
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
int blockInNAND)
{
int result;
blockInNAND -= dev->blockOffset;
dev->nBlockErasures++;
result = dev->eraseBlockInNAND(dev, blockInNAND);
return result;
}
int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
{
return dev->initialiseNAND(dev);
}

View File

@ -1,44 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_NAND_H__
#define __YAFFS_NAND_H__
#include "yaffs_guts.h"
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * buffer,
yaffs_ExtendedTags * tags);
int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev,
int chunkInNAND,
const __u8 * buffer,
yaffs_ExtendedTags * tags);
int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo);
int yaffs_QueryInitialBlockState(yaffs_Device * dev,
int blockNo,
yaffs_BlockState * state,
unsigned *sequenceNumber);
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
int blockInNAND);
int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev);
#endif

View File

@ -1,39 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/* Interface to emulated NAND functions (2k page size) */
#ifndef __YAFFS_NANDEMUL2K_H__
#define __YAFFS_NANDEMUL2K_H__
#include "yaffs_guts.h"
int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND, const __u8 * data,
yaffs_ExtendedTags * tags);
int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND, __u8 * data,
yaffs_ExtendedTags * tags);
int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState * state, int *sequenceNumber);
int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
int blockInNAND);
int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);
int nandemul2k_GetBytesPerChunk(void);
int nandemul2k_GetChunksPerBlock(void);
int nandemul2k_GetNumberOfBlocks(void);
#endif

View File

@ -1,52 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "yaffs_packedtags1.h"
#include "yportenv.h"
void yaffs_PackTags1(yaffs_PackedTags1 * pt, const yaffs_ExtendedTags * t)
{
pt->chunkId = t->chunkId;
pt->serialNumber = t->serialNumber;
pt->byteCount = t->byteCount;
pt->objectId = t->objectId;
pt->ecc = 0;
pt->deleted = (t->chunkDeleted) ? 0 : 1;
pt->unusedStuff = 0;
pt->shouldBeFF = 0xFFFFFFFF;
}
void yaffs_UnpackTags1(yaffs_ExtendedTags * t, const yaffs_PackedTags1 * pt)
{
static const __u8 allFF[] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff };
if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) {
t->blockBad = 0;
if (pt->shouldBeFF != 0xFFFFFFFF) {
t->blockBad = 1;
}
t->chunkUsed = 1;
t->objectId = pt->objectId;
t->chunkId = pt->chunkId;
t->byteCount = pt->byteCount;
t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
t->chunkDeleted = (pt->deleted) ? 0 : 1;
t->serialNumber = pt->serialNumber;
} else {
memset(t, 0, sizeof(yaffs_ExtendedTags));
}
}

View File

@ -1,37 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */
#ifndef __YAFFS_PACKEDTAGS1_H__
#define __YAFFS_PACKEDTAGS1_H__
#include "yaffs_guts.h"
typedef struct {
unsigned chunkId:20;
unsigned serialNumber:2;
unsigned byteCount:10;
unsigned objectId:18;
unsigned ecc:12;
unsigned deleted:1;
unsigned unusedStuff:1;
unsigned shouldBeFF;
} yaffs_PackedTags1;
void yaffs_PackTags1(yaffs_PackedTags1 * pt, const yaffs_ExtendedTags * t);
void yaffs_UnpackTags1(yaffs_ExtendedTags * t, const yaffs_PackedTags1 * pt);
#endif

View File

@ -1,182 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "yaffs_packedtags2.h"
#include "yportenv.h"
#include "yaffs_tagsvalidity.h"
/* This code packs a set of extended tags into a binary structure for
* NAND storage
*/
/* Some of the information is "extra" struff which can be packed in to
* speed scanning
* This is defined by having the EXTRA_HEADER_INFO_FLAG set.
*/
/* Extra flags applied to chunkId */
#define EXTRA_HEADER_INFO_FLAG 0x80000000
#define EXTRA_SHRINK_FLAG 0x40000000
#define EXTRA_SHADOWS_FLAG 0x20000000
#define EXTRA_SPARE_FLAGS 0x10000000
#define ALL_EXTRA_FLAGS 0xF0000000
/* Also, the top 4 bits of the object Id are set to the object type. */
#define EXTRA_OBJECT_TYPE_SHIFT (28)
#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT)
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt)
{
T(YAFFS_TRACE_MTD,
(TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
pt->t.objectId, pt->t.chunkId, pt->t.byteCount,
pt->t.sequenceNumber));
}
static void yaffs_DumpTags2(const yaffs_ExtendedTags * t)
{
T(YAFFS_TRACE_MTD,
(TSTR
("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte "
"%d del %d ser %d seq %d"
TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId,
t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,
t->sequenceNumber));
}
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
{
pt->t.chunkId = t->chunkId;
pt->t.sequenceNumber = t->sequenceNumber;
pt->t.byteCount = t->byteCount;
pt->t.objectId = t->objectId;
if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {
/* Store the extra header info instead */
/* We save the parent object in the chunkId */
pt->t.chunkId = EXTRA_HEADER_INFO_FLAG
| t->extraParentObjectId;
if (t->extraIsShrinkHeader) {
pt->t.chunkId |= EXTRA_SHRINK_FLAG;
}
if (t->extraShadows) {
pt->t.chunkId |= EXTRA_SHADOWS_FLAG;
}
pt->t.objectId &= ~EXTRA_OBJECT_TYPE_MASK;
pt->t.objectId |=
(t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
pt->t.byteCount = t->extraEquivalentObjectId;
} else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) {
pt->t.byteCount = t->extraFileLength;
} else {
pt->t.byteCount = 0;
}
}
yaffs_DumpPackedTags2(pt);
yaffs_DumpTags2(t);
#ifndef YAFFS_IGNORE_TAGS_ECC
{
yaffs_ECCCalculateOther((unsigned char *)&pt->t,
sizeof(yaffs_PackedTags2TagsPart),
&pt->ecc);
}
#endif
}
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt)
{
memset(t, 0, sizeof(yaffs_ExtendedTags));
yaffs_InitialiseTags(t);
if (pt->t.sequenceNumber != 0xFFFFFFFF) {
/* Page is in use */
#ifdef YAFFS_IGNORE_TAGS_ECC
{
t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
}
#else
{
yaffs_ECCOther ecc;
int result;
yaffs_ECCCalculateOther((unsigned char *)&pt->t,
sizeof
(yaffs_PackedTags2TagsPart),
&ecc);
result =
yaffs_ECCCorrectOther((unsigned char *)&pt->t,
sizeof
(yaffs_PackedTags2TagsPart),
&pt->ecc, &ecc);
switch(result){
case 0:
t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
break;
case 1:
t->eccResult = YAFFS_ECC_RESULT_FIXED;
break;
case -1:
t->eccResult = YAFFS_ECC_RESULT_UNFIXED;
break;
default:
t->eccResult = YAFFS_ECC_RESULT_UNKNOWN;
}
}
#endif
t->blockBad = 0;
t->chunkUsed = 1;
t->objectId = pt->t.objectId;
t->chunkId = pt->t.chunkId;
t->byteCount = pt->t.byteCount;
t->chunkDeleted = 0;
t->serialNumber = 0;
t->sequenceNumber = pt->t.sequenceNumber;
/* Do extra header info stuff */
if (pt->t.chunkId & EXTRA_HEADER_INFO_FLAG) {
t->chunkId = 0;
t->byteCount = 0;
t->extraHeaderInfoAvailable = 1;
t->extraParentObjectId =
pt->t.chunkId & (~(ALL_EXTRA_FLAGS));
t->extraIsShrinkHeader =
(pt->t.chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
t->extraShadows =
(pt->t.chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
t->extraObjectType =
pt->t.objectId >> EXTRA_OBJECT_TYPE_SHIFT;
t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
t->extraEquivalentObjectId = pt->t.byteCount;
} else {
t->extraFileLength = pt->t.byteCount;
}
}
}
yaffs_DumpPackedTags2(pt);
yaffs_DumpTags2(t);
}

View File

@ -1,38 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/* This is used to pack YAFFS2 tags, not YAFFS1tags. */
#ifndef __YAFFS_PACKEDTAGS2_H__
#define __YAFFS_PACKEDTAGS2_H__
#include "yaffs_guts.h"
#include "yaffs_ecc.h"
typedef struct {
unsigned sequenceNumber;
unsigned objectId;
unsigned chunkId;
unsigned byteCount;
} yaffs_PackedTags2TagsPart;
typedef struct {
yaffs_PackedTags2TagsPart t;
yaffs_ECCOther ecc;
} yaffs_PackedTags2;
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t);
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt);
#endif

View File

@ -1,160 +0,0 @@
/*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*/
#include "yportenv.h"
//#include <linux/string.h>
/*
* Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
*/
#define swapcode(TYPE, parmi, parmj, n) { \
long i = (n) / sizeof (TYPE); \
register TYPE *pi = (TYPE *) (parmi); \
register TYPE *pj = (TYPE *) (parmj); \
do { \
register TYPE t = *pi; \
*pi++ = *pj; \
*pj++ = t; \
} while (--i > 0); \
}
#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
static __inline void
swapfunc(char *a, char *b, int n, int swaptype)
{
if (swaptype <= 1)
swapcode(long, a, b, n)
else
swapcode(char, a, b, n)
}
#define swap(a, b) \
if (swaptype == 0) { \
long t = *(long *)(a); \
*(long *)(a) = *(long *)(b); \
*(long *)(b) = t; \
} else \
swapfunc(a, b, es, swaptype)
#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
static __inline char *
med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
{
return cmp(a, b) < 0 ?
(cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
:(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
}
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
void
yaffs_qsort(void *aa, size_t n, size_t es,
int (*cmp)(const void *, const void *))
{
char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
int d, r, swaptype, swap_cnt;
register char *a = aa;
loop: SWAPINIT(a, es);
swap_cnt = 0;
if (n < 7) {
for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
pl -= es)
swap(pl, pl - es);
return;
}
pm = (char *)a + (n / 2) * es;
if (n > 7) {
pl = (char *)a;
pn = (char *)a + (n - 1) * es;
if (n > 40) {
d = (n / 8) * es;
pl = med3(pl, pl + d, pl + 2 * d, cmp);
pm = med3(pm - d, pm, pm + d, cmp);
pn = med3(pn - 2 * d, pn - d, pn, cmp);
}
pm = med3(pl, pm, pn, cmp);
}
swap(a, pm);
pa = pb = (char *)a + es;
pc = pd = (char *)a + (n - 1) * es;
for (;;) {
while (pb <= pc && (r = cmp(pb, a)) <= 0) {
if (r == 0) {
swap_cnt = 1;
swap(pa, pb);
pa += es;
}
pb += es;
}
while (pb <= pc && (r = cmp(pc, a)) >= 0) {
if (r == 0) {
swap_cnt = 1;
swap(pc, pd);
pd -= es;
}
pc -= es;
}
if (pb > pc)
break;
swap(pb, pc);
swap_cnt = 1;
pb += es;
pc -= es;
}
if (swap_cnt == 0) { /* Switch to insertion sort */
for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
pl -= es)
swap(pl, pl - es);
return;
}
pn = (char *)a + n * es;
r = min(pa - (char *)a, pb - pa);
vecswap(a, pb - r, r);
r = min((long)(pd - pc), (long)(pn - pd - es));
vecswap(pb, pn - r, r);
if ((r = pb - pa) > es)
yaffs_qsort(a, r / es, es, cmp);
if ((r = pd - pc) > es) {
/* Iterate rather than recurse to save stack space */
a = pn - r;
n = r / es;
goto loop;
}
/* yaffs_qsort(pn - r, r / es, es, cmp);*/
}

View File

@ -1,23 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_QSORT_H__
#define __YAFFS_QSORT_H__
extern void yaffs_qsort (void *const base, size_t total_elems, size_t size,
int (*cmp)(const void *, const void *));
#endif

View File

@ -1,530 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "yaffs_guts.h"
#include "yaffs_tagscompat.h"
#include "yaffs_ecc.h"
static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND);
#ifdef NOTYET
static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND);
static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
const __u8 * data,
const yaffs_Spare * spare);
static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
const yaffs_Spare * spare);
static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND);
#endif
static const char yaffs_countBitsTable[256] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};
int yaffs_CountBits(__u8 x)
{
int retVal;
retVal = yaffs_countBitsTable[x];
return retVal;
}
/********** Tags ECC calculations *********/
void yaffs_CalcECC(const __u8 * data, yaffs_Spare * spare)
{
yaffs_ECCCalculate(data, spare->ecc1);
yaffs_ECCCalculate(&data[256], spare->ecc2);
}
void yaffs_CalcTagsECC(yaffs_Tags * tags)
{
/* Calculate an ecc */
unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
unsigned i, j;
unsigned ecc = 0;
unsigned bit = 0;
tags->ecc = 0;
for (i = 0; i < 8; i++) {
for (j = 1; j & 0xff; j <<= 1) {
bit++;
if (b[i] & j) {
ecc ^= bit;
}
}
}
tags->ecc = ecc;
}
int yaffs_CheckECCOnTags(yaffs_Tags * tags)
{
unsigned ecc = tags->ecc;
yaffs_CalcTagsECC(tags);
ecc ^= tags->ecc;
if (ecc && ecc <= 64) {
/* TODO: Handle the failure better. Retire? */
unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
ecc--;
b[ecc / 8] ^= (1 << (ecc & 7));
/* Now recvalc the ecc */
yaffs_CalcTagsECC(tags);
return 1; /* recovered error */
} else if (ecc) {
/* Wierd ecc failure value */
/* TODO Need to do somethiong here */
return -1; /* unrecovered error */
}
return 0;
}
/********** Tags **********/
static void yaffs_LoadTagsIntoSpare(yaffs_Spare * sparePtr,
yaffs_Tags * tagsPtr)
{
yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
yaffs_CalcTagsECC(tagsPtr);
sparePtr->tagByte0 = tu->asBytes[0];
sparePtr->tagByte1 = tu->asBytes[1];
sparePtr->tagByte2 = tu->asBytes[2];
sparePtr->tagByte3 = tu->asBytes[3];
sparePtr->tagByte4 = tu->asBytes[4];
sparePtr->tagByte5 = tu->asBytes[5];
sparePtr->tagByte6 = tu->asBytes[6];
sparePtr->tagByte7 = tu->asBytes[7];
}
static void yaffs_GetTagsFromSpare(yaffs_Device * dev, yaffs_Spare * sparePtr,
yaffs_Tags * tagsPtr)
{
yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
int result;
tu->asBytes[0] = sparePtr->tagByte0;
tu->asBytes[1] = sparePtr->tagByte1;
tu->asBytes[2] = sparePtr->tagByte2;
tu->asBytes[3] = sparePtr->tagByte3;
tu->asBytes[4] = sparePtr->tagByte4;
tu->asBytes[5] = sparePtr->tagByte5;
tu->asBytes[6] = sparePtr->tagByte6;
tu->asBytes[7] = sparePtr->tagByte7;
result = yaffs_CheckECCOnTags(tagsPtr);
if (result > 0) {
dev->tagsEccFixed++;
} else if (result < 0) {
dev->tagsEccUnfixed++;
}
}
static void yaffs_SpareInitialise(yaffs_Spare * spare)
{
memset(spare, 0xFF, sizeof(yaffs_Spare));
}
static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND, const __u8 * data,
yaffs_Spare * spare)
{
if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
T(YAFFS_TRACE_ERROR,
(TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
chunkInNAND));
return YAFFS_FAIL;
}
dev->nPageWrites++;
return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
}
static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND,
__u8 * data,
yaffs_Spare * spare,
yaffs_ECCResult * eccResult,
int doErrorCorrection)
{
int retVal;
yaffs_Spare localSpare;
dev->nPageReads++;
if (!spare && data) {
/* If we don't have a real spare, then we use a local one. */
/* Need this for the calculation of the ecc */
spare = &localSpare;
}
if (!dev->useNANDECC) {
retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
if (data && doErrorCorrection) {
/* Do ECC correction */
/* Todo handle any errors */
int eccResult1, eccResult2;
__u8 calcEcc[3];
yaffs_ECCCalculate(data, calcEcc);
eccResult1 =
yaffs_ECCCorrect(data, spare->ecc1, calcEcc);
yaffs_ECCCalculate(&data[256], calcEcc);
eccResult2 =
yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc);
if (eccResult1 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>yaffs ecc error fix performed on chunk %d:0"
TENDSTR), chunkInNAND));
dev->eccFixed++;
} else if (eccResult1 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>yaffs ecc error unfixed on chunk %d:0"
TENDSTR), chunkInNAND));
dev->eccUnfixed++;
}
if (eccResult2 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>yaffs ecc error fix performed on chunk %d:1"
TENDSTR), chunkInNAND));
dev->eccFixed++;
} else if (eccResult2 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>yaffs ecc error unfixed on chunk %d:1"
TENDSTR), chunkInNAND));
dev->eccUnfixed++;
}
if (eccResult1 || eccResult2) {
/* We had a data problem on this page */
yaffs_HandleReadDataError(dev, chunkInNAND);
}
if (eccResult1 < 0 || eccResult2 < 0)
*eccResult = YAFFS_ECC_RESULT_UNFIXED;
else if (eccResult1 > 0 || eccResult2 > 0)
*eccResult = YAFFS_ECC_RESULT_FIXED;
else
*eccResult = YAFFS_ECC_RESULT_NO_ERROR;
}
} else {
/* Must allocate enough memory for spare+2*sizeof(int) */
/* for ecc results from device. */
struct yaffs_NANDSpare nspare;
retVal =
dev->readChunkFromNAND(dev, chunkInNAND, data,
(yaffs_Spare *) & nspare);
memcpy(spare, &nspare, sizeof(yaffs_Spare));
if (data && doErrorCorrection) {
if (nspare.eccres1 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error fix performed on chunk %d:0"
TENDSTR), chunkInNAND));
} else if (nspare.eccres1 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error unfixed on chunk %d:0"
TENDSTR), chunkInNAND));
}
if (nspare.eccres2 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error fix performed on chunk %d:1"
TENDSTR), chunkInNAND));
} else if (nspare.eccres2 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error unfixed on chunk %d:1"
TENDSTR), chunkInNAND));
}
if (nspare.eccres1 || nspare.eccres2) {
/* We had a data problem on this page */
yaffs_HandleReadDataError(dev, chunkInNAND);
}
if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
*eccResult = YAFFS_ECC_RESULT_UNFIXED;
else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
*eccResult = YAFFS_ECC_RESULT_FIXED;
else
*eccResult = YAFFS_ECC_RESULT_NO_ERROR;
}
}
return retVal;
}
#ifdef NOTYET
static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
int chunkInNAND)
{
static int init = 0;
static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
static __u8 data[YAFFS_BYTES_PER_CHUNK];
/* Might as well always allocate the larger size for */
/* dev->useNANDECC == true; */
static __u8 spare[sizeof(struct yaffs_NANDSpare)];
dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
if (!init) {
memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
init = 1;
}
if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK))
return YAFFS_FAIL;
if (memcmp(cmpbuf, spare, 16))
return YAFFS_FAIL;
return YAFFS_OK;
}
#endif
/*
* Functions for robustisizing
*/
static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND)
{
int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
/* Mark the block for retirement */
yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
(TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND));
/* TODO:
* Just do a garbage collection on the affected block
* then retire the block
* NB recursion
*/
}
#ifdef NOTYET
static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND)
{
}
static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
const __u8 * data,
const yaffs_Spare * spare)
{
}
static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
const yaffs_Spare * spare)
{
}
static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND)
{
int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
/* Mark the block for retirement */
yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
/* Delete the chunk */
yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
}
static int yaffs_VerifyCompare(const __u8 * d0, const __u8 * d1,
const yaffs_Spare * s0, const yaffs_Spare * s1)
{
if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
s0->tagByte0 != s1->tagByte0 ||
s0->tagByte1 != s1->tagByte1 ||
s0->tagByte2 != s1->tagByte2 ||
s0->tagByte3 != s1->tagByte3 ||
s0->tagByte4 != s1->tagByte4 ||
s0->tagByte5 != s1->tagByte5 ||
s0->tagByte6 != s1->tagByte6 ||
s0->tagByte7 != s1->tagByte7 ||
s0->ecc1[0] != s1->ecc1[0] ||
s0->ecc1[1] != s1->ecc1[1] ||
s0->ecc1[2] != s1->ecc1[2] ||
s0->ecc2[0] != s1->ecc2[0] ||
s0->ecc2[1] != s1->ecc2[1] || s0->ecc2[2] != s1->ecc2[2]) {
return 0;
}
return 1;
}
#endif /* NOTYET */
int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device * dev,
int chunkInNAND,
const __u8 * data,
const yaffs_ExtendedTags *
eTags)
{
yaffs_Spare spare;
yaffs_Tags tags;
yaffs_SpareInitialise(&spare);
if (eTags->chunkDeleted) {
spare.pageStatus = 0;
} else {
tags.objectId = eTags->objectId;
tags.chunkId = eTags->chunkId;
tags.byteCount = eTags->byteCount;
tags.serialNumber = eTags->serialNumber;
if (!dev->useNANDECC && data) {
yaffs_CalcECC(data, &spare);
}
yaffs_LoadTagsIntoSpare(&spare, &tags);
}
return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare);
}
int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
int chunkInNAND,
__u8 * data,
yaffs_ExtendedTags * eTags)
{
yaffs_Spare spare;
yaffs_Tags tags;
yaffs_ECCResult eccResult;
static yaffs_Spare spareFF;
static int init;
if (!init) {
memset(&spareFF, 0xFF, sizeof(spareFF));
init = 1;
}
if (yaffs_ReadChunkFromNAND
(dev, chunkInNAND, data, &spare, &eccResult, 1)) {
/* eTags may be NULL */
if (eTags) {
int deleted =
(yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
eTags->chunkDeleted = deleted;
eTags->eccResult = eccResult;
eTags->blockBad = 0; /* We're reading it */
/* therefore it is not a bad block */
eTags->chunkUsed =
(memcmp(&spareFF, &spare, sizeof(spareFF)) !=
0) ? 1 : 0;
if (eTags->chunkUsed) {
yaffs_GetTagsFromSpare(dev, &spare, &tags);
eTags->objectId = tags.objectId;
eTags->chunkId = tags.chunkId;
eTags->byteCount = tags.byteCount;
eTags->serialNumber = tags.serialNumber;
}
}
return YAFFS_OK;
} else {
return YAFFS_FAIL;
}
}
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
int blockInNAND)
{
yaffs_Spare spare;
memset(&spare, 0xff, sizeof(yaffs_Spare));
spare.blockStatus = 'Y';
yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,
&spare);
yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
NULL, &spare);
return YAFFS_OK;
}
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
int blockNo, yaffs_BlockState *
state,
int *sequenceNumber)
{
yaffs_Spare spare0, spare1;
static yaffs_Spare spareFF;
static int init;
yaffs_ECCResult dummy;
if (!init) {
memset(&spareFF, 0xFF, sizeof(spareFF));
init = 1;
}
*sequenceNumber = 0;
yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
&spare0, &dummy, 1);
yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
&spare1, &dummy, 1);
if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
*state = YAFFS_BLOCK_STATE_DEAD;
else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
*state = YAFFS_BLOCK_STATE_EMPTY;
else
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
return YAFFS_OK;
}

View File

@ -1,40 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_TAGSCOMPAT_H__
#define __YAFFS_TAGSCOMPAT_H__
#include "yaffs_guts.h"
int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device * dev,
int chunkInNAND,
const __u8 * data,
const yaffs_ExtendedTags *
tags);
int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
int chunkInNAND,
__u8 * data,
yaffs_ExtendedTags *
tags);
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
int blockNo);
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
int blockNo, yaffs_BlockState *
state, int *sequenceNumber);
void yaffs_CalcTagsECC(yaffs_Tags * tags);
int yaffs_CheckECCOnTags(yaffs_Tags * tags);
int yaffs_CountBits(__u8 byte);
#endif

View File

@ -1,28 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "yaffs_tagsvalidity.h"
void yaffs_InitialiseTags(yaffs_ExtendedTags * tags)
{
memset(tags, 0, sizeof(yaffs_ExtendedTags));
tags->validMarker0 = 0xAAAAAAAA;
tags->validMarker1 = 0x55555555;
}
int yaffs_ValidateTags(yaffs_ExtendedTags * tags)
{
return (tags->validMarker0 == 0xAAAAAAAA &&
tags->validMarker1 == 0x55555555);
}

View File

@ -1,24 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_TAGS_VALIDITY_H__
#define __YAFFS_TAGS_VALIDITY_H__
#include "yaffs_guts.h"
void yaffs_InitialiseTags(yaffs_ExtendedTags * tags);
int yaffs_ValidateTags(yaffs_ExtendedTags * tags);
#endif

View File

@ -1,21 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFSINTERFACE_H__
#define __YAFFSINTERFACE_H__
int yaffs_Initialise(unsigned nBlocks);
#endif

View File

@ -1,187 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YPORTENV_H__
#define __YPORTENV_H__
#if defined CONFIG_YAFFS_WINCE
#include "ywinceenv.h"
#elif defined __KERNEL__
#include "moduleconfig.h"
/* Linux kernel */
#include <linux/version.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
#include <linux/config.h>
#endif
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#define YCHAR char
#define YUCHAR unsigned char
#define _Y(x) x
#define yaffs_strcpy(a,b) strcpy(a,b)
#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
#define yaffs_strncmp(a,b,c) strncmp(a,b,c)
#define yaffs_strlen(s) strlen(s)
#define yaffs_sprintf sprintf
#define yaffs_toupper(a) toupper(a)
#define Y_INLINE inline
#define YAFFS_LOSTNFOUND_NAME "lost+found"
#define YAFFS_LOSTNFOUND_PREFIX "obj"
/* #define YPRINTF(x) printk x */
#define YMALLOC(x) kmalloc(x,GFP_KERNEL)
#define YFREE(x) kfree(x)
#define YMALLOC_ALT(x) vmalloc(x)
#define YFREE_ALT(x) vfree(x)
#define YMALLOC_DMA(x) YMALLOC(x)
// KR - added for use in scan so processes aren't blocked indefinitely.
#define YYIELD() schedule()
#define YAFFS_ROOT_MODE 0666
#define YAFFS_LOSTNFOUND_MODE 0666
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
#define Y_TIME_CONVERT(x) (x).tv_sec
#else
#define Y_CURRENT_TIME CURRENT_TIME
#define Y_TIME_CONVERT(x) (x)
#endif
#define yaffs_SumCompare(x,y) ((x) == (y))
#define yaffs_strcmp(a,b) strcmp(a,b)
#define TENDSTR "\n"
#define TSTR(x) KERN_WARNING x
#define TOUT(p) printk p
#define yaffs_trace(mask, fmt, args...) \
do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \
printk(KERN_WARNING "yaffs: " fmt, ## args); \
} while (0)
#define compile_time_assertion(assertion) \
({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
#elif defined CONFIG_YAFFS_DIRECT
/* Direct interface */
#include "ydirectenv.h"
#elif defined CONFIG_YAFFS_UTIL
/* Stuff for YAFFS utilities */
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "devextras.h"
#define YMALLOC(x) malloc(x)
#define YFREE(x) free(x)
#define YMALLOC_ALT(x) malloc(x)
#define YFREE_ALT(x) free(x)
#define YCHAR char
#define YUCHAR unsigned char
#define _Y(x) x
#define yaffs_strcpy(a,b) strcpy(a,b)
#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
#define yaffs_strlen(s) strlen(s)
#define yaffs_sprintf sprintf
#define yaffs_toupper(a) toupper(a)
#define Y_INLINE inline
/* #define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s)) */
/* #define YALERT(s) YINFO(s) */
#define TENDSTR "\n"
#define TSTR(x) x
#define TOUT(p) printf p
#define YAFFS_LOSTNFOUND_NAME "lost+found"
#define YAFFS_LOSTNFOUND_PREFIX "obj"
/* #define YPRINTF(x) printf x */
#define YAFFS_ROOT_MODE 0666
#define YAFFS_LOSTNFOUND_MODE 0666
#define yaffs_SumCompare(x,y) ((x) == (y))
#define yaffs_strcmp(a,b) strcmp(a,b)
#else
/* Should have specified a configuration type */
#error Unknown configuration
#endif
/* see yaffs_fs.c */
extern unsigned int yaffs_traceMask;
extern unsigned int yaffs_wr_attempts;
/*
* Tracing flags.
* The flags masked in YAFFS_TRACE_ALWAYS are always traced.
*/
#define YAFFS_TRACE_OS 0x00000002
#define YAFFS_TRACE_ALLOCATE 0x00000004
#define YAFFS_TRACE_SCAN 0x00000008
#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
#define YAFFS_TRACE_ERASE 0x00000020
#define YAFFS_TRACE_GC 0x00000040
#define YAFFS_TRACE_WRITE 0x00000080
#define YAFFS_TRACE_TRACING 0x00000100
#define YAFFS_TRACE_DELETION 0x00000200
#define YAFFS_TRACE_BUFFERS 0x00000400
#define YAFFS_TRACE_NANDACCESS 0x00000800
#define YAFFS_TRACE_GC_DETAIL 0x00001000
#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
#define YAFFS_TRACE_MTD 0x00004000
#define YAFFS_TRACE_CHECKPOINT 0x00008000
#define YAFFS_TRACE_VERIFY 0x00010000
#define YAFFS_TRACE_VERIFY_NAND 0x00020000
#define YAFFS_TRACE_VERIFY_FULL 0x00040000
#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
#define YAFFS_TRACE_ERROR 0x40000000
#define YAFFS_TRACE_BUG 0x80000000
#define YAFFS_TRACE_ALWAYS 0xF0000000
#define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p);} while(0)
#ifndef CONFIG_YAFFS_WINCE
#define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__))
#endif
#endif

View File

@ -1,175 +0,0 @@
#
# YAFFS file system configurations
#
config YAFFS_FS
tristate "YAFFS2 file system support"
default n
depends on MTD
select YAFFS_YAFFS1
select YAFFS_YAFFS2
help
YAFFS2, or Yet Another Flash Filing System, is a filing system
optimised for NAND Flash chips.
To compile the YAFFS2 file system support as a module, choose M
here: the module will be called yaffs2.
If unsure, say N.
Further information on YAFFS2 is available at
<http://www.aleph1.co.uk/yaffs/>.
config YAFFS_YAFFS1
bool "512 byte / page devices"
depends on YAFFS_FS
default y
help
Enable YAFFS1 support -- yaffs for 512 byte / page devices
Not needed for 2K-page devices.
If unsure, say Y.
config YAFFS_9BYTE_TAGS
bool "Use older-style on-NAND data format with pageStatus byte"
depends on YAFFS_YAFFS1
default n
help
Older-style on-NAND data format has a "pageStatus" byte to record
chunk/page state. This byte is zero when the page is discarded.
Choose this option if you have existing on-NAND data using this
format that you need to continue to support. New data written
also uses the older-style format. Note: Use of this option
generally requires that MTD's oob layout be adjusted to use the
older-style format. See notes on tags formats and MTD versions.
If unsure, say N.
config YAFFS_DOES_ECC
bool "Lets Yaffs do its own ECC"
depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS
default n
help
This enables Yaffs to use its own ECC functions instead of using
the ones from the generic MTD-NAND driver.
If unsure, say N.
config YAFFS_ECC_WRONG_ORDER
bool "Use the same ecc byte order as Steven Hill's nand_ecc.c"
depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS
default n
help
This makes yaffs_ecc.c use the same ecc byte order as Steven
Hill's nand_ecc.c. If not set, then you get the same ecc byte
order as SmartMedia.
If unsure, say N.
config YAFFS_YAFFS2
bool "2048 byte (or larger) / page devices"
depends on YAFFS_FS
default y
help
Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices
If unsure, say Y.
config YAFFS_AUTO_YAFFS2
bool "Autoselect yaffs2 format"
depends on YAFFS_YAFFS2
default y
help
Without this, you need to explicitely use yaffs2 as the file
system type. With this, you can say "yaffs" and yaffs or yaffs2
will be used depending on the device page size (yaffs on
512-byte page devices, yaffs2 on 2K page devices).
If unsure, say Y.
config YAFFS_DISABLE_LAZY_LOAD
bool "Disable lazy loading"
depends on YAFFS_YAFFS2
default n
help
"Lazy loading" defers loading file details until they are
required. This saves mount time, but makes the first look-up
a bit longer.
Lazy loading will only happen if enabled by this option being 'n'
and if the appropriate tags are available, else yaffs2 will
automatically fall back to immediate loading and do the right
thing.
Lazy laoding will be required by checkpointing.
Setting this to 'y' will disable lazy loading.
If unsure, say N.
config YAFFS_CHECKPOINT_RESERVED_BLOCKS
int "Reserved blocks for checkpointing"
depends on YAFFS_YAFFS2
default 10
help
Give the number of Blocks to reserve for checkpointing.
Checkpointing saves the state at unmount so that mounting is
much faster as a scan of all the flash to regenerate this state
is not needed. These Blocks are reserved per partition, so if
you have very small partitions the default (10) may be a mess
for you. You can set this value to 0, but that does not mean
checkpointing is disabled at all. There only won't be any
specially reserved blocks for checkpointing, so if there is
enough free space on the filesystem, it will be used for
checkpointing.
If unsure, leave at default (10), but don't wonder if there are
always 2MB used on your large page device partition (10 x 2k
pagesize). When using small partitions or when being very small
on space, you probably want to set this to zero.
config YAFFS_DISABLE_WIDE_TNODES
bool "Turn off wide tnodes"
depends on YAFFS_FS
default n
help
Wide tnodes are only used for NAND arrays >=32MB for 512-byte
page devices and >=128MB for 2k page devices. They use slightly
more RAM but are faster since they eliminate chunk group
searching.
Setting this to 'y' will force tnode width to 16 bits and save
memory but make large arrays slower.
If unsure, say N.
config YAFFS_ALWAYS_CHECK_CHUNK_ERASED
bool "Force chunk erase check"
depends on YAFFS_FS
default n
help
Normally YAFFS only checks chunks before writing until an erased
chunk is found. This helps to detect any partially written
chunks that might have happened due to power loss.
Enabling this forces on the test that chunks are erased in flash
before writing to them. This takes more time but is potentially
a bit more secure.
Suggest setting Y during development and ironing out driver
issues etc. Suggest setting to N if you want faster writing.
If unsure, say Y.
config YAFFS_SHORT_NAMES_IN_RAM
bool "Cache short names in RAM"
depends on YAFFS_FS
default y
help
If this config is set, then short names are stored with the
yaffs_Object. This costs an extra 16 bytes of RAM per object,
but makes look-ups faster.
If unsure, say Y.

View File

@ -1,11 +0,0 @@
#
# Makefile for the linux YAFFS filesystem routines.
#
obj-$(CONFIG_YAFFS_FS) += yaffs.o
yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o
yaffs-y += yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
yaffs-y += yaffs_mtdif1.o yaffs_packedtags1.o
yaffs-y += yaffs_mtdif.o yaffs_mtdif2.o

View File

@ -1,264 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/*
* This file is just holds extra declarations used during development.
* Most of these are from kernel includes placed here so we can use them in
* applications.
*
*/
#ifndef __EXTRAS_H__
#define __EXTRAS_H__
#if defined WIN32
#define __inline__ __inline
#define new newHack
#endif
#if !(defined __KERNEL__) || (defined WIN32)
/* User space defines */
typedef unsigned char __u8;
typedef unsigned short __u16;
typedef unsigned __u32;
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
#define prefetch(x) 1
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static __inline__ void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static __inline__ void list_add_tail(struct list_head *new,
struct list_head *head)
{
__list_add(new, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_del(struct list_head *prev,
struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is
* in an undefined state.
*/
static __inline__ void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
/**
* list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static __inline__ void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static __inline__ int list_empty(struct list_head *head)
{
return head->next == head;
}
/**
* list_splice - join two lists
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static __inline__ void list_splice(struct list_head *list,
struct list_head *head)
{
struct list_head *first = list->next;
if (first != list) {
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
}
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*/
#define list_for_each(pos, head) \
for (pos = (head)->next, prefetch(pos->next); pos != (head); \
pos = pos->next, prefetch(pos->next))
/**
* list_for_each_safe - iterate over a list safe against removal
* of list entry
* @pos: the &struct list_head to use as a loop counter.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/*
* File types
*/
#define DT_UNKNOWN 0
#define DT_FIFO 1
#define DT_CHR 2
#define DT_DIR 4
#define DT_BLK 6
#define DT_REG 8
#define DT_LNK 10
#define DT_SOCK 12
#define DT_WHT 14
#ifndef WIN32
#include <sys/stat.h>
#endif
/*
* Attribute flags. These should be or-ed together to figure out what
* has been changed!
*/
#define ATTR_MODE 1
#define ATTR_UID 2
#define ATTR_GID 4
#define ATTR_SIZE 8
#define ATTR_ATIME 16
#define ATTR_MTIME 32
#define ATTR_CTIME 64
#define ATTR_ATIME_SET 128
#define ATTR_MTIME_SET 256
#define ATTR_FORCE 512 /* Not a change, but a change it */
#define ATTR_ATTR_FLAG 1024
struct iattr {
unsigned int ia_valid;
unsigned ia_mode;
unsigned ia_uid;
unsigned ia_gid;
unsigned ia_size;
unsigned ia_atime;
unsigned ia_mtime;
unsigned ia_ctime;
unsigned int ia_attr_flags;
};
#define KERN_DEBUG
#else
#ifndef WIN32
#include <linux/types.h>
#include <linux/list.h>
#include <linux/fs.h>
#include <linux/stat.h>
#endif
#endif
#if defined WIN32
#undef new
#endif
#endif

View File

@ -1,65 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Martin Fouts <Martin.Fouts@palmsource.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_CONFIG_H__
#define __YAFFS_CONFIG_H__
#ifdef YAFFS_OUT_OF_TREE
/* DO NOT UNSET THESE THREE. YAFFS2 will not compile if you do. */
#define CONFIG_YAFFS_FS
#define CONFIG_YAFFS_YAFFS1
#define CONFIG_YAFFS_YAFFS2
/* These options are independent of each other. Select those that matter. */
/* Default: Not selected */
/* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
//#define CONFIG_YAFFS_DOES_ECC
/* Default: Not selected */
/* Meaning: ECC byte order is 'wrong'. Only meaningful if */
/* CONFIG_YAFFS_DOES_ECC is set */
//#define CONFIG_YAFFS_ECC_WRONG_ORDER
/* Default: Selected */
/* Meaning: Disables testing whether chunks are erased before writing to them*/
#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
/* Default: Selected */
/* Meaning: Cache short names, taking more RAM, but faster look-ups */
#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
/* Default: 10 */
/* Meaning: set the count of blocks to reserve for checkpointing */
#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10
/*
Older-style on-NAND data format has a "pageStatus" byte to record
chunk/page state. This byte is zeroed when the page is discarded.
Choose this option if you have existing on-NAND data in this format
that you need to continue to support. New data written also uses the
older-style format.
Note: Use of this option generally requires that MTD's oob layout be
adjusted to use the older-style format. See notes on tags formats and
MTD versions.
*/
/* Default: Not selected */
/* Meaning: Use older-style on-NAND data format with pageStatus byte */
#define CONFIG_YAFFS_9BYTE_TAGS
#endif /* YAFFS_OUT_OF_TREE */
#endif /* __YAFFS_CONFIG_H__ */

View File

@ -1,404 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
const char *yaffs_checkptrw_c_version =
"$Id: yaffs_checkptrw.c,v 1.14 2007-05-15 20:07:40 charles Exp $";
#include "yaffs_checkptrw.h"
static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
{
int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
T(YAFFS_TRACE_CHECKPOINT,
(TSTR("checkpt blocks available = %d" TENDSTR),
blocksAvailable));
return (blocksAvailable <= 0) ? 0 : 1;
}
static int yaffs_CheckpointErase(yaffs_Device *dev)
{
int i;
if(!dev->eraseBlockInNAND)
return 0;
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checking blocks %d to %d"TENDSTR),
dev->internalStartBlock,dev->internalEndBlock));
for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
if(bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT){
T(YAFFS_TRACE_CHECKPOINT,(TSTR("erasing checkpt block %d"TENDSTR),i));
if(dev->eraseBlockInNAND(dev,i- dev->blockOffset /* realign */)){
bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
dev->nErasedBlocks++;
dev->nFreeChunks += dev->nChunksPerBlock;
}
else {
dev->markNANDBlockBad(dev,i);
bi->blockState = YAFFS_BLOCK_STATE_DEAD;
}
}
}
dev->blocksInCheckpoint = 0;
return 1;
}
static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
{
int i;
int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
T(YAFFS_TRACE_CHECKPOINT,
(TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),
dev->nErasedBlocks,dev->nReservedBlocks,blocksAvailable,dev->checkpointNextBlock));
if(dev->checkpointNextBlock >= 0 &&
dev->checkpointNextBlock <= dev->internalEndBlock &&
blocksAvailable > 0){
for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY){
dev->checkpointNextBlock = i + 1;
dev->checkpointCurrentBlock = i;
T(YAFFS_TRACE_CHECKPOINT,(TSTR("allocating checkpt block %d"TENDSTR),i));
return;
}
}
}
T(YAFFS_TRACE_CHECKPOINT,(TSTR("out of checkpt blocks"TENDSTR)));
dev->checkpointNextBlock = -1;
dev->checkpointCurrentBlock = -1;
}
static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
{
int i;
yaffs_ExtendedTags tags;
T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR),
dev->blocksInCheckpoint, dev->checkpointNextBlock));
if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){
int chunk = i * dev->nChunksPerBlock;
int realignedChunk = chunk - dev->chunkOffset;
dev->readChunkWithTagsFromNAND(dev,realignedChunk,NULL,&tags);
T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
i, tags.objectId,tags.sequenceNumber,tags.eccResult));
if(tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA){
/* Right kind of block */
dev->checkpointNextBlock = tags.objectId;
dev->checkpointCurrentBlock = i;
dev->checkpointBlockList[dev->blocksInCheckpoint] = i;
dev->blocksInCheckpoint++;
T(YAFFS_TRACE_CHECKPOINT,(TSTR("found checkpt block %d"TENDSTR),i));
return;
}
}
T(YAFFS_TRACE_CHECKPOINT,(TSTR("found no more checkpt blocks"TENDSTR)));
dev->checkpointNextBlock = -1;
dev->checkpointCurrentBlock = -1;
}
int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
{
/* Got the functions we need? */
if (!dev->writeChunkWithTagsToNAND ||
!dev->readChunkWithTagsFromNAND ||
!dev->eraseBlockInNAND ||
!dev->markNANDBlockBad)
return 0;
if(forWriting && !yaffs_CheckpointSpaceOk(dev))
return 0;
if(!dev->checkpointBuffer)
dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk);
if(!dev->checkpointBuffer)
return 0;
dev->checkpointPageSequence = 0;
dev->checkpointOpenForWrite = forWriting;
dev->checkpointByteCount = 0;
dev->checkpointSum = 0;
dev->checkpointXor = 0;
dev->checkpointCurrentBlock = -1;
dev->checkpointCurrentChunk = -1;
dev->checkpointNextBlock = dev->internalStartBlock;
/* Erase all the blocks in the checkpoint area */
if(forWriting){
memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
dev->checkpointByteOffset = 0;
return yaffs_CheckpointErase(dev);
} else {
int i;
/* Set to a value that will kick off a read */
dev->checkpointByteOffset = dev->nDataBytesPerChunk;
/* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
* going to be way more than we need */
dev->blocksInCheckpoint = 0;
dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
for(i = 0; i < dev->checkpointMaxBlocks; i++)
dev->checkpointBlockList[i] = -1;
}
return 1;
}
int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
{
__u32 compositeSum;
compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
*sum = compositeSum;
return 1;
}
static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
{
int chunk;
int realignedChunk;
yaffs_ExtendedTags tags;
if(dev->checkpointCurrentBlock < 0){
yaffs_CheckpointFindNextErasedBlock(dev);
dev->checkpointCurrentChunk = 0;
}
if(dev->checkpointCurrentBlock < 0)
return 0;
tags.chunkDeleted = 0;
tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */
tags.chunkId = dev->checkpointPageSequence + 1;
tags.sequenceNumber = YAFFS_SEQUENCE_CHECKPOINT_DATA;
tags.byteCount = dev->nDataBytesPerChunk;
if(dev->checkpointCurrentChunk == 0){
/* First chunk we write for the block? Set block state to
checkpoint */
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointCurrentBlock);
bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
dev->blocksInCheckpoint++;
}
chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk,tags.objectId,tags.chunkId));
realignedChunk = chunk - dev->chunkOffset;
dev->writeChunkWithTagsToNAND(dev,realignedChunk,dev->checkpointBuffer,&tags);
dev->checkpointByteOffset = 0;
dev->checkpointPageSequence++;
dev->checkpointCurrentChunk++;
if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock){
dev->checkpointCurrentChunk = 0;
dev->checkpointCurrentBlock = -1;
}
memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
return 1;
}
int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes)
{
int i=0;
int ok = 1;
__u8 * dataBytes = (__u8 *)data;
if(!dev->checkpointBuffer)
return 0;
if(!dev->checkpointOpenForWrite)
return -1;
while(i < nBytes && ok) {
dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ;
dev->checkpointSum += *dataBytes;
dev->checkpointXor ^= *dataBytes;
dev->checkpointByteOffset++;
i++;
dataBytes++;
dev->checkpointByteCount++;
if(dev->checkpointByteOffset < 0 ||
dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
ok = yaffs_CheckpointFlushBuffer(dev);
}
return i;
}
int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
{
int i=0;
int ok = 1;
yaffs_ExtendedTags tags;
int chunk;
int realignedChunk;
__u8 *dataBytes = (__u8 *)data;
if(!dev->checkpointBuffer)
return 0;
if(dev->checkpointOpenForWrite)
return -1;
while(i < nBytes && ok) {
if(dev->checkpointByteOffset < 0 ||
dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
if(dev->checkpointCurrentBlock < 0){
yaffs_CheckpointFindNextCheckpointBlock(dev);
dev->checkpointCurrentChunk = 0;
}
if(dev->checkpointCurrentBlock < 0)
ok = 0;
else {
chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock +
dev->checkpointCurrentChunk;
realignedChunk = chunk - dev->chunkOffset;
/* read in the next chunk */
/* printf("read checkpoint page %d\n",dev->checkpointPage); */
dev->readChunkWithTagsFromNAND(dev, realignedChunk,
dev->checkpointBuffer,
&tags);
if(tags.chunkId != (dev->checkpointPageSequence + 1) ||
tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
ok = 0;
dev->checkpointByteOffset = 0;
dev->checkpointPageSequence++;
dev->checkpointCurrentChunk++;
if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
dev->checkpointCurrentBlock = -1;
}
}
if(ok){
*dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
dev->checkpointSum += *dataBytes;
dev->checkpointXor ^= *dataBytes;
dev->checkpointByteOffset++;
i++;
dataBytes++;
dev->checkpointByteCount++;
}
}
return i;
}
int yaffs_CheckpointClose(yaffs_Device *dev)
{
if(dev->checkpointOpenForWrite){
if(dev->checkpointByteOffset != 0)
yaffs_CheckpointFlushBuffer(dev);
} else {
int i;
for(i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++){
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointBlockList[i]);
if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
else {
// Todo this looks odd...
}
}
YFREE(dev->checkpointBlockList);
dev->checkpointBlockList = NULL;
}
dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
dev->nErasedBlocks -= dev->blocksInCheckpoint;
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint byte count %d" TENDSTR),
dev->checkpointByteCount));
if(dev->checkpointBuffer){
/* free the buffer */
YFREE(dev->checkpointBuffer);
dev->checkpointBuffer = NULL;
return 1;
}
else
return 0;
}
int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
{
/* Erase the first checksum block */
T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint invalidate"TENDSTR)));
if(!yaffs_CheckpointSpaceOk(dev))
return 0;
return yaffs_CheckpointErase(dev);
}

View File

@ -1,35 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_CHECKPTRW_H__
#define __YAFFS_CHECKPTRW_H__
#include "yaffs_guts.h"
int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting);
int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes);
int yaffs_CheckpointRead(yaffs_Device *dev,void *data, int nBytes);
int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
int yaffs_CheckpointClose(yaffs_Device *dev);
int yaffs_CheckpointInvalidateStream(yaffs_Device *dev);
#endif

View File

@ -1,331 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* This code implements the ECC algorithm used in SmartMedia.
*
* The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
* The two unused bit are set to 1.
* The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
* blocks are used on a 512-byte NAND page.
*
*/
/* Table generated by gen-ecc.c
* Using a table means we do not have to calculate p1..p4 and p1'..p4'
* for each byte of data. These are instead provided in a table in bits7..2.
* Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore
* this bytes influence on the line parity.
*/
const char *yaffs_ecc_c_version =
"$Id: yaffs_ecc.c,v 1.9 2007-02-14 01:09:06 wookey Exp $";
#include "yportenv.h"
#include "yaffs_ecc.h"
static const unsigned char column_parity_table[] = {
0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
};
/* Count the bits in an unsigned char or a U32 */
static int yaffs_CountBits(unsigned char x)
{
int r = 0;
while (x) {
if (x & 1)
r++;
x >>= 1;
}
return r;
}
static int yaffs_CountBits32(unsigned x)
{
int r = 0;
while (x) {
if (x & 1)
r++;
x >>= 1;
}
return r;
}
/* Calculate the ECC for a 256-byte block of data */
void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)
{
unsigned int i;
unsigned char col_parity = 0;
unsigned char line_parity = 0;
unsigned char line_parity_prime = 0;
unsigned char t;
unsigned char b;
for (i = 0; i < 256; i++) {
b = column_parity_table[*data++];
col_parity ^= b;
if (b & 0x01) // odd number of bits in the byte
{
line_parity ^= i;
line_parity_prime ^= ~i;
}
}
ecc[2] = (~col_parity) | 0x03;
t = 0;
if (line_parity & 0x80)
t |= 0x80;
if (line_parity_prime & 0x80)
t |= 0x40;
if (line_parity & 0x40)
t |= 0x20;
if (line_parity_prime & 0x40)
t |= 0x10;
if (line_parity & 0x20)
t |= 0x08;
if (line_parity_prime & 0x20)
t |= 0x04;
if (line_parity & 0x10)
t |= 0x02;
if (line_parity_prime & 0x10)
t |= 0x01;
ecc[1] = ~t;
t = 0;
if (line_parity & 0x08)
t |= 0x80;
if (line_parity_prime & 0x08)
t |= 0x40;
if (line_parity & 0x04)
t |= 0x20;
if (line_parity_prime & 0x04)
t |= 0x10;
if (line_parity & 0x02)
t |= 0x08;
if (line_parity_prime & 0x02)
t |= 0x04;
if (line_parity & 0x01)
t |= 0x02;
if (line_parity_prime & 0x01)
t |= 0x01;
ecc[0] = ~t;
#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
// Swap the bytes into the wrong order
t = ecc[0];
ecc[0] = ecc[1];
ecc[1] = t;
#endif
}
/* Correct the ECC on a 256 byte block of data */
int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
const unsigned char *test_ecc)
{
unsigned char d0, d1, d2; /* deltas */
d0 = read_ecc[0] ^ test_ecc[0];
d1 = read_ecc[1] ^ test_ecc[1];
d2 = read_ecc[2] ^ test_ecc[2];
if ((d0 | d1 | d2) == 0)
return 0; /* no error */
if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
/* Single bit (recoverable) error in data */
unsigned byte;
unsigned bit;
#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
// swap the bytes to correct for the wrong order
unsigned char t;
t = d0;
d0 = d1;
d1 = t;
#endif
bit = byte = 0;
if (d1 & 0x80)
byte |= 0x80;
if (d1 & 0x20)
byte |= 0x40;
if (d1 & 0x08)
byte |= 0x20;
if (d1 & 0x02)
byte |= 0x10;
if (d0 & 0x80)
byte |= 0x08;
if (d0 & 0x20)
byte |= 0x04;
if (d0 & 0x08)
byte |= 0x02;
if (d0 & 0x02)
byte |= 0x01;
if (d2 & 0x80)
bit |= 0x04;
if (d2 & 0x20)
bit |= 0x02;
if (d2 & 0x08)
bit |= 0x01;
data[byte] ^= (1 << bit);
return 1; /* Corrected the error */
}
if ((yaffs_CountBits(d0) +
yaffs_CountBits(d1) +
yaffs_CountBits(d2)) == 1) {
/* Reccoverable error in ecc */
read_ecc[0] = test_ecc[0];
read_ecc[1] = test_ecc[1];
read_ecc[2] = test_ecc[2];
return 1; /* Corrected the error */
}
/* Unrecoverable error */
return -1;
}
/*
* ECCxxxOther does ECC calcs on arbitrary n bytes of data
*/
void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
yaffs_ECCOther * eccOther)
{
unsigned int i;
unsigned char col_parity = 0;
unsigned line_parity = 0;
unsigned line_parity_prime = 0;
unsigned char b;
for (i = 0; i < nBytes; i++) {
b = column_parity_table[*data++];
col_parity ^= b;
if (b & 0x01) {
/* odd number of bits in the byte */
line_parity ^= i;
line_parity_prime ^= ~i;
}
}
eccOther->colParity = (col_parity >> 2) & 0x3f;
eccOther->lineParity = line_parity;
eccOther->lineParityPrime = line_parity_prime;
}
int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
yaffs_ECCOther * read_ecc,
const yaffs_ECCOther * test_ecc)
{
unsigned char cDelta; /* column parity delta */
unsigned lDelta; /* line parity delta */
unsigned lDeltaPrime; /* line parity delta */
unsigned bit;
cDelta = read_ecc->colParity ^ test_ecc->colParity;
lDelta = read_ecc->lineParity ^ test_ecc->lineParity;
lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime;
if ((cDelta | lDelta | lDeltaPrime) == 0)
return 0; /* no error */
if (lDelta == ~lDeltaPrime &&
(((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15))
{
/* Single bit (recoverable) error in data */
bit = 0;
if (cDelta & 0x20)
bit |= 0x04;
if (cDelta & 0x08)
bit |= 0x02;
if (cDelta & 0x02)
bit |= 0x01;
if(lDelta >= nBytes)
return -1;
data[lDelta] ^= (1 << bit);
return 1; /* corrected */
}
if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) +
yaffs_CountBits(cDelta)) == 1) {
/* Reccoverable error in ecc */
*read_ecc = *test_ecc;
return 1; /* corrected */
}
/* Unrecoverable error */
return -1;
}

View File

@ -1,44 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/*
* This code implements the ECC algorithm used in SmartMedia.
*
* The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
* The two unused bit are set to 1.
* The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
* blocks are used on a 512-byte NAND page.
*
*/
#ifndef __YAFFS_ECC_H__
#define __YAFFS_ECC_H__
typedef struct {
unsigned char colParity;
unsigned lineParity;
unsigned lineParityPrime;
} yaffs_ECCOther;
void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc);
int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
const unsigned char *test_ecc);
void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
yaffs_ECCOther * ecc);
int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
yaffs_ECCOther * read_ecc,
const yaffs_ECCOther * test_ecc);
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,902 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_GUTS_H__
#define __YAFFS_GUTS_H__
#include "devextras.h"
#include "yportenv.h"
#define YAFFS_OK 1
#define YAFFS_FAIL 0
/* Give us a Y=0x59,
* Give us an A=0x41,
* Give us an FF=0xFF
* Give us an S=0x53
* And what have we got...
*/
#define YAFFS_MAGIC 0x5941FF53
#define YAFFS_NTNODES_LEVEL0 16
#define YAFFS_TNODES_LEVEL0_BITS 4
#define YAFFS_TNODES_LEVEL0_MASK 0xf
#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2)
#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1)
#define YAFFS_TNODES_INTERNAL_MASK 0x7
#define YAFFS_TNODES_MAX_LEVEL 6
#ifndef CONFIG_YAFFS_NO_YAFFS1
#define YAFFS_BYTES_PER_SPARE 16
#define YAFFS_BYTES_PER_CHUNK 512
#define YAFFS_CHUNK_SIZE_SHIFT 9
#define YAFFS_CHUNKS_PER_BLOCK 32
#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
#endif
#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024
#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32
#define YAFFS_MAX_CHUNK_ID 0x000FFFFF
#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF
#define YAFFS_ALLOCATION_NOBJECTS 100
#define YAFFS_ALLOCATION_NTNODES 100
#define YAFFS_ALLOCATION_NLINKS 100
#define YAFFS_NOBJECT_BUCKETS 256
#define YAFFS_OBJECT_SPACE 0x40000
#define YAFFS_CHECKPOINT_VERSION 3
#ifdef CONFIG_YAFFS_UNICODE
#define YAFFS_MAX_NAME_LENGTH 127
#define YAFFS_MAX_ALIAS_LENGTH 79
#else
#define YAFFS_MAX_NAME_LENGTH 255
#define YAFFS_MAX_ALIAS_LENGTH 159
#endif
#define YAFFS_SHORT_NAME_LENGTH 15
/* Some special object ids for pseudo objects */
#define YAFFS_OBJECTID_ROOT 1
#define YAFFS_OBJECTID_LOSTNFOUND 2
#define YAFFS_OBJECTID_UNLINKED 3
#define YAFFS_OBJECTID_DELETED 4
/* Sseudo object ids for checkpointing */
#define YAFFS_OBJECTID_SB_HEADER 0x10
#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
/* */
#define YAFFS_MAX_SHORT_OP_CACHES 20
#define YAFFS_N_TEMP_BUFFERS 4
/* We limit the number attempts at sucessfully saving a chunk of data.
* Small-page devices have 32 pages per block; large-page devices have 64.
* Default to something in the order of 5 to 10 blocks worth of chunks.
*/
#define YAFFS_WR_ATTEMPTS (5*64)
/* Sequence numbers are used in YAFFS2 to determine block allocation order.
* The range is limited slightly to help distinguish bad numbers from good.
* This also allows us to perhaps in the future use special numbers for
* special purposes.
* EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years,
* and is a larger number than the lifetime of a 2GB device.
*/
#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000
#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xEFFFFF00
/* ChunkCache is used for short read/write operations.*/
typedef struct {
struct yaffs_ObjectStruct *object;
int chunkId;
int lastUse;
int dirty;
int nBytes; /* Only valid if the cache is dirty */
int locked; /* Can't push out or flush while locked. */
#ifdef CONFIG_YAFFS_YAFFS2
__u8 *data;
#else
__u8 data[YAFFS_BYTES_PER_CHUNK];
#endif
} yaffs_ChunkCache;
/* Tags structures in RAM
* NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise
* the structure size will get blown out.
*/
#ifndef CONFIG_YAFFS_NO_YAFFS1
typedef struct {
unsigned chunkId:20;
unsigned serialNumber:2;
unsigned byteCount:10;
unsigned objectId:18;
unsigned ecc:12;
unsigned unusedStuff:2;
} yaffs_Tags;
typedef union {
yaffs_Tags asTags;
__u8 asBytes[8];
} yaffs_TagsUnion;
#endif
/* Stuff used for extended tags in YAFFS2 */
typedef enum {
YAFFS_ECC_RESULT_UNKNOWN,
YAFFS_ECC_RESULT_NO_ERROR,
YAFFS_ECC_RESULT_FIXED,
YAFFS_ECC_RESULT_UNFIXED
} yaffs_ECCResult;
typedef enum {
YAFFS_OBJECT_TYPE_UNKNOWN,
YAFFS_OBJECT_TYPE_FILE,
YAFFS_OBJECT_TYPE_SYMLINK,
YAFFS_OBJECT_TYPE_DIRECTORY,
YAFFS_OBJECT_TYPE_HARDLINK,
YAFFS_OBJECT_TYPE_SPECIAL
} yaffs_ObjectType;
#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
typedef struct {
unsigned validMarker0;
unsigned chunkUsed; /* Status of the chunk: used or unused */
unsigned objectId; /* If 0 then this is not part of an object (unused) */
unsigned chunkId; /* If 0 then this is a header, else a data chunk */
unsigned byteCount; /* Only valid for data chunks */
/* The following stuff only has meaning when we read */
yaffs_ECCResult eccResult;
unsigned blockBad;
/* YAFFS 1 stuff */
unsigned chunkDeleted; /* The chunk is marked deleted */
unsigned serialNumber; /* Yaffs1 2-bit serial number */
/* YAFFS2 stuff */
unsigned sequenceNumber; /* The sequence number of this block */
/* Extra info if this is an object header (YAFFS2 only) */
unsigned extraHeaderInfoAvailable; /* There is extra info available if this is not zero */
unsigned extraParentObjectId; /* The parent object */
unsigned extraIsShrinkHeader; /* Is it a shrink header? */
unsigned extraShadows; /* Does this shadow another object? */
yaffs_ObjectType extraObjectType; /* What object type? */
unsigned extraFileLength; /* Length if it is a file */
unsigned extraEquivalentObjectId; /* Equivalent object Id if it is a hard link */
unsigned validMarker1;
} yaffs_ExtendedTags;
/* Spare structure for YAFFS1 */
typedef struct {
__u8 tagByte0;
__u8 tagByte1;
__u8 tagByte2;
__u8 tagByte3;
__u8 pageStatus; /* set to 0 to delete the chunk */
__u8 blockStatus;
__u8 tagByte4;
__u8 tagByte5;
__u8 ecc1[3];
__u8 tagByte6;
__u8 tagByte7;
__u8 ecc2[3];
} yaffs_Spare;
/*Special structure for passing through to mtd */
struct yaffs_NANDSpare {
yaffs_Spare spare;
int eccres1;
int eccres2;
};
/* Block data in RAM */
typedef enum {
YAFFS_BLOCK_STATE_UNKNOWN = 0,
YAFFS_BLOCK_STATE_SCANNING,
YAFFS_BLOCK_STATE_NEEDS_SCANNING,
/* The block might have something on it (ie it is allocating or full, perhaps empty)
* but it needs to be scanned to determine its true state.
* This state is only valid during yaffs_Scan.
* NB We tolerate empty because the pre-scanner might be incapable of deciding
* However, if this state is returned on a YAFFS2 device, then we expect a sequence number
*/
YAFFS_BLOCK_STATE_EMPTY,
/* This block is empty */
YAFFS_BLOCK_STATE_ALLOCATING,
/* This block is partially allocated.
* At least one page holds valid data.
* This is the one currently being used for page
* allocation. Should never be more than one of these
*/
YAFFS_BLOCK_STATE_FULL,
/* All the pages in this block have been allocated.
*/
YAFFS_BLOCK_STATE_DIRTY,
/* All pages have been allocated and deleted.
* Erase me, reuse me.
*/
YAFFS_BLOCK_STATE_CHECKPOINT,
/* This block is assigned to holding checkpoint data.
*/
YAFFS_BLOCK_STATE_COLLECTING,
/* This block is being garbage collected */
YAFFS_BLOCK_STATE_DEAD
/* This block has failed and is not in use */
} yaffs_BlockState;
#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
typedef struct {
int softDeletions:10; /* number of soft deleted pages */
int pagesInUse:10; /* number of pages in use */
yaffs_BlockState blockState:4; /* One of the above block states */
__u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */
/* and retire the block. */
__u32 skipErasedCheck: 1; /* If this is set we can skip the erased check on this block */
__u32 gcPrioritise: 1; /* An ECC check or blank check has failed on this block.
It should be prioritised for GC */
__u32 chunkErrorStrikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */
#ifdef CONFIG_YAFFS_YAFFS2
__u32 hasShrinkHeader:1; /* This block has at least one shrink object header */
__u32 sequenceNumber; /* block sequence number for yaffs2 */
#endif
} yaffs_BlockInfo;
/* -------------------------- Object structure -------------------------------*/
/* This is the object structure as stored on NAND */
typedef struct {
yaffs_ObjectType type;
/* Apply to everything */
int parentObjectId;
__u16 sum__NoLongerUsed; /* checksum of name. No longer used */
YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
/* Thes following apply to directories, files, symlinks - not hard links */
__u32 yst_mode; /* protection */
#ifdef CONFIG_YAFFS_WINCE
__u32 notForWinCE[5];
#else
__u32 yst_uid;
__u32 yst_gid;
__u32 yst_atime;
__u32 yst_mtime;
__u32 yst_ctime;
#endif
/* File size applies to files only */
int fileSize;
/* Equivalent object id applies to hard links only. */
int equivalentObjectId;
/* Alias is for symlinks only. */
YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
__u32 yst_rdev; /* device stuff for block and char devices (major/min) */
#ifdef CONFIG_YAFFS_WINCE
__u32 win_ctime[2];
__u32 win_atime[2];
__u32 win_mtime[2];
__u32 roomToGrow[4];
#else
__u32 roomToGrow[10];
#endif
int shadowsObject; /* This object header shadows the specified object if > 0 */
/* isShrink applies to object headers written when we shrink the file (ie resize) */
__u32 isShrink;
} yaffs_ObjectHeader;
/*--------------------------- Tnode -------------------------- */
union yaffs_Tnode_union {
#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1];
#else
union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL];
#endif
/* __u16 level0[YAFFS_NTNODES_LEVEL0]; */
};
typedef union yaffs_Tnode_union yaffs_Tnode;
struct yaffs_TnodeList_struct {
struct yaffs_TnodeList_struct *next;
yaffs_Tnode *tnodes;
};
typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
/*------------------------ Object -----------------------------*/
/* An object can be one of:
* - a directory (no data, has children links
* - a regular file (data.... not prunes :->).
* - a symlink [symbolic link] (the alias).
* - a hard link
*/
typedef struct {
__u32 fileSize;
__u32 scannedFileSize;
__u32 shrinkSize;
int topLevel;
yaffs_Tnode *top;
} yaffs_FileStructure;
typedef struct {
struct list_head children; /* list of child links */
} yaffs_DirectoryStructure;
typedef struct {
YCHAR *alias;
} yaffs_SymLinkStructure;
typedef struct {
struct yaffs_ObjectStruct *equivalentObject;
__u32 equivalentObjectId;
} yaffs_HardLinkStructure;
typedef union {
yaffs_FileStructure fileVariant;
yaffs_DirectoryStructure directoryVariant;
yaffs_SymLinkStructure symLinkVariant;
yaffs_HardLinkStructure hardLinkVariant;
} yaffs_ObjectVariant;
struct yaffs_ObjectStruct {
__u8 deleted:1; /* This should only apply to unlinked files. */
__u8 softDeleted:1; /* it has also been soft deleted */
__u8 unlinked:1; /* An unlinked file. The file should be in the unlinked directory.*/
__u8 fake:1; /* A fake object has no presence on NAND. */
__u8 renameAllowed:1; /* Some objects are not allowed to be renamed. */
__u8 unlinkAllowed:1;
__u8 dirty:1; /* the object needs to be written to flash */
__u8 valid:1; /* When the file system is being loaded up, this
* object might be created before the data
* is available (ie. file data records appear before the header).
*/
__u8 lazyLoaded:1; /* This object has been lazy loaded and is missing some detail */
__u8 deferedFree:1; /* For Linux kernel. Object is removed from NAND, but is
* still in the inode cache. Free of object is defered.
* until the inode is released.
*/
__u8 serial; /* serial number of chunk in NAND. Cached here */
__u16 sum; /* sum of the name to speed searching */
struct yaffs_DeviceStruct *myDev; /* The device I'm on */
struct list_head hashLink; /* list of objects in this hash bucket */
struct list_head hardLinks; /* all the equivalent hard linked objects */
/* directory structure stuff */
/* also used for linking up the free list */
struct yaffs_ObjectStruct *parent;
struct list_head siblings;
/* Where's my object header in NAND? */
int chunkId;
int nDataChunks; /* Number of data chunks attached to the file. */
__u32 objectId; /* the object id value */
__u32 yst_mode;
#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1];
#endif
#ifndef __KERNEL__
__u32 inUse;
#endif
#ifdef CONFIG_YAFFS_WINCE
__u32 win_ctime[2];
__u32 win_mtime[2];
__u32 win_atime[2];
#else
__u32 yst_uid;
__u32 yst_gid;
__u32 yst_atime;
__u32 yst_mtime;
__u32 yst_ctime;
#endif
__u32 yst_rdev;
#ifdef __KERNEL__
struct inode *myInode;
#endif
yaffs_ObjectType variantType;
yaffs_ObjectVariant variant;
};
typedef struct yaffs_ObjectStruct yaffs_Object;
struct yaffs_ObjectList_struct {
yaffs_Object *objects;
struct yaffs_ObjectList_struct *next;
};
typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
typedef struct {
struct list_head list;
int count;
} yaffs_ObjectBucket;
/* yaffs_CheckpointObject holds the definition of an object as dumped
* by checkpointing.
*/
typedef struct {
int structType;
__u32 objectId;
__u32 parentId;
int chunkId;
yaffs_ObjectType variantType:3;
__u8 deleted:1;
__u8 softDeleted:1;
__u8 unlinked:1;
__u8 fake:1;
__u8 renameAllowed:1;
__u8 unlinkAllowed:1;
__u8 serial;
int nDataChunks;
__u32 fileSizeOrEquivalentObjectId;
}yaffs_CheckpointObject;
/*--------------------- Temporary buffers ----------------
*
* These are chunk-sized working buffers. Each device has a few
*/
typedef struct {
__u8 *buffer;
int line; /* track from whence this buffer was allocated */
int maxLine;
} yaffs_TempBuffer;
/*----------------- Device ---------------------------------*/
struct yaffs_DeviceStruct {
struct list_head devList;
const char *name;
/* Entry parameters set up way early. Yaffs sets up the rest.*/
int nDataBytesPerChunk; /* Should be a power of 2 >= 512 */
int nChunksPerBlock; /* does not need to be a power of 2 */
int nBytesPerSpare; /* spare area size */
int startBlock; /* Start block we're allowed to use */
int endBlock; /* End block we're allowed to use */
int nReservedBlocks; /* We want this tuneable so that we can reduce */
/* reserved blocks on NOR and RAM. */
/* Stuff used by the shared space checkpointing mechanism */
/* If this value is zero, then this mechanism is disabled */
int nCheckpointReservedBlocks; /* Blocks to reserve for checkpoint data */
int nShortOpCaches; /* If <= 0, then short op caching is disabled, else
* the number of short op caches (don't use too many)
*/
int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */
int useNANDECC; /* Flag to decide whether or not to use NANDECC */
void *genericDevice; /* Pointer to device context
* On an mtd this holds the mtd pointer.
*/
void *superBlock;
/* NAND access functions (Must be set before calling YAFFS)*/
int (*writeChunkToNAND) (struct yaffs_DeviceStruct * dev,
int chunkInNAND, const __u8 * data,
const yaffs_Spare * spare);
int (*readChunkFromNAND) (struct yaffs_DeviceStruct * dev,
int chunkInNAND, __u8 * data,
yaffs_Spare * spare);
int (*eraseBlockInNAND) (struct yaffs_DeviceStruct * dev,
int blockInNAND);
int (*initialiseNAND) (struct yaffs_DeviceStruct * dev);
#ifdef CONFIG_YAFFS_YAFFS2
int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct * dev,
int chunkInNAND, const __u8 * data,
const yaffs_ExtendedTags * tags);
int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct * dev,
int chunkInNAND, __u8 * data,
yaffs_ExtendedTags * tags);
int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo);
int (*queryNANDBlock) (struct yaffs_DeviceStruct * dev, int blockNo,
yaffs_BlockState * state, int *sequenceNumber);
#endif
int isYaffs2;
/* The removeObjectCallback function must be supplied by OS flavours that
* need it. The Linux kernel does not use this, but yaffs direct does use
* it to implement the faster readdir
*/
void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj);
/* Callback to mark the superblock dirsty */
void (*markSuperBlockDirty)(void * superblock);
int wideTnodesDisabled; /* Set to disable wide tnodes */
/* End of stuff that must be set before initialisation. */
/* Checkpoint control. Can be set before or after initialisation */
__u8 skipCheckpointRead;
__u8 skipCheckpointWrite;
/* Runtime parameters. Set up by YAFFS. */
__u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */
__u16 chunkGroupSize; /* == 2^^chunkGroupBits */
/* Stuff to support wide tnodes */
__u32 tnodeWidth;
__u32 tnodeMask;
/* Stuff to support various file offses to chunk/offset translations */
/* "Crumbs" for nDataBytesPerChunk not being a power of 2 */
__u32 crumbMask;
__u32 crumbShift;
__u32 crumbsPerChunk;
/* Straight shifting for nDataBytesPerChunk being a power of 2 */
__u32 chunkShift;
__u32 chunkMask;
#ifdef __KERNEL__
struct semaphore sem; /* Semaphore for waiting on erasure.*/
struct semaphore grossLock; /* Gross locking semaphore */
__u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer
* at compile time so we have to allocate it.
*/
void (*putSuperFunc) (struct super_block * sb);
#endif
int isMounted;
int isCheckpointed;
/* Stuff to support block offsetting to support start block zero */
int internalStartBlock;
int internalEndBlock;
int blockOffset;
int chunkOffset;
/* Runtime checkpointing stuff */
int checkpointPageSequence; /* running sequence number of checkpoint pages */
int checkpointByteCount;
int checkpointByteOffset;
__u8 *checkpointBuffer;
int checkpointOpenForWrite;
int blocksInCheckpoint;
int checkpointCurrentChunk;
int checkpointCurrentBlock;
int checkpointNextBlock;
int *checkpointBlockList;
int checkpointMaxBlocks;
__u32 checkpointSum;
__u32 checkpointXor;
/* Block Info */
yaffs_BlockInfo *blockInfo;
__u8 *chunkBits; /* bitmap of chunks in use */
unsigned blockInfoAlt:1; /* was allocated using alternative strategy */
unsigned chunkBitsAlt:1; /* was allocated using alternative strategy */
int chunkBitmapStride; /* Number of bytes of chunkBits per block.
* Must be consistent with nChunksPerBlock.
*/
int nErasedBlocks;
int allocationBlock; /* Current block being allocated off */
__u32 allocationPage;
int allocationBlockFinder; /* Used to search for next allocation block */
/* Runtime state */
int nTnodesCreated;
yaffs_Tnode *freeTnodes;
int nFreeTnodes;
yaffs_TnodeList *allocatedTnodeList;
int isDoingGC;
int nObjectsCreated;
yaffs_Object *freeObjects;
int nFreeObjects;
yaffs_ObjectList *allocatedObjectList;
yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS];
int nFreeChunks;
int currentDirtyChecker; /* Used to find current dirtiest block */
__u32 *gcCleanupList; /* objects to delete at the end of a GC. */
int nonAggressiveSkip; /* GC state/mode */
/* Statistcs */
int nPageWrites;
int nPageReads;
int nBlockErasures;
int nErasureFailures;
int nGCCopies;
int garbageCollections;
int passiveGarbageCollections;
int nRetriedWrites;
int nRetiredBlocks;
int eccFixed;
int eccUnfixed;
int tagsEccFixed;
int tagsEccUnfixed;
int nDeletions;
int nUnmarkedDeletions;
int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */
/* Special directories */
yaffs_Object *rootDir;
yaffs_Object *lostNFoundDir;
/* Buffer areas for storing data to recover from write failures TODO
* __u8 bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK];
* yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK];
*/
int bufferedBlock; /* Which block is buffered here? */
int doingBufferedBlockRewrite;
yaffs_ChunkCache *srCache;
int srLastUse;
int cacheHits;
/* Stuff for background deletion and unlinked files.*/
yaffs_Object *unlinkedDir; /* Directory where unlinked and deleted files live. */
yaffs_Object *deletedDir; /* Directory where deleted objects are sent to disappear. */
yaffs_Object *unlinkedDeletion; /* Current file being background deleted.*/
int nDeletedFiles; /* Count of files awaiting deletion;*/
int nUnlinkedFiles; /* Count of unlinked files. */
int nBackgroundDeletions; /* Count of background deletions. */
yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
int maxTemp;
int unmanagedTempAllocations;
int unmanagedTempDeallocations;
/* yaffs2 runtime stuff */
unsigned sequenceNumber; /* Sequence number of currently allocating block */
unsigned oldestDirtySequence;
};
typedef struct yaffs_DeviceStruct yaffs_Device;
/* The static layout of bllock usage etc is stored in the super block header */
typedef struct {
int StructType;
int version;
int checkpointStartBlock;
int checkpointEndBlock;
int startBlock;
int endBlock;
int rfu[100];
} yaffs_SuperBlockHeader;
/* The CheckpointDevice structure holds the device information that changes at runtime and
* must be preserved over unmount/mount cycles.
*/
typedef struct {
int structType;
int nErasedBlocks;
int allocationBlock; /* Current block being allocated off */
__u32 allocationPage;
int nFreeChunks;
int nDeletedFiles; /* Count of files awaiting deletion;*/
int nUnlinkedFiles; /* Count of unlinked files. */
int nBackgroundDeletions; /* Count of background deletions. */
/* yaffs2 runtime stuff */
unsigned sequenceNumber; /* Sequence number of currently allocating block */
unsigned oldestDirtySequence;
} yaffs_CheckpointDevice;
typedef struct {
int structType;
__u32 magic;
__u32 version;
__u32 head;
} yaffs_CheckpointValidity;
/* Function to manipulate block info */
static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
{
if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
blk));
YBUG();
}
return &dev->blockInfo[blk - dev->internalStartBlock];
}
/*----------------------- YAFFS Functions -----------------------*/
int yaffs_GutsInitialise(yaffs_Device * dev);
void yaffs_Deinitialise(yaffs_Device * dev);
int yaffs_GetNumberOfFreeChunks(yaffs_Device * dev);
int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName,
yaffs_Object * newDir, const YCHAR * newName);
int yaffs_Unlink(yaffs_Object * dir, const YCHAR * name);
int yaffs_DeleteFile(yaffs_Object * obj);
int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize);
int yaffs_GetObjectFileLength(yaffs_Object * obj);
int yaffs_GetObjectInode(yaffs_Object * obj);
unsigned yaffs_GetObjectType(yaffs_Object * obj);
int yaffs_GetObjectLinkCount(yaffs_Object * obj);
int yaffs_SetAttributes(yaffs_Object * obj, struct iattr *attr);
int yaffs_GetAttributes(yaffs_Object * obj, struct iattr *attr);
/* File operations */
int yaffs_ReadDataFromFile(yaffs_Object * obj, __u8 * buffer, loff_t offset,
int nBytes);
int yaffs_WriteDataToFile(yaffs_Object * obj, const __u8 * buffer, loff_t offset,
int nBytes, int writeThrough);
int yaffs_ResizeFile(yaffs_Object * obj, loff_t newSize);
yaffs_Object *yaffs_MknodFile(yaffs_Object * parent, const YCHAR * name,
__u32 mode, __u32 uid, __u32 gid);
int yaffs_FlushFile(yaffs_Object * obj, int updateTime);
/* Flushing and checkpointing */
void yaffs_FlushEntireDeviceCache(yaffs_Device *dev);
int yaffs_CheckpointSave(yaffs_Device *dev);
int yaffs_CheckpointRestore(yaffs_Device *dev);
/* Directory operations */
yaffs_Object *yaffs_MknodDirectory(yaffs_Object * parent, const YCHAR * name,
__u32 mode, __u32 uid, __u32 gid);
yaffs_Object *yaffs_FindObjectByName(yaffs_Object * theDir, const YCHAR * name);
int yaffs_ApplyToDirectoryChildren(yaffs_Object * theDir,
int (*fn) (yaffs_Object *));
yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device * dev, __u32 number);
/* Link operations */
yaffs_Object *yaffs_Link(yaffs_Object * parent, const YCHAR * name,
yaffs_Object * equivalentObject);
yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object * obj);
/* Symlink operations */
yaffs_Object *yaffs_MknodSymLink(yaffs_Object * parent, const YCHAR * name,
__u32 mode, __u32 uid, __u32 gid,
const YCHAR * alias);
YCHAR *yaffs_GetSymlinkAlias(yaffs_Object * obj);
/* Special inodes (fifos, sockets and devices) */
yaffs_Object *yaffs_MknodSpecial(yaffs_Object * parent, const YCHAR * name,
__u32 mode, __u32 uid, __u32 gid, __u32 rdev);
/* Special directories */
yaffs_Object *yaffs_Root(yaffs_Device * dev);
yaffs_Object *yaffs_LostNFound(yaffs_Device * dev);
#ifdef CONFIG_YAFFS_WINCE
/* CONFIG_YAFFS_WINCE special stuff */
void yfsd_WinFileTimeNow(__u32 target[2]);
#endif
#ifdef __KERNEL__
void yaffs_HandleDeferedFree(yaffs_Object * obj);
#endif
/* Debug dump */
int yaffs_DumpObject(yaffs_Object * obj);
void yaffs_GutsTest(yaffs_Device * dev);
/* A few useful functions */
void yaffs_InitialiseTags(yaffs_ExtendedTags * tags);
void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn);
int yaffs_CheckFF(__u8 * buffer, int nBytes);
void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi);
#endif

View File

@ -1,241 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
const char *yaffs_mtdif_c_version =
"$Id: yaffs_mtdif.c,v 1.19 2007-02-14 01:09:06 wookey Exp $";
#include "yportenv.h"
#include "yaffs_mtdif.h"
#include "linux/mtd/mtd.h"
#include "linux/types.h"
#include "linux/time.h"
#include "linux/mtd/nand.h"
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
static struct nand_oobinfo yaffs_oobinfo = {
.useecc = 1,
.eccbytes = 6,
.eccpos = {8, 9, 10, 13, 14, 15}
};
static struct nand_oobinfo yaffs_noeccinfo = {
.useecc = 0,
};
#endif
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
{
oob[0] = spare->tagByte0;
oob[1] = spare->tagByte1;
oob[2] = spare->tagByte2;
oob[3] = spare->tagByte3;
oob[4] = spare->tagByte4;
oob[5] = spare->tagByte5 & 0x3f;
oob[5] |= spare->blockStatus == 'Y' ? 0: 0x80;
oob[5] |= spare->pageStatus == 0 ? 0: 0x40;
oob[6] = spare->tagByte6;
oob[7] = spare->tagByte7;
}
static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob)
{
struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare;
spare->tagByte0 = oob[0];
spare->tagByte1 = oob[1];
spare->tagByte2 = oob[2];
spare->tagByte3 = oob[3];
spare->tagByte4 = oob[4];
spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y';
spare->pageStatus = oob[5] & 0x40 ? 0xff : 0;
spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff;
spare->tagByte6 = oob[6];
spare->tagByte7 = oob[7];
spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff;
nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */
}
#endif
int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data, const yaffs_Spare * spare)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
struct mtd_oob_ops ops;
#endif
size_t dummy;
int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
__u8 spareAsBytes[8]; /* OOB */
if (data && !spare)
retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data);
else if (spare) {
if (dev->useNANDECC) {
translate_spare2oob(spare, spareAsBytes);
ops.mode = MTD_OOB_AUTO;
ops.ooblen = 8; /* temp hack */
} else {
ops.mode = MTD_OOB_RAW;
ops.ooblen = YAFFS_BYTES_PER_SPARE;
}
ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
ops.datbuf = (u8 *)data;
ops.ooboffs = 0;
ops.oobbuf = spareAsBytes;
retval = mtd->write_oob(mtd, addr, &ops);
}
#else
__u8 *spareAsBytes = (__u8 *) spare;
if (data && spare) {
if (dev->useNANDECC)
retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, spareAsBytes,
&yaffs_oobinfo);
else
retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, spareAsBytes,
&yaffs_noeccinfo);
} else {
if (data)
retval =
mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
data);
if (spare)
retval =
mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
&dummy, spareAsBytes);
}
#endif
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
yaffs_Spare * spare)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
struct mtd_oob_ops ops;
#endif
size_t dummy;
int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
__u8 spareAsBytes[8]; /* OOB */
if (data && !spare)
retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data);
else if (spare) {
if (dev->useNANDECC) {
ops.mode = MTD_OOB_AUTO;
ops.ooblen = 8; /* temp hack */
} else {
ops.mode = MTD_OOB_RAW;
ops.ooblen = YAFFS_BYTES_PER_SPARE;
}
ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
ops.datbuf = data;
ops.ooboffs = 0;
ops.oobbuf = spareAsBytes;
retval = mtd->read_oob(mtd, addr, &ops);
if (dev->useNANDECC)
translate_oob2spare(spare, spareAsBytes);
}
#else
__u8 *spareAsBytes = (__u8 *) spare;
if (data && spare) {
if (dev->useNANDECC) {
/* Careful, this call adds 2 ints */
/* to the end of the spare data. Calling function */
/* should allocate enough memory for spare, */
/* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */
retval =
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, spareAsBytes,
&yaffs_oobinfo);
} else {
retval =
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, spareAsBytes,
&yaffs_noeccinfo);
}
} else {
if (data)
retval =
mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
data);
if (spare)
retval =
mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
&dummy, spareAsBytes);
}
#endif
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
__u32 addr =
((loff_t) blockNumber) * dev->nDataBytesPerChunk
* dev->nChunksPerBlock;
struct erase_info ei;
int retval = 0;
ei.mtd = mtd;
ei.addr = addr;
ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;
ei.time = 1000;
ei.retries = 2;
ei.callback = NULL;
ei.priv = (u_long) dev;
/* Todo finish off the ei if required */
sema_init(&dev->sem, 0);
retval = mtd->erase(mtd, &ei);
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd_InitialiseNAND(yaffs_Device * dev)
{
return YAFFS_OK;
}

View File

@ -1,27 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_MTDIF_H__
#define __YAFFS_MTDIF_H__
#include "yaffs_guts.h"
int nandmtd_WriteChunkToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data, const yaffs_Spare * spare);
int nandmtd_ReadChunkFromNAND(yaffs_Device * dev, int chunkInNAND, __u8 * data,
yaffs_Spare * spare);
int nandmtd_EraseBlockInNAND(yaffs_Device * dev, int blockNumber);
int nandmtd_InitialiseNAND(yaffs_Device * dev);
#endif

View File

@ -1,434 +0,0 @@
From ian@brightstareng.com Fri May 18 15:06:49 2007
From ian@brightstareng.com Fri May 18 15:08:21 2007
Received: from 206.173.66.57.ptr.us.xo.net ([206.173.66.57] helo=zebra.brightstareng.com)
by apollo.linkchoose.co.uk with esmtp (Exim 4.60)
(envelope-from <ian@brightstareng.com>)
id 1Hp380-00011e-T6
for david.goodenough@linkchoose.co.uk; Fri, 18 May 2007 15:08:21 +0100
Received: from localhost (localhost.localdomain [127.0.0.1])
by zebra.brightstareng.com (Postfix) with ESMTP
id 4819F28C004; Fri, 18 May 2007 10:07:49 -0400 (EDT)
Received: from zebra.brightstareng.com ([127.0.0.1])
by localhost (zebra [127.0.0.1]) (amavisd-new, port 10024) with ESMTP
id 05328-06; Fri, 18 May 2007 10:07:16 -0400 (EDT)
Received: from pippin (unknown [192.168.1.25])
by zebra.brightstareng.com (Postfix) with ESMTP
id 8BEF528C1BC; Fri, 18 May 2007 10:06:53 -0400 (EDT)
From: Ian McDonnell <ian@brightstareng.com>
To: David Goodenough <david.goodenough@linkchoose.co.uk>
Subject: Re: something tested this time -- yaffs_mtdif1-compat.c
Date: Fri, 18 May 2007 10:06:49 -0400
User-Agent: KMail/1.9.1
References: <200705142207.06909.ian@brightstareng.com> <200705171131.53536.ian@brightstareng.com> <200705181334.32166.david.goodenough@linkchoose.co.uk>
In-Reply-To: <200705181334.32166.david.goodenough@linkchoose.co.uk>
Cc: Andrea Conti <alyf@alyf.net>,
Charles Manning <manningc2@actrix.gen.nz>
MIME-Version: 1.0
Content-Type: Multipart/Mixed;
boundary="Boundary-00=_5LbTGmt62YoutxM"
Message-Id: <200705181006.49860.ian@brightstareng.com>
X-Virus-Scanned: by amavisd-new at brightstareng.com
Status: R
X-Status: NT
X-KMail-EncryptionState:
X-KMail-SignatureState:
X-KMail-MDN-Sent:
--Boundary-00=_5LbTGmt62YoutxM
Content-Type: text/plain;
charset="iso-8859-15"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
David, Andrea,
On Friday 18 May 2007 08:34, you wrote:
> Yea team. With this fix in place (I put it in the wrong place
> at first) I can now mount and ls the Yaffs partition without
> an error messages!
Good news!
Attached is a newer yaffs_mtdif1.c with a bandaid to help the
2.6.18 and 2.6.19 versions of MTD not trip on the oob read.
See the LINUX_VERSION_CODE conditional in
nandmtd1_ReadChunkWithTagsFromNAND.
-imcd
--Boundary-00=_5LbTGmt62YoutxM
Content-Type: text/x-csrc;
charset="iso-8859-15";
name="yaffs_mtdif1.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="yaffs_mtdif1.c"
/*
* YAFFS: Yet another FFS. A NAND-flash specific file system.
* yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
*
* Copyright (C) 2002 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* This module provides the interface between yaffs_nand.c and the
* MTD API. This version is used when the MTD interface supports the
* 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
* and we have small-page NAND device.
*
* These functions are invoked via function pointers in yaffs_nand.c.
* This replaces functionality provided by functions in yaffs_mtdif.c
* and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
* called in yaffs_mtdif.c when the function pointers are NULL.
* We assume the MTD layer is performing ECC (useNANDECC is true).
*/
#include "yportenv.h"
#include "yaffs_guts.h"
#include "yaffs_packedtags1.h"
#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC
#include "linux/kernel.h"
#include "linux/version.h"
#include "linux/types.h"
#include "linux/mtd/mtd.h"
/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
const char *yaffs_mtdif1_c_version = "$Id$";
#ifndef CONFIG_YAFFS_9BYTE_TAGS
# define YTAG1_SIZE 8
#else
# define YTAG1_SIZE 9
#endif
#if 0
/* Use the following nand_ecclayout with MTD when using
* CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout.
* If you have existing Yaffs images and the byte order differs from this,
* adjust 'oobfree' to match your existing Yaffs data.
*
* This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
* pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
* the 9th byte.
*
* Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
* We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
* where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
* byte and B is the small-page bad-block indicator byte.
*/
static struct nand_ecclayout nand_oob_16 = {
.eccbytes = 6,
.eccpos = { 8, 9, 10, 13, 14, 15 },
.oobavail = 9,
.oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
};
#endif
/* Write a chunk (page) of data to NAND.
*
* Caller always provides ExtendedTags data which are converted to a more
* compact (packed) form for storage in NAND. A mini-ECC runs over the
* contents of the tags meta-data; used to valid the tags when read.
*
* - Pack ExtendedTags to PackedTags1 form
* - Compute mini-ECC for PackedTags1
* - Write data and packed tags to NAND.
*
* Note: Due to the use of the PackedTags1 meta-data which does not include
* a full sequence number (as found in the larger PackedTags2 form) it is
* necessary for Yaffs to re-write a chunk/page (just once) to mark it as
* discarded and dirty. This is not ideal: newer NAND parts are supposed
* to be written just once. When Yaffs performs this operation, this
* function is called with a NULL data pointer -- calling MTD write_oob
* without data is valid usage (2.6.17).
*
* Any underlying MTD error results in YAFFS_FAIL.
* Returns YAFFS_OK or YAFFS_FAIL.
*/
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags)
{
struct mtd_info * mtd = dev->genericDevice;
int chunkBytes = dev->nDataBytesPerChunk;
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
struct mtd_oob_ops ops;
yaffs_PackedTags1 pt1;
int retval;
/* we assume that PackedTags1 and yaffs_Tags are compatible */
compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
compile_time_assertion(sizeof(yaffs_Tags) == 8);
yaffs_PackTags1(&pt1, etags);
yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
/* When deleting a chunk, the upper layer provides only skeletal
* etags, one with chunkDeleted set. However, we need to update the
* tags, not erase them completely. So we use the NAND write property
* that only zeroed-bits stick and set tag bytes to all-ones and
* zero just the (not) deleted bit.
*/
#ifndef CONFIG_YAFFS_9BYTE_TAGS
if (etags->chunkDeleted) {
memset(&pt1, 0xff, 8);
/* clear delete status bit to indicate deleted */
pt1.deleted = 0;
}
#else
((__u8 *)&pt1)[8] = 0xff;
if (etags->chunkDeleted) {
memset(&pt1, 0xff, 8);
/* zero pageStatus byte to indicate deleted */
((__u8 *)&pt1)[8] = 0;
}
#endif
memset(&ops, 0, sizeof(ops));
ops.mode = MTD_OOB_AUTO;
ops.len = (data) ? chunkBytes : 0;
ops.ooblen = YTAG1_SIZE;
ops.datbuf = (__u8 *)data;
ops.oobbuf = (__u8 *)&pt1;
retval = mtd->write_oob(mtd, addr, &ops);
if (retval) {
yaffs_trace(YAFFS_TRACE_MTD,
"write_oob failed, chunk %d, mtd error %d\n",
chunkInNAND, retval);
}
return retval ? YAFFS_FAIL : YAFFS_OK;
}
/* Return with empty ExtendedTags but add eccResult.
*/
static int rettags(yaffs_ExtendedTags * etags, int eccResult, int retval)
{
if (etags) {
memset(etags, 0, sizeof(*etags));
etags->eccResult = eccResult;
}
return retval;
}
/* Read a chunk (page) from NAND.
*
* Caller expects ExtendedTags data to be usable even on error; that is,
* all members except eccResult and blockBad are zeroed.
*
* - Check ECC results for data (if applicable)
* - Check for blank/erased block (return empty ExtendedTags if blank)
* - Check the PackedTags1 mini-ECC (correct if necessary/possible)
* - Convert PackedTags1 to ExtendedTags
* - Update eccResult and blockBad members to refect state.
*
* Returns YAFFS_OK or YAFFS_FAIL.
*/
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
int chunkInNAND, __u8 * data, yaffs_ExtendedTags * etags)
{
struct mtd_info * mtd = dev->genericDevice;
int chunkBytes = dev->nDataBytesPerChunk;
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
int eccres = YAFFS_ECC_RESULT_NO_ERROR;
struct mtd_oob_ops ops;
yaffs_PackedTags1 pt1;
int retval;
int deleted;
memset(&ops, 0, sizeof(ops));
ops.mode = MTD_OOB_AUTO;
ops.len = (data) ? chunkBytes : 0;
ops.ooblen = YTAG1_SIZE;
ops.datbuf = data;
ops.oobbuf = (__u8 *)&pt1;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
/* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
* help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
*/
ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
#endif
/* Read page and oob using MTD.
* Check status and determine ECC result.
*/
retval = mtd->read_oob(mtd, addr, &ops);
if (retval) {
yaffs_trace(YAFFS_TRACE_MTD,
"read_oob failed, chunk %d, mtd error %d\n",
chunkInNAND, retval);
}
switch (retval) {
case 0:
/* no error */
break;
case -EUCLEAN:
/* MTD's ECC fixed the data */
eccres = YAFFS_ECC_RESULT_FIXED;
dev->eccFixed++;
break;
case -EBADMSG:
/* MTD's ECC could not fix the data */
dev->eccUnfixed++;
/* fall into... */
default:
rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
etags->blockBad = (mtd->block_isbad)(mtd, addr);
return YAFFS_FAIL;
}
/* Check for a blank/erased chunk.
*/
if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
/* when blank, upper layers want eccResult to be <= NO_ERROR */
return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
}
#ifndef CONFIG_YAFFS_9BYTE_TAGS
/* Read deleted status (bit) then return it to it's non-deleted
* state before performing tags mini-ECC check. pt1.deleted is
* inverted.
*/
deleted = !pt1.deleted;
pt1.deleted = 1;
#else
(void) deleted; /* not used */
#endif
/* Check the packed tags mini-ECC and correct if necessary/possible.
*/
retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
switch (retval) {
case 0:
/* no tags error, use MTD result */
break;
case 1:
/* recovered tags-ECC error */
dev->tagsEccFixed++;
eccres = YAFFS_ECC_RESULT_FIXED;
break;
default:
/* unrecovered tags-ECC error */
dev->tagsEccUnfixed++;
return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
}
/* Unpack the tags to extended form and set ECC result.
* [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
*/
pt1.shouldBeFF = 0xFFFFFFFF;
yaffs_UnpackTags1(etags, &pt1);
etags->eccResult = eccres;
/* Set deleted state.
*/
#ifndef CONFIG_YAFFS_9BYTE_TAGS
etags->chunkDeleted = deleted;
#else
etags->chunkDeleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
#endif
return YAFFS_OK;
}
/* Mark a block bad.
*
* This is a persistant state.
* Use of this function should be rare.
*
* Returns YAFFS_OK or YAFFS_FAIL.
*/
int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
{
struct mtd_info * mtd = dev->genericDevice;
int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
int retval;
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo);
retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
return (retval) ? YAFFS_FAIL : YAFFS_OK;
}
/* Check any MTD prerequists.
*
* Returns YAFFS_OK or YAFFS_FAIL.
*/
static int nandmtd1_TestPrerequists(struct mtd_info * mtd)
{
/* 2.6.18 has mtd->ecclayout->oobavail */
/* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
int oobavail = mtd->ecclayout->oobavail;
if (oobavail < YTAG1_SIZE) {
yaffs_trace(YAFFS_TRACE_ERROR,
"mtd device has only %d bytes for tags, need %d",
oobavail, YTAG1_SIZE);
return YAFFS_FAIL;
}
return YAFFS_OK;
}
/* Query for the current state of a specific block.
*
* Examine the tags of the first chunk of the block and return the state:
* - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
* - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
* - YAFFS_BLOCK_STATE_EMPTY, the block is clean
*
* Always returns YAFFS_OK.
*/
int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState * pState, int *pSequenceNumber)
{
struct mtd_info * mtd = dev->genericDevice;
int chunkNo = blockNo * dev->nChunksPerBlock;
yaffs_ExtendedTags etags;
int state = YAFFS_BLOCK_STATE_DEAD;
int seqnum = 0;
int retval;
/* We don't yet have a good place to test for MTD config prerequists.
* Do it here as we are called during the initial scan.
*/
if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) {
return YAFFS_FAIL;
}
retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
if (etags.blockBad) {
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
"block %d is marked bad", blockNo);
state = YAFFS_BLOCK_STATE_DEAD;
}
else if (etags.chunkUsed) {
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
seqnum = etags.sequenceNumber;
}
else {
state = YAFFS_BLOCK_STATE_EMPTY;
}
*pState = state;
*pSequenceNumber = seqnum;
/* query always succeeds */
return YAFFS_OK;
}
#endif /*KERNEL_VERSION*/
--Boundary-00=_5LbTGmt62YoutxM--

View File

@ -1,363 +0,0 @@
/*
* YAFFS: Yet another FFS. A NAND-flash specific file system.
* yaffs_mtdif1.c NAND mtd interface functions for small-page NAND.
*
* Copyright (C) 2002 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* This module provides the interface between yaffs_nand.c and the
* MTD API. This version is used when the MTD interface supports the
* 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
* and we have small-page NAND device.
*
* These functions are invoked via function pointers in yaffs_nand.c.
* This replaces functionality provided by functions in yaffs_mtdif.c
* and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
* called in yaffs_mtdif.c when the function pointers are NULL.
* We assume the MTD layer is performing ECC (useNANDECC is true).
*/
#include "yportenv.h"
#include "yaffs_guts.h"
#include "yaffs_packedtags1.h"
#include "yaffs_tagscompat.h" // for yaffs_CalcTagsECC
#include "linux/kernel.h"
#include "linux/version.h"
#include "linux/types.h"
#include "linux/mtd/mtd.h"
/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.3 2007/05/15 20:16:11 ian Exp $";
#ifndef CONFIG_YAFFS_9BYTE_TAGS
# define YTAG1_SIZE 8
#else
# define YTAG1_SIZE 9
#endif
#if 0
/* Use the following nand_ecclayout with MTD when using
* CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout.
* If you have existing Yaffs images and the byte order differs from this,
* adjust 'oobfree' to match your existing Yaffs data.
*
* This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
* pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
* the 9th byte.
*
* Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
* We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
* where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
* byte and B is the small-page bad-block indicator byte.
*/
static struct nand_ecclayout nand_oob_16 = {
.eccbytes = 6,
.eccpos = { 8, 9, 10, 13, 14, 15 },
.oobavail = 9,
.oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
};
#endif
/* Write a chunk (page) of data to NAND.
*
* Caller always provides ExtendedTags data which are converted to a more
* compact (packed) form for storage in NAND. A mini-ECC runs over the
* contents of the tags meta-data; used to valid the tags when read.
*
* - Pack ExtendedTags to PackedTags1 form
* - Compute mini-ECC for PackedTags1
* - Write data and packed tags to NAND.
*
* Note: Due to the use of the PackedTags1 meta-data which does not include
* a full sequence number (as found in the larger PackedTags2 form) it is
* necessary for Yaffs to re-write a chunk/page (just once) to mark it as
* discarded and dirty. This is not ideal: newer NAND parts are supposed
* to be written just once. When Yaffs performs this operation, this
* function is called with a NULL data pointer -- calling MTD write_oob
* without data is valid usage (2.6.17).
*
* Any underlying MTD error results in YAFFS_FAIL.
* Returns YAFFS_OK or YAFFS_FAIL.
*/
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
int chunkInNAND, const __u8 * data, const yaffs_ExtendedTags * etags)
{
struct mtd_info * mtd = dev->genericDevice;
int chunkBytes = dev->nDataBytesPerChunk;
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
struct mtd_oob_ops ops;
yaffs_PackedTags1 pt1;
int retval;
/* we assume that PackedTags1 and yaffs_Tags are compatible */
compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
compile_time_assertion(sizeof(yaffs_Tags) == 8);
dev->nPageWrites++;
yaffs_PackTags1(&pt1, etags);
yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
/* When deleting a chunk, the upper layer provides only skeletal
* etags, one with chunkDeleted set. However, we need to update the
* tags, not erase them completely. So we use the NAND write property
* that only zeroed-bits stick and set tag bytes to all-ones and
* zero just the (not) deleted bit.
*/
#ifndef CONFIG_YAFFS_9BYTE_TAGS
if (etags->chunkDeleted) {
memset(&pt1, 0xff, 8);
/* clear delete status bit to indicate deleted */
pt1.deleted = 0;
}
#else
((__u8 *)&pt1)[8] = 0xff;
if (etags->chunkDeleted) {
memset(&pt1, 0xff, 8);
/* zero pageStatus byte to indicate deleted */
((__u8 *)&pt1)[8] = 0;
}
#endif
memset(&ops, 0, sizeof(ops));
ops.mode = MTD_OOB_AUTO;
ops.len = (data) ? chunkBytes : 0;
ops.ooblen = YTAG1_SIZE;
ops.datbuf = (__u8 *)data;
ops.oobbuf = (__u8 *)&pt1;
retval = mtd->write_oob(mtd, addr, &ops);
if (retval) {
yaffs_trace(YAFFS_TRACE_MTD,
"write_oob failed, chunk %d, mtd error %d\n",
chunkInNAND, retval);
}
return retval ? YAFFS_FAIL : YAFFS_OK;
}
/* Return with empty ExtendedTags but add eccResult.
*/
static int rettags(yaffs_ExtendedTags * etags, int eccResult, int retval)
{
if (etags) {
memset(etags, 0, sizeof(*etags));
etags->eccResult = eccResult;
}
return retval;
}
/* Read a chunk (page) from NAND.
*
* Caller expects ExtendedTags data to be usable even on error; that is,
* all members except eccResult and blockBad are zeroed.
*
* - Check ECC results for data (if applicable)
* - Check for blank/erased block (return empty ExtendedTags if blank)
* - Check the PackedTags1 mini-ECC (correct if necessary/possible)
* - Convert PackedTags1 to ExtendedTags
* - Update eccResult and blockBad members to refect state.
*
* Returns YAFFS_OK or YAFFS_FAIL.
*/
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
int chunkInNAND, __u8 * data, yaffs_ExtendedTags * etags)
{
struct mtd_info * mtd = dev->genericDevice;
int chunkBytes = dev->nDataBytesPerChunk;
loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
int eccres = YAFFS_ECC_RESULT_NO_ERROR;
struct mtd_oob_ops ops;
yaffs_PackedTags1 pt1;
int retval;
int deleted;
dev->nPageReads++;
memset(&ops, 0, sizeof(ops));
ops.mode = MTD_OOB_AUTO;
ops.len = (data) ? chunkBytes : 0;
ops.ooblen = YTAG1_SIZE;
ops.datbuf = data;
ops.oobbuf = (__u8 *)&pt1;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
/* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
* help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
*/
ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
#endif
/* Read page and oob using MTD.
* Check status and determine ECC result.
*/
retval = mtd->read_oob(mtd, addr, &ops);
if (retval) {
yaffs_trace(YAFFS_TRACE_MTD,
"read_oob failed, chunk %d, mtd error %d\n",
chunkInNAND, retval);
}
switch (retval) {
case 0:
/* no error */
break;
case -EUCLEAN:
/* MTD's ECC fixed the data */
eccres = YAFFS_ECC_RESULT_FIXED;
dev->eccFixed++;
break;
case -EBADMSG:
/* MTD's ECC could not fix the data */
dev->eccUnfixed++;
/* fall into... */
default:
rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
etags->blockBad = (mtd->block_isbad)(mtd, addr);
return YAFFS_FAIL;
}
/* Check for a blank/erased chunk.
*/
if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
/* when blank, upper layers want eccResult to be <= NO_ERROR */
return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
}
#ifndef CONFIG_YAFFS_9BYTE_TAGS
/* Read deleted status (bit) then return it to it's non-deleted
* state before performing tags mini-ECC check. pt1.deleted is
* inverted.
*/
deleted = !pt1.deleted;
pt1.deleted = 1;
#else
deleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
#endif
/* Check the packed tags mini-ECC and correct if necessary/possible.
*/
retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
switch (retval) {
case 0:
/* no tags error, use MTD result */
break;
case 1:
/* recovered tags-ECC error */
dev->tagsEccFixed++;
if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
eccres = YAFFS_ECC_RESULT_FIXED;
break;
default:
/* unrecovered tags-ECC error */
dev->tagsEccUnfixed++;
return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
}
/* Unpack the tags to extended form and set ECC result.
* [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
*/
pt1.shouldBeFF = 0xFFFFFFFF;
yaffs_UnpackTags1(etags, &pt1);
etags->eccResult = eccres;
/* Set deleted state */
etags->chunkDeleted = deleted;
return YAFFS_OK;
}
/* Mark a block bad.
*
* This is a persistant state.
* Use of this function should be rare.
*
* Returns YAFFS_OK or YAFFS_FAIL.
*/
int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
{
struct mtd_info * mtd = dev->genericDevice;
int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
int retval;
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", blockNo);
retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
return (retval) ? YAFFS_FAIL : YAFFS_OK;
}
/* Check any MTD prerequists.
*
* Returns YAFFS_OK or YAFFS_FAIL.
*/
static int nandmtd1_TestPrerequists(struct mtd_info * mtd)
{
/* 2.6.18 has mtd->ecclayout->oobavail */
/* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
int oobavail = mtd->ecclayout->oobavail;
if (oobavail < YTAG1_SIZE) {
yaffs_trace(YAFFS_TRACE_ERROR,
"mtd device has only %d bytes for tags, need %d\n",
oobavail, YTAG1_SIZE);
return YAFFS_FAIL;
}
return YAFFS_OK;
}
/* Query for the current state of a specific block.
*
* Examine the tags of the first chunk of the block and return the state:
* - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
* - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
* - YAFFS_BLOCK_STATE_EMPTY, the block is clean
*
* Always returns YAFFS_OK.
*/
int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState * pState, int *pSequenceNumber)
{
struct mtd_info * mtd = dev->genericDevice;
int chunkNo = blockNo * dev->nChunksPerBlock;
yaffs_ExtendedTags etags;
int state = YAFFS_BLOCK_STATE_DEAD;
int seqnum = 0;
int retval;
/* We don't yet have a good place to test for MTD config prerequists.
* Do it here as we are called during the initial scan.
*/
if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK) {
return YAFFS_FAIL;
}
retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
if (etags.blockBad) {
yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
"block %d is marked bad", blockNo);
state = YAFFS_BLOCK_STATE_DEAD;
}
else if (etags.chunkUsed) {
state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
seqnum = etags.sequenceNumber;
}
else {
state = YAFFS_BLOCK_STATE_EMPTY;
}
*pState = state;
*pSequenceNumber = seqnum;
/* query always succeeds */
return YAFFS_OK;
}
#endif /*KERNEL_VERSION*/

View File

@ -1,28 +0,0 @@
/*
* YAFFS: Yet another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_MTDIF1_H__
#define __YAFFS_MTDIF1_H__
int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data, const yaffs_ExtendedTags * tags);
int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * data, yaffs_ExtendedTags * tags);
int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState * state, int *sequenceNumber);
#endif

View File

@ -1,232 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/* mtd interface for YAFFS2 */
const char *yaffs_mtdif2_c_version =
"$Id: yaffs_mtdif2.c,v 1.17 2007-02-14 01:09:06 wookey Exp $";
#include "yportenv.h"
#include "yaffs_mtdif2.h"
#include "linux/mtd/mtd.h"
#include "linux/types.h"
#include "linux/time.h"
#include "yaffs_packedtags2.h"
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data,
const yaffs_ExtendedTags * tags)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
struct mtd_oob_ops ops;
#else
size_t dummy;
#endif
int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
yaffs_PackedTags2 pt;
T(YAFFS_TRACE_MTD,
(TSTR
("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
TENDSTR), chunkInNAND, data, tags));
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
if (tags)
yaffs_PackTags2(&pt, tags);
else
BUG(); /* both tags and data should always be present */
if (data) {
ops.mode = MTD_OOB_AUTO;
ops.ooblen = sizeof(pt);
ops.len = dev->nDataBytesPerChunk;
ops.ooboffs = 0;
ops.datbuf = (__u8 *)data;
ops.oobbuf = (void *)&pt;
retval = mtd->write_oob(mtd, addr, &ops);
} else
BUG(); /* both tags and data should always be present */
#else
if (tags) {
yaffs_PackTags2(&pt, tags);
}
if (data && tags) {
if (dev->useNANDECC)
retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, (__u8 *) & pt, NULL);
else
retval =
mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, (__u8 *) & pt, NULL);
} else {
if (data)
retval =
mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
data);
if (tags)
retval =
mtd->write_oob(mtd, addr, mtd->oobsize, &dummy,
(__u8 *) & pt);
}
#endif
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * data, yaffs_ExtendedTags * tags)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
struct mtd_oob_ops ops;
#endif
size_t dummy;
int retval = 0;
loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
yaffs_PackedTags2 pt;
T(YAFFS_TRACE_MTD,
(TSTR
("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
TENDSTR), chunkInNAND, data, tags));
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
if (data && !tags)
retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data);
else if (tags) {
ops.mode = MTD_OOB_AUTO;
ops.ooblen = sizeof(pt);
ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
ops.ooboffs = 0;
ops.datbuf = data;
ops.oobbuf = dev->spareBuffer;
retval = mtd->read_oob(mtd, addr, &ops);
}
#else
if (data && tags) {
if (dev->useNANDECC) {
retval =
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, dev->spareBuffer,
NULL);
} else {
retval =
mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
&dummy, data, dev->spareBuffer,
NULL);
}
} else {
if (data)
retval =
mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
data);
if (tags)
retval =
mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
dev->spareBuffer);
}
#endif
memcpy(&pt, dev->spareBuffer, sizeof(pt));
if (tags)
yaffs_UnpackTags2(tags, &pt);
if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
int retval;
T(YAFFS_TRACE_MTD,
(TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
retval =
mtd->block_markbad(mtd,
blockNo * dev->nChunksPerBlock *
dev->nDataBytesPerChunk);
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState * state, int *sequenceNumber)
{
struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
int retval;
T(YAFFS_TRACE_MTD,
(TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
retval =
mtd->block_isbad(mtd,
blockNo * dev->nChunksPerBlock *
dev->nDataBytesPerChunk);
if (retval) {
T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
*state = YAFFS_BLOCK_STATE_DEAD;
*sequenceNumber = 0;
} else {
yaffs_ExtendedTags t;
nandmtd2_ReadChunkWithTagsFromNAND(dev,
blockNo *
dev->nChunksPerBlock, NULL,
&t);
if (t.chunkUsed) {
*sequenceNumber = t.sequenceNumber;
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
} else {
*sequenceNumber = 0;
*state = YAFFS_BLOCK_STATE_EMPTY;
}
}
T(YAFFS_TRACE_MTD,
(TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
*state));
if (retval == 0)
return YAFFS_OK;
else
return YAFFS_FAIL;
}

View File

@ -1,29 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_MTDIF2_H__
#define __YAFFS_MTDIF2_H__
#include "yaffs_guts.h"
int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device * dev, int chunkInNAND,
const __u8 * data,
const yaffs_ExtendedTags * tags);
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * data, yaffs_ExtendedTags * tags);
int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState * state, int *sequenceNumber);
#endif

View File

@ -1,134 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
const char *yaffs_nand_c_version =
"$Id: yaffs_nand.c,v 1.7 2007-02-14 01:09:06 wookey Exp $";
#include "yaffs_nand.h"
#include "yaffs_tagscompat.h"
#include "yaffs_tagsvalidity.h"
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * buffer,
yaffs_ExtendedTags * tags)
{
int result;
yaffs_ExtendedTags localTags;
int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
/* If there are no tags provided, use local tags to get prioritised gc working */
if(!tags)
tags = &localTags;
if (dev->readChunkWithTagsFromNAND)
result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
tags);
else
result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
realignedChunkInNAND,
buffer,
tags);
if(tags &&
tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR){
yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock);
yaffs_HandleChunkError(dev,bi);
}
return result;
}
int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev,
int chunkInNAND,
const __u8 * buffer,
yaffs_ExtendedTags * tags)
{
chunkInNAND -= dev->chunkOffset;
if (tags) {
tags->sequenceNumber = dev->sequenceNumber;
tags->chunkUsed = 1;
if (!yaffs_ValidateTags(tags)) {
T(YAFFS_TRACE_ERROR,
(TSTR("Writing uninitialised tags" TENDSTR)));
YBUG();
}
T(YAFFS_TRACE_WRITE,
(TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND,
tags->objectId, tags->chunkId));
} else {
T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));
YBUG();
}
if (dev->writeChunkWithTagsToNAND)
return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
tags);
else
return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
chunkInNAND,
buffer,
tags);
}
int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo)
{
blockNo -= dev->blockOffset;
;
if (dev->markNANDBlockBad)
return dev->markNANDBlockBad(dev, blockNo);
else
return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);
}
int yaffs_QueryInitialBlockState(yaffs_Device * dev,
int blockNo,
yaffs_BlockState * state,
unsigned *sequenceNumber)
{
blockNo -= dev->blockOffset;
if (dev->queryNANDBlock)
return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber);
else
return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,
state,
sequenceNumber);
}
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
int blockInNAND)
{
int result;
blockInNAND -= dev->blockOffset;
dev->nBlockErasures++;
result = dev->eraseBlockInNAND(dev, blockInNAND);
return result;
}
int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
{
return dev->initialiseNAND(dev);
}

View File

@ -1,44 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_NAND_H__
#define __YAFFS_NAND_H__
#include "yaffs_guts.h"
int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
__u8 * buffer,
yaffs_ExtendedTags * tags);
int yaffs_WriteChunkWithTagsToNAND(yaffs_Device * dev,
int chunkInNAND,
const __u8 * buffer,
yaffs_ExtendedTags * tags);
int yaffs_MarkBlockBad(yaffs_Device * dev, int blockNo);
int yaffs_QueryInitialBlockState(yaffs_Device * dev,
int blockNo,
yaffs_BlockState * state,
unsigned *sequenceNumber);
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
int blockInNAND);
int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev);
#endif

View File

@ -1,39 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/* Interface to emulated NAND functions (2k page size) */
#ifndef __YAFFS_NANDEMUL2K_H__
#define __YAFFS_NANDEMUL2K_H__
#include "yaffs_guts.h"
int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND, const __u8 * data,
yaffs_ExtendedTags * tags);
int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND, __u8 * data,
yaffs_ExtendedTags * tags);
int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
yaffs_BlockState * state, int *sequenceNumber);
int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
int blockInNAND);
int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);
int nandemul2k_GetBytesPerChunk(void);
int nandemul2k_GetChunksPerBlock(void);
int nandemul2k_GetNumberOfBlocks(void);
#endif

View File

@ -1,52 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "yaffs_packedtags1.h"
#include "yportenv.h"
void yaffs_PackTags1(yaffs_PackedTags1 * pt, const yaffs_ExtendedTags * t)
{
pt->chunkId = t->chunkId;
pt->serialNumber = t->serialNumber;
pt->byteCount = t->byteCount;
pt->objectId = t->objectId;
pt->ecc = 0;
pt->deleted = (t->chunkDeleted) ? 0 : 1;
pt->unusedStuff = 0;
pt->shouldBeFF = 0xFFFFFFFF;
}
void yaffs_UnpackTags1(yaffs_ExtendedTags * t, const yaffs_PackedTags1 * pt)
{
static const __u8 allFF[] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff };
if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) {
t->blockBad = 0;
if (pt->shouldBeFF != 0xFFFFFFFF) {
t->blockBad = 1;
}
t->chunkUsed = 1;
t->objectId = pt->objectId;
t->chunkId = pt->chunkId;
t->byteCount = pt->byteCount;
t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
t->chunkDeleted = (pt->deleted) ? 0 : 1;
t->serialNumber = pt->serialNumber;
} else {
memset(t, 0, sizeof(yaffs_ExtendedTags));
}
}

View File

@ -1,37 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */
#ifndef __YAFFS_PACKEDTAGS1_H__
#define __YAFFS_PACKEDTAGS1_H__
#include "yaffs_guts.h"
typedef struct {
unsigned chunkId:20;
unsigned serialNumber:2;
unsigned byteCount:10;
unsigned objectId:18;
unsigned ecc:12;
unsigned deleted:1;
unsigned unusedStuff:1;
unsigned shouldBeFF;
} yaffs_PackedTags1;
void yaffs_PackTags1(yaffs_PackedTags1 * pt, const yaffs_ExtendedTags * t);
void yaffs_UnpackTags1(yaffs_ExtendedTags * t, const yaffs_PackedTags1 * pt);
#endif

View File

@ -1,182 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "yaffs_packedtags2.h"
#include "yportenv.h"
#include "yaffs_tagsvalidity.h"
/* This code packs a set of extended tags into a binary structure for
* NAND storage
*/
/* Some of the information is "extra" struff which can be packed in to
* speed scanning
* This is defined by having the EXTRA_HEADER_INFO_FLAG set.
*/
/* Extra flags applied to chunkId */
#define EXTRA_HEADER_INFO_FLAG 0x80000000
#define EXTRA_SHRINK_FLAG 0x40000000
#define EXTRA_SHADOWS_FLAG 0x20000000
#define EXTRA_SPARE_FLAGS 0x10000000
#define ALL_EXTRA_FLAGS 0xF0000000
/* Also, the top 4 bits of the object Id are set to the object type. */
#define EXTRA_OBJECT_TYPE_SHIFT (28)
#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT)
static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt)
{
T(YAFFS_TRACE_MTD,
(TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
pt->t.objectId, pt->t.chunkId, pt->t.byteCount,
pt->t.sequenceNumber));
}
static void yaffs_DumpTags2(const yaffs_ExtendedTags * t)
{
T(YAFFS_TRACE_MTD,
(TSTR
("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte "
"%d del %d ser %d seq %d"
TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId,
t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,
t->sequenceNumber));
}
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t)
{
pt->t.chunkId = t->chunkId;
pt->t.sequenceNumber = t->sequenceNumber;
pt->t.byteCount = t->byteCount;
pt->t.objectId = t->objectId;
if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {
/* Store the extra header info instead */
/* We save the parent object in the chunkId */
pt->t.chunkId = EXTRA_HEADER_INFO_FLAG
| t->extraParentObjectId;
if (t->extraIsShrinkHeader) {
pt->t.chunkId |= EXTRA_SHRINK_FLAG;
}
if (t->extraShadows) {
pt->t.chunkId |= EXTRA_SHADOWS_FLAG;
}
pt->t.objectId &= ~EXTRA_OBJECT_TYPE_MASK;
pt->t.objectId |=
(t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
pt->t.byteCount = t->extraEquivalentObjectId;
} else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) {
pt->t.byteCount = t->extraFileLength;
} else {
pt->t.byteCount = 0;
}
}
yaffs_DumpPackedTags2(pt);
yaffs_DumpTags2(t);
#ifndef YAFFS_IGNORE_TAGS_ECC
{
yaffs_ECCCalculateOther((unsigned char *)&pt->t,
sizeof(yaffs_PackedTags2TagsPart),
&pt->ecc);
}
#endif
}
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt)
{
memset(t, 0, sizeof(yaffs_ExtendedTags));
yaffs_InitialiseTags(t);
if (pt->t.sequenceNumber != 0xFFFFFFFF) {
/* Page is in use */
#ifdef YAFFS_IGNORE_TAGS_ECC
{
t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
}
#else
{
yaffs_ECCOther ecc;
int result;
yaffs_ECCCalculateOther((unsigned char *)&pt->t,
sizeof
(yaffs_PackedTags2TagsPart),
&ecc);
result =
yaffs_ECCCorrectOther((unsigned char *)&pt->t,
sizeof
(yaffs_PackedTags2TagsPart),
&pt->ecc, &ecc);
switch(result){
case 0:
t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
break;
case 1:
t->eccResult = YAFFS_ECC_RESULT_FIXED;
break;
case -1:
t->eccResult = YAFFS_ECC_RESULT_UNFIXED;
break;
default:
t->eccResult = YAFFS_ECC_RESULT_UNKNOWN;
}
}
#endif
t->blockBad = 0;
t->chunkUsed = 1;
t->objectId = pt->t.objectId;
t->chunkId = pt->t.chunkId;
t->byteCount = pt->t.byteCount;
t->chunkDeleted = 0;
t->serialNumber = 0;
t->sequenceNumber = pt->t.sequenceNumber;
/* Do extra header info stuff */
if (pt->t.chunkId & EXTRA_HEADER_INFO_FLAG) {
t->chunkId = 0;
t->byteCount = 0;
t->extraHeaderInfoAvailable = 1;
t->extraParentObjectId =
pt->t.chunkId & (~(ALL_EXTRA_FLAGS));
t->extraIsShrinkHeader =
(pt->t.chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
t->extraShadows =
(pt->t.chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
t->extraObjectType =
pt->t.objectId >> EXTRA_OBJECT_TYPE_SHIFT;
t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) {
t->extraEquivalentObjectId = pt->t.byteCount;
} else {
t->extraFileLength = pt->t.byteCount;
}
}
}
yaffs_DumpPackedTags2(pt);
yaffs_DumpTags2(t);
}

View File

@ -1,38 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
/* This is used to pack YAFFS2 tags, not YAFFS1tags. */
#ifndef __YAFFS_PACKEDTAGS2_H__
#define __YAFFS_PACKEDTAGS2_H__
#include "yaffs_guts.h"
#include "yaffs_ecc.h"
typedef struct {
unsigned sequenceNumber;
unsigned objectId;
unsigned chunkId;
unsigned byteCount;
} yaffs_PackedTags2TagsPart;
typedef struct {
yaffs_PackedTags2TagsPart t;
yaffs_ECCOther ecc;
} yaffs_PackedTags2;
void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t);
void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt);
#endif

View File

@ -1,160 +0,0 @@
/*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*/
#include "yportenv.h"
//#include <linux/string.h>
/*
* Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
*/
#define swapcode(TYPE, parmi, parmj, n) { \
long i = (n) / sizeof (TYPE); \
register TYPE *pi = (TYPE *) (parmi); \
register TYPE *pj = (TYPE *) (parmj); \
do { \
register TYPE t = *pi; \
*pi++ = *pj; \
*pj++ = t; \
} while (--i > 0); \
}
#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
static __inline void
swapfunc(char *a, char *b, int n, int swaptype)
{
if (swaptype <= 1)
swapcode(long, a, b, n)
else
swapcode(char, a, b, n)
}
#define swap(a, b) \
if (swaptype == 0) { \
long t = *(long *)(a); \
*(long *)(a) = *(long *)(b); \
*(long *)(b) = t; \
} else \
swapfunc(a, b, es, swaptype)
#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
static __inline char *
med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
{
return cmp(a, b) < 0 ?
(cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
:(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
}
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
void
yaffs_qsort(void *aa, size_t n, size_t es,
int (*cmp)(const void *, const void *))
{
char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
int d, r, swaptype, swap_cnt;
register char *a = aa;
loop: SWAPINIT(a, es);
swap_cnt = 0;
if (n < 7) {
for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
pl -= es)
swap(pl, pl - es);
return;
}
pm = (char *)a + (n / 2) * es;
if (n > 7) {
pl = (char *)a;
pn = (char *)a + (n - 1) * es;
if (n > 40) {
d = (n / 8) * es;
pl = med3(pl, pl + d, pl + 2 * d, cmp);
pm = med3(pm - d, pm, pm + d, cmp);
pn = med3(pn - 2 * d, pn - d, pn, cmp);
}
pm = med3(pl, pm, pn, cmp);
}
swap(a, pm);
pa = pb = (char *)a + es;
pc = pd = (char *)a + (n - 1) * es;
for (;;) {
while (pb <= pc && (r = cmp(pb, a)) <= 0) {
if (r == 0) {
swap_cnt = 1;
swap(pa, pb);
pa += es;
}
pb += es;
}
while (pb <= pc && (r = cmp(pc, a)) >= 0) {
if (r == 0) {
swap_cnt = 1;
swap(pc, pd);
pd -= es;
}
pc -= es;
}
if (pb > pc)
break;
swap(pb, pc);
swap_cnt = 1;
pb += es;
pc -= es;
}
if (swap_cnt == 0) { /* Switch to insertion sort */
for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
pl -= es)
swap(pl, pl - es);
return;
}
pn = (char *)a + n * es;
r = min(pa - (char *)a, pb - pa);
vecswap(a, pb - r, r);
r = min((long)(pd - pc), (long)(pn - pd - es));
vecswap(pb, pn - r, r);
if ((r = pb - pa) > es)
yaffs_qsort(a, r / es, es, cmp);
if ((r = pd - pc) > es) {
/* Iterate rather than recurse to save stack space */
a = pn - r;
n = r / es;
goto loop;
}
/* yaffs_qsort(pn - r, r / es, es, cmp);*/
}

View File

@ -1,23 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_QSORT_H__
#define __YAFFS_QSORT_H__
extern void yaffs_qsort (void *const base, size_t total_elems, size_t size,
int (*cmp)(const void *, const void *));
#endif

View File

@ -1,530 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "yaffs_guts.h"
#include "yaffs_tagscompat.h"
#include "yaffs_ecc.h"
static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND);
#ifdef NOTYET
static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND);
static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
const __u8 * data,
const yaffs_Spare * spare);
static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
const yaffs_Spare * spare);
static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND);
#endif
static const char yaffs_countBitsTable[256] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};
int yaffs_CountBits(__u8 x)
{
int retVal;
retVal = yaffs_countBitsTable[x];
return retVal;
}
/********** Tags ECC calculations *********/
void yaffs_CalcECC(const __u8 * data, yaffs_Spare * spare)
{
yaffs_ECCCalculate(data, spare->ecc1);
yaffs_ECCCalculate(&data[256], spare->ecc2);
}
void yaffs_CalcTagsECC(yaffs_Tags * tags)
{
/* Calculate an ecc */
unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
unsigned i, j;
unsigned ecc = 0;
unsigned bit = 0;
tags->ecc = 0;
for (i = 0; i < 8; i++) {
for (j = 1; j & 0xff; j <<= 1) {
bit++;
if (b[i] & j) {
ecc ^= bit;
}
}
}
tags->ecc = ecc;
}
int yaffs_CheckECCOnTags(yaffs_Tags * tags)
{
unsigned ecc = tags->ecc;
yaffs_CalcTagsECC(tags);
ecc ^= tags->ecc;
if (ecc && ecc <= 64) {
/* TODO: Handle the failure better. Retire? */
unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
ecc--;
b[ecc / 8] ^= (1 << (ecc & 7));
/* Now recvalc the ecc */
yaffs_CalcTagsECC(tags);
return 1; /* recovered error */
} else if (ecc) {
/* Wierd ecc failure value */
/* TODO Need to do somethiong here */
return -1; /* unrecovered error */
}
return 0;
}
/********** Tags **********/
static void yaffs_LoadTagsIntoSpare(yaffs_Spare * sparePtr,
yaffs_Tags * tagsPtr)
{
yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
yaffs_CalcTagsECC(tagsPtr);
sparePtr->tagByte0 = tu->asBytes[0];
sparePtr->tagByte1 = tu->asBytes[1];
sparePtr->tagByte2 = tu->asBytes[2];
sparePtr->tagByte3 = tu->asBytes[3];
sparePtr->tagByte4 = tu->asBytes[4];
sparePtr->tagByte5 = tu->asBytes[5];
sparePtr->tagByte6 = tu->asBytes[6];
sparePtr->tagByte7 = tu->asBytes[7];
}
static void yaffs_GetTagsFromSpare(yaffs_Device * dev, yaffs_Spare * sparePtr,
yaffs_Tags * tagsPtr)
{
yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
int result;
tu->asBytes[0] = sparePtr->tagByte0;
tu->asBytes[1] = sparePtr->tagByte1;
tu->asBytes[2] = sparePtr->tagByte2;
tu->asBytes[3] = sparePtr->tagByte3;
tu->asBytes[4] = sparePtr->tagByte4;
tu->asBytes[5] = sparePtr->tagByte5;
tu->asBytes[6] = sparePtr->tagByte6;
tu->asBytes[7] = sparePtr->tagByte7;
result = yaffs_CheckECCOnTags(tagsPtr);
if (result > 0) {
dev->tagsEccFixed++;
} else if (result < 0) {
dev->tagsEccUnfixed++;
}
}
static void yaffs_SpareInitialise(yaffs_Spare * spare)
{
memset(spare, 0xFF, sizeof(yaffs_Spare));
}
static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND, const __u8 * data,
yaffs_Spare * spare)
{
if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
T(YAFFS_TRACE_ERROR,
(TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
chunkInNAND));
return YAFFS_FAIL;
}
dev->nPageWrites++;
return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
}
static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
int chunkInNAND,
__u8 * data,
yaffs_Spare * spare,
yaffs_ECCResult * eccResult,
int doErrorCorrection)
{
int retVal;
yaffs_Spare localSpare;
dev->nPageReads++;
if (!spare && data) {
/* If we don't have a real spare, then we use a local one. */
/* Need this for the calculation of the ecc */
spare = &localSpare;
}
if (!dev->useNANDECC) {
retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
if (data && doErrorCorrection) {
/* Do ECC correction */
/* Todo handle any errors */
int eccResult1, eccResult2;
__u8 calcEcc[3];
yaffs_ECCCalculate(data, calcEcc);
eccResult1 =
yaffs_ECCCorrect(data, spare->ecc1, calcEcc);
yaffs_ECCCalculate(&data[256], calcEcc);
eccResult2 =
yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc);
if (eccResult1 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>yaffs ecc error fix performed on chunk %d:0"
TENDSTR), chunkInNAND));
dev->eccFixed++;
} else if (eccResult1 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>yaffs ecc error unfixed on chunk %d:0"
TENDSTR), chunkInNAND));
dev->eccUnfixed++;
}
if (eccResult2 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>yaffs ecc error fix performed on chunk %d:1"
TENDSTR), chunkInNAND));
dev->eccFixed++;
} else if (eccResult2 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>yaffs ecc error unfixed on chunk %d:1"
TENDSTR), chunkInNAND));
dev->eccUnfixed++;
}
if (eccResult1 || eccResult2) {
/* We had a data problem on this page */
yaffs_HandleReadDataError(dev, chunkInNAND);
}
if (eccResult1 < 0 || eccResult2 < 0)
*eccResult = YAFFS_ECC_RESULT_UNFIXED;
else if (eccResult1 > 0 || eccResult2 > 0)
*eccResult = YAFFS_ECC_RESULT_FIXED;
else
*eccResult = YAFFS_ECC_RESULT_NO_ERROR;
}
} else {
/* Must allocate enough memory for spare+2*sizeof(int) */
/* for ecc results from device. */
struct yaffs_NANDSpare nspare;
retVal =
dev->readChunkFromNAND(dev, chunkInNAND, data,
(yaffs_Spare *) & nspare);
memcpy(spare, &nspare, sizeof(yaffs_Spare));
if (data && doErrorCorrection) {
if (nspare.eccres1 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error fix performed on chunk %d:0"
TENDSTR), chunkInNAND));
} else if (nspare.eccres1 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error unfixed on chunk %d:0"
TENDSTR), chunkInNAND));
}
if (nspare.eccres2 > 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error fix performed on chunk %d:1"
TENDSTR), chunkInNAND));
} else if (nspare.eccres2 < 0) {
T(YAFFS_TRACE_ERROR,
(TSTR
("**>>mtd ecc error unfixed on chunk %d:1"
TENDSTR), chunkInNAND));
}
if (nspare.eccres1 || nspare.eccres2) {
/* We had a data problem on this page */
yaffs_HandleReadDataError(dev, chunkInNAND);
}
if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
*eccResult = YAFFS_ECC_RESULT_UNFIXED;
else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
*eccResult = YAFFS_ECC_RESULT_FIXED;
else
*eccResult = YAFFS_ECC_RESULT_NO_ERROR;
}
}
return retVal;
}
#ifdef NOTYET
static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
int chunkInNAND)
{
static int init = 0;
static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
static __u8 data[YAFFS_BYTES_PER_CHUNK];
/* Might as well always allocate the larger size for */
/* dev->useNANDECC == true; */
static __u8 spare[sizeof(struct yaffs_NANDSpare)];
dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
if (!init) {
memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
init = 1;
}
if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK))
return YAFFS_FAIL;
if (memcmp(cmpbuf, spare, 16))
return YAFFS_FAIL;
return YAFFS_OK;
}
#endif
/*
* Functions for robustisizing
*/
static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND)
{
int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
/* Mark the block for retirement */
yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
(TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND));
/* TODO:
* Just do a garbage collection on the affected block
* then retire the block
* NB recursion
*/
}
#ifdef NOTYET
static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND)
{
}
static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
const __u8 * data,
const yaffs_Spare * spare)
{
}
static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
const yaffs_Spare * spare)
{
}
static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND)
{
int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
/* Mark the block for retirement */
yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
/* Delete the chunk */
yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
}
static int yaffs_VerifyCompare(const __u8 * d0, const __u8 * d1,
const yaffs_Spare * s0, const yaffs_Spare * s1)
{
if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
s0->tagByte0 != s1->tagByte0 ||
s0->tagByte1 != s1->tagByte1 ||
s0->tagByte2 != s1->tagByte2 ||
s0->tagByte3 != s1->tagByte3 ||
s0->tagByte4 != s1->tagByte4 ||
s0->tagByte5 != s1->tagByte5 ||
s0->tagByte6 != s1->tagByte6 ||
s0->tagByte7 != s1->tagByte7 ||
s0->ecc1[0] != s1->ecc1[0] ||
s0->ecc1[1] != s1->ecc1[1] ||
s0->ecc1[2] != s1->ecc1[2] ||
s0->ecc2[0] != s1->ecc2[0] ||
s0->ecc2[1] != s1->ecc2[1] || s0->ecc2[2] != s1->ecc2[2]) {
return 0;
}
return 1;
}
#endif /* NOTYET */
int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device * dev,
int chunkInNAND,
const __u8 * data,
const yaffs_ExtendedTags *
eTags)
{
yaffs_Spare spare;
yaffs_Tags tags;
yaffs_SpareInitialise(&spare);
if (eTags->chunkDeleted) {
spare.pageStatus = 0;
} else {
tags.objectId = eTags->objectId;
tags.chunkId = eTags->chunkId;
tags.byteCount = eTags->byteCount;
tags.serialNumber = eTags->serialNumber;
if (!dev->useNANDECC && data) {
yaffs_CalcECC(data, &spare);
}
yaffs_LoadTagsIntoSpare(&spare, &tags);
}
return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare);
}
int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
int chunkInNAND,
__u8 * data,
yaffs_ExtendedTags * eTags)
{
yaffs_Spare spare;
yaffs_Tags tags;
yaffs_ECCResult eccResult;
static yaffs_Spare spareFF;
static int init;
if (!init) {
memset(&spareFF, 0xFF, sizeof(spareFF));
init = 1;
}
if (yaffs_ReadChunkFromNAND
(dev, chunkInNAND, data, &spare, &eccResult, 1)) {
/* eTags may be NULL */
if (eTags) {
int deleted =
(yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
eTags->chunkDeleted = deleted;
eTags->eccResult = eccResult;
eTags->blockBad = 0; /* We're reading it */
/* therefore it is not a bad block */
eTags->chunkUsed =
(memcmp(&spareFF, &spare, sizeof(spareFF)) !=
0) ? 1 : 0;
if (eTags->chunkUsed) {
yaffs_GetTagsFromSpare(dev, &spare, &tags);
eTags->objectId = tags.objectId;
eTags->chunkId = tags.chunkId;
eTags->byteCount = tags.byteCount;
eTags->serialNumber = tags.serialNumber;
}
}
return YAFFS_OK;
} else {
return YAFFS_FAIL;
}
}
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
int blockInNAND)
{
yaffs_Spare spare;
memset(&spare, 0xff, sizeof(yaffs_Spare));
spare.blockStatus = 'Y';
yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,
&spare);
yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
NULL, &spare);
return YAFFS_OK;
}
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
int blockNo, yaffs_BlockState *
state,
int *sequenceNumber)
{
yaffs_Spare spare0, spare1;
static yaffs_Spare spareFF;
static int init;
yaffs_ECCResult dummy;
if (!init) {
memset(&spareFF, 0xFF, sizeof(spareFF));
init = 1;
}
*sequenceNumber = 0;
yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
&spare0, &dummy, 1);
yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
&spare1, &dummy, 1);
if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
*state = YAFFS_BLOCK_STATE_DEAD;
else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
*state = YAFFS_BLOCK_STATE_EMPTY;
else
*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
return YAFFS_OK;
}

View File

@ -1,40 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_TAGSCOMPAT_H__
#define __YAFFS_TAGSCOMPAT_H__
#include "yaffs_guts.h"
int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device * dev,
int chunkInNAND,
const __u8 * data,
const yaffs_ExtendedTags *
tags);
int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
int chunkInNAND,
__u8 * data,
yaffs_ExtendedTags *
tags);
int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
int blockNo);
int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
int blockNo, yaffs_BlockState *
state, int *sequenceNumber);
void yaffs_CalcTagsECC(yaffs_Tags * tags);
int yaffs_CheckECCOnTags(yaffs_Tags * tags);
int yaffs_CountBits(__u8 byte);
#endif

View File

@ -1,28 +0,0 @@
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "yaffs_tagsvalidity.h"
void yaffs_InitialiseTags(yaffs_ExtendedTags * tags)
{
memset(tags, 0, sizeof(yaffs_ExtendedTags));
tags->validMarker0 = 0xAAAAAAAA;
tags->validMarker1 = 0x55555555;
}
int yaffs_ValidateTags(yaffs_ExtendedTags * tags)
{
return (tags->validMarker0 == 0xAAAAAAAA &&
tags->validMarker1 == 0x55555555);
}

View File

@ -1,24 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFS_TAGS_VALIDITY_H__
#define __YAFFS_TAGS_VALIDITY_H__
#include "yaffs_guts.h"
void yaffs_InitialiseTags(yaffs_ExtendedTags * tags);
int yaffs_ValidateTags(yaffs_ExtendedTags * tags);
#endif

View File

@ -1,21 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YAFFSINTERFACE_H__
#define __YAFFSINTERFACE_H__
int yaffs_Initialise(unsigned nBlocks);
#endif

View File

@ -1,187 +0,0 @@
/*
* YAFFS: Yet another Flash File System . A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1 as
* published by the Free Software Foundation.
*
* Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
*/
#ifndef __YPORTENV_H__
#define __YPORTENV_H__
#if defined CONFIG_YAFFS_WINCE
#include "ywinceenv.h"
#elif defined __KERNEL__
#include "moduleconfig.h"
/* Linux kernel */
#include <linux/version.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
#include <linux/config.h>
#endif
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#define YCHAR char
#define YUCHAR unsigned char
#define _Y(x) x
#define yaffs_strcpy(a,b) strcpy(a,b)
#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
#define yaffs_strncmp(a,b,c) strncmp(a,b,c)
#define yaffs_strlen(s) strlen(s)
#define yaffs_sprintf sprintf
#define yaffs_toupper(a) toupper(a)
#define Y_INLINE inline
#define YAFFS_LOSTNFOUND_NAME "lost+found"
#define YAFFS_LOSTNFOUND_PREFIX "obj"
/* #define YPRINTF(x) printk x */
#define YMALLOC(x) kmalloc(x,GFP_KERNEL)
#define YFREE(x) kfree(x)
#define YMALLOC_ALT(x) vmalloc(x)
#define YFREE_ALT(x) vfree(x)
#define YMALLOC_DMA(x) YMALLOC(x)
// KR - added for use in scan so processes aren't blocked indefinitely.
#define YYIELD() schedule()
#define YAFFS_ROOT_MODE 0666
#define YAFFS_LOSTNFOUND_MODE 0666
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
#define Y_TIME_CONVERT(x) (x).tv_sec
#else
#define Y_CURRENT_TIME CURRENT_TIME
#define Y_TIME_CONVERT(x) (x)
#endif
#define yaffs_SumCompare(x,y) ((x) == (y))
#define yaffs_strcmp(a,b) strcmp(a,b)
#define TENDSTR "\n"
#define TSTR(x) KERN_WARNING x
#define TOUT(p) printk p
#define yaffs_trace(mask, fmt, args...) \
do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \
printk(KERN_WARNING "yaffs: " fmt, ## args); \
} while (0)
#define compile_time_assertion(assertion) \
({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
#elif defined CONFIG_YAFFS_DIRECT
/* Direct interface */
#include "ydirectenv.h"
#elif defined CONFIG_YAFFS_UTIL
/* Stuff for YAFFS utilities */
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "devextras.h"
#define YMALLOC(x) malloc(x)
#define YFREE(x) free(x)
#define YMALLOC_ALT(x) malloc(x)
#define YFREE_ALT(x) free(x)
#define YCHAR char
#define YUCHAR unsigned char
#define _Y(x) x
#define yaffs_strcpy(a,b) strcpy(a,b)
#define yaffs_strncpy(a,b,c) strncpy(a,b,c)
#define yaffs_strlen(s) strlen(s)
#define yaffs_sprintf sprintf
#define yaffs_toupper(a) toupper(a)
#define Y_INLINE inline
/* #define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s)) */
/* #define YALERT(s) YINFO(s) */
#define TENDSTR "\n"
#define TSTR(x) x
#define TOUT(p) printf p
#define YAFFS_LOSTNFOUND_NAME "lost+found"
#define YAFFS_LOSTNFOUND_PREFIX "obj"
/* #define YPRINTF(x) printf x */
#define YAFFS_ROOT_MODE 0666
#define YAFFS_LOSTNFOUND_MODE 0666
#define yaffs_SumCompare(x,y) ((x) == (y))
#define yaffs_strcmp(a,b) strcmp(a,b)
#else
/* Should have specified a configuration type */
#error Unknown configuration
#endif
/* see yaffs_fs.c */
extern unsigned int yaffs_traceMask;
extern unsigned int yaffs_wr_attempts;
/*
* Tracing flags.
* The flags masked in YAFFS_TRACE_ALWAYS are always traced.
*/
#define YAFFS_TRACE_OS 0x00000002
#define YAFFS_TRACE_ALLOCATE 0x00000004
#define YAFFS_TRACE_SCAN 0x00000008
#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
#define YAFFS_TRACE_ERASE 0x00000020
#define YAFFS_TRACE_GC 0x00000040
#define YAFFS_TRACE_WRITE 0x00000080
#define YAFFS_TRACE_TRACING 0x00000100
#define YAFFS_TRACE_DELETION 0x00000200
#define YAFFS_TRACE_BUFFERS 0x00000400
#define YAFFS_TRACE_NANDACCESS 0x00000800
#define YAFFS_TRACE_GC_DETAIL 0x00001000
#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
#define YAFFS_TRACE_MTD 0x00004000
#define YAFFS_TRACE_CHECKPOINT 0x00008000
#define YAFFS_TRACE_VERIFY 0x00010000
#define YAFFS_TRACE_VERIFY_NAND 0x00020000
#define YAFFS_TRACE_VERIFY_FULL 0x00040000
#define YAFFS_TRACE_VERIFY_ALL 0x000F0000
#define YAFFS_TRACE_ERROR 0x40000000
#define YAFFS_TRACE_BUG 0x80000000
#define YAFFS_TRACE_ALWAYS 0xF0000000
#define T(mask,p) do{ if((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p);} while(0)
#ifndef CONFIG_YAFFS_WINCE
#define YBUG() T(YAFFS_TRACE_BUG,(TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR),__LINE__))
#endif
#endif

View File

@ -1,175 +0,0 @@
#
# YAFFS file system configurations
#
config YAFFS_FS
tristate "YAFFS2 file system support"
default n
depends on MTD
select YAFFS_YAFFS1
select YAFFS_YAFFS2
help
YAFFS2, or Yet Another Flash Filing System, is a filing system
optimised for NAND Flash chips.
To compile the YAFFS2 file system support as a module, choose M
here: the module will be called yaffs2.
If unsure, say N.
Further information on YAFFS2 is available at
<http://www.aleph1.co.uk/yaffs/>.
config YAFFS_YAFFS1
bool "512 byte / page devices"
depends on YAFFS_FS
default y
help
Enable YAFFS1 support -- yaffs for 512 byte / page devices
Not needed for 2K-page devices.
If unsure, say Y.
config YAFFS_9BYTE_TAGS
bool "Use older-style on-NAND data format with pageStatus byte"
depends on YAFFS_YAFFS1
default n
help
Older-style on-NAND data format has a "pageStatus" byte to record
chunk/page state. This byte is zero when the page is discarded.
Choose this option if you have existing on-NAND data using this
format that you need to continue to support. New data written
also uses the older-style format. Note: Use of this option
generally requires that MTD's oob layout be adjusted to use the
older-style format. See notes on tags formats and MTD versions.
If unsure, say N.
config YAFFS_DOES_ECC
bool "Lets Yaffs do its own ECC"
depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS
default n
help
This enables Yaffs to use its own ECC functions instead of using
the ones from the generic MTD-NAND driver.
If unsure, say N.
config YAFFS_ECC_WRONG_ORDER
bool "Use the same ecc byte order as Steven Hill's nand_ecc.c"
depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS
default n
help
This makes yaffs_ecc.c use the same ecc byte order as Steven
Hill's nand_ecc.c. If not set, then you get the same ecc byte
order as SmartMedia.
If unsure, say N.
config YAFFS_YAFFS2
bool "2048 byte (or larger) / page devices"
depends on YAFFS_FS
default y
help
Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices
If unsure, say Y.
config YAFFS_AUTO_YAFFS2
bool "Autoselect yaffs2 format"
depends on YAFFS_YAFFS2
default y
help
Without this, you need to explicitely use yaffs2 as the file
system type. With this, you can say "yaffs" and yaffs or yaffs2
will be used depending on the device page size (yaffs on
512-byte page devices, yaffs2 on 2K page devices).
If unsure, say Y.
config YAFFS_DISABLE_LAZY_LOAD
bool "Disable lazy loading"
depends on YAFFS_YAFFS2
default n
help
"Lazy loading" defers loading file details until they are
required. This saves mount time, but makes the first look-up
a bit longer.
Lazy loading will only happen if enabled by this option being 'n'
and if the appropriate tags are available, else yaffs2 will
automatically fall back to immediate loading and do the right
thing.
Lazy laoding will be required by checkpointing.
Setting this to 'y' will disable lazy loading.
If unsure, say N.
config YAFFS_CHECKPOINT_RESERVED_BLOCKS
int "Reserved blocks for checkpointing"
depends on YAFFS_YAFFS2
default 10
help
Give the number of Blocks to reserve for checkpointing.
Checkpointing saves the state at unmount so that mounting is
much faster as a scan of all the flash to regenerate this state
is not needed. These Blocks are reserved per partition, so if
you have very small partitions the default (10) may be a mess
for you. You can set this value to 0, but that does not mean
checkpointing is disabled at all. There only won't be any
specially reserved blocks for checkpointing, so if there is
enough free space on the filesystem, it will be used for
checkpointing.
If unsure, leave at default (10), but don't wonder if there are
always 2MB used on your large page device partition (10 x 2k
pagesize). When using small partitions or when being very small
on space, you probably want to set this to zero.
config YAFFS_DISABLE_WIDE_TNODES
bool "Turn off wide tnodes"
depends on YAFFS_FS
default n
help
Wide tnodes are only used for NAND arrays >=32MB for 512-byte
page devices and >=128MB for 2k page devices. They use slightly
more RAM but are faster since they eliminate chunk group
searching.
Setting this to 'y' will force tnode width to 16 bits and save
memory but make large arrays slower.
If unsure, say N.
config YAFFS_ALWAYS_CHECK_CHUNK_ERASED
bool "Force chunk erase check"
depends on YAFFS_FS
default n
help
Normally YAFFS only checks chunks before writing until an erased
chunk is found. This helps to detect any partially written
chunks that might have happened due to power loss.
Enabling this forces on the test that chunks are erased in flash
before writing to them. This takes more time but is potentially
a bit more secure.
Suggest setting Y during development and ironing out driver
issues etc. Suggest setting to N if you want faster writing.
If unsure, say Y.
config YAFFS_SHORT_NAMES_IN_RAM
bool "Cache short names in RAM"
depends on YAFFS_FS
default y
help
If this config is set, then short names are stored with the
yaffs_Object. This costs an extra 16 bytes of RAM per object,
but makes look-ups faster.
If unsure, say Y.

Some files were not shown because too many files have changed in this diff Show More