revert 15922 - add back 2.6.29 kernel support

SVN-Revision: 16127
This commit is contained in:
Hamish Guthrie 2009-05-28 10:00:48 +00:00
parent 52d975c359
commit 7adb67f184
93 changed files with 43950 additions and 0 deletions

View file

@ -28,6 +28,9 @@ endif
ifeq ($(LINUX_VERSION),2.6.28.10)
LINUX_KERNEL_MD5SUM:=c4efb2c494d749cb5de274f8ae41c3fa
endif
ifeq ($(LINUX_VERSION),2.6.29.2)
LINUX_KERNEL_MD5SUM:=a6839571a9e70baf821d2fb752f9c4c6
endif
# disable the md5sum check for unknown kernel versions
LINUX_KERNEL_MD5SUM?=x

File diff suppressed because it is too large Load diff

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);
device_create(gpiodev_class, NULL, MKDEV(dev_major, 0), dev, 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,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,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,12 @@
--- a/Makefile
+++ b/Makefile
@@ -560,6 +560,9 @@ endif
NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include)
CHECKFLAGS += $(NOSTDINC_FLAGS)
+# improve gcc optimization
+CFLAGS += $(call cc-option,-funit-at-a-time,)
+
# warn about C99 declaration after statement
KBUILD_CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)

View file

@ -0,0 +1,11 @@
--- a/arch/mips/include/asm/system.h
+++ b/arch/mips/include/asm/system.h
@@ -187,7 +187,7 @@ extern __u64 __xchg_u64_unsupported_on_3
if something tries to do an invalid xchg(). */
extern void __xchg_called_with_bad_pointer(void);
-static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+static __always_inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
{
switch (size) {
case 4:

View file

@ -0,0 +1,36 @@
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -51,6 +51,7 @@
#define SST49LF040B 0x0050
#define SST49LF008A 0x005a
#define AT49BV6416 0x00d6
+#define MANUFACTURER_SAMSUNG 0x00ec
static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
@@ -375,12 +376,19 @@ struct mtd_info *cfi_cmdset_0002(struct
if (extp->MajorVersion != '1' ||
(extp->MinorVersion < '0' || extp->MinorVersion > '4')) {
- printk(KERN_ERR " Unknown Amd/Fujitsu Extended Query "
- "version %c.%c.\n", extp->MajorVersion,
- extp->MinorVersion);
- kfree(extp);
- kfree(mtd);
- return NULL;
+ if (cfi->mfr == MANUFACTURER_SAMSUNG &&
+ (extp->MajorVersion == '3' && extp->MinorVersion == '3')) {
+ printk(KERN_NOTICE " Newer Samsung flash detected, "
+ "should be compatibile with Amd/Fujitsu.\n");
+ }
+ else {
+ printk(KERN_ERR " Unknown Amd/Fujitsu Extended Query "
+ "version %c.%c.\n", extp->MajorVersion,
+ extp->MinorVersion);
+ kfree(extp);
+ kfree(mtd);
+ return NULL;
+ }
}
/* Install our own private info structure */

View file

@ -0,0 +1,11 @@
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -121,6 +121,8 @@
#endif
.endm
+ j kernel_entry
+ nop
#ifndef CONFIG_NO_EXCEPT_FILL
/*
* Reserved space for exception handlers.

View file

@ -0,0 +1,157 @@
--- /dev/null
+++ b/include/asm-mips/mips_machine.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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 __ASM_MIPS_MACHINE_H
+#define __ASM_MIPS_MACHINE_H
+
+#include <linux/init.h>
+#include <linux/list.h>
+
+#define MIPS_MACHINE_NAME_LEN 64
+
+struct mips_machine {
+ unsigned long mach_type;
+ void (*mach_setup)(void);
+ unsigned char mach_name[MIPS_MACHINE_NAME_LEN];
+ struct list_head list;
+};
+
+void mips_machine_register(struct mips_machine *) __init;
+void mips_machine_setup(unsigned long machtype) __init;
+
+extern unsigned char mips_machine_name[MIPS_MACHINE_NAME_LEN];
+
+#define MIPS_MACHINE(_type, _name, _setup) \
+static struct mips_machine machine_##_type __initdata = \
+{ \
+ .mach_type = _type, \
+ .mach_name = _name, \
+ .mach_setup = _setup, \
+}; \
+ \
+static int __init register_machine_##_type(void) \
+{ \
+ mips_machine_register(&machine_##_type); \
+ return 0; \
+} \
+ \
+pure_initcall(register_machine_##_type)
+
+#endif /* __ASM_MIPS_MACHINE_H */
+
--- /dev/null
+++ b/arch/mips/kernel/mips_machine.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * 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 <asm/mips_machine.h>
+#include <asm/bootinfo.h>
+
+static struct list_head mips_machines __initdata =
+ LIST_HEAD_INIT(mips_machines);
+
+unsigned char mips_machine_name[MIPS_MACHINE_NAME_LEN] = "Unknown";
+
+static struct mips_machine * __init mips_machine_find(unsigned long machtype)
+{
+ struct list_head *this;
+
+ list_for_each(this, &mips_machines) {
+ struct mips_machine *mach;
+
+ mach = list_entry(this, struct mips_machine, list);
+ if (mach->mach_type == machtype)
+ return mach;
+ }
+
+ return NULL;
+}
+
+void __init mips_machine_register(struct mips_machine *mach)
+{
+ list_add_tail(&mach->list, &mips_machines);
+}
+
+void __init mips_machine_setup(unsigned long machtype)
+{
+ struct mips_machine *mach;
+
+ mach = mips_machine_find(machtype);
+ if (!mach) {
+ printk(KERN_ALERT "MIPS: no machine registered for "
+ "machtype %lu\n", machtype);
+ return;
+ }
+
+ if (mach->mach_name[0])
+ strncpy(mips_machine_name, mach->mach_name,
+ MIPS_MACHINE_NAME_LEN);
+
+ printk(KERN_INFO "MIPS: machine is %s\n", mips_machine_name);
+
+ if (mach->mach_setup)
+ mach->mach_setup();
+}
+
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -85,6 +85,7 @@ obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+obj-$(CONFIG_MIPS_MACHINE) += mips_machine.o
CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi)
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -810,6 +810,9 @@ config MIPS_DISABLE_OBSOLETE_IDE
config SYNC_R4K
bool
+config MIPS_MACHINE
+ def_bool n
+
config NO_IOPORT
def_bool n
--- a/arch/mips/kernel/proc.c
+++ b/arch/mips/kernel/proc.c
@@ -14,6 +14,7 @@
#include <asm/cpu-features.h>
#include <asm/mipsregs.h>
#include <asm/processor.h>
+#include <asm/mips_machine.h>
unsigned int vced_count, vcei_count;
@@ -33,8 +34,12 @@ static int show_cpuinfo(struct seq_file
/*
* For the first processor also print the system type
*/
- if (n == 0)
+ if (n == 0) {
seq_printf(m, "system type\t\t: %s\n", get_system_type());
+#ifdef CONFIG_MIPS_MACHINE
+ seq_printf(m, "machine\t\t\t: %s\n", mips_machine_name);
+#endif
+ }
seq_printf(m, "processor\t\t: %ld\n", n);
sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n",

View file

@ -0,0 +1,50 @@
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -812,6 +812,9 @@ config SYNC_R4K
config MIPS_MACHINE
def_bool n
+
+config PROM_EMU
+ def_bool n
config NO_IOPORT
def_bool n
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -143,6 +143,15 @@ FEXPORT(__kernel_entry)
j kernel_entry
#endif
+#ifdef CONFIG_PROM_EMU
+EXPORT(prom_emu_argv)
+ .word 0
+ .word prom_emu_cmdline
+ .ascii "CMDLINE:"
+EXPORT(prom_emu_cmdline)
+ .fill 0x400
+#endif
+
__REF
NESTED(kernel_entry, 16, sp) # kernel entry point
@@ -183,6 +192,19 @@ NESTED(kernel_entry, 16, sp) # kernel
LONG_S zero, (t0)
bne t0, t1, 1b
+#ifdef CONFIG_PROM_EMU
+ PTR_LA t0, prom_emu_cmdline
+ LONG_L t1, 0(t0)
+ beqz t1, 1f
+
+ li a0, 2
+ PTR_LA a1, prom_emu_argv
+ move a2, zero
+ move a3, zero
+
+1:
+#endif /* CONFIG_PROM_EMU */
+
LONG_S a0, fw_arg0 # firmware arguments
LONG_S a1, fw_arg1
LONG_S a2, fw_arg2

View file

@ -0,0 +1,173 @@
From: Ralf Baechle <ralf@linux-mips.org>
Date: Thu, 30 Apr 2009 16:14:56 +0000 (+0200)
Subject: MIPS: Rewrite <asm/div64.h> to work with gcc 4.4.0.
X-Git-Url: http://www.linux-mips.org/git?p=linux.git;a=commitdiff_plain;h=a1b68289997030df64cba8478d5767fe10e42a58
MIPS: Rewrite <asm/div64.h> to work with gcc 4.4.0.
The inline assembler used on 32-bit kernels was using the "h" constraint
which was considered dangerous and removed for gcc 4.4.0.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
---
diff --git a/arch/mips/include/asm/div64.h b/arch/mips/include/asm/div64.h
index d1d6991..dc5ea57 100644
--- a/arch/mips/include/asm/div64.h
+++ b/arch/mips/include/asm/div64.h
@@ -6,105 +6,63 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
-#ifndef _ASM_DIV64_H
-#define _ASM_DIV64_H
+#ifndef __ASM_DIV64_H
+#define __ASM_DIV64_H
-#include <linux/types.h>
+#include <asm-generic/div64.h>
-#if (_MIPS_SZLONG == 32)
+#if BITS_PER_LONG == 64
-#include <asm/compiler.h>
+#include <linux/types.h>
/*
* No traps on overflows for any of these...
*/
-#define do_div64_32(res, high, low, base) ({ \
- unsigned long __quot32, __mod32; \
- unsigned long __cf, __tmp, __tmp2, __i; \
- \
- __asm__(".set push\n\t" \
- ".set noat\n\t" \
- ".set noreorder\n\t" \
- "move %2, $0\n\t" \
- "move %3, $0\n\t" \
- "b 1f\n\t" \
- " li %4, 0x21\n" \
- "0:\n\t" \
- "sll $1, %0, 0x1\n\t" \
- "srl %3, %0, 0x1f\n\t" \
- "or %0, $1, %5\n\t" \
- "sll %1, %1, 0x1\n\t" \
- "sll %2, %2, 0x1\n" \
- "1:\n\t" \
- "bnez %3, 2f\n\t" \
- " sltu %5, %0, %z6\n\t" \
- "bnez %5, 3f\n" \
- "2:\n\t" \
- " addiu %4, %4, -1\n\t" \
- "subu %0, %0, %z6\n\t" \
- "addiu %2, %2, 1\n" \
- "3:\n\t" \
- "bnez %4, 0b\n\t" \
- " srl %5, %1, 0x1f\n\t" \
- ".set pop" \
- : "=&r" (__mod32), "=&r" (__tmp), \
- "=&r" (__quot32), "=&r" (__cf), \
- "=&r" (__i), "=&r" (__tmp2) \
- : "Jr" (base), "0" (high), "1" (low)); \
- \
- (res) = __quot32; \
- __mod32; })
-
-#define do_div(n, base) ({ \
- unsigned long long __quot; \
- unsigned long __mod; \
- unsigned long long __div; \
- unsigned long __upper, __low, __high, __base; \
- \
- __div = (n); \
- __base = (base); \
- \
- __high = __div >> 32; \
- __low = __div; \
- __upper = __high; \
- \
- if (__high) \
- __asm__("divu $0, %z2, %z3" \
- : "=h" (__upper), "=l" (__high) \
- : "Jr" (__high), "Jr" (__base) \
- : GCC_REG_ACCUM); \
- \
- __mod = do_div64_32(__low, __upper, __low, __base); \
- \
- __quot = __high; \
- __quot = __quot << 32 | __low; \
- (n) = __quot; \
- __mod; })
-
-#endif /* (_MIPS_SZLONG == 32) */
-
-#if (_MIPS_SZLONG == 64)
-
-/*
- * Hey, we're already 64-bit, no
- * need to play games..
- */
-#define do_div(n, base) ({ \
- unsigned long __quot; \
- unsigned int __mod; \
- unsigned long __div; \
- unsigned int __base; \
- \
- __div = (n); \
- __base = (base); \
- \
- __mod = __div % __base; \
- __quot = __div / __base; \
- \
- (n) = __quot; \
- __mod; })
+#define __div64_32(n, base) \
+({ \
+ unsigned long __cf, __tmp, __tmp2, __i; \
+ unsigned long __quot32, __mod32; \
+ unsigned long __high, __low; \
+ unsigned long long __n; \
+ \
+ __high = *__n >> 32; \
+ __low = __n; \
+ __asm__( \
+ " .set push \n" \
+ " .set noat \n" \
+ " .set noreorder \n" \
+ " move %2, $0 \n" \
+ " move %3, $0 \n" \
+ " b 1f \n" \
+ " li %4, 0x21 \n" \
+ "0: \n" \
+ " sll $1, %0, 0x1 \n" \
+ " srl %3, %0, 0x1f \n" \
+ " or %0, $1, %5 \n" \
+ " sll %1, %1, 0x1 \n" \
+ " sll %2, %2, 0x1 \n" \
+ "1: \n" \
+ " bnez %3, 2f \n" \
+ " sltu %5, %0, %z6 \n" \
+ " bnez %5, 3f \n" \
+ "2: \n" \
+ " addiu %4, %4, -1 \n" \
+ " subu %0, %0, %z6 \n" \
+ " addiu %2, %2, 1 \n" \
+ "3: \n" \
+ " bnez %4, 0b\n\t" \
+ " srl %5, %1, 0x1f\n\t" \
+ " .set pop" \
+ : "=&r" (__mod32), "=&r" (__tmp), \
+ "=&r" (__quot32), "=&r" (__cf), \
+ "=&r" (__i), "=&r" (__tmp2) \
+ : "Jr" (base), "0" (__high), "1" (__low)); \
+ \
+ (__n) = __quot32; \
+ __mod32; \
+})
-#endif /* (_MIPS_SZLONG == 64) */
+#endif /* BITS_PER_LONG == 64 */
-#endif /* _ASM_DIV64_H */
+#endif /* __ASM_DIV64_H */

View file

@ -0,0 +1,40 @@
When init is started it is SIGNAL_UNKILLABLE. If it were to get an
address error, we would try to send it SIGBUS, but it would be ignored
and the faulting instruction restarted. This results in an endless
loop.
We need to use force_sig() instead so it will actually die and give us
some useful information.
Reported-by: Florian Fainelli <florian@openwrt.org>
Signed-off-by: David Daney <ddaney@caviumnetworks.com>
---
arch/mips/kernel/unaligned.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -482,19 +482,19 @@ fault:
return;
die_if_kernel("Unhandled kernel unaligned access", regs);
- send_sig(SIGSEGV, current, 1);
+ force_sig(SIGSEGV, current);
return;
sigbus:
die_if_kernel("Unhandled kernel unaligned access", regs);
- send_sig(SIGBUS, current, 1);
+ force_sig(SIGBUS, current);
return;
sigill:
die_if_kernel("Unhandled kernel unaligned access or invalid instruction", regs);
- send_sig(SIGILL, current, 1);
+ force_sig(SIGILL, current);
}
asmlinkage void do_ade(struct pt_regs *regs)

View file

@ -0,0 +1,110 @@
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -14,6 +14,7 @@
#include <linux/list.h>
#include <linux/init.h>
#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
#include <linux/buffer_head.h>
#include <linux/mutex.h>
#include <linux/mount.h>
@@ -232,10 +233,11 @@ static void block2mtd_free_device(struct
/* FIXME: ensure that mtd->size % erase_size == 0 */
-static struct block2mtd_dev *add_device(char *devname, int erase_size)
+static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname)
{
struct block_device *bdev;
struct block2mtd_dev *dev;
+ struct mtd_partition *part;
char *name;
if (!devname)
@@ -273,17 +275,17 @@ static struct block2mtd_dev *add_device(
mutex_init(&dev->write_mutex);
- /* Setup the MTD structure */
- /* make the name contain the block device in */
- name = kmalloc(sizeof("block2mtd: ") + strlen(devname) + 1,
- GFP_KERNEL);
+ if (!mtdname)
+ mtdname = devname;
+
+ name = kmalloc(strlen(mtdname) + 1, GFP_KERNEL);
if (!name)
goto devinit_err;
- sprintf(name, "block2mtd: %s", devname);
+ strcpy(name, mtdname);
dev->mtd.name = name;
- dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
+ dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK & ~(erase_size - 1);
dev->mtd.erasesize = erase_size;
dev->mtd.writesize = 1;
dev->mtd.type = MTD_RAM;
@@ -296,14 +298,17 @@ static struct block2mtd_dev *add_device(
dev->mtd.priv = dev;
dev->mtd.owner = THIS_MODULE;
- if (add_mtd_device(&dev->mtd)) {
+ part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL);
+ part->name = dev->mtd.name;
+ part->offset = 0;
+ part->size = dev->mtd.size;
+ if (add_mtd_partitions(&dev->mtd, part, 1)) {
/* Device didnt get added, so free the entry */
goto devinit_err;
}
list_add(&dev->list, &blkmtd_device_list);
INFO("mtd%d: [%s] erase_size = %dKiB [%d]", dev->mtd.index,
- dev->mtd.name + strlen("block2mtd: "),
- dev->mtd.erasesize >> 10, dev->mtd.erasesize);
+ mtdname, dev->mtd.erasesize >> 10, dev->mtd.erasesize);
return dev;
devinit_err:
@@ -376,9 +381,9 @@ static char block2mtd_paramline[80 + 12]
static int block2mtd_setup2(const char *val)
{
- char buf[80 + 12]; /* 80 for device, 12 for erase size */
+ char buf[80 + 12 + 80]; /* 80 for device, 12 for erase size, 80 for name */
char *str = buf;
- char *token[2];
+ char *token[3];
char *name;
size_t erase_size = PAGE_SIZE;
int i, ret;
@@ -389,7 +394,7 @@ static int block2mtd_setup2(const char *
strcpy(str, val);
kill_final_newline(str);
- for (i = 0; i < 2; i++)
+ for (i = 0; i < 3; i++)
token[i] = strsep(&str, ",");
if (str)
@@ -408,8 +413,10 @@ static int block2mtd_setup2(const char *
parse_err("illegal erase size");
}
}
+ if (token[2] && (strlen(token[2]) + 1 > 80))
+ parse_err("mtd device name too long");
- add_device(name, erase_size);
+ add_device(name, erase_size, token[2]);
return 0;
}
@@ -443,7 +450,7 @@ static int block2mtd_setup(const char *v
module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200);
-MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>]\"");
+MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>[,<name>]]\"");
static int __init block2mtd_init(void)
{

View file

@ -0,0 +1,633 @@
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -53,6 +53,16 @@ config MTD_TESTS
should normally be compiled as kernel modules. The modules perform
various checks and verifications when loaded.
+config MTD_ROOTFS_ROOT_DEV
+ bool "Automatically set 'rootfs' partition to be root filesystem"
+ depends on MTD_PARTITIONS
+ default y
+
+config MTD_ROOTFS_SPLIT
+ bool "Automatically split 'rootfs' partition for squashfs"
+ depends on MTD_PARTITIONS
+ default y
+
config MTD_REDBOOT_PARTS
tristate "RedBoot partition table parsing"
depends on MTD_PARTITIONS
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -18,6 +18,8 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/compatmac.h>
+#include <linux/root_dev.h>
+#include <linux/magic.h>
/* Our partition linked list */
static LIST_HEAD(mtd_partitions);
@@ -37,7 +39,7 @@ struct mtd_part {
* the pointer to that structure with this macro.
*/
#define PART(x) ((struct mtd_part *)(x))
-
+#define IS_PART(mtd) (mtd->read == part_read)
/*
* MTD methods which simply translate the effective address and pass through
@@ -489,6 +491,156 @@ out_register:
return slave;
}
+#ifdef CONFIG_MTD_ROOTFS_SPLIT
+#define ROOTFS_SPLIT_NAME "rootfs_data"
+#define ROOTFS_REMOVED_NAME "<removed>"
+
+struct squashfs_super_block {
+ __le32 s_magic;
+ __le32 pad0[9];
+ __le64 bytes_used;
+};
+
+
+static int split_squashfs(struct mtd_info *master, int offset, int *split_offset)
+{
+ char buf[512];
+ struct squashfs_super_block *sb = (struct squashfs_super_block *) buf;
+ int len, ret;
+
+ ret = master->read(master, offset, sizeof(*sb), &len, buf);
+ if (ret || (len != sizeof(*sb))) {
+ printk(KERN_ALERT "split_squashfs: error occured while reading "
+ "from \"%s\"\n", master->name);
+ return -EINVAL;
+ }
+
+ if (*((u32 *) buf) != SQUASHFS_MAGIC) {
+ printk(KERN_ALERT "split_squashfs: no squashfs found in \"%s\"\n",
+ master->name);
+ *split_offset = 0;
+ return 0;
+ }
+
+ if (sb->bytes_used <= 0) {
+ printk(KERN_ALERT "split_squashfs: squashfs is empty in \"%s\"\n",
+ master->name);
+ *split_offset = 0;
+ return 0;
+ }
+
+ len = (u32) sb->bytes_used;
+ len += (offset & 0x000fffff);
+ len += (master->erasesize - 1);
+ len &= ~(master->erasesize - 1);
+ len -= (offset & 0x000fffff);
+ *split_offset = offset + len;
+
+ return 0;
+}
+
+static int split_rootfs_data(struct mtd_info *master, struct mtd_info *rpart, const struct mtd_partition *part,
+ int index)
+{
+ struct mtd_partition *dpart;
+ struct mtd_part *slave = NULL;
+ int split_offset = 0;
+ int ret;
+
+ ret = split_squashfs(master, part->offset, &split_offset);
+ if (ret)
+ return ret;
+
+ if (split_offset <= 0)
+ return 0;
+
+ dpart = kmalloc(sizeof(*part)+sizeof(ROOTFS_SPLIT_NAME)+1, GFP_KERNEL);
+ if (dpart == NULL) {
+ printk(KERN_INFO "split_squashfs: no memory for partition \"%s\"\n",
+ ROOTFS_SPLIT_NAME);
+ return -ENOMEM;
+ }
+
+ memcpy(dpart, part, sizeof(*part));
+ dpart->name = (unsigned char *)&dpart[1];
+ strcpy(dpart->name, ROOTFS_SPLIT_NAME);
+
+ dpart->size -= split_offset - dpart->offset;
+ dpart->offset = split_offset;
+
+ if (dpart == NULL)
+ return 1;
+
+ printk(KERN_INFO "mtd: partition \"%s\" created automatically, ofs=%llX, len=%llX \n",
+ ROOTFS_SPLIT_NAME, dpart->offset, dpart->size);
+
+ slave = add_one_partition(master, dpart, index, split_offset);
+ if (!slave) {
+ kfree(dpart);
+ return -ENOMEM;
+ }
+ rpart->split = &slave->mtd;
+
+ return 0;
+}
+
+static int refresh_rootfs_split(struct mtd_info *mtd)
+{
+ struct mtd_partition tpart;
+ struct mtd_part *part;
+ char *name;
+ int index = 0;
+ int offset, size;
+ int ret;
+
+ part = PART(mtd);
+
+ /* check for the new squashfs offset first */
+ ret = split_squashfs(part->master, part->offset, &offset);
+ if (ret)
+ return ret;
+
+ if ((offset > 0) && !mtd->split) {
+ printk(KERN_INFO "%s: creating new split partition for \"%s\"\n", __func__, mtd->name);
+ /* if we don't have a rootfs split partition, create a new one */
+ tpart.name = (char *) mtd->name;
+ tpart.size = mtd->size;
+ tpart.offset = part->offset;
+
+ /* find the index of the last partition */
+ if (!list_empty(&mtd_partitions))
+ index = list_first_entry(&mtd_partitions, struct mtd_part, list)->index + 1;
+
+ return split_rootfs_data(part->master, &part->mtd, &tpart, index);
+ } else if ((offset > 0) && mtd->split) {
+ /* update the offsets of the existing partition */
+ size = mtd->size + part->offset - offset;
+
+ part = PART(mtd->split);
+ part->offset = offset;
+ part->mtd.size = size;
+ printk(KERN_INFO "%s: %s partition \"" ROOTFS_SPLIT_NAME "\", offset: 0x%06x (0x%06x)\n",
+ __func__, (!strcmp(part->mtd.name, ROOTFS_SPLIT_NAME) ? "updating" : "creating"),
+ (u32) part->offset, (u32) part->mtd.size);
+ name = kmalloc(sizeof(ROOTFS_SPLIT_NAME) + 1, GFP_KERNEL);
+ strcpy(name, ROOTFS_SPLIT_NAME);
+ part->mtd.name = name;
+ } else if ((offset <= 0) && mtd->split) {
+ printk(KERN_INFO "%s: removing partition \"%s\"\n", __func__, mtd->split->name);
+
+ /* mark existing partition as removed */
+ part = PART(mtd->split);
+ name = kmalloc(sizeof(ROOTFS_SPLIT_NAME) + 1, GFP_KERNEL);
+ strcpy(name, ROOTFS_REMOVED_NAME);
+ part->mtd.name = name;
+ part->offset = 0;
+ part->mtd.size = 0;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_MTD_ROOTFS_SPLIT */
+
/*
* This function, given a master MTD object and a partition table, creates
* and registers slave MTD objects which are bound to the master according to
@@ -502,14 +654,29 @@ int add_mtd_partitions(struct mtd_info *
{
struct mtd_part *slave;
uint64_t cur_offset = 0;
- int i;
+ int i, j, ret;
printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
- for (i = 0; i < nbparts; i++) {
- slave = add_one_partition(master, parts + i, i, cur_offset);
+ for (i = 0, j = 0; i < nbparts; i++) {
+ slave = add_one_partition(master, parts + i, j++, cur_offset);
if (!slave)
return -ENOMEM;
+
+ if (!strcmp(parts[i].name, "rootfs") && slave->registered) {
+#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
+ if (ROOT_DEV == 0) {
+ printk(KERN_NOTICE "mtd: partition \"rootfs\" "
+ "set to be root filesystem\n");
+ ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, slave->mtd.index);
+ }
+#endif
+#ifdef CONFIG_MTD_ROOTFS_SPLIT
+ ret = split_rootfs_data(master, &slave->mtd, &parts[i], j);
+ if (ret == 0)
+ j++;
+#endif
+ }
cur_offset = slave->offset + slave->mtd.size;
}
@@ -517,6 +684,32 @@ int add_mtd_partitions(struct mtd_info *
}
EXPORT_SYMBOL(add_mtd_partitions);
+int refresh_mtd_partitions(struct mtd_info *mtd)
+{
+ int ret = 0;
+
+ if (IS_PART(mtd)) {
+ struct mtd_part *part;
+ struct mtd_info *master;
+
+ part = PART(mtd);
+ master = part->master;
+ if (master->refresh_device)
+ ret = master->refresh_device(master);
+ }
+
+ if (!ret && mtd->refresh_device)
+ ret = mtd->refresh_device(mtd);
+
+#ifdef CONFIG_MTD_ROOTFS_SPLIT
+ if (!ret && IS_PART(mtd) && !strcmp(mtd->name, "rootfs"))
+ refresh_rootfs_split(mtd);
+#endif
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(refresh_mtd_partitions);
+
static DEFINE_SPINLOCK(part_parser_lock);
static LIST_HEAD(part_parsers);
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -29,6 +29,8 @@ struct block2mtd_dev {
struct block_device *blkdev;
struct mtd_info mtd;
struct mutex write_mutex;
+ rwlock_t bdev_mutex;
+ char devname[0];
};
@@ -81,6 +83,12 @@ static int block2mtd_erase(struct mtd_in
size_t len = instr->len;
int err;
+ read_lock(&dev->bdev_mutex);
+ if (!dev->blkdev) {
+ err = -EINVAL;
+ goto done;
+ }
+
instr->state = MTD_ERASING;
mutex_lock(&dev->write_mutex);
err = _block2mtd_erase(dev, from, len);
@@ -93,6 +101,10 @@ static int block2mtd_erase(struct mtd_in
instr->state = MTD_ERASE_DONE;
mtd_erase_callback(instr);
+
+done:
+ read_unlock(&dev->bdev_mutex);
+
return err;
}
@@ -104,10 +116,14 @@ static int block2mtd_read(struct mtd_inf
struct page *page;
int index = from >> PAGE_SHIFT;
int offset = from & (PAGE_SIZE-1);
- int cpylen;
+ int cpylen, err = 0;
+
+ read_lock(&dev->bdev_mutex);
+ if (!dev->blkdev || (from > mtd->size)) {
+ err = -EINVAL;
+ goto done;
+ }
- if (from > mtd->size)
- return -EINVAL;
if (from + len > mtd->size)
len = mtd->size - from;
@@ -122,10 +138,14 @@ static int block2mtd_read(struct mtd_inf
len = len - cpylen;
page = page_read(dev->blkdev->bd_inode->i_mapping, index);
- if (!page)
- return -ENOMEM;
- if (IS_ERR(page))
- return PTR_ERR(page);
+ if (!page) {
+ err = -ENOMEM;
+ goto done;
+ }
+ if (IS_ERR(page)) {
+ err = PTR_ERR(page);
+ goto done;
+ }
memcpy(buf, page_address(page) + offset, cpylen);
page_cache_release(page);
@@ -136,7 +156,10 @@ static int block2mtd_read(struct mtd_inf
offset = 0;
index++;
}
- return 0;
+
+done:
+ read_unlock(&dev->bdev_mutex);
+ return err;
}
@@ -188,12 +211,22 @@ static int block2mtd_write(struct mtd_in
size_t *retlen, const u_char *buf)
{
struct block2mtd_dev *dev = mtd->priv;
- int err;
+ int err = 0;
+
+ read_lock(&dev->bdev_mutex);
+ if (!dev->blkdev) {
+ err = -EINVAL;
+ goto done;
+ }
if (!len)
- return 0;
- if (to >= mtd->size)
- return -ENOSPC;
+ goto done;
+
+ if (to >= mtd->size) {
+ err = -ENOSPC;
+ goto done;
+ }
+
if (to + len > mtd->size)
len = mtd->size - to;
@@ -202,6 +235,9 @@ static int block2mtd_write(struct mtd_in
mutex_unlock(&dev->write_mutex);
if (err > 0)
err = 0;
+
+done:
+ read_unlock(&dev->bdev_mutex);
return err;
}
@@ -210,52 +246,29 @@ static int block2mtd_write(struct mtd_in
static void block2mtd_sync(struct mtd_info *mtd)
{
struct block2mtd_dev *dev = mtd->priv;
- sync_blockdev(dev->blkdev);
- return;
-}
-
-
-static void block2mtd_free_device(struct block2mtd_dev *dev)
-{
- if (!dev)
- return;
-
- kfree(dev->mtd.name);
- if (dev->blkdev) {
- invalidate_mapping_pages(dev->blkdev->bd_inode->i_mapping,
- 0, -1);
- close_bdev_exclusive(dev->blkdev, FMODE_READ|FMODE_WRITE);
- }
+ read_lock(&dev->bdev_mutex);
+ if (dev->blkdev)
+ sync_blockdev(dev->blkdev);
+ read_unlock(&dev->bdev_mutex);
- kfree(dev);
+ return;
}
-/* FIXME: ensure that mtd->size % erase_size == 0 */
-static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname)
+static int _open_bdev(struct block2mtd_dev *dev)
{
struct block_device *bdev;
- struct block2mtd_dev *dev;
- struct mtd_partition *part;
- char *name;
-
- if (!devname)
- return NULL;
-
- dev = kzalloc(sizeof(struct block2mtd_dev), GFP_KERNEL);
- if (!dev)
- return NULL;
/* Get a handle on the device */
- bdev = open_bdev_exclusive(devname, FMODE_READ|FMODE_WRITE, NULL);
+ bdev = open_bdev_exclusive(dev->devname, FMODE_READ|FMODE_WRITE, NULL);
#ifndef MODULE
if (IS_ERR(bdev)) {
/* We might not have rootfs mounted at this point. Try
to resolve the device name by other means. */
- dev_t devt = name_to_dev_t(devname);
+ dev_t devt = name_to_dev_t(dev->devname);
if (devt) {
bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ);
}
@@ -263,17 +276,97 @@ static struct block2mtd_dev *add_device(
#endif
if (IS_ERR(bdev)) {
- ERROR("error: cannot open device %s", devname);
- goto devinit_err;
+ ERROR("error: cannot open device %s", dev->devname);
+ return 1;
}
dev->blkdev = bdev;
if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
ERROR("attempting to use an MTD device as a block device");
- goto devinit_err;
+ return 1;
}
+ return 0;
+}
+
+static void _close_bdev(struct block2mtd_dev *dev)
+{
+ struct block_device *bdev;
+
+ if (!dev->blkdev)
+ return;
+
+ bdev = dev->blkdev;
+ invalidate_mapping_pages(dev->blkdev->bd_inode->i_mapping, 0, -1);
+ close_bdev_exclusive(dev->blkdev, FMODE_READ|FMODE_WRITE);
+ dev->blkdev = NULL;
+}
+
+static void block2mtd_free_device(struct block2mtd_dev *dev)
+{
+ if (!dev)
+ return;
+
+ kfree(dev->mtd.name);
+ _close_bdev(dev);
+ kfree(dev);
+}
+
+
+static int block2mtd_refresh(struct mtd_info *mtd)
+{
+ struct block2mtd_dev *dev = mtd->priv;
+ struct block_device *bdev;
+ dev_t devt;
+ int err = 0;
+
+ /* no other mtd function can run at this point */
+ write_lock(&dev->bdev_mutex);
+
+ /* get the device number for the whole disk */
+ devt = MKDEV(MAJOR(dev->blkdev->bd_dev), 0);
+
+ /* close the old block device */
+ _close_bdev(dev);
+
+ /* open the whole disk, issue a partition rescan, then */
+ bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ);
+ if (!bdev || !bdev->bd_disk)
+ err = -EINVAL;
+ else {
+ err = rescan_partitions(bdev->bd_disk, bdev);
+ }
+ if (bdev)
+ close_bdev_exclusive(bdev, FMODE_READ|FMODE_WRITE);
+
+ /* try to open the partition block device again */
+ _open_bdev(dev);
+ write_unlock(&dev->bdev_mutex);
+
+ return err;
+}
+
+/* FIXME: ensure that mtd->size % erase_size == 0 */
+static struct block2mtd_dev *add_device(char *devname, int erase_size, char *mtdname)
+{
+ struct block2mtd_dev *dev;
+ struct mtd_partition *part;
+ char *name;
+
+ if (!devname)
+ return NULL;
+
+ dev = kzalloc(sizeof(struct block2mtd_dev) + strlen(devname) + 1, GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ strcpy(dev->devname, devname);
+
+ if (_open_bdev(dev))
+ goto devinit_err;
+
mutex_init(&dev->write_mutex);
+ rwlock_init(&dev->bdev_mutex);
if (!mtdname)
mtdname = devname;
@@ -297,6 +390,7 @@ static struct block2mtd_dev *add_device(
dev->mtd.read = block2mtd_read;
dev->mtd.priv = dev;
dev->mtd.owner = THIS_MODULE;
+ dev->mtd.refresh_device = block2mtd_refresh;
part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL);
part->name = dev->mtd.name;
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -16,6 +16,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/compatmac.h>
+#include <linux/mtd/partitions.h>
#include <asm/uaccess.h>
@@ -773,6 +774,13 @@ static int mtd_ioctl(struct inode *inode
file->f_pos = 0;
break;
}
+#ifdef CONFIG_MTD_PARTITIONS
+ case MTDREFRESH:
+ {
+ ret = refresh_mtd_partitions(mtd);
+ break;
+ }
+#endif
default:
ret = -ENOTTY;
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -100,6 +100,7 @@ struct mtd_oob_ops {
uint8_t *oobbuf;
};
+struct mtd_info;
struct mtd_info {
u_char type;
uint32_t flags;
@@ -225,6 +226,9 @@ struct mtd_info {
struct module *owner;
int usecount;
+ int (*refresh_device)(struct mtd_info *mtd);
+ struct mtd_info *split;
+
/* If the driver is something smart, like UBI, it may need to maintain
* its own reference counting. The below functions are only for driver.
* The driver may register its callbacks. These callbacks are not
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -34,6 +34,7 @@
* erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK).
*/
+struct mtd_partition;
struct mtd_partition {
char *name; /* identifier string */
uint64_t size; /* partition size */
@@ -41,6 +42,7 @@ struct mtd_partition {
uint32_t mask_flags; /* master MTD flags to mask out for this partition */
struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only)*/
struct mtd_info **mtdp; /* pointer to store the MTD object */
+ int (*refresh_partition)(struct mtd_info *);
};
#define MTDPART_OFS_NXTBLK (-2)
@@ -50,6 +52,7 @@ struct mtd_partition {
int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
int del_mtd_partitions(struct mtd_info *);
+int refresh_mtd_partitions(struct mtd_info *);
/*
* Functions dealing with the various ways of partitioning the space
--- a/include/mtd/mtd-abi.h
+++ b/include/mtd/mtd-abi.h
@@ -93,6 +93,7 @@ struct otp_info {
#define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout)
#define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats)
#define MTDFILEMODE _IO('M', 19)
+#define MTDREFRESH _IO('M', 23)
/*
* Obsolete legacy interface. Keep it in order not to break userspace

View file

@ -0,0 +1,27 @@
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -515,21 +515,21 @@ static int split_squashfs(struct mtd_inf
return -EINVAL;
}
- if (*((u32 *) buf) != SQUASHFS_MAGIC) {
+ if (SQUASHFS_MAGIC != le32_to_cpu(sb->s_magic) ) {
printk(KERN_ALERT "split_squashfs: no squashfs found in \"%s\"\n",
master->name);
*split_offset = 0;
return 0;
}
- if (sb->bytes_used <= 0) {
+ if (le64_to_cpu((sb->bytes_used)) <= 0) {
printk(KERN_ALERT "split_squashfs: squashfs is empty in \"%s\"\n",
master->name);
*split_offset = 0;
return 0;
}
- len = (u32) sb->bytes_used;
+ len = (u32) le64_to_cpu(sb->bytes_used);
len += (offset & 0x000fffff);
len += (master->erasesize - 1);
len &= ~(master->erasesize - 1);

View file

@ -0,0 +1,30 @@
--- a/drivers/mtd/redboot.c
+++ b/drivers/mtd/redboot.c
@@ -249,14 +249,21 @@ static int parse_redboot_partitions(stru
#endif
names += strlen(names)+1;
-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
- i++;
- parts[i].offset = parts[i-1].size + parts[i-1].offset;
- parts[i].size = fl->next->img->flash_base - parts[i].offset;
- parts[i].name = nullname;
- }
+ if (!strcmp(parts[i].name, "rootfs")) {
+ parts[i].size = fl->next->img->flash_base;
+ parts[i].size &= ~(master->erasesize - 1);
+ parts[i].size -= parts[i].offset;
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+ nrparts--;
+ } else {
+ i++;
+ parts[i].offset = parts[i-1].size + parts[i-1].offset;
+ parts[i].size = fl->next->img->flash_base - parts[i].offset;
+ parts[i].name = nullname;
#endif
+ }
+ }
tmp_fl = fl;
fl = fl->next;
kfree(tmp_fl);

View file

@ -0,0 +1,60 @@
--- a/drivers/mtd/redboot.c
+++ b/drivers/mtd/redboot.c
@@ -11,6 +11,8 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#define BOARD_CONFIG_PART "boardconfig"
+
struct fis_image_desc {
unsigned char name[16]; // Null terminated name
uint32_t flash_base; // Address within FLASH of image
@@ -41,6 +43,7 @@ static int parse_redboot_partitions(stru
struct mtd_partition **pparts,
unsigned long fis_origin)
{
+ unsigned long max_offset = 0;
int nrparts = 0;
struct fis_image_desc *buf;
struct mtd_partition *parts;
@@ -209,14 +212,14 @@ static int parse_redboot_partitions(stru
}
}
#endif
- parts = kzalloc(sizeof(*parts)*nrparts + nulllen + namelen, GFP_KERNEL);
+ parts = kzalloc(sizeof(*parts) * (nrparts + 1) + nulllen + namelen + sizeof(BOARD_CONFIG_PART), GFP_KERNEL);
if (!parts) {
ret = -ENOMEM;
goto out;
}
- nullname = (char *)&parts[nrparts];
+ nullname = (char *)&parts[nrparts + 1];
#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
if (nulllen > 0) {
strcpy(nullname, nullstring);
@@ -235,6 +238,8 @@ static int parse_redboot_partitions(stru
}
#endif
for ( ; i<nrparts; i++) {
+ if(max_offset < buf[i].flash_base + buf[i].size)
+ max_offset = buf[i].flash_base + buf[i].size;
parts[i].size = fl->img->size;
parts[i].offset = fl->img->flash_base;
parts[i].name = names;
@@ -268,6 +273,14 @@ static int parse_redboot_partitions(stru
fl = fl->next;
kfree(tmp_fl);
}
+ if(master->size - max_offset >= master->erasesize)
+ {
+ parts[nrparts].size = master->size - max_offset;
+ parts[nrparts].offset = max_offset;
+ parts[nrparts].name = names;
+ strcpy(names, BOARD_CONFIG_PART);
+ nrparts++;
+ }
ret = nrparts;
*pparts = parts;
out:

View file

@ -0,0 +1,32 @@
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -574,6 +574,7 @@ struct platform_nand_chip {
int chip_delay;
unsigned int options;
const char **part_probe_types;
+ int (*chip_fixup)(struct mtd_info *mtd);
void *priv;
};
--- a/drivers/mtd/nand/plat_nand.c
+++ b/drivers/mtd/nand/plat_nand.c
@@ -71,7 +71,18 @@ static int __init plat_nand_probe(struct
platform_set_drvdata(pdev, data);
/* Scan to find existance of the device */
- if (nand_scan(&data->mtd, 1)) {
+ if (nand_scan_ident(&data->mtd, 1)) {
+ res = -ENXIO;
+ goto out;
+ }
+
+ if (pdata->chip.chip_fixup) {
+ res = pdata->chip.chip_fixup(&data->mtd);
+ if (res)
+ goto out;
+ }
+
+ if (nand_scan_tail(&data->mtd)) {
res = -ENXIO;
goto out;
}

View file

@ -0,0 +1,35 @@
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -180,6 +180,22 @@ config MTD_AR7_PARTS
---help---
TI AR7 partitioning support
+config MTD_MYLOADER_PARTS
+ tristate "MyLoader partition parsing"
+ depends on MTD_PARTITIONS && (ADM5120 || ATHEROS || ATHEROS_AR71XX)
+ ---help---
+ MyLoader is a bootloader which allows the user to define partitions
+ in flash devices, by putting a table in the second erase block
+ on the device, similar to a partition table. This table gives the
+ offsets and lengths of the user defined partitions.
+
+ If you need code which can detect and parse these tables, and
+ register MTD 'partitions' corresponding to each image detected,
+ enable this option.
+
+ You will still need the parsing functions to be called by the driver
+ for your particular device. It won't happen automatically.
+
comment "User Modules And Translation Layers"
config MTD_CHAR
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdli
obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o
obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
+obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o
# 'Users' - code which presents functionality to userspace.
obj-$(CONFIG_MTD_CHAR) += mtdchar.o

View file

@ -0,0 +1,11 @@
--- a/drivers/mtd/myloader.c
+++ b/drivers/mtd/myloader.c
@@ -19,7 +19,7 @@
#include <linux/vmalloc.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
-#include <linux/byteorder/generic.h>
+#include <linux/byteorder.h>
#include <linux/myloader.h>
#define BLOCK_LEN_MIN 0x10000

View file

@ -0,0 +1,12 @@
--- a/drivers/mtd/nand/nand_ecc.c
+++ b/drivers/mtd/nand/nand_ecc.c
@@ -492,8 +492,7 @@ int nand_correct_data(struct mtd_info *m
if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1)
return 1; /* error in ecc data; no action needed */
- printk(KERN_ERR "uncorrectable error : ");
- return -1;
+ return -EBADMSG;
}
EXPORT_SYMBOL(nand_correct_data);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,108 @@
--- a/include/linux/netfilter/xt_layer7.h
+++ b/include/linux/netfilter/xt_layer7.h
@@ -8,6 +8,7 @@ struct xt_layer7_info {
char protocol[MAX_PROTOCOL_LEN];
char pattern[MAX_PATTERN_LEN];
u_int8_t invert;
+ u_int8_t pkt;
};
#endif /* _XT_LAYER7_H */
--- a/net/netfilter/xt_layer7.c
+++ b/net/netfilter/xt_layer7.c
@@ -314,33 +314,35 @@ static int match_no_append(struct nf_con
}
/* add the new app data to the conntrack. Return number of bytes added. */
-static int add_data(struct nf_conn * master_conntrack,
- char * app_data, int appdatalen)
+static int add_datastr(char *target, int offset, char *app_data, int len)
{
int length = 0, i;
- int oldlength = master_conntrack->layer7.app_data_len;
-
- /* This is a fix for a race condition by Deti Fliegl. However, I'm not
- clear on whether the race condition exists or whether this really
- fixes it. I might just be being dense... Anyway, if it's not really
- a fix, all it does is waste a very small amount of time. */
- if(!master_conntrack->layer7.app_data) return 0;
+ if (!target) return 0;
/* Strip nulls. Make everything lower case (our regex lib doesn't
do case insensitivity). Add it to the end of the current data. */
- for(i = 0; i < maxdatalen-oldlength-1 &&
- i < appdatalen; i++) {
+ for(i = 0; i < maxdatalen-offset-1 && i < len; i++) {
if(app_data[i] != '\0') {
/* the kernel version of tolower mungs 'upper ascii' */
- master_conntrack->layer7.app_data[length+oldlength] =
+ target[length+offset] =
isascii(app_data[i])?
tolower(app_data[i]) : app_data[i];
length++;
}
}
+ target[length+offset] = '\0';
+
+ return length;
+}
+
+/* add the new app data to the conntrack. Return number of bytes added. */
+static int add_data(struct nf_conn * master_conntrack,
+ char * app_data, int appdatalen)
+{
+ int length;
- master_conntrack->layer7.app_data[length+oldlength] = '\0';
- master_conntrack->layer7.app_data_len = length + oldlength;
+ length = add_datastr(master_conntrack->layer7.app_data, master_conntrack->layer7.app_data_len, app_data, appdatalen);
+ master_conntrack->layer7.app_data_len += length;
return length;
}
@@ -438,7 +440,7 @@ match(const struct sk_buff *skbin,
enum ip_conntrack_info master_ctinfo, ctinfo;
struct nf_conn *master_conntrack, *conntrack;
- unsigned char * app_data;
+ unsigned char *app_data, *tmp_data;
unsigned int pattern_result, appdatalen;
regexp * comppattern;
@@ -466,8 +468,8 @@ match(const struct sk_buff *skbin,
master_conntrack = master_ct(master_conntrack);
/* if we've classified it or seen too many packets */
- if(total_acct_packets(master_conntrack) > num_packets ||
- master_conntrack->layer7.app_proto) {
+ if(!info->pkt && (total_acct_packets(master_conntrack) > num_packets ||
+ master_conntrack->layer7.app_proto)) {
pattern_result = match_no_append(conntrack, master_conntrack,
ctinfo, master_ctinfo, info);
@@ -500,6 +502,25 @@ match(const struct sk_buff *skbin,
/* the return value gets checked later, when we're ready to use it */
comppattern = compile_and_cache(info->pattern, info->protocol);
+ if (info->pkt) {
+ tmp_data = kmalloc(maxdatalen, GFP_ATOMIC);
+ if(!tmp_data){
+ if (net_ratelimit())
+ printk(KERN_ERR "layer7: out of memory in match, bailing.\n");
+ return info->invert;
+ }
+
+ tmp_data[0] = '\0';
+ add_datastr(tmp_data, 0, app_data, appdatalen);
+ pattern_result = ((comppattern && regexec(comppattern, tmp_data)) ? 1 : 0);
+
+ kfree(tmp_data);
+ tmp_data = NULL;
+ spin_unlock_bh(&l7_lock);
+
+ return (pattern_result ^ info->invert);
+ }
+
/* On the first packet of a connection, allocate space for app data */
if(total_acct_packets(master_conntrack) == 1 && !skb->cb[0] &&
!master_conntrack->layer7.app_data){

View file

@ -0,0 +1,119 @@
--- a/include/linux/netfilter_ipv4/ip_tables.h
+++ b/include/linux/netfilter_ipv4/ip_tables.h
@@ -62,6 +62,7 @@ struct ipt_ip {
#define IPT_F_FRAG 0x01 /* Set if rule is a fragment rule */
#define IPT_F_GOTO 0x02 /* Set if jump is a goto */
#define IPT_F_MASK 0x03 /* All possible flag bits mask. */
+#define IPT_F_NO_DEF_MATCH 0x80 /* Internal: no default match rules present */
/* Values for "inv" field in struct ipt_ip. */
#define IPT_INV_VIA_IN 0x01 /* Invert the sense of IN IFACE. */
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -88,6 +88,9 @@ ip_packet_match(const struct iphdr *ip,
#define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg)))
+ if (ipinfo->flags & IPT_F_NO_DEF_MATCH)
+ return true;
+
if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
IPT_INV_SRCIP)
|| FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
@@ -147,13 +150,35 @@ ip_packet_match(const struct iphdr *ip,
return false;
}
+#undef FWINV
return true;
}
static bool
-ip_checkentry(const struct ipt_ip *ip)
+ip_checkentry(struct ipt_ip *ip)
{
- if (ip->flags & ~IPT_F_MASK) {
+#define FWINV(bool, invflg) ((bool) || (ip->invflags & (invflg)))
+
+ if (FWINV(ip->smsk.s_addr, IPT_INV_SRCIP) ||
+ FWINV(ip->dmsk.s_addr, IPT_INV_DSTIP))
+ goto has_match_rules;
+
+ if (FWINV(!!((const unsigned long *)ip->iniface_mask)[0],
+ IPT_INV_VIA_IN) ||
+ FWINV(!!((const unsigned long *)ip->outiface_mask)[0],
+ IPT_INV_VIA_OUT))
+ goto has_match_rules;
+
+ if (FWINV(ip->proto, IPT_INV_PROTO))
+ goto has_match_rules;
+
+ if (FWINV(ip->flags&IPT_F_FRAG, IPT_INV_FRAG))
+ goto has_match_rules;
+
+ ip->flags |= IPT_F_NO_DEF_MATCH;
+
+has_match_rules:
+ if (ip->flags & ~(IPT_F_MASK|IPT_F_NO_DEF_MATCH)) {
duprintf("Unknown flag bits set: %08X\n",
ip->flags & ~IPT_F_MASK);
return false;
@@ -163,6 +188,8 @@ ip_checkentry(const struct ipt_ip *ip)
ip->invflags & ~IPT_INV_MASK);
return false;
}
+
+#undef FWINV
return true;
}
@@ -210,7 +237,6 @@ unconditional(const struct ipt_ip *ip)
return 0;
return 1;
-#undef FWINV
}
#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
@@ -328,8 +354,27 @@ ipt_do_table(struct sk_buff *skb,
struct xt_match_param mtpar;
struct xt_target_param tgpar;
- /* Initialization */
ip = ip_hdr(skb);
+
+ read_lock_bh(&table->lock);
+ IP_NF_ASSERT(table->valid_hooks & (1 << hook));
+ private = table->private;
+ table_base = (void *)private->entries[smp_processor_id()];
+ e = get_entry(table_base, private->hook_entry[hook]);
+ if (e->target_offset <= sizeof(struct ipt_entry) &&
+ (e->ip.flags & IPT_F_NO_DEF_MATCH)) {
+ struct ipt_entry_target *t = ipt_get_target(e);
+ if (!t->u.kernel.target->target) {
+ int v = ((struct ipt_standard_target *)t)->verdict;
+ if ((v < 0) && (v != IPT_RETURN)) {
+ ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1);
+ read_unlock_bh(&table->lock);
+ return (unsigned)(-v) - 1;
+ }
+ }
+ }
+
+ /* Initialization */
datalen = skb->len - ip->ihl * 4;
indev = in ? in->name : nulldevname;
outdev = out ? out->name : nulldevname;
@@ -347,12 +392,6 @@ ipt_do_table(struct sk_buff *skb,
mtpar.family = tgpar.family = NFPROTO_IPV4;
tgpar.hooknum = hook;
- read_lock_bh(&table->lock);
- IP_NF_ASSERT(table->valid_hooks & (1 << hook));
- private = table->private;
- table_base = (void *)private->entries[smp_processor_id()];
- e = get_entry(table_base, private->hook_entry[hook]);
-
/* For return from builtin chain */
back = get_entry(table_base, private->underflow[hook]);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,18 @@
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -160,7 +160,6 @@ config NF_CONNTRACK_FTP
config NF_CONNTRACK_H323
tristate "H.323 protocol support"
- depends on (IPV6 || IPV6=n)
depends on NETFILTER_ADVANCED
help
H.323 is a VoIP signalling protocol from ITU-T. As one of the most
@@ -466,7 +465,6 @@ config NETFILTER_XT_TARGET_SECMARK
config NETFILTER_XT_TARGET_TCPMSS
tristate '"TCPMSS" target support'
- depends on (IPV6 || IPV6=n)
default m if NETFILTER_ADVANCED=n
---help---
This option adds a `TCPMSS' target, which allows you to alter the

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,793 @@
--- a/include/linux/pkt_sched.h
+++ b/include/linux/pkt_sched.h
@@ -182,8 +182,37 @@ struct tc_sfq_xstats
*
* The only reason for this is efficiency, it is possible
* to change these parameters in compile time.
+ *
+ * If you need to play with these values, use esfq instead.
*/
+/* ESFQ section */
+
+enum
+{
+ /* traditional */
+ TCA_SFQ_HASH_CLASSIC,
+ TCA_SFQ_HASH_DST,
+ TCA_SFQ_HASH_SRC,
+ TCA_SFQ_HASH_FWMARK,
+ /* conntrack */
+ TCA_SFQ_HASH_CTORIGDST,
+ TCA_SFQ_HASH_CTORIGSRC,
+ TCA_SFQ_HASH_CTREPLDST,
+ TCA_SFQ_HASH_CTREPLSRC,
+ TCA_SFQ_HASH_CTNATCHG,
+};
+
+struct tc_esfq_qopt
+{
+ unsigned quantum; /* Bytes per round allocated to flow */
+ int perturb_period; /* Period of hash perturbation */
+ __u32 limit; /* Maximal packets in queue */
+ unsigned divisor; /* Hash divisor */
+ unsigned flows; /* Maximal number of flows */
+ unsigned hash_kind; /* Hash function to use for flow identification */
+};
+
/* RED section */
enum
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -137,6 +137,37 @@ config NET_SCH_SFQ
To compile this code as a module, choose M here: the
module will be called sch_sfq.
+config NET_SCH_ESFQ
+ tristate "Enhanced Stochastic Fairness Queueing (ESFQ)"
+ ---help---
+ Say Y here if you want to use the Enhanced Stochastic Fairness
+ Queueing (ESFQ) packet scheduling algorithm for some of your network
+ devices or as a leaf discipline for a classful qdisc such as HTB or
+ CBQ (see the top of <file:net/sched/sch_esfq.c> for details and
+ references to the SFQ algorithm).
+
+ This is an enchanced SFQ version which allows you to control some
+ hardcoded values in the SFQ scheduler.
+
+ ESFQ also adds control of the hash function used to identify packet
+ flows. The original SFQ discipline hashes by connection; ESFQ add
+ several other hashing methods, such as by src IP or by dst IP, which
+ can be more fair to users in some networking situations.
+
+ To compile this code as a module, choose M here: the
+ module will be called sch_esfq.
+
+config NET_SCH_ESFQ_NFCT
+ bool "Connection Tracking Hash Types"
+ depends on NET_SCH_ESFQ && NF_CONNTRACK
+ ---help---
+ Say Y here to enable support for hashing based on netfilter connection
+ tracking information. This is useful for a router that is also using
+ NAT to connect privately-addressed hosts to the Internet. If you want
+ to provide fair distribution of upstream bandwidth, ESFQ must use
+ connection tracking information, since all outgoing packets will share
+ the same source address.
+
config NET_SCH_TEQL
tristate "True Link Equalizer (TEQL)"
---help---
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_NET_SCH_GRED) += sch_gred.o
obj-$(CONFIG_NET_SCH_INGRESS) += sch_ingress.o
obj-$(CONFIG_NET_SCH_DSMARK) += sch_dsmark.o
obj-$(CONFIG_NET_SCH_SFQ) += sch_sfq.o
+obj-$(CONFIG_NET_SCH_ESFQ) += sch_esfq.o
obj-$(CONFIG_NET_SCH_TBF) += sch_tbf.o
obj-$(CONFIG_NET_SCH_TEQL) += sch_teql.o
obj-$(CONFIG_NET_SCH_PRIO) += sch_prio.o
--- /dev/null
+++ b/net/sched/sch_esfq.c
@@ -0,0 +1,700 @@
+/*
+ * net/sched/sch_esfq.c Extended Stochastic Fairness Queueing discipline.
+ *
+ * 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.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ * Changes: Alexander Atanasov, <alex@ssi.bg>
+ * Added dynamic depth,limit,divisor,hash_kind options.
+ * Added dst and src hashes.
+ *
+ * Alexander Clouter, <alex@digriz.org.uk>
+ * Ported ESFQ to Linux 2.6.
+ *
+ * Corey Hickey, <bugfood-c@fatooh.org>
+ * Maintenance of the Linux 2.6 port.
+ * Added fwmark hash (thanks to Robert Kurjata).
+ * Added usage of jhash.
+ * Added conntrack support.
+ * Added ctnatchg hash (thanks to Ben Pfountz).
+ */
+
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/bitops.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/notifier.h>
+#include <linux/init.h>
+#include <net/ip.h>
+#include <net/netlink.h>
+#include <linux/ipv6.h>
+#include <net/route.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/pkt_sched.h>
+#include <linux/jhash.h>
+#include <net/netfilter/nf_conntrack.h>
+
+/* Stochastic Fairness Queuing algorithm.
+ For more comments look at sch_sfq.c.
+ The difference is that you can change limit, depth,
+ hash table size and choose alternate hash types.
+
+ classic: same as in sch_sfq.c
+ dst: destination IP address
+ src: source IP address
+ fwmark: netfilter mark value
+ ctorigdst: original destination IP address
+ ctorigsrc: original source IP address
+ ctrepldst: reply destination IP address
+ ctreplsrc: reply source IP
+
+*/
+
+#define ESFQ_HEAD 0
+#define ESFQ_TAIL 1
+
+/* This type should contain at least SFQ_DEPTH*2 values */
+typedef unsigned int esfq_index;
+
+struct esfq_head
+{
+ esfq_index next;
+ esfq_index prev;
+};
+
+struct esfq_sched_data
+{
+/* Parameters */
+ int perturb_period;
+ unsigned quantum; /* Allotment per round: MUST BE >= MTU */
+ int limit;
+ unsigned depth;
+ unsigned hash_divisor;
+ unsigned hash_kind;
+/* Variables */
+ struct timer_list perturb_timer;
+ int perturbation;
+ esfq_index tail; /* Index of current slot in round */
+ esfq_index max_depth; /* Maximal depth */
+
+ esfq_index *ht; /* Hash table */
+ esfq_index *next; /* Active slots link */
+ short *allot; /* Current allotment per slot */
+ unsigned short *hash; /* Hash value indexed by slots */
+ struct sk_buff_head *qs; /* Slot queue */
+ struct esfq_head *dep; /* Linked list of slots, indexed by depth */
+};
+
+/* This contains the info we will hash. */
+struct esfq_packet_info
+{
+ u32 proto; /* protocol or port */
+ u32 src; /* source from packet header */
+ u32 dst; /* destination from packet header */
+ u32 ctorigsrc; /* original source from conntrack */
+ u32 ctorigdst; /* original destination from conntrack */
+ u32 ctreplsrc; /* reply source from conntrack */
+ u32 ctrepldst; /* reply destination from conntrack */
+ u32 mark; /* netfilter mark (fwmark) */
+};
+
+static __inline__ unsigned esfq_jhash_1word(struct esfq_sched_data *q,u32 a)
+{
+ return jhash_1word(a, q->perturbation) & (q->hash_divisor-1);
+}
+
+static __inline__ unsigned esfq_jhash_2words(struct esfq_sched_data *q, u32 a, u32 b)
+{
+ return jhash_2words(a, b, q->perturbation) & (q->hash_divisor-1);
+}
+
+static __inline__ unsigned esfq_jhash_3words(struct esfq_sched_data *q, u32 a, u32 b, u32 c)
+{
+ return jhash_3words(a, b, c, q->perturbation) & (q->hash_divisor-1);
+}
+
+static unsigned esfq_hash(struct esfq_sched_data *q, struct sk_buff *skb)
+{
+ struct esfq_packet_info info;
+#ifdef CONFIG_NET_SCH_ESFQ_NFCT
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+#endif
+
+ switch (skb->protocol) {
+ case __constant_htons(ETH_P_IP):
+ {
+ struct iphdr *iph = ip_hdr(skb);
+ info.dst = iph->daddr;
+ info.src = iph->saddr;
+ if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
+ (iph->protocol == IPPROTO_TCP ||
+ iph->protocol == IPPROTO_UDP ||
+ iph->protocol == IPPROTO_SCTP ||
+ iph->protocol == IPPROTO_DCCP ||
+ iph->protocol == IPPROTO_ESP))
+ info.proto = *(((u32*)iph) + iph->ihl);
+ else
+ info.proto = iph->protocol;
+ break;
+ }
+ case __constant_htons(ETH_P_IPV6):
+ {
+ struct ipv6hdr *iph = ipv6_hdr(skb);
+ /* Hash ipv6 addresses into a u32. This isn't ideal,
+ * but the code is simple. */
+ info.dst = jhash2(iph->daddr.s6_addr32, 4, q->perturbation);
+ info.src = jhash2(iph->saddr.s6_addr32, 4, q->perturbation);
+ if (iph->nexthdr == IPPROTO_TCP ||
+ iph->nexthdr == IPPROTO_UDP ||
+ iph->nexthdr == IPPROTO_SCTP ||
+ iph->nexthdr == IPPROTO_DCCP ||
+ iph->nexthdr == IPPROTO_ESP)
+ info.proto = *(u32*)&iph[1];
+ else
+ info.proto = iph->nexthdr;
+ break;
+ }
+ default:
+ info.dst = (u32)(unsigned long)skb->dst;
+ info.src = (u32)(unsigned long)skb->sk;
+ info.proto = skb->protocol;
+ }
+
+ info.mark = skb->mark;
+
+#ifdef CONFIG_NET_SCH_ESFQ_NFCT
+ /* defaults if there is no conntrack info */
+ info.ctorigsrc = info.src;
+ info.ctorigdst = info.dst;
+ info.ctreplsrc = info.dst;
+ info.ctrepldst = info.src;
+ /* collect conntrack info */
+ if (ct && ct != &nf_conntrack_untracked) {
+ if (skb->protocol == __constant_htons(ETH_P_IP)) {
+ info.ctorigsrc = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip;
+ info.ctorigdst = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip;
+ info.ctreplsrc = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip;
+ info.ctrepldst = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip;
+ }
+ else if (skb->protocol == __constant_htons(ETH_P_IPV6)) {
+ /* Again, hash ipv6 addresses into a single u32. */
+ info.ctorigsrc = jhash2(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip6, 4, q->perturbation);
+ info.ctorigdst = jhash2(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip6, 4, q->perturbation);
+ info.ctreplsrc = jhash2(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip6, 4, q->perturbation);
+ info.ctrepldst = jhash2(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip6, 4, q->perturbation);
+ }
+
+ }
+#endif
+
+ switch(q->hash_kind) {
+ case TCA_SFQ_HASH_CLASSIC:
+ return esfq_jhash_3words(q, info.dst, info.src, info.proto);
+ case TCA_SFQ_HASH_DST:
+ return esfq_jhash_1word(q, info.dst);
+ case TCA_SFQ_HASH_SRC:
+ return esfq_jhash_1word(q, info.src);
+ case TCA_SFQ_HASH_FWMARK:
+ return esfq_jhash_1word(q, info.mark);
+#ifdef CONFIG_NET_SCH_ESFQ_NFCT
+ case TCA_SFQ_HASH_CTORIGDST:
+ return esfq_jhash_1word(q, info.ctorigdst);
+ case TCA_SFQ_HASH_CTORIGSRC:
+ return esfq_jhash_1word(q, info.ctorigsrc);
+ case TCA_SFQ_HASH_CTREPLDST:
+ return esfq_jhash_1word(q, info.ctrepldst);
+ case TCA_SFQ_HASH_CTREPLSRC:
+ return esfq_jhash_1word(q, info.ctreplsrc);
+ case TCA_SFQ_HASH_CTNATCHG:
+ {
+ if (info.ctorigdst == info.ctreplsrc)
+ return esfq_jhash_1word(q, info.ctorigsrc);
+ return esfq_jhash_1word(q, info.ctreplsrc);
+ }
+#endif
+ default:
+ if (net_ratelimit())
+ printk(KERN_WARNING "ESFQ: Unknown hash method. Falling back to classic.\n");
+ }
+ return esfq_jhash_3words(q, info.dst, info.src, info.proto);
+}
+
+static inline void esfq_link(struct esfq_sched_data *q, esfq_index x)
+{
+ esfq_index p, n;
+ int d = q->qs[x].qlen + q->depth;
+
+ p = d;
+ n = q->dep[d].next;
+ q->dep[x].next = n;
+ q->dep[x].prev = p;
+ q->dep[p].next = q->dep[n].prev = x;
+}
+
+static inline void esfq_dec(struct esfq_sched_data *q, esfq_index x)
+{
+ esfq_index p, n;
+
+ n = q->dep[x].next;
+ p = q->dep[x].prev;
+ q->dep[p].next = n;
+ q->dep[n].prev = p;
+
+ if (n == p && q->max_depth == q->qs[x].qlen + 1)
+ q->max_depth--;
+
+ esfq_link(q, x);
+}
+
+static inline void esfq_inc(struct esfq_sched_data *q, esfq_index x)
+{
+ esfq_index p, n;
+ int d;
+
+ n = q->dep[x].next;
+ p = q->dep[x].prev;
+ q->dep[p].next = n;
+ q->dep[n].prev = p;
+ d = q->qs[x].qlen;
+ if (q->max_depth < d)
+ q->max_depth = d;
+
+ esfq_link(q, x);
+}
+
+static unsigned int esfq_drop(struct Qdisc *sch)
+{
+ struct esfq_sched_data *q = qdisc_priv(sch);
+ esfq_index d = q->max_depth;
+ struct sk_buff *skb;
+ unsigned int len;
+
+ /* Queue is full! Find the longest slot and
+ drop a packet from it */
+
+ if (d > 1) {
+ esfq_index x = q->dep[d+q->depth].next;
+ skb = q->qs[x].prev;
+ len = skb->len;
+ __skb_unlink(skb, &q->qs[x]);
+ kfree_skb(skb);
+ esfq_dec(q, x);
+ sch->q.qlen--;
+ sch->qstats.drops++;
+ sch->qstats.backlog -= len;
+ return len;
+ }
+
+ if (d == 1) {
+ /* It is difficult to believe, but ALL THE SLOTS HAVE LENGTH 1. */
+ d = q->next[q->tail];
+ q->next[q->tail] = q->next[d];
+ q->allot[q->next[d]] += q->quantum;
+ skb = q->qs[d].prev;
+ len = skb->len;
+ __skb_unlink(skb, &q->qs[d]);
+ kfree_skb(skb);
+ esfq_dec(q, d);
+ sch->q.qlen--;
+ q->ht[q->hash[d]] = q->depth;
+ sch->qstats.drops++;
+ sch->qstats.backlog -= len;
+ return len;
+ }
+
+ return 0;
+}
+
+static void esfq_q_enqueue(struct sk_buff *skb, struct esfq_sched_data *q, unsigned int end)
+{
+ unsigned hash = esfq_hash(q, skb);
+ unsigned depth = q->depth;
+ esfq_index x;
+
+ x = q->ht[hash];
+ if (x == depth) {
+ q->ht[hash] = x = q->dep[depth].next;
+ q->hash[x] = hash;
+ }
+
+ if (end == ESFQ_TAIL)
+ __skb_queue_tail(&q->qs[x], skb);
+ else
+ __skb_queue_head(&q->qs[x], skb);
+
+ esfq_inc(q, x);
+ if (q->qs[x].qlen == 1) { /* The flow is new */
+ if (q->tail == depth) { /* It is the first flow */
+ q->tail = x;
+ q->next[x] = x;
+ q->allot[x] = q->quantum;
+ } else {
+ q->next[x] = q->next[q->tail];
+ q->next[q->tail] = x;
+ q->tail = x;
+ }
+ }
+}
+
+static int esfq_enqueue(struct sk_buff *skb, struct Qdisc* sch)
+{
+ struct esfq_sched_data *q = qdisc_priv(sch);
+ esfq_q_enqueue(skb, q, ESFQ_TAIL);
+ sch->qstats.backlog += skb->len;
+ if (++sch->q.qlen < q->limit-1) {
+ sch->bstats.bytes += skb->len;
+ sch->bstats.packets++;
+ return 0;
+ }
+
+ sch->qstats.drops++;
+ esfq_drop(sch);
+ return NET_XMIT_CN;
+}
+
+static struct sk_buff *esfq_peek(struct Qdisc* sch)
+{
+ struct esfq_sched_data *q = qdisc_priv(sch);
+ esfq_index a;
+
+ /* No active slots */
+ if (q->tail == q->depth)
+ return NULL;
+
+ a = q->next[q->tail];
+ return skb_peek(&q->qs[a]);
+}
+
+static struct sk_buff *esfq_q_dequeue(struct esfq_sched_data *q)
+{
+ struct sk_buff *skb;
+ unsigned depth = q->depth;
+ esfq_index a, old_a;
+
+ /* No active slots */
+ if (q->tail == depth)
+ return NULL;
+
+ a = old_a = q->next[q->tail];
+
+ /* Grab packet */
+ skb = __skb_dequeue(&q->qs[a]);
+ esfq_dec(q, a);
+
+ /* Is the slot empty? */
+ if (q->qs[a].qlen == 0) {
+ q->ht[q->hash[a]] = depth;
+ a = q->next[a];
+ if (a == old_a) {
+ q->tail = depth;
+ return skb;
+ }
+ q->next[q->tail] = a;
+ q->allot[a] += q->quantum;
+ } else if ((q->allot[a] -= skb->len) <= 0) {
+ q->tail = a;
+ a = q->next[a];
+ q->allot[a] += q->quantum;
+ }
+
+ return skb;
+}
+
+static struct sk_buff *esfq_dequeue(struct Qdisc* sch)
+{
+ struct esfq_sched_data *q = qdisc_priv(sch);
+ struct sk_buff *skb;
+
+ skb = esfq_q_dequeue(q);
+ if (skb == NULL)
+ return NULL;
+ sch->q.qlen--;
+ sch->qstats.backlog -= skb->len;
+ return skb;
+}
+
+static void esfq_q_destroy(struct esfq_sched_data *q)
+{
+ del_timer(&q->perturb_timer);
+ if(q->ht)
+ kfree(q->ht);
+ if(q->dep)
+ kfree(q->dep);
+ if(q->next)
+ kfree(q->next);
+ if(q->allot)
+ kfree(q->allot);
+ if(q->hash)
+ kfree(q->hash);
+ if(q->qs)
+ kfree(q->qs);
+}
+
+static void esfq_destroy(struct Qdisc *sch)
+{
+ struct esfq_sched_data *q = qdisc_priv(sch);
+ esfq_q_destroy(q);
+}
+
+
+static void esfq_reset(struct Qdisc* sch)
+{
+ struct sk_buff *skb;
+
+ while ((skb = esfq_dequeue(sch)) != NULL)
+ kfree_skb(skb);
+}
+
+static void esfq_perturbation(unsigned long arg)
+{
+ struct Qdisc *sch = (struct Qdisc*)arg;
+ struct esfq_sched_data *q = qdisc_priv(sch);
+
+ q->perturbation = net_random()&0x1F;
+
+ if (q->perturb_period) {
+ q->perturb_timer.expires = jiffies + q->perturb_period;
+ add_timer(&q->perturb_timer);
+ }
+}
+
+static unsigned int esfq_check_hash(unsigned int kind)
+{
+ switch (kind) {
+ case TCA_SFQ_HASH_CTORIGDST:
+ case TCA_SFQ_HASH_CTORIGSRC:
+ case TCA_SFQ_HASH_CTREPLDST:
+ case TCA_SFQ_HASH_CTREPLSRC:
+ case TCA_SFQ_HASH_CTNATCHG:
+#ifndef CONFIG_NET_SCH_ESFQ_NFCT
+ {
+ if (net_ratelimit())
+ printk(KERN_WARNING "ESFQ: Conntrack hash types disabled in kernel config. Falling back to classic.\n");
+ return TCA_SFQ_HASH_CLASSIC;
+ }
+#endif
+ case TCA_SFQ_HASH_CLASSIC:
+ case TCA_SFQ_HASH_DST:
+ case TCA_SFQ_HASH_SRC:
+ case TCA_SFQ_HASH_FWMARK:
+ return kind;
+ default:
+ {
+ if (net_ratelimit())
+ printk(KERN_WARNING "ESFQ: Unknown hash type. Falling back to classic.\n");
+ return TCA_SFQ_HASH_CLASSIC;
+ }
+ }
+}
+
+static int esfq_q_init(struct esfq_sched_data *q, struct nlattr *opt)
+{
+ struct tc_esfq_qopt *ctl = nla_data(opt);
+ esfq_index p = ~0U/2;
+ int i;
+
+ if (opt && opt->nla_len < nla_attr_size(sizeof(*ctl)))
+ return -EINVAL;
+
+ q->perturbation = 0;
+ q->hash_kind = TCA_SFQ_HASH_CLASSIC;
+ q->max_depth = 0;
+ if (opt == NULL) {
+ q->perturb_period = 0;
+ q->hash_divisor = 1024;
+ q->tail = q->limit = q->depth = 128;
+
+ } else {
+ struct tc_esfq_qopt *ctl = nla_data(opt);
+ if (ctl->quantum)
+ q->quantum = ctl->quantum;
+ q->perturb_period = ctl->perturb_period*HZ;
+ q->hash_divisor = ctl->divisor ? : 1024;
+ q->tail = q->limit = q->depth = ctl->flows ? : 128;
+
+ if ( q->depth > p - 1 )
+ return -EINVAL;
+
+ if (ctl->limit)
+ q->limit = min_t(u32, ctl->limit, q->depth);
+
+ if (ctl->hash_kind) {
+ q->hash_kind = esfq_check_hash(ctl->hash_kind);
+ }
+ }
+
+ q->ht = kmalloc(q->hash_divisor*sizeof(esfq_index), GFP_KERNEL);
+ if (!q->ht)
+ goto err_case;
+ q->dep = kmalloc((1+q->depth*2)*sizeof(struct esfq_head), GFP_KERNEL);
+ if (!q->dep)
+ goto err_case;
+ q->next = kmalloc(q->depth*sizeof(esfq_index), GFP_KERNEL);
+ if (!q->next)
+ goto err_case;
+ q->allot = kmalloc(q->depth*sizeof(short), GFP_KERNEL);
+ if (!q->allot)
+ goto err_case;
+ q->hash = kmalloc(q->depth*sizeof(unsigned short), GFP_KERNEL);
+ if (!q->hash)
+ goto err_case;
+ q->qs = kmalloc(q->depth*sizeof(struct sk_buff_head), GFP_KERNEL);
+ if (!q->qs)
+ goto err_case;
+
+ for (i=0; i< q->hash_divisor; i++)
+ q->ht[i] = q->depth;
+ for (i=0; i<q->depth; i++) {
+ skb_queue_head_init(&q->qs[i]);
+ q->dep[i+q->depth].next = i+q->depth;
+ q->dep[i+q->depth].prev = i+q->depth;
+ }
+
+ for (i=0; i<q->depth; i++)
+ esfq_link(q, i);
+ return 0;
+err_case:
+ esfq_q_destroy(q);
+ return -ENOBUFS;
+}
+
+static int esfq_init(struct Qdisc *sch, struct nlattr *opt)
+{
+ struct esfq_sched_data *q = qdisc_priv(sch);
+ int err;
+
+ q->quantum = psched_mtu(qdisc_dev(sch)); /* default */
+ if ((err = esfq_q_init(q, opt)))
+ return err;
+
+ init_timer(&q->perturb_timer);
+ q->perturb_timer.data = (unsigned long)sch;
+ q->perturb_timer.function = esfq_perturbation;
+ if (q->perturb_period) {
+ q->perturb_timer.expires = jiffies + q->perturb_period;
+ add_timer(&q->perturb_timer);
+ }
+
+ return 0;
+}
+
+static int esfq_change(struct Qdisc *sch, struct nlattr *opt)
+{
+ struct esfq_sched_data *q = qdisc_priv(sch);
+ struct esfq_sched_data new;
+ struct sk_buff *skb;
+ int err;
+
+ /* set up new queue */
+ memset(&new, 0, sizeof(struct esfq_sched_data));
+ new.quantum = psched_mtu(qdisc_dev(sch)); /* default */
+ if ((err = esfq_q_init(&new, opt)))
+ return err;
+
+ /* copy all packets from the old queue to the new queue */
+ sch_tree_lock(sch);
+ while ((skb = esfq_q_dequeue(q)) != NULL)
+ esfq_q_enqueue(skb, &new, ESFQ_TAIL);
+
+ /* clean up the old queue */
+ esfq_q_destroy(q);
+
+ /* copy elements of the new queue into the old queue */
+ q->perturb_period = new.perturb_period;
+ q->quantum = new.quantum;
+ q->limit = new.limit;
+ q->depth = new.depth;
+ q->hash_divisor = new.hash_divisor;
+ q->hash_kind = new.hash_kind;
+ q->tail = new.tail;
+ q->max_depth = new.max_depth;
+ q->ht = new.ht;
+ q->dep = new.dep;
+ q->next = new.next;
+ q->allot = new.allot;
+ q->hash = new.hash;
+ q->qs = new.qs;
+
+ /* finish up */
+ if (q->perturb_period) {
+ q->perturb_timer.expires = jiffies + q->perturb_period;
+ add_timer(&q->perturb_timer);
+ } else {
+ q->perturbation = 0;
+ }
+ sch_tree_unlock(sch);
+ return 0;
+}
+
+static int esfq_dump(struct Qdisc *sch, struct sk_buff *skb)
+{
+ struct esfq_sched_data *q = qdisc_priv(sch);
+ unsigned char *b = skb_tail_pointer(skb);
+ struct tc_esfq_qopt opt;
+
+ opt.quantum = q->quantum;
+ opt.perturb_period = q->perturb_period/HZ;
+
+ opt.limit = q->limit;
+ opt.divisor = q->hash_divisor;
+ opt.flows = q->depth;
+ opt.hash_kind = q->hash_kind;
+
+ NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
+
+ return skb->len;
+
+nla_put_failure:
+ nlmsg_trim(skb, b);
+ return -1;
+}
+
+static struct Qdisc_ops esfq_qdisc_ops =
+{
+ .next = NULL,
+ .cl_ops = NULL,
+ .id = "esfq",
+ .priv_size = sizeof(struct esfq_sched_data),
+ .enqueue = esfq_enqueue,
+ .dequeue = esfq_dequeue,
+ .peek = esfq_peek,
+ .drop = esfq_drop,
+ .init = esfq_init,
+ .reset = esfq_reset,
+ .destroy = esfq_destroy,
+ .change = esfq_change,
+ .dump = esfq_dump,
+ .owner = THIS_MODULE,
+};
+
+static int __init esfq_module_init(void)
+{
+ return register_qdisc(&esfq_qdisc_ops);
+}
+static void __exit esfq_module_exit(void)
+{
+ unregister_qdisc(&esfq_qdisc_ops);
+}
+module_init(esfq_module_init)
+module_exit(esfq_module_exit)
+MODULE_LICENSE("GPL");

View file

@ -0,0 +1,227 @@
--- a/include/linux/jhash.h
+++ b/include/linux/jhash.h
@@ -3,80 +3,95 @@
/* jhash.h: Jenkins hash support.
*
- * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
+ * Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net)
*
* http://burtleburtle.net/bob/hash/
*
* These are the credits from Bob's sources:
*
- * lookup2.c, by Bob Jenkins, December 1996, Public Domain.
- * hash(), hash2(), hash3, and mix() are externally useful functions.
- * Routines to test the hash are included if SELF_TEST is defined.
- * You can use this free for any purpose. It has no warranty.
+ * lookup3.c, by Bob Jenkins, May 2006, Public Domain.
*
- * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * These are functions for producing 32-bit hashes for hash table lookup.
+ * hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
+ * are externally useful functions. Routines to test the hash are included
+ * if SELF_TEST is defined. You can use this free for any purpose. It's in
+ * the public domain. It has no warranty.
+ *
+ * Copyright (C) 2009 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
*
* I've modified Bob's hash to be useful in the Linux kernel, and
- * any bugs present are surely my fault. -DaveM
+ * any bugs present are my fault. Jozsef
*/
-/* NOTE: Arguments are modified. */
-#define __jhash_mix(a, b, c) \
+#define __rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+/* __jhash_mix - mix 3 32-bit values reversibly. */
+#define __jhash_mix(a,b,c) \
+{ \
+ a -= c; a ^= __rot(c, 4); c += b; \
+ b -= a; b ^= __rot(a, 6); a += c; \
+ c -= b; c ^= __rot(b, 8); b += a; \
+ a -= c; a ^= __rot(c,16); c += b; \
+ b -= a; b ^= __rot(a,19); a += c; \
+ c -= b; c ^= __rot(b, 4); b += a; \
+}
+
+/* __jhash_final - final mixing of 3 32-bit values (a,b,c) into c */
+#define __jhash_final(a,b,c) \
{ \
- a -= b; a -= c; a ^= (c>>13); \
- b -= c; b -= a; b ^= (a<<8); \
- c -= a; c -= b; c ^= (b>>13); \
- a -= b; a -= c; a ^= (c>>12); \
- b -= c; b -= a; b ^= (a<<16); \
- c -= a; c -= b; c ^= (b>>5); \
- a -= b; a -= c; a ^= (c>>3); \
- b -= c; b -= a; b ^= (a<<10); \
- c -= a; c -= b; c ^= (b>>15); \
+ c ^= b; c -= __rot(b,14); \
+ a ^= c; a -= __rot(c,11); \
+ b ^= a; b -= __rot(a,25); \
+ c ^= b; c -= __rot(b,16); \
+ a ^= c; a -= __rot(c,4); \
+ b ^= a; b -= __rot(a,14); \
+ c ^= b; c -= __rot(b,24); \
}
-/* The golden ration: an arbitrary value */
-#define JHASH_GOLDEN_RATIO 0x9e3779b9
+/* An arbitrary initial parameter */
+#define JHASH_GOLDEN_RATIO 0xdeadbeef
/* The most generic version, hashes an arbitrary sequence
* of bytes. No alignment or length assumptions are made about
- * the input key.
+ * the input key. The result depends on endianness.
*/
static inline u32 jhash(const void *key, u32 length, u32 initval)
{
- u32 a, b, c, len;
+ u32 a,b,c;
const u8 *k = key;
- len = length;
- a = b = JHASH_GOLDEN_RATIO;
- c = initval;
-
- while (len >= 12) {
- a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24));
- b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24));
- c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24));
-
- __jhash_mix(a,b,c);
+ /* Set up the internal state */
+ a = b = c = JHASH_GOLDEN_RATIO + length + initval;
+ /* all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12) {
+ a += (k[0] + ((u32)k[1]<<8) + ((u32)k[2]<<16) + ((u32)k[3]<<24));
+ b += (k[4] + ((u32)k[5]<<8) + ((u32)k[6]<<16) + ((u32)k[7]<<24));
+ c += (k[8] + ((u32)k[9]<<8) + ((u32)k[10]<<16) + ((u32)k[11]<<24));
+ __jhash_mix(a, b, c);
+ length -= 12;
k += 12;
- len -= 12;
}
- c += length;
- switch (len) {
- case 11: c += ((u32)k[10]<<24);
- case 10: c += ((u32)k[9]<<16);
- case 9 : c += ((u32)k[8]<<8);
- case 8 : b += ((u32)k[7]<<24);
- case 7 : b += ((u32)k[6]<<16);
- case 6 : b += ((u32)k[5]<<8);
+ /* last block: affect all 32 bits of (c) */
+ /* all the case statements fall through */
+ switch (length) {
+ case 12: c += (u32)k[11]<<24;
+ case 11: c += (u32)k[10]<<16;
+ case 10: c += (u32)k[9]<<8;
+ case 9 : c += k[8];
+ case 8 : b += (u32)k[7]<<24;
+ case 7 : b += (u32)k[6]<<16;
+ case 6 : b += (u32)k[5]<<8;
case 5 : b += k[4];
- case 4 : a += ((u32)k[3]<<24);
- case 3 : a += ((u32)k[2]<<16);
- case 2 : a += ((u32)k[1]<<8);
+ case 4 : a += (u32)k[3]<<24;
+ case 3 : a += (u32)k[2]<<16;
+ case 2 : a += (u32)k[1]<<8;
case 1 : a += k[0];
- };
-
- __jhash_mix(a,b,c);
+ __jhash_final(a, b, c);
+ case 0 :
+ break;
+ }
return c;
}
@@ -86,58 +101,57 @@ static inline u32 jhash(const void *key,
*/
static inline u32 jhash2(const u32 *k, u32 length, u32 initval)
{
- u32 a, b, c, len;
+ u32 a, b, c;
- a = b = JHASH_GOLDEN_RATIO;
- c = initval;
- len = length;
+ /* Set up the internal state */
+ a = b = c = JHASH_GOLDEN_RATIO + (length<<2) + initval;
- while (len >= 3) {
+ /* handle most of the key */
+ while (length > 3) {
a += k[0];
b += k[1];
c += k[2];
__jhash_mix(a, b, c);
- k += 3; len -= 3;
+ length -= 3;
+ k += 3;
}
- c += length * 4;
-
- switch (len) {
- case 2 : b += k[1];
- case 1 : a += k[0];
- };
-
- __jhash_mix(a,b,c);
+ /* handle the last 3 u32's */
+ /* all the case statements fall through */
+ switch (length) {
+ case 3: c += k[2];
+ case 2: b += k[1];
+ case 1: a += k[0];
+ __jhash_final(a, b, c);
+ case 0: /* case 0: nothing left to add */
+ break;
+ }
return c;
}
-
/* A special ultra-optimized versions that knows they are hashing exactly
* 3, 2 or 1 word(s).
- *
- * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
- * done at the end is not done here.
*/
static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
{
- a += JHASH_GOLDEN_RATIO;
- b += JHASH_GOLDEN_RATIO;
- c += initval;
+ a += JHASH_GOLDEN_RATIO + initval;
+ b += JHASH_GOLDEN_RATIO + initval;
+ c += JHASH_GOLDEN_RATIO + initval;
- __jhash_mix(a, b, c);
+ __jhash_final(a, b, c);
return c;
}
static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
{
- return jhash_3words(a, b, 0, initval);
+ return jhash_3words(0, a, b, initval);
}
static inline u32 jhash_1word(u32 a, u32 initval)
{
- return jhash_3words(a, 0, 0, initval);
+ return jhash_3words(0, 0, a, initval);
}
#endif /* _LINUX_JHASH_H */

View file

@ -0,0 +1,12 @@
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -602,6 +602,9 @@ else
load-$(CONFIG_CPU_CAVIUM_OCTEON) += 0xffffffff81100000
endif
+# temporary until string.h is fixed
+cflags-y += -ffreestanding
+
cflags-y += -I$(srctree)/arch/mips/include/asm/mach-generic
drivers-$(CONFIG_PCI) += arch/mips/pci/

View file

@ -0,0 +1,13 @@
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -115,8 +115,8 @@ int kmem_ptr_validate(struct kmem_cache
* to do various tricks to work around compiler limitations in order to
* ensure proper constant folding.
*/
-#define KMALLOC_SHIFT_HIGH ((MAX_ORDER + PAGE_SHIFT - 1) <= 25 ? \
- (MAX_ORDER + PAGE_SHIFT - 1) : 25)
+#define KMALLOC_SHIFT_HIGH ((MAX_ORDER + PAGE_SHIFT - 1) <= 17 ? \
+ (MAX_ORDER + PAGE_SHIFT - 1) : 17)
#define KMALLOC_MAX_SIZE (1UL << KMALLOC_SHIFT_HIGH)
#define KMALLOC_MAX_ORDER (KMALLOC_SHIFT_HIGH - PAGE_SHIFT)

View file

@ -0,0 +1,132 @@
--- a/fs/jffs2/build.c
+++ b/fs/jffs2/build.c
@@ -111,6 +111,17 @@ static int jffs2_build_filesystem(struct
dbg_fsbuild("scanned flash completely\n");
jffs2_dbg_dump_block_lists_nolock(c);
+ if (c->flags & (1 << 7)) {
+ printk("%s(): unlocking the mtd device... ", __func__);
+ if (c->mtd->unlock)
+ c->mtd->unlock(c->mtd, 0, c->mtd->size);
+ printk("done.\n");
+
+ printk("%s(): erasing all blocks after the end marker... ", __func__);
+ jffs2_erase_pending_blocks(c, -1);
+ printk("done.\n");
+ }
+
dbg_fsbuild("pass 1 starting\n");
c->flags |= JFFS2_SB_FLAG_BUILDING;
/* Now scan the directory tree, increasing nlink according to every dirent found. */
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -72,7 +72,7 @@ static int file_dirty(struct jffs2_sb_in
return ret;
if ((ret = jffs2_scan_dirty_space(c, jeb, jeb->free_size)))
return ret;
- /* Turned wasted size into dirty, since we apparently
+ /* Turned wasted size into dirty, since we apparently
think it's recoverable now. */
jeb->dirty_size += jeb->wasted_size;
c->dirty_size += jeb->wasted_size;
@@ -144,8 +144,11 @@ int jffs2_scan_medium(struct jffs2_sb_in
/* reset summary info for next eraseblock scan */
jffs2_sum_reset_collected(s);
- ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
- buf_size, s);
+ if (c->flags & (1 << 7))
+ ret = BLK_STATE_ALLFF;
+ else
+ ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
+ buf_size, s);
if (ret < 0)
goto out;
@@ -400,7 +403,7 @@ static int jffs2_scan_xref_node(struct j
if (!ref)
return -ENOMEM;
- /* BEFORE jffs2_build_xattr_subsystem() called,
+ /* BEFORE jffs2_build_xattr_subsystem() called,
* and AFTER xattr_ref is marked as a dead xref,
* ref->xid is used to store 32bit xid, xd is not used
* ref->ino is used to store 32bit inode-number, ic is not used
@@ -473,7 +476,7 @@ static int jffs2_scan_eraseblock (struct
struct jffs2_sum_marker *sm;
void *sumptr = NULL;
uint32_t sumlen;
-
+
if (!buf_size) {
/* XIP case. Just look, point at the summary if it's there */
sm = (void *)buf + c->sector_size - sizeof(*sm);
@@ -489,9 +492,9 @@ static int jffs2_scan_eraseblock (struct
buf_len = sizeof(*sm);
/* Read as much as we want into the _end_ of the preallocated buffer */
- err = jffs2_fill_scan_buf(c, buf + buf_size - buf_len,
+ err = jffs2_fill_scan_buf(c, buf + buf_size - buf_len,
jeb->offset + c->sector_size - buf_len,
- buf_len);
+ buf_len);
if (err)
return err;
@@ -510,9 +513,9 @@ static int jffs2_scan_eraseblock (struct
}
if (buf_len < sumlen) {
/* Need to read more so that the entire summary node is present */
- err = jffs2_fill_scan_buf(c, sumptr,
+ err = jffs2_fill_scan_buf(c, sumptr,
jeb->offset + c->sector_size - sumlen,
- sumlen - buf_len);
+ sumlen - buf_len);
if (err)
return err;
}
@@ -525,7 +528,7 @@ static int jffs2_scan_eraseblock (struct
if (buf_size && sumlen > buf_size)
kfree(sumptr);
- /* If it returns with a real error, bail.
+ /* If it returns with a real error, bail.
If it returns positive, that's a block classification
(i.e. BLK_STATE_xxx) so return that too.
If it returns zero, fall through to full scan. */
@@ -546,6 +549,17 @@ static int jffs2_scan_eraseblock (struct
return err;
}
+ if ((buf[0] == 0xde) &&
+ (buf[1] == 0xad) &&
+ (buf[2] == 0xc0) &&
+ (buf[3] == 0xde)) {
+ /* end of filesystem. erase everything after this point */
+ printk("%s(): End of filesystem marker found at 0x%x\n", __func__, jeb->offset);
+ c->flags |= (1 << 7);
+
+ return BLK_STATE_ALLFF;
+ }
+
/* We temporarily use 'ofs' as a pointer into the buffer/jeb */
ofs = 0;
@@ -671,7 +685,7 @@ scan_more:
scan_end = buf_len;
goto more_empty;
}
-
+
/* See how much more there is to read in this eraseblock... */
buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
if (!buf_len) {
@@ -907,7 +921,7 @@ scan_more:
D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x, wasted 0x%08x\n",
jeb->offset,jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size, jeb->wasted_size));
-
+
/* mark_node_obsolete can add to wasted !! */
if (jeb->wasted_size) {
jeb->dirty_size += jeb->wasted_size;

View file

@ -0,0 +1,56 @@
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1306,11 +1306,18 @@ static inline int skb_network_offset(con
*
* Various parts of the networking layer expect at least 16 bytes of
* headroom, you should not reduce this.
+ *
+ * This has been changed to 64 to acommodate for routing between ethernet
+ * and wireless, but only for new allocations
*/
#ifndef NET_SKB_PAD
#define NET_SKB_PAD 16
#endif
+#ifndef NET_SKB_PAD_ALLOC
+#define NET_SKB_PAD_ALLOC 64
+#endif
+
extern int ___pskb_trim(struct sk_buff *skb, unsigned int len);
static inline void __skb_trim(struct sk_buff *skb, unsigned int len)
@@ -1400,9 +1407,9 @@ static inline void __skb_queue_purge(str
static inline struct sk_buff *__dev_alloc_skb(unsigned int length,
gfp_t gfp_mask)
{
- struct sk_buff *skb = alloc_skb(length + NET_SKB_PAD, gfp_mask);
+ struct sk_buff *skb = alloc_skb(length + NET_SKB_PAD_ALLOC, gfp_mask);
if (likely(skb))
- skb_reserve(skb, NET_SKB_PAD);
+ skb_reserve(skb, NET_SKB_PAD_ALLOC);
return skb;
}
@@ -1475,7 +1482,7 @@ static inline int __skb_cow(struct sk_bu
delta = headroom - skb_headroom(skb);
if (delta || cloned)
- return pskb_expand_head(skb, ALIGN(delta, NET_SKB_PAD), 0,
+ return pskb_expand_head(skb, ALIGN(delta, NET_SKB_PAD_ALLOC), 0,
GFP_ATOMIC);
return 0;
}
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -320,9 +320,9 @@ struct sk_buff *__netdev_alloc_skb(struc
int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1;
struct sk_buff *skb;
- skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask, 0, node);
+ skb = __alloc_skb(length + NET_SKB_PAD_ALLOC, gfp_mask, 0, node);
if (likely(skb)) {
- skb_reserve(skb, NET_SKB_PAD);
+ skb_reserve(skb, NET_SKB_PAD_ALLOC);
skb->dev = dev;
}
return skb;

View file

@ -0,0 +1,9 @@
--- /dev/null
+++ b/include/asm-powerpc/segment.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_SEGMENT_H
+#define _ASM_SEGMENT_H
+
+/* Only here because we have some old header files that expect it.. */
+
+#endif /* _ASM_SEGMENT_H */

View file

@ -0,0 +1,42 @@
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -1890,7 +1890,7 @@ static const struct rtl_cfg_info {
.hw_start = rtl_hw_start_8169,
.region = 1,
.align = 0,
- .intr_event = SYSErr | LinkChg | RxOverflow |
+ .intr_event = LinkChg | RxOverflow |
RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
.napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
.features = RTL_FEATURE_GMII
@@ -1899,7 +1899,7 @@ static const struct rtl_cfg_info {
.hw_start = rtl_hw_start_8168,
.region = 2,
.align = 8,
- .intr_event = SYSErr | LinkChg | RxOverflow |
+ .intr_event = LinkChg | RxOverflow |
TxErr | TxOK | RxOK | RxErr,
.napi_event = TxErr | TxOK | RxOK | RxOverflow,
.features = RTL_FEATURE_GMII | RTL_FEATURE_MSI
@@ -1908,7 +1908,7 @@ static const struct rtl_cfg_info {
.hw_start = rtl_hw_start_8101,
.region = 2,
.align = 8,
- .intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout |
+ .intr_event = LinkChg | RxOverflow | PCSTimeout |
RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
.napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
.features = RTL_FEATURE_MSI
@@ -3582,10 +3582,12 @@ static irqreturn_t rtl8169_interrupt(int
goto out;
}
+#if 0
if (unlikely(status & SYSErr)) {
rtl8169_pcierr_interrupt(dev);
goto out;
}
+#endif
if (status & LinkChg)
rtl8169_check_link_status(dev, tp, ioaddr);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,143 @@
--- a/fs/mini_fo/main.c
+++ b/fs/mini_fo/main.c
@@ -79,6 +79,7 @@ mini_fo_tri_interpose(dentry_t *hidden_d
* of the new inode's fields
*/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
/*
* original: inode = iget(sb, hidden_inode->i_ino);
*/
@@ -87,6 +88,13 @@ mini_fo_tri_interpose(dentry_t *hidden_d
err = -EACCES; /* should be impossible??? */
goto out;
}
+#else
+ inode = mini_fo_iget(sb, iunique(sb, 25));
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ goto out;
+ }
+#endif
/*
* interpose the inode if not already interposed
@@ -184,9 +192,9 @@ mini_fo_parse_options(super_block_t *sb,
hidden_root = ERR_PTR(err);
goto out;
}
- hidden_root = nd.dentry;
- stopd(sb)->base_dir_dentry = nd.dentry;
- stopd(sb)->hidden_mnt = nd.mnt;
+ hidden_root = nd_get_dentry(&nd);
+ stopd(sb)->base_dir_dentry = nd_get_dentry(&nd);
+ stopd(sb)->hidden_mnt = nd_get_mnt(&nd);
} else if(!strncmp("sto=", options, 4)) {
/* parse the storage dir */
@@ -204,9 +212,9 @@ mini_fo_parse_options(super_block_t *sb,
hidden_root2 = ERR_PTR(err);
goto out;
}
- hidden_root2 = nd2.dentry;
- stopd(sb)->storage_dir_dentry = nd2.dentry;
- stopd(sb)->hidden_mnt2 = nd2.mnt;
+ hidden_root2 = nd_get_dentry(&nd2);
+ stopd(sb)->storage_dir_dentry = nd_get_dentry(&nd2);
+ stopd(sb)->hidden_mnt2 = nd_get_mnt(&nd2);
stohs2(sb) = hidden_root2->d_sb;
/* validate storage dir, this is done in
--- a/fs/mini_fo/mini_fo.h
+++ b/fs/mini_fo/mini_fo.h
@@ -302,6 +302,10 @@ extern int mini_fo_tri_interpose(dentry_
extern int mini_fo_cp_cont(dentry_t *tgt_dentry, struct vfsmount *tgt_mnt,
dentry_t *src_dentry, struct vfsmount *src_mnt);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
+extern struct inode *mini_fo_iget(struct super_block *sb, unsigned long ino);
+#endif
+
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
extern int mini_fo_create(inode_t *dir, dentry_t *dentry, int mode, struct nameidata *nd);
@@ -501,6 +505,29 @@ static inline void double_unlock(struct
#endif /* if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) */
#endif /* __KERNEL__ */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
+static inline dentry_t *nd_get_dentry(struct nameidata *nd)
+{
+ return (nd->path.dentry);
+}
+
+static inline struct vfsmount *nd_get_mnt(struct nameidata *nd)
+{
+ return (nd->path.mnt);
+}
+#else
+static inline dentry_t *nd_get_dentry(struct nameidata *nd)
+{
+ return (nd->dentry);
+}
+
+static inline struct vfsmount *nd_get_mnt(struct nameidata *nd)
+{
+ return (nd->mnt);
+}
+#endif
+
/*
* Definitions for user and kernel code
*/
--- a/fs/mini_fo/super.c
+++ b/fs/mini_fo/super.c
@@ -262,10 +262,31 @@ mini_fo_umount_begin(super_block_t *sb)
}
#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
+struct inode *
+mini_fo_iget(struct super_block *sb, unsigned long ino)
+{
+ struct inode *inode;
+
+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+
+ if (!(inode->i_state & I_NEW))
+ return inode;
+
+ mini_fo_read_inode(inode);
+
+ unlock_new_inode(inode);
+ return inode;
+}
+#endif /* if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25) */
struct super_operations mini_fo_sops =
{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
read_inode: mini_fo_read_inode,
+#endif
#if defined(FIST_DEBUG) || defined(FIST_FILTER_SCA)
write_inode: mini_fo_write_inode,
#endif /* defined(FIST_DEBUG) || defined(FIST_FILTER_SCA) */
--- a/fs/mini_fo/aux.c
+++ b/fs/mini_fo/aux.c
@@ -164,11 +164,11 @@ dentry_t *bpath_walk(super_block_t *sb,
err = vfs_path_lookup(mnt->mnt_root, mnt, bpath+1, 0, &nd);
/* validate */
- if (err || !nd.dentry || !nd.dentry->d_inode) {
+ if (err || !nd_get_dentry(&nd) || !nd_get_dentry(&nd)->d_inode) {
printk(KERN_CRIT "mini_fo: bpath_walk: path_walk failed.\n");
return NULL;
}
- return nd.dentry;
+ return nd_get_dentry(&nd);
}

View file

@ -0,0 +1,66 @@
--- a/fs/mini_fo/meta.c
+++ b/fs/mini_fo/meta.c
@@ -442,6 +442,11 @@ int meta_write_d_entry(dentry_t *dentry,
S_IRUSR | S_IWUSR);
#endif
}
+
+ /* $%& err, is this correct? */
+ meta_mnt = stopd(dentry->d_inode->i_sb)->hidden_mnt2;
+ mntget(meta_mnt);
+
/* open META-file for writing */
meta_file = dentry_open(meta_dentry, meta_mnt, 0x1);
if(!meta_file || IS_ERR(meta_file)) {
@@ -535,6 +540,11 @@ int meta_write_r_entry(dentry_t *dentry,
meta_dentry, S_IRUSR | S_IWUSR);
#endif
}
+
+ /* $%& err, is this correct? */
+ meta_mnt = stopd(dentry->d_inode->i_sb)->hidden_mnt2;
+ mntget(meta_mnt);
+
/* open META-file for writing */
meta_file = dentry_open(meta_dentry, meta_mnt, 0x1);
if(!meta_file || IS_ERR(meta_file)) {
@@ -671,14 +681,16 @@ int meta_sync_d_list(dentry_t *dentry, i
}
}
+ /* $%& err, is this correct? */
+ meta_mnt = stopd(dentry->d_inode->i_sb)->hidden_mnt2;
+ mntget(meta_mnt);
+
/* open META-file for writing */
meta_file = dentry_open(meta_dentry, meta_mnt, 0x1);
if(!meta_file || IS_ERR(meta_file)) {
printk(KERN_CRIT "mini_fo: meta_sync_d_list: \
ERROR opening meta file.\n");
- /* we don't mntget so we dont't mntput (for now)
- * mntput(meta_mnt);
- */
+ mntput(meta_mnt);
dput(meta_dentry);
err = -1;
goto out;
@@ -811,14 +823,16 @@ int meta_sync_r_list(dentry_t *dentry, i
}
}
+ /* $%& err, is this correct? */
+ meta_mnt = stopd(dentry->d_inode->i_sb)->hidden_mnt2;
+ mntget(meta_mnt);
+
/* open META-file for writing */
meta_file = dentry_open(meta_dentry, meta_mnt, 0x1);
if(!meta_file || IS_ERR(meta_file)) {
printk(KERN_CRIT "mini_fo: meta_sync_r_list: \
ERROR opening meta file.\n");
- /* we don't mntget so we dont't mntput (for now)
- * mntput(meta_mnt);
- */
+ mntput(meta_mnt);
dput(meta_dentry);
err = -1;
goto out;

View file

@ -0,0 +1,37 @@
--- a/fs/mini_fo/super.c
+++ b/fs/mini_fo/super.c
@@ -84,6 +84,7 @@ mini_fo_write_inode(inode_t *inode, int
#endif /* defined(FIST_DEBUG) || defined(FIST_FILTER_SCA) */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
STATIC void
mini_fo_put_inode(inode_t *inode)
{
@@ -99,6 +100,7 @@ mini_fo_put_inode(inode_t *inode)
if (atomic_read(&inode->i_count) == 1)
inode->i_nlink = 0;
}
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) */
#if defined(FIST_DEBUG) || defined(FIST_FILTER_SCA)
@@ -238,7 +240,7 @@ mini_fo_clear_inode(inode_t *inode)
* dies.
*/
STATIC void
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26))
mini_fo_umount_begin(struct vfsmount *mnt, int flags)
{
struct vfsmount *hidden_mnt;
@@ -290,7 +292,9 @@ struct super_operations mini_fo_sops =
#if defined(FIST_DEBUG) || defined(FIST_FILTER_SCA)
write_inode: mini_fo_write_inode,
#endif /* defined(FIST_DEBUG) || defined(FIST_FILTER_SCA) */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
put_inode: mini_fo_put_inode,
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) */
#if defined(FIST_DEBUG) || defined(FIST_FILTER_SCA)
delete_inode: mini_fo_delete_inode,
#endif /* defined(FIST_DEBUG) || defined(FIST_FILTER_SCA) */

View file

@ -0,0 +1,41 @@
--- a/fs/mini_fo/inode.c
+++ b/fs/mini_fo/inode.c
@@ -439,7 +439,7 @@ mini_fo_symlink(inode_t *dir, dentry_t *
int err=0;
dentry_t *hidden_sto_dentry;
dentry_t *hidden_sto_dir_dentry;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27))
umode_t mode;
#endif
@@ -466,7 +466,7 @@ mini_fo_symlink(inode_t *dir, dentry_t *
down(&hidden_sto_dir_dentry->d_inode->i_sem);
#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27))
mode = S_IALLUGO;
err = vfs_symlink(hidden_sto_dir_dentry->d_inode,
hidden_sto_dentry, symname, mode);
@@ -1128,7 +1128,7 @@ void mini_fo_put_link(struct dentry *den
#endif
STATIC int
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27))
mini_fo_permission(inode_t *inode, int mask, struct nameidata *nd)
#else
mini_fo_permission(inode_t *inode, int mask)
@@ -1150,8 +1150,9 @@ mini_fo_permission(inode_t *inode, int m
* if (err)
* goto out;
*/
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+ err = inode_permission(hidden_inode, mask);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
err = permission(hidden_inode, mask, nd);
#else
err = permission(hidden_inode, mask);

View file

@ -0,0 +1,96 @@
--- a/fs/mini_fo/aux.c
+++ b/fs/mini_fo/aux.c
@@ -236,7 +236,7 @@ int mini_fo_cp_cont(dentry_t *tgt_dentry
mntget(src_mnt);
/* open file write only */
- tgt_file = dentry_open(tgt_dentry, tgt_mnt, 0x1);
+ tgt_file = dentry_open(tgt_dentry, tgt_mnt, 0x1, current_cred());
if(!tgt_file || IS_ERR(tgt_file)) {
printk(KERN_CRIT "mini_fo_cp_cont: ERROR opening target file.\n");
err = PTR_ERR(tgt_file);
@@ -244,7 +244,7 @@ int mini_fo_cp_cont(dentry_t *tgt_dentry
}
/* open file read only */
- src_file = dentry_open(src_dentry, src_mnt, 0x0);
+ src_file = dentry_open(src_dentry, src_mnt, 0x0, current_cred());
if(!src_file || IS_ERR(src_file)) {
printk(KERN_CRIT "mini_fo_cp_cont: ERROR opening source file.\n");
err = PTR_ERR(src_file);
--- a/fs/mini_fo/file.c
+++ b/fs/mini_fo/file.c
@@ -437,7 +437,7 @@ mini_fo_open(inode_t *inode, file_t *fil
mntget(stopd(inode->i_sb)->hidden_mnt);
hidden_file = dentry_open(hidden_dentry,
stopd(inode->i_sb)->hidden_mnt,
- hidden_flags);
+ hidden_flags, file->f_cred);
if (IS_ERR(hidden_file)) {
err = PTR_ERR(hidden_file);
dput(hidden_dentry);
@@ -479,7 +479,7 @@ mini_fo_open(inode_t *inode, file_t *fil
mntget(stopd(inode->i_sb)->hidden_mnt);
hidden_file = dentry_open(hidden_dentry,
stopd(inode->i_sb)->hidden_mnt,
- hidden_flags);
+ hidden_flags, file->f_cred);
if (IS_ERR(hidden_file)) {
err = PTR_ERR(hidden_file);
dput(hidden_dentry);
@@ -512,7 +512,7 @@ mini_fo_open(inode_t *inode, file_t *fil
mntget(stopd(inode->i_sb)->hidden_mnt2);
hidden_sto_file = dentry_open(hidden_sto_dentry,
stopd(inode->i_sb)->hidden_mnt2,
- hidden_flags);
+ hidden_flags, file->f_cred);
/* dentry_open dputs the dentry if it fails */
if (IS_ERR(hidden_sto_file)) {
--- a/fs/mini_fo/meta.c
+++ b/fs/mini_fo/meta.c
@@ -56,7 +56,7 @@ int meta_build_lists(dentry_t *dentry)
/* open META-file for reading */
- meta_file = dentry_open(meta_dentry, meta_mnt, 0x0);
+ meta_file = dentry_open(meta_dentry, meta_mnt, 0x0, current_cred());
if(!meta_file || IS_ERR(meta_file)) {
printk(KERN_CRIT "mini_fo: meta_build_lists: \
ERROR opening META file.\n");
@@ -448,7 +448,7 @@ int meta_write_d_entry(dentry_t *dentry,
mntget(meta_mnt);
/* open META-file for writing */
- meta_file = dentry_open(meta_dentry, meta_mnt, 0x1);
+ meta_file = dentry_open(meta_dentry, meta_mnt, 0x1, current_cred());
if(!meta_file || IS_ERR(meta_file)) {
printk(KERN_CRIT "mini_fo: meta_write_d_entry: \
ERROR opening meta file.\n");
@@ -546,7 +546,7 @@ int meta_write_r_entry(dentry_t *dentry,
mntget(meta_mnt);
/* open META-file for writing */
- meta_file = dentry_open(meta_dentry, meta_mnt, 0x1);
+ meta_file = dentry_open(meta_dentry, meta_mnt, 0x1, current_cred());
if(!meta_file || IS_ERR(meta_file)) {
printk(KERN_CRIT "mini_fo: meta_write_r_entry: \
ERROR opening meta file.\n");
@@ -686,7 +686,7 @@ int meta_sync_d_list(dentry_t *dentry, i
mntget(meta_mnt);
/* open META-file for writing */
- meta_file = dentry_open(meta_dentry, meta_mnt, 0x1);
+ meta_file = dentry_open(meta_dentry, meta_mnt, 0x1, current_cred());
if(!meta_file || IS_ERR(meta_file)) {
printk(KERN_CRIT "mini_fo: meta_sync_d_list: \
ERROR opening meta file.\n");
@@ -828,7 +828,7 @@ int meta_sync_r_list(dentry_t *dentry, i
mntget(meta_mnt);
/* open META-file for writing */
- meta_file = dentry_open(meta_dentry, meta_mnt, 0x1);
+ meta_file = dentry_open(meta_dentry, meta_mnt, 0x1, current_cred());
if(!meta_file || IS_ERR(meta_file)) {
printk(KERN_CRIT "mini_fo: meta_sync_r_list: \
ERROR opening meta file.\n");

View file

@ -0,0 +1,42 @@
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -29,7 +29,8 @@ u64 uevent_seqnum;
char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
static DEFINE_SPINLOCK(sequence_lock);
#if defined(CONFIG_NET)
-static struct sock *uevent_sock;
+struct sock *uevent_sock = NULL;
+EXPORT_SYMBOL_GPL(uevent_sock);
#endif
/* the strings here must match the enum in include/linux/kobject.h */
@@ -42,6 +43,18 @@ static const char *kobject_actions[] = {
[KOBJ_OFFLINE] = "offline",
};
+u64 uevent_next_seqnum(void)
+{
+ u64 seq;
+
+ spin_lock(&sequence_lock);
+ seq = ++uevent_seqnum;
+ spin_unlock(&sequence_lock);
+
+ return seq;
+}
+EXPORT_SYMBOL_GPL(uevent_next_seqnum);
+
/**
* kobject_action_type - translate action string to numeric type
*
@@ -194,9 +207,7 @@ int kobject_uevent_env(struct kobject *k
kobj->state_remove_uevent_sent = 1;
/* we will send an event, so request a new sequence number */
- spin_lock(&sequence_lock);
- seq = ++uevent_seqnum;
- spin_unlock(&sequence_lock);
+ seq = uevent_next_seqnum();
retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq);
if (retval)
goto exit;

View file

@ -0,0 +1,11 @@
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -7,7 +7,7 @@ config SND_PCM
select SND_TIMER
config SND_HWDEP
- tristate
+ tristate "Sound hardware support"
config SND_RAWMIDI
tristate

View file

@ -0,0 +1,11 @@
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1211,7 +1211,7 @@ static unsigned long vma_dump_size(struc
if (FILTER(ELF_HEADERS) &&
vma->vm_pgoff == 0 && (vma->vm_flags & VM_READ)) {
u32 __user *header = (u32 __user *) vma->vm_start;
- u32 word;
+ u32 word = 0;
mm_segment_t fs = get_fs();
/*
* Doing it this way gets the constant folded by GCC.

View file

@ -0,0 +1,132 @@
This patch allows the user to specify desired packet types (outgoing,
broadcast, unicast, etc.) on packet sockets via setsockopt.
This can reduce the load in situations where only a limited number
of packet types are necessary
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
--- a/include/linux/if_packet.h
+++ b/include/linux/if_packet.h
@@ -31,6 +31,8 @@ struct sockaddr_ll
/* These ones are invisible by user level */
#define PACKET_LOOPBACK 5 /* MC/BRD frame looped back */
#define PACKET_FASTROUTE 6 /* Fastrouted frame */
+#define PACKET_MASK_ANY 0xffffffff /* mask for packet type bits */
+
/* Packet socket options */
@@ -46,6 +48,7 @@ struct sockaddr_ll
#define PACKET_VERSION 10
#define PACKET_HDRLEN 11
#define PACKET_RESERVE 12
+#define PACKET_RECV_TYPE 13
struct tpacket_stats
{
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -192,6 +192,7 @@ struct packet_sock {
unsigned int tp_hdrlen;
unsigned int tp_reserve;
#endif
+ unsigned int pkt_type;
};
struct packet_skb_cb {
@@ -282,6 +283,7 @@ static int packet_rcv_spkt(struct sk_buf
{
struct sock *sk;
struct sockaddr_pkt *spkt;
+ struct packet_sock *po;
/*
* When we registered the protocol we saved the socket in the data
@@ -289,6 +291,7 @@ static int packet_rcv_spkt(struct sk_buf
*/
sk = pt->af_packet_priv;
+ po = pkt_sk(sk);
/*
* Yank back the headers [hope the device set this
@@ -301,7 +304,7 @@ static int packet_rcv_spkt(struct sk_buf
* so that this procedure is noop.
*/
- if (skb->pkt_type == PACKET_LOOPBACK)
+ if (!(po->pkt_type & (1 << skb->pkt_type)))
goto out;
if (dev_net(dev) != sock_net(sk))
@@ -486,12 +489,12 @@ static int packet_rcv(struct sk_buff *sk
int skb_len = skb->len;
unsigned int snaplen, res;
- if (skb->pkt_type == PACKET_LOOPBACK)
- goto drop;
-
sk = pt->af_packet_priv;
po = pkt_sk(sk);
+ if (!(po->pkt_type & (1 << skb->pkt_type)))
+ goto drop;
+
if (dev_net(dev) != sock_net(sk))
goto drop;
@@ -608,12 +611,12 @@ static int tpacket_rcv(struct sk_buff *s
struct timeval tv;
struct timespec ts;
- if (skb->pkt_type == PACKET_LOOPBACK)
- goto drop;
-
sk = pt->af_packet_priv;
po = pkt_sk(sk);
+ if (!(po->pkt_type & (1 << skb->pkt_type)))
+ goto drop;
+
if (dev_net(dev) != sock_net(sk))
goto drop;
@@ -1073,6 +1076,7 @@ static int packet_create(struct net *net
spin_lock_init(&po->bind_lock);
mutex_init(&po->pg_vec_lock);
po->prot_hook.func = packet_rcv;
+ po->pkt_type = PACKET_MASK_ANY & ~(1 << PACKET_LOOPBACK);
if (sock->type == SOCK_PACKET)
po->prot_hook.func = packet_rcv_spkt;
@@ -1413,6 +1417,16 @@ packet_setsockopt(struct socket *sock, i
ret = packet_mc_drop(sk, &mreq);
return ret;
}
+ case PACKET_RECV_TYPE:
+ {
+ unsigned int val;
+ if (optlen != sizeof(val))
+ return -EINVAL;
+ if (copy_from_user(&val, optval, sizeof(val)))
+ return -EFAULT;
+ po->pkt_type = val & ~PACKET_LOOPBACK;
+ return 0;
+ }
#ifdef CONFIG_PACKET_MMAP
case PACKET_RX_RING:
@@ -1544,6 +1558,13 @@ static int packet_getsockopt(struct sock
data = &val;
break;
+ case PACKET_RECV_TYPE:
+ if (len > sizeof(unsigned int))
+ len = sizeof(unsigned int);
+ val = po->pkt_type;
+
+ data = &val;
+ break;
#ifdef CONFIG_PACKET_MMAP
case PACKET_VERSION:
if (len > sizeof(int))

View file

@ -0,0 +1,18 @@
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -223,4 +223,8 @@ config LEDS_TRIGGER_DEFAULT_ON
This allows LEDs to be initialised in the ON state.
If unsure, say Y.
+config LEDS_TRIGGER_MORSE
+ tristate "LED Morse Trigger"
+ depends on LEDS_TRIGGERS
+
endif # NEW_LEDS
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -31,3 +31,4 @@ obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += l
obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o
obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
+obj-$(CONFIG_LEDS_TRIGGER_MORSE) += ledtrig-morse.o

View file

@ -0,0 +1,21 @@
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -227,4 +227,11 @@ config LEDS_TRIGGER_MORSE
tristate "LED Morse Trigger"
depends on LEDS_TRIGGERS
+config LEDS_TRIGGER_NETDEV
+ tristate "LED Netdev Trigger"
+ depends on LEDS_TRIGGERS
+ help
+ This allows LEDs to be controlled by network device activity.
+ If unsure, say Y.
+
endif # NEW_LEDS
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -32,3 +32,4 @@ obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) +=
obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o
obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
obj-$(CONFIG_LEDS_TRIGGER_MORSE) += ledtrig-morse.o
+obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o

View file

@ -0,0 +1,30 @@
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -227,4 +227,20 @@ config INPUT_PCF50633_PMU
Say Y to include support for delivering PMU events via input
layer on NXP PCF50633.
+config INPUT_GPIO_BUTTONS
+ tristate "Polled GPIO buttons interface"
+ depends on GENERIC_GPIO
+ select INPUT_POLLDEV
+ help
+ This driver implements support for buttons connected
+ to GPIO pins of various CPUs (and some other chips).
+
+ Say Y here if your device has buttons connected
+ directly to such GPIO pins. Your board-specific
+ setup logic must also provide a platform device,
+ with configuration data saying which GPIOs are used.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gpio-buttons.
+
endif
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -22,3 +22,4 @@ obj-$(CONFIG_INPUT_UINPUT) += uinput.o
obj-$(CONFIG_INPUT_APANEL) += apanel.o
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o
+obj-$(CONFIG_INPUT_GPIO_BUTTONS) += gpio_buttons.o

View file

@ -0,0 +1,26 @@
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -1016,6 +1016,13 @@ config CS5535_GPIO
If compiled as a module, it will be called cs5535_gpio.
+config GPIO_DEVICE
+ tristate "GPIO device support"
+ depends on GENERIC_GPIO
+ help
+ Say Y to enable Linux GPIO device support. This allows control of
+ GPIO pins using a character device
+
config GPIO_VR41XX
tristate "NEC VR4100 series General-purpose I/O Unit support"
depends on CPU_VR41XX
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -94,6 +94,7 @@ obj-$(CONFIG_SCx200_GPIO) += scx200_gpio
obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o
obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o
obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o
+obj-$(CONFIG_GPIO_DEVICE) += gpio_dev.o
obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o
obj-$(CONFIG_GPIO_TB0219) += tb0219.o
obj-$(CONFIG_TELCLOCK) += tlclk.o

View file

@ -0,0 +1,134 @@
Subject: [PATCH 2/3] I2C: at24: add kernel interface for reading/writing EEPROM
Date: Monday 25 August 2008
From: Kevin Hilman <khilman@deeprootsystems.com>
To: davinci-linux-open-source@linux.davincidsp.com
This patch adds an interface by which other kernel code can read/write
detected EEPROM.
The platform code registers a 'setup' callback with the
at24_platform_data. When the at24 driver detects an EEPROM, it fills
out the read and write functions of at24_iface and calls the setup
callback. The platform code can then use the read/write functions in
the at24_iface struct for reading and writing the EEPROM.
Original idea, review and updates by David Brownell <david-b@pacbell.net>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
drivers/i2c/chips/at24.c | 42 +++++++++++++++++++++++++++++++++++-------
include/linux/i2c/at24.h | 10 ++++++++++
2 files changed, 45 insertions(+), 7 deletions(-)
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -53,6 +53,7 @@
struct at24_data {
struct at24_platform_data chip;
+ struct at24_iface iface;
bool use_smbus;
/*
@@ -264,13 +265,6 @@ static ssize_t at24_bin_read(struct kobj
/*
- * REVISIT: export at24_bin{read,write}() to let other kernel code use
- * eeprom data. For example, it might hold a board's Ethernet address, or
- * board-specific calibration data generated on the manufacturing floor.
- */
-
-
-/*
* Note that if the hardware write-protect pin is pulled high, the whole
* chip is normally write protected. But there are plenty of product
* variants here, including OTP fuses and partial chip protect.
@@ -386,6 +380,30 @@ static ssize_t at24_bin_write(struct kob
/*-------------------------------------------------------------------------*/
+/*
+ * This lets other kernel code access the eeprom data. For example, it
+ * might hold a board's Ethernet address, or board-specific calibration
+ * data generated on the manufacturing floor.
+ */
+
+static ssize_t at24_iface_read(struct at24_iface *iface, char *buf,
+ off_t offset, size_t count)
+{
+ struct at24_data *at24 = container_of(iface, struct at24_data, iface);
+
+ return at24_eeprom_read(at24, buf, offset, count);
+}
+
+static ssize_t at24_iface_write(struct at24_iface *iface, char *buf,
+ off_t offset, size_t count)
+{
+ struct at24_data *at24 = container_of(iface, struct at24_data, iface);
+
+ return at24_eeprom_write(at24, buf, offset, count);
+}
+
+/*-------------------------------------------------------------------------*/
+
static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct at24_platform_data chip;
@@ -413,6 +431,9 @@ static int at24_probe(struct i2c_client
* is recommended anyhow.
*/
chip.page_size = 1;
+
+ chip.setup = NULL;
+ chip.context = NULL;
}
if (!is_power_of_2(chip.byte_len))
@@ -449,6 +470,9 @@ static int at24_probe(struct i2c_client
goto err_out;
}
+ at24->iface.read = at24_iface_read;
+ at24->iface.write = at24_iface_write;
+
mutex_init(&at24->lock);
at24->use_smbus = use_smbus;
at24->chip = chip;
@@ -520,6 +544,10 @@ static int at24_probe(struct i2c_client
at24->write_max,
use_smbus ? ", use_smbus" : "");
+ /* export data to kernel code */
+ if (chip.setup)
+ chip.setup(&at24->iface, chip.context);
+
return 0;
err_clients:
--- a/include/linux/i2c/at24.h
+++ b/include/linux/i2c/at24.h
@@ -15,6 +15,13 @@
* is bigger than what the chip actually supports!
*/
+struct at24_iface {
+ ssize_t (*read)(struct at24_iface *, char *buf, off_t offset,
+ size_t count);
+ ssize_t (*write)(struct at24_iface *, char *buf, off_t offset,
+ size_t count);
+};
+
struct at24_platform_data {
u32 byte_len; /* size (sum of all addr) */
u16 page_size; /* for writes */
@@ -23,6 +30,9 @@ struct at24_platform_data {
#define AT24_FLAG_READONLY 0x40 /* sysfs-entry will be read-only */
#define AT24_FLAG_IRUGO 0x20 /* sysfs-entry will be world-readable */
#define AT24_FLAG_TAKE8ADDR 0x10 /* take always 8 addresses (24c00) */
+
+ int (*setup)(struct at24_iface *, void *context);
+ void *context;
};
#endif /* _LINUX_AT24_H */

View file

@ -0,0 +1,17 @@
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -223,6 +223,7 @@ source "fs/qnx4/Kconfig"
source "fs/romfs/Kconfig"
source "fs/sysv/Kconfig"
source "fs/ufs/Kconfig"
+source "fs/yaffs2/Kconfig"
endif # MISC_FILESYSTEMS
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -125,3 +125,4 @@ obj-$(CONFIG_DEBUG_FS) += debugfs/
obj-$(CONFIG_OCFS2_FS) += ocfs2/
obj-$(CONFIG_BTRFS_FS) += btrfs/
obj-$(CONFIG_GFS2_FS) += gfs2/
+obj-$(CONFIG_YAFFS_FS) += yaffs2/

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,83 @@
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -299,6 +299,50 @@ int phy_ethtool_gset(struct phy_device *
}
EXPORT_SYMBOL(phy_ethtool_gset);
+int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr)
+{
+ u32 cmd;
+ int tmp;
+ struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+ struct ethtool_value edata = { ETHTOOL_GLINK };
+
+ if (get_user(cmd, (u32 *) useraddr))
+ return -EFAULT;
+
+ switch (cmd) {
+ case ETHTOOL_GSET:
+ phy_ethtool_gset(phydev, &ecmd);
+ if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+ return -EFAULT;
+ return 0;
+
+ case ETHTOOL_SSET:
+ if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+ return -EFAULT;
+ return phy_ethtool_sset(phydev, &ecmd);
+
+ case ETHTOOL_NWAY_RST:
+ /* if autoneg is off, it's an error */
+ tmp = phy_read(phydev, MII_BMCR);
+ if (tmp & BMCR_ANENABLE) {
+ tmp |= (BMCR_ANRESTART);
+ phy_write(phydev, MII_BMCR, tmp);
+ return 0;
+ }
+ return -EINVAL;
+
+ case ETHTOOL_GLINK:
+ edata.data = (phy_read(phydev,
+ MII_BMSR) & BMSR_LSTATUS) ? 1 : 0;
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ return 0;
+ }
+
+ return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL(phy_ethtool_ioctl);
+
/**
* phy_mii_ioctl - generic PHY MII ioctl interface
* @phydev: the phy_device struct
@@ -355,8 +399,8 @@ int phy_mii_ioctl(struct phy_device *phy
}
phy_write(phydev, mii_data->reg_num, val);
-
- if (mii_data->reg_num == MII_BMCR
+
+ if (mii_data->reg_num == MII_BMCR
&& val & BMCR_RESET
&& phydev->drv->config_init) {
phy_scan_fixups(phydev);
@@ -476,7 +520,7 @@ static void phy_force_reduction(struct p
int idx;
idx = phy_find_setting(phydev->speed, phydev->duplex);
-
+
idx++;
idx = phy_find_valid(idx, phydev->supported);
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -478,6 +478,7 @@ void phy_start_machine(struct phy_device
void phy_stop_machine(struct phy_device *phydev);
int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);
int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);
+int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr);
int phy_mii_ioctl(struct phy_device *phydev,
struct mii_ioctl_data *mii_data, int cmd);
int phy_start_interrupts(struct phy_device *phydev);

View file

@ -0,0 +1,24 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -82,6 +82,11 @@ config LSI_ET1011C_PHY
---help---
Supports the LSI ET1011C PHY.
+config ADM6996_PHY
+ tristate "Driver for ADM6996 switches"
+ ---help---
+ Currently supports the ADM6996F switch
+
config FIXED_PHY
bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
depends on PHYLIB=y
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_SMSC_PHY) += smsc.o
obj-$(CONFIG_VITESSE_PHY) += vitesse.o
obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
obj-$(CONFIG_ICPLUS_PHY) += icplus.o
+obj-$(CONFIG_ADM6996_PHY) += adm6996.o
obj-$(CONFIG_REALTEK_PHY) += realtek.o
obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
obj-$(CONFIG_FIXED_PHY) += fixed.o

View file

@ -0,0 +1,63 @@
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -143,6 +143,18 @@ int phy_scan_fixups(struct phy_device *p
}
EXPORT_SYMBOL(phy_scan_fixups);
+static int generic_receive_skb(struct sk_buff *skb)
+{
+ skb->protocol = eth_type_trans(skb, skb->dev);
+ return netif_receive_skb(skb);
+}
+
+static int generic_rx(struct sk_buff *skb)
+{
+ skb->protocol = eth_type_trans(skb, skb->dev);
+ return netif_rx(skb);
+}
+
struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
{
struct phy_device *dev;
@@ -168,6 +180,8 @@ struct phy_device* phy_device_create(str
dev->bus = bus;
dev->state = PHY_DOWN;
+ dev->netif_receive_skb = &generic_receive_skb;
+ dev->netif_rx = &generic_rx;
mutex_init(&dev->lock);
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -326,6 +326,20 @@ struct phy_device {
void (*adjust_link)(struct net_device *dev);
void (*adjust_state)(struct net_device *dev);
+
+ /*
+ * By default these point to the original functions
+ * with the same name. adding them to the phy_device
+ * allows the phy driver to override them for packet
+ * mangling if the ethernet driver supports it
+ * This is required to support some really horrible
+ * switches such as the Marvell 88E6060
+ */
+ int (*netif_receive_skb)(struct sk_buff *skb);
+ int (*netif_rx)(struct sk_buff *skb);
+
+ /* alignment offset for packets */
+ int pkt_align;
};
#define to_phy_device(d) container_of(d, struct phy_device, dev)
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -747,6 +747,7 @@ struct net_device
void *ax25_ptr; /* AX.25 specific data */
struct wireless_dev *ieee80211_ptr; /* IEEE 802.11 specific data,
assign before registering */
+ void *phy_ptr; /* PHY device specific data */
/*
* Cache line mostly used on receive path (including eth_type_trans())

View file

@ -0,0 +1,25 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -13,6 +13,12 @@ menuconfig PHYLIB
if PHYLIB
+config SWCONFIG
+ tristate "Switch configuration API"
+ ---help---
+ Switch configuration API using netlink. This allows
+ you to configure the VLAN features of certain switches.
+
comment "MII PHY device drivers"
config MARVELL_PHY
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -3,6 +3,7 @@
libphy-objs := phy.o phy_device.o mdio_bus.o
obj-$(CONFIG_PHYLIB) += libphy.o
+obj-$(CONFIG_SWCONFIG) += swconfig.o
obj-$(CONFIG_MARVELL_PHY) += marvell.o
obj-$(CONFIG_DAVICOM_PHY) += davicom.o
obj-$(CONFIG_CICADA_PHY) += cicada.o

View file

@ -0,0 +1,22 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -93,6 +93,9 @@ config ADM6996_PHY
---help---
Currently supports the ADM6996F switch
+config MVSWITCH_PHY
+ tristate "Driver for Marvell 88E6060 switches"
+
config FIXED_PHY
bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
depends on PHYLIB=y
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_VITESSE_PHY) += vitesse.o
obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
obj-$(CONFIG_ICPLUS_PHY) += icplus.o
obj-$(CONFIG_ADM6996_PHY) += adm6996.o
+obj-$(CONFIG_MVSWITCH_PHY) += mvswitch.o
obj-$(CONFIG_REALTEK_PHY) += realtek.o
obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
obj-$(CONFIG_FIXED_PHY) += fixed.o

View file

@ -0,0 +1,23 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -96,6 +96,10 @@ config ADM6996_PHY
config MVSWITCH_PHY
tristate "Driver for Marvell 88E6060 switches"
+config IP175C_PHY
+ tristate "Driver for IC+ IP175C/IP178C switches"
+ select SWCONFIG
+
config FIXED_PHY
bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
depends on PHYLIB=y
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
obj-$(CONFIG_ICPLUS_PHY) += icplus.o
obj-$(CONFIG_ADM6996_PHY) += adm6996.o
obj-$(CONFIG_MVSWITCH_PHY) += mvswitch.o
+obj-$(CONFIG_IP175C_PHY) += ip175c.o
obj-$(CONFIG_REALTEK_PHY) += realtek.o
obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
obj-$(CONFIG_FIXED_PHY) += fixed.o

View file

@ -0,0 +1,23 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -100,6 +100,10 @@ config IP175C_PHY
tristate "Driver for IC+ IP175C/IP178C switches"
select SWCONFIG
+config AR8216_PHY
+ tristate "Driver for Atheros AR8216 switches"
+ select SWCONFIG
+
config FIXED_PHY
bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
depends on PHYLIB=y
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_ICPLUS_PHY) += icplus.o
obj-$(CONFIG_ADM6996_PHY) += adm6996.o
obj-$(CONFIG_MVSWITCH_PHY) += mvswitch.o
obj-$(CONFIG_IP175C_PHY) += ip175c.o
+obj-$(CONFIG_AR8216_PHY) += ar8216.o
obj-$(CONFIG_REALTEK_PHY) += realtek.o
obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
obj-$(CONFIG_FIXED_PHY) += fixed.o

View file

@ -0,0 +1,250 @@
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -515,6 +515,15 @@ config RTC_DRV_PCF50633
If you say yes here you get support for the RTC subsystem of the
NXP PCF50633 used in embedded systems.
+config RTC_DRV_RTC7301
+ tristate "Epson RTC-7301 SF/DG"
+ help
+ If you say Y here you will get support for the
+ Epson RTC-7301 SF/DG RTC chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-7301.
+
comment "on-CPU RTC drivers"
config RTC_DRV_OMAP
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701
obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
+obj-$(CONFIG_RTC_DRV_RTC7301) += rtc-rtc7301.o
obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o
obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o
obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
--- /dev/null
+++ b/drivers/rtc/rtc-rtc7301.c
@@ -0,0 +1,219 @@
+/*
+ * Driver for Epson RTC-7301SF/DG
+ *
+ * Copyright (C) 2009 Jose Vasconcellos
+ *
+ * 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/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/bcd.h>
+
+#define RTC_NAME "rtc7301"
+#define RTC_VERSION "0.1"
+
+/* Epson RTC-7301 register addresses */
+#define RTC7301_SEC 0x00
+#define RTC7301_SEC10 0x01
+#define RTC7301_MIN 0x02
+#define RTC7301_MIN10 0x03
+#define RTC7301_HOUR 0x04
+#define RTC7301_HOUR10 0x05
+#define RTC7301_WEEKDAY 0x06
+#define RTC7301_DAY 0x07
+#define RTC7301_DAY10 0x08
+#define RTC7301_MON 0x09
+#define RTC7301_MON10 0x0A
+#define RTC7301_YEAR 0x0B
+#define RTC7301_YEAR10 0x0C
+#define RTC7301_YEAR100 0x0D
+#define RTC7301_YEAR1000 0x0E
+#define RTC7301_CTRLREG 0x0F
+
+static uint8_t __iomem *rtc7301_base;
+
+#define read_reg(offset) (readb(rtc7301_base + offset) & 0xf)
+#define write_reg(offset, data) writeb(data, rtc7301_base + (offset))
+
+#define rtc7301_isbusy() (read_reg(RTC7301_CTRLREG) & 1)
+
+static void rtc7301_init_settings(void)
+{
+ int i;
+
+ write_reg(RTC7301_CTRLREG, 2);
+ write_reg(RTC7301_YEAR1000, 2);
+ udelay(122);
+
+ /* bank 1 */
+ write_reg(RTC7301_CTRLREG, 6);
+ for (i=0; i<15; i++)
+ write_reg(i, 0);
+
+ /* bank 2 */
+ write_reg(RTC7301_CTRLREG, 14);
+ for (i=0; i<15; i++)
+ write_reg(i, 0);
+ write_reg(RTC7301_CTRLREG, 0);
+}
+
+static int rtc7301_get_datetime(struct device *dev, struct rtc_time *dt)
+{
+ int cnt;
+ uint8_t buf[16];
+
+ cnt = 0;
+ while (rtc7301_isbusy()) {
+ udelay(244);
+ if (cnt++ > 100) {
+ dev_err(dev, "%s: timeout error %x\n", __func__, rtc7301_base[RTC7301_CTRLREG]);
+ return -EIO;
+ }
+ }
+
+ for (cnt=0; cnt<16; cnt++)
+ buf[cnt] = read_reg(cnt);
+
+ if (buf[RTC7301_SEC10] & 8) {
+ dev_err(dev, "%s: RTC not set\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(dt, 0, sizeof(*dt));
+
+ dt->tm_sec = buf[RTC7301_SEC] + buf[RTC7301_SEC10]*10;
+ dt->tm_min = buf[RTC7301_MIN] + buf[RTC7301_MIN10]*10;
+ dt->tm_hour = buf[RTC7301_HOUR] + buf[RTC7301_HOUR10]*10;
+
+ dt->tm_mday = buf[RTC7301_DAY] + buf[RTC7301_DAY10]*10;
+ dt->tm_mon = buf[RTC7301_MON] + buf[RTC7301_MON10]*10 - 1;
+ dt->tm_year = buf[RTC7301_YEAR] + buf[RTC7301_YEAR10]*10 +
+ buf[RTC7301_YEAR100]*100 +
+ ((buf[RTC7301_YEAR1000] & 3)*1000) - 1900;
+
+ /* the rtc device may contain illegal values on power up
+ * according to the data sheet. make sure they are valid.
+ */
+
+ return rtc_valid_tm(dt);
+}
+
+static int rtc7301_set_datetime(struct device *dev, struct rtc_time *dt)
+{
+ int data;
+
+ data = dt->tm_year + 1900;
+ if (data >= 2100 || data < 1900)
+ return -EINVAL;
+
+ write_reg(RTC7301_CTRLREG, 2);
+ udelay(122);
+
+ data = bin2bcd(dt->tm_sec);
+ write_reg(RTC7301_SEC, data);
+ write_reg(RTC7301_SEC10, (data >> 4));
+
+ data = bin2bcd(dt->tm_min);
+ write_reg(RTC7301_MIN, data );
+ write_reg(RTC7301_MIN10, (data >> 4));
+
+ data = bin2bcd(dt->tm_hour);
+ write_reg(RTC7301_HOUR, data);
+ write_reg(RTC7301_HOUR10, (data >> 4));
+
+ data = bin2bcd(dt->tm_mday);
+ write_reg(RTC7301_DAY, data);
+ write_reg(RTC7301_DAY10, (data>> 4));
+
+ data = bin2bcd(dt->tm_mon + 1);
+ write_reg(RTC7301_MON, data);
+ write_reg(RTC7301_MON10, (data >> 4));
+
+ data = bin2bcd(dt->tm_year % 100);
+ write_reg(RTC7301_YEAR, data);
+ write_reg(RTC7301_YEAR10, (data >> 4));
+ data = bin2bcd((1900 + dt->tm_year) / 100);
+ write_reg(RTC7301_YEAR100, data);
+
+ data = bin2bcd(dt->tm_wday);
+ write_reg(RTC7301_WEEKDAY, data);
+
+ write_reg(RTC7301_CTRLREG, 0);
+
+ return 0;
+}
+
+static const struct rtc_class_ops rtc7301_rtc_ops = {
+ .read_time = rtc7301_get_datetime,
+ .set_time = rtc7301_set_datetime,
+};
+
+static int __devinit rtc7301_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENOENT;
+
+ rtc7301_base = ioremap_nocache(res->start, 0x1000 /*res->end - res->start + 1*/);
+ if (!rtc7301_base)
+ return -EINVAL;
+
+ rtc = rtc_device_register(RTC_NAME, &pdev->dev,
+ &rtc7301_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ iounmap(rtc7301_base);
+ return PTR_ERR(rtc);
+ }
+
+ platform_set_drvdata(pdev, rtc);
+
+ rtc7301_init_settings();
+ return 0;
+}
+
+static int __devexit rtc7301_remove(struct platform_device *pdev)
+{
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+
+ if (rtc)
+ rtc_device_unregister(rtc);
+ if (rtc7301_base)
+ iounmap(rtc7301_base);
+ return 0;
+}
+
+static struct platform_driver rtc7301_driver = {
+ .driver = {
+ .name = RTC_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = rtc7301_probe,
+ .remove = __devexit_p(rtc7301_remove),
+};
+
+static __init int rtc7301_init(void)
+{
+ return platform_driver_register(&rtc7301_driver);
+}
+module_init(rtc7301_init);
+
+static __exit void rtc7301_exit(void)
+{
+ platform_driver_unregister(&rtc7301_driver);
+}
+module_exit(rtc7301_exit);
+
+MODULE_DESCRIPTION("Epson 7301 RTC driver");
+MODULE_AUTHOR("Jose Vasconcellos <jvasco@verizon.net>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" RTC_NAME);
+MODULE_VERSION(RTC_VERSION);

View file

@ -0,0 +1,25 @@
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -59,6 +59,7 @@ static struct usb_driver usb_serial_driv
drivers depend on it.
*/
+static ushort maxSize = 0;
static int debug;
/* initially all NULL */
static struct usb_serial *serial_table[SERIAL_TTY_MINORS];
@@ -861,7 +862,7 @@ int usb_serial_probe(struct usb_interfac
dev_err(&interface->dev, "No free urbs available\n");
goto probe_error;
}
- buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ buffer_size = (endpoint->wMaxPacketSize > maxSize) ? endpoint->wMaxPacketSize : maxSize;
port->bulk_in_size = buffer_size;
port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
@@ -1306,3 +1307,5 @@ MODULE_LICENSE("GPL");
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
+module_param(maxSize, ushort,0);
+MODULE_PARM_DESC(maxSize,"User specified USB endpoint size");

View file

@ -0,0 +1,11 @@
--- a/init/main.c
+++ b/init/main.c
@@ -797,7 +797,7 @@ static noinline int init_post(void)
numa_default_policy();
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
- printk(KERN_WARNING "Warning: unable to open an initial console.\n");
+ printk(KERN_WARNING "Please be patient, while OpenWrt loads ...\n");
(void) sys_dup(0);
(void) sys_dup(0);

View file

@ -0,0 +1,46 @@
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -1,6 +1,10 @@
#ifndef _LINUX_TIME_H
#define _LINUX_TIME_H
+#ifndef __KERNEL__
+#include <time.h>
+#else
+
#include <linux/types.h>
#ifdef __KERNEL__
@@ -240,4 +244,6 @@ struct itimerval {
*/
#define TIMER_ABSTIME 0x01
+#endif /* __KERNEL__ DEBIAN */
+
#endif
--- a/include/linux/types.h
+++ b/include/linux/types.h
@@ -1,6 +1,14 @@
#ifndef _LINUX_TYPES_H
#define _LINUX_TYPES_H
+/* Debian: Use userland types instead. */
+#ifndef __KERNEL__
+# include <sys/types.h>
+/* For other kernel headers. */
+# include <linux/posix_types.h>
+# include <asm/types.h>
+#else
+
#ifdef __KERNEL__
#define DECLARE_BITMAP(name,bits) \
@@ -156,6 +164,8 @@ typedef unsigned long blkcnt_t;
#endif /* __KERNEL_STRICT_NAMES */
+#endif /* __KERNEL__ DEBIAN */
+
/*
* Below are truly Linux-specific types that should never collide with
* any application/library that wants linux/types.h.

View file

@ -0,0 +1,102 @@
--- a/scripts/genksyms/parse.c_shipped
+++ b/scripts/genksyms/parse.c_shipped
@@ -160,7 +160,9 @@
#include <assert.h>
+#ifndef __APPLE__
#include <malloc.h>
+#endif
#include "genksyms.h"
static int is_typedef;
--- a/scripts/genksyms/parse.y
+++ b/scripts/genksyms/parse.y
@@ -24,7 +24,9 @@
%{
#include <assert.h>
+#ifndef __APPLE__
#include <malloc.h>
+#endif
#include "genksyms.h"
static int is_typedef;
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -22,6 +22,35 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
+#ifdef __APPLE__
+/* Darwin has no memmem implementation, this one is ripped of the uClibc-0.9.28 source */
+void *memmem (const void *haystack, size_t haystack_len,
+ const void *needle, size_t needle_len)
+{
+ const char *begin;
+ const char *const last_possible
+ = (const char *) haystack + haystack_len - needle_len;
+
+ if (needle_len == 0)
+ /* The first occurrence of the empty string is deemed to occur at
+ the beginning of the string. */
+ return (void *) haystack;
+
+ /* Sanity check, otherwise the loop might search through the whole
+ memory. */
+ if (__builtin_expect (haystack_len < needle_len, 0))
+ return NULL;
+
+ for (begin = (const char *) haystack; begin <= last_possible; ++begin)
+ if (begin[0] == ((const char *) needle)[0] &&
+ !memcmp ((const void *) &begin[1],
+ (const void *) ((const char *) needle + 1),
+ needle_len - 1))
+ return (void *) begin;
+
+ return NULL;
+}
+#endif
#define KSYM_NAME_LEN 128
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -97,6 +97,9 @@ check-lxdialog := $(srctree)/$(src)/lxd
# we really need to do so. (Do not call gcc as part of make mrproper)
HOST_EXTRACFLAGS = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags)
HOST_LOADLIBES = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
+ifeq ($(shell uname -s),Darwin)
+HOST_LOADLIBES += -lncurses
+endif
HOST_EXTRACFLAGS += -DLOCALE
--- a/scripts/mod/mk_elfconfig.c
+++ b/scripts/mod/mk_elfconfig.c
@@ -1,7 +1,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#ifndef __APPLE__
#include <elf.h>
+#else
+#include "../../../../../tools/sstrip/include/elf.h"
+#endif
int
main(int argc, char **argv)
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -7,7 +7,11 @@
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
+#ifndef __APPLE__
#include <elf.h>
+#else
+#include "../../../../../tools/sstrip/include/elf.h"
+#endif
#include "elfconfig.h"

View file

@ -0,0 +1,154 @@
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -2346,13 +2346,13 @@ int prism2_ap_get_sta_qual(local_info_t
addr[count].sa_family = ARPHRD_ETHER;
memcpy(addr[count].sa_data, sta->addr, ETH_ALEN);
if (sta->last_rx_silence == 0)
- qual[count].qual = sta->last_rx_signal < 27 ?
- 0 : (sta->last_rx_signal - 27) * 92 / 127;
+ qual[count].qual = (sta->last_rx_signal - 156) == 0 ?
+ 0 : (sta->last_rx_signal - 156) * 92 / 64;
else
- qual[count].qual = sta->last_rx_signal -
- sta->last_rx_silence - 35;
- qual[count].level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal);
- qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence);
+ qual[count].qual = (sta->last_rx_signal -
+ sta->last_rx_silence) * 92 / 64;
+ qual[count].level = sta->last_rx_signal;
+ qual[count].noise = sta->last_rx_silence;
qual[count].updated = sta->last_rx_updated;
sta->last_rx_updated = IW_QUAL_DBM;
@@ -2418,13 +2418,13 @@ int prism2_ap_translate_scan(struct net_
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVQUAL;
if (sta->last_rx_silence == 0)
- iwe.u.qual.qual = sta->last_rx_signal < 27 ?
- 0 : (sta->last_rx_signal - 27) * 92 / 127;
+ iwe.u.qual.qual = (sta->last_rx_signal -156) == 0 ?
+ 0 : (sta->last_rx_signal - 156) * 92 / 64;
else
- iwe.u.qual.qual = sta->last_rx_signal -
- sta->last_rx_silence - 35;
- iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal);
- iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence);
+ iwe.u.qual.qual = (sta->last_rx_signal -
+ sta->last_rx_silence) * 92 / 64;
+ iwe.u.qual.level = sta->last_rx_signal;
+ iwe.u.qual.noise = sta->last_rx_silence;
iwe.u.qual.updated = sta->last_rx_updated;
iwe.len = IW_EV_QUAL_LEN;
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
--- a/drivers/net/wireless/hostap/hostap_config.h
+++ b/drivers/net/wireless/hostap/hostap_config.h
@@ -45,4 +45,9 @@
*/
/* #define PRISM2_NO_STATION_MODES */
+/* Enable TX power Setting functions
+ * (min att = -128 , max att = 127)
+ */
+#define RAW_TXPOWER_SETTING
+
#endif /* HOSTAP_CONFIG_H */
--- a/drivers/net/wireless/hostap/hostap.h
+++ b/drivers/net/wireless/hostap/hostap.h
@@ -90,6 +90,7 @@ extern const struct iw_handler_def hosta
extern const struct ethtool_ops prism2_ethtool_ops;
int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+int hostap_restore_power(struct net_device *dev);
#endif /* HOSTAP_H */
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -933,6 +933,7 @@ static int hfa384x_set_rid(struct net_de
prism2_hw_reset(dev);
}
+ hostap_restore_power(dev);
return res;
}
--- a/drivers/net/wireless/hostap/hostap_info.c
+++ b/drivers/net/wireless/hostap/hostap_info.c
@@ -430,6 +430,11 @@ static void handle_info_queue_linkstatus
}
/* Get BSSID if we have a valid AP address */
+
+ if ( val == HFA384X_LINKSTATUS_CONNECTED ||
+ val == HFA384X_LINKSTATUS_DISCONNECTED )
+ hostap_restore_power(local->dev);
+
if (connected) {
netif_carrier_on(local->dev);
netif_carrier_on(local->ddev);
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -1474,23 +1474,20 @@ static int prism2_txpower_hfa386x_to_dBm
val = 255;
tmp = val;
- tmp >>= 2;
- return -12 - tmp;
+ return tmp;
}
static u16 prism2_txpower_dBm_to_hfa386x(int val)
{
signed char tmp;
- if (val > 20)
- return 128;
- else if (val < -43)
+ if (val > 127)
return 127;
+ else if (val < -128)
+ return 128;
tmp = val;
- tmp = -12 - tmp;
- tmp <<= 2;
return (unsigned char) tmp;
}
@@ -4054,3 +4051,35 @@ int hostap_ioctl(struct net_device *dev,
return ret;
}
+
+/* BUG FIX: Restore power setting value when lost due to F/W bug */
+
+int hostap_restore_power(struct net_device *dev)
+{
+ struct hostap_interface *iface = netdev_priv(dev);
+ local_info_t *local = iface->local;
+
+ u16 val;
+ int ret = 0;
+
+ if (local->txpower_type == PRISM2_TXPOWER_OFF) {
+ val = 0xff; /* use all standby and sleep modes */
+ ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF,
+ HFA386X_CR_A_D_TEST_MODES2,
+ &val, NULL);
+ }
+
+#ifdef RAW_TXPOWER_SETTING
+ if (local->txpower_type == PRISM2_TXPOWER_FIXED) {
+ val = HFA384X_TEST_CFG_BIT_ALC;
+ local->func->cmd(dev, HFA384X_CMDCODE_TEST |
+ (HFA384X_TEST_CFG_BITS << 8), 0, &val, NULL);
+ val = prism2_txpower_dBm_to_hfa386x(local->txpower);
+ ret = (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF,
+ HFA386X_CR_MANUAL_TX_POWER, &val, NULL));
+ }
+#endif /* RAW_TXPOWER_SETTING */
+ return (ret ? -EOPNOTSUPP : 0);
+}
+
+EXPORT_SYMBOL(hostap_restore_power);

View file

@ -0,0 +1,17 @@
--- a/include/linux/stddef.h
+++ b/include/linux/stddef.h
@@ -16,6 +16,7 @@ enum {
false = 0,
true = 1
};
+#endif /* __KERNEL__ */
#undef offsetof
#ifdef __compiler_offsetof
@@ -23,6 +24,5 @@ enum {
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
-#endif /* __KERNEL__ */
#endif

View file

@ -0,0 +1,10 @@
--- a/arch/x86/boot/tools/build.c
+++ b/arch/x86/boot/tools/build.c
@@ -29,7 +29,6 @@
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
-#include <sys/sysmacros.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

View file

@ -0,0 +1,60 @@
Fix spi-gpio for hotplug.
--mb
--- a/drivers/spi/spi_gpio.c
+++ b/drivers/spi/spi_gpio.c
@@ -213,7 +213,7 @@ static void spi_gpio_cleanup(struct spi_
spi_bitbang_cleanup(spi);
}
-static int __init spi_gpio_alloc(unsigned pin, const char *label, bool is_in)
+static int __devinit spi_gpio_alloc(unsigned pin, const char *label, bool is_in)
{
int value;
@@ -227,7 +227,7 @@ static int __init spi_gpio_alloc(unsigne
return value;
}
-static int __init
+static int __devinit
spi_gpio_request(struct spi_gpio_platform_data *pdata, const char *label)
{
int value;
@@ -256,7 +256,7 @@ done:
return value;
}
-static int __init spi_gpio_probe(struct platform_device *pdev)
+static int __devinit spi_gpio_probe(struct platform_device *pdev)
{
int status;
struct spi_master *master;
@@ -312,7 +312,7 @@ gpio_free:
return status;
}
-static int __exit spi_gpio_remove(struct platform_device *pdev)
+static int __devexit spi_gpio_remove(struct platform_device *pdev)
{
struct spi_gpio *spi_gpio;
struct spi_gpio_platform_data *pdata;
@@ -339,12 +339,13 @@ MODULE_ALIAS("platform:" DRIVER_NAME);
static struct platform_driver spi_gpio_driver = {
.driver.name = DRIVER_NAME,
.driver.owner = THIS_MODULE,
- .remove = __exit_p(spi_gpio_remove),
+ .probe = spi_gpio_probe,
+ .remove = __devexit_p(spi_gpio_remove),
};
static int __init spi_gpio_init(void)
{
- return platform_driver_probe(&spi_gpio_driver, spi_gpio_probe);
+ return platform_driver_register(&spi_gpio_driver);
}
module_init(spi_gpio_init);

View file

@ -0,0 +1,73 @@
Optionally omit the CS signal, if there's only one device on the bus.
--mb
--- a/drivers/spi/spi_gpio.c
+++ b/drivers/spi/spi_gpio.c
@@ -178,8 +178,10 @@ static void spi_gpio_chipselect(struct s
if (is_active)
setsck(spi, spi->mode & SPI_CPOL);
- /* SPI is normally active-low */
- gpio_set_value(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
+ if (cs != SPI_GPIO_NO_CHIPSELECT) {
+ /* SPI is normally active-low */
+ gpio_set_value(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active);
+ }
}
static int spi_gpio_setup(struct spi_device *spi)
@@ -191,15 +193,17 @@ static int spi_gpio_setup(struct spi_dev
return -EINVAL;
if (!spi->controller_state) {
- status = gpio_request(cs, spi->dev.bus_id);
- if (status)
- return status;
- status = gpio_direction_output(cs, spi->mode & SPI_CS_HIGH);
+ if (cs != SPI_GPIO_NO_CHIPSELECT) {
+ status = gpio_request(cs, spi->dev.bus_id);
+ if (status)
+ return status;
+ status = gpio_direction_output(cs, spi->mode & SPI_CS_HIGH);
+ }
}
if (!status)
status = spi_bitbang_setup(spi);
if (status) {
- if (!spi->controller_state)
+ if (!spi->controller_state && cs != SPI_GPIO_NO_CHIPSELECT)
gpio_free(cs);
}
return status;
@@ -209,7 +213,8 @@ static void spi_gpio_cleanup(struct spi_
{
unsigned long cs = (unsigned long) spi->controller_data;
- gpio_free(cs);
+ if (cs != SPI_GPIO_NO_CHIPSELECT)
+ gpio_free(cs);
spi_bitbang_cleanup(spi);
}
--- a/include/linux/spi/spi_gpio.h
+++ b/include/linux/spi/spi_gpio.h
@@ -25,10 +25,16 @@
* ...
* };
*
+ * If chipselect is not used (there's only one device on the bus), assign
+ * SPI_GPIO_NO_CHIPSELECT to the controller_data:
+ * .controller_data = (void *) SPI_GPIO_NO_CHIPSELECT;
+ *
* If the bitbanged bus is later switched to a "native" controller,
* that platform_device and controller_data should be removed.
*/
+#define SPI_GPIO_NO_CHIPSELECT ((unsigned long)-1l)
+
/**
* struct spi_gpio_platform_data - parameter for bitbanged SPI master
* @sck: number of the GPIO used for clock output

View file

@ -0,0 +1,58 @@
Implement the SPI-GPIO delay function for busses that need speed limitation.
--mb
--- a/drivers/spi/spi_gpio.c
+++ b/drivers/spi/spi_gpio.c
@@ -21,6 +21,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
+#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
@@ -69,6 +70,7 @@ struct spi_gpio {
* #define SPI_MOSI_GPIO 120
* #define SPI_SCK_GPIO 121
* #define SPI_N_CHIPSEL 4
+ * #undef NEED_SPIDELAY
* #include "spi_gpio.c"
*/
@@ -76,6 +78,7 @@ struct spi_gpio {
#define DRIVER_NAME "spi_gpio"
#define GENERIC_BITBANG /* vs tight inlines */
+#define NEED_SPIDELAY 1
/* all functions referencing these symbols must define pdata */
#define SPI_MISO_GPIO ((pdata)->miso)
@@ -120,12 +123,20 @@ static inline int getmiso(const struct s
#undef pdata
/*
- * NOTE: this clocks "as fast as we can". It "should" be a function of the
- * requested device clock. Software overhead means we usually have trouble
- * reaching even one Mbit/sec (except when we can inline bitops), so for now
- * we'll just assume we never need additional per-bit slowdowns.
+ * NOTE: to clock "as fast as we can", set spi_device.max_speed_hz
+ * and spi_transfer.speed_hz to 0.
+ * Otherwise this is a function of the requested device clock.
+ * Software overhead means we usually have trouble
+ * reaching even one Mbit/sec (except when we can inline bitops). So on small
+ * embedded devices with fast SPI slaves you usually don't need a delay.
*/
-#define spidelay(nsecs) do {} while (0)
+static inline void spidelay(unsigned nsecs)
+{
+#ifdef NEED_SPIDELAY
+ if (unlikely(nsecs))
+ ndelay(nsecs);
+#endif /* NEED_SPIDELAY */
+}
#define EXPAND_BITBANG_TXRX
#include <linux/spi/spi_bitbang.h>

View file

@ -0,0 +1,366 @@
THIS CODE IS DEPRECATED.
Please use the new mainline SPI-GPIO driver, as of 2.6.29.
--mb
--- /dev/null
+++ b/include/linux/spi/spi_gpio_old.h
@@ -0,0 +1,73 @@
+/*
+ * spi_gpio interface to platform code
+ *
+ * Copyright (c) 2008 Piotr Skamruk
+ * Copyright (c) 2008 Michael Buesch
+ *
+ * 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;
+};
+
+/**
+ * SPI_GPIO_PLATDEV_NAME - The platform device name string.
+ *
+ * The name string that has to be used for platform_device_alloc
+ * when allocating a spi-gpio device.
+ */
+#define SPI_GPIO_PLATDEV_NAME "spi-gpio"
+
+/**
+ * spi_gpio_next_id - Get another platform device ID number.
+ *
+ * This returns the next platform device ID number that has to be used
+ * for platform_device_alloc. The ID is opaque and should not be used for
+ * anything else.
+ */
+int spi_gpio_next_id(void);
+
+#endif /* _LINUX_SPI_SPI_GPIO */
--- /dev/null
+++ b/drivers/spi/spi_gpio_old.c
@@ -0,0 +1,251 @@
+/*
+ * 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_old.h>
+#include <linux/gpio.h>
+#include <asm/atomic.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_PLATDEV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = spi_gpio_probe,
+ .remove = __devexit_p(spi_gpio_remove),
+};
+
+int spi_gpio_next_id(void)
+{
+ static atomic_t counter = ATOMIC_INIT(-1);
+
+ return atomic_inc_return(&counter);
+}
+EXPORT_SYMBOL(spi_gpio_next_id);
+
+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 bitbanging SPI driver");
+MODULE_LICENSE("GPL v2");
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -116,6 +116,15 @@ config SPI_GPIO
GPIO operations, you should be able to leverage that for better
speed with a custom version of this driver; see the source code.
+config SPI_GPIO_OLD
+ tristate "Old GPIO API based bitbanging SPI controller (DEPRECATED)"
+ depends on SPI_MASTER && GENERIC_GPIO
+ select SPI_BITBANG
+ help
+ This code is deprecated. Please use the new mainline SPI-GPIO driver.
+
+ If unsure, say N.
+
config SPI_IMX
tristate "Freescale iMX SPI controller"
depends on ARCH_IMX && EXPERIMENTAL
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_SPI_BITBANG) += spi_bitban
obj-$(CONFIG_SPI_AU1550) += au1550_spi.o
obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
obj-$(CONFIG_SPI_GPIO) += spi_gpio.o
+obj-$(CONFIG_SPI_GPIO_OLD) += spi_gpio_old.o
obj-$(CONFIG_SPI_IMX) += spi_imx.o
obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o
obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o

View file

@ -0,0 +1,838 @@
--- /dev/null
+++ b/drivers/mmc/host/gpiommc.c
@@ -0,0 +1,608 @@
+/*
+ * Driver an MMC/SD card on a bitbanging GPIO SPI bus.
+ * This module hooks up the mmc_spi and spi_gpio modules and also
+ * provides a configfs interface.
+ *
+ * Copyright 2008 Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/mmc/gpiommc.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/spi/spi_gpio_old.h>
+#include <linux/configfs.h>
+#include <linux/gpio.h>
+#include <asm/atomic.h>
+
+
+#define PFX "gpio-mmc: "
+
+
+struct gpiommc_device {
+ struct platform_device *pdev;
+ struct platform_device *spi_pdev;
+ struct spi_board_info boardinfo;
+};
+
+
+MODULE_DESCRIPTION("GPIO based MMC driver");
+MODULE_AUTHOR("Michael Buesch");
+MODULE_LICENSE("GPL");
+
+
+static int gpiommc_boardinfo_setup(struct spi_board_info *bi,
+ struct spi_master *master,
+ void *data)
+{
+ struct gpiommc_device *d = data;
+ struct gpiommc_platform_data *pdata = d->pdev->dev.platform_data;
+
+ /* Bind the SPI master to the MMC-SPI host driver. */
+ strlcpy(bi->modalias, "mmc_spi", sizeof(bi->modalias));
+
+ bi->max_speed_hz = pdata->max_bus_speed;
+ bi->bus_num = master->bus_num;
+ bi->mode = pdata->mode;
+
+ return 0;
+}
+
+static int gpiommc_probe(struct platform_device *pdev)
+{
+ struct gpiommc_platform_data *mmc_pdata = pdev->dev.platform_data;
+ struct spi_gpio_platform_data spi_pdata;
+ struct gpiommc_device *d;
+ int err;
+
+ err = -ENXIO;
+ if (!mmc_pdata)
+ goto error;
+
+#ifdef CONFIG_MMC_SPI_MODULE
+ err = request_module("mmc_spi");
+ if (err) {
+ printk(KERN_WARNING PFX
+ "Failed to request mmc_spi module.\n");
+ }
+#endif /* CONFIG_MMC_SPI_MODULE */
+
+ /* Allocate the GPIO-MMC device */
+ err = -ENOMEM;
+ d = kzalloc(sizeof(*d), GFP_KERNEL);
+ if (!d)
+ goto error;
+ d->pdev = pdev;
+
+ /* Create the SPI-GPIO device */
+ d->spi_pdev = platform_device_alloc(SPI_GPIO_PLATDEV_NAME,
+ spi_gpio_next_id());
+ if (!d->spi_pdev)
+ goto err_free_d;
+
+ memset(&spi_pdata, 0, sizeof(spi_pdata));
+ spi_pdata.pin_clk = mmc_pdata->pins.gpio_clk;
+ spi_pdata.pin_miso = mmc_pdata->pins.gpio_do;
+ spi_pdata.pin_mosi = mmc_pdata->pins.gpio_di;
+ spi_pdata.pin_cs = mmc_pdata->pins.gpio_cs;
+ spi_pdata.cs_activelow = mmc_pdata->pins.cs_activelow;
+ spi_pdata.no_spi_delay = mmc_pdata->no_spi_delay;
+ spi_pdata.boardinfo_setup = gpiommc_boardinfo_setup;
+ spi_pdata.boardinfo_setup_data = d;
+
+ err = platform_device_add_data(d->spi_pdev, &spi_pdata,
+ sizeof(spi_pdata));
+ if (err)
+ goto err_free_pdev;
+ err = platform_device_add(d->spi_pdev);
+ if (err)
+ goto err_free_pdata;
+ platform_set_drvdata(pdev, d);
+
+ printk(KERN_INFO PFX "MMC-Card \"%s\" "
+ "attached to GPIO pins di=%u, do=%u, clk=%u, cs=%u\n",
+ mmc_pdata->name, mmc_pdata->pins.gpio_di,
+ mmc_pdata->pins.gpio_do,
+ mmc_pdata->pins.gpio_clk,
+ mmc_pdata->pins.gpio_cs);
+
+ return 0;
+
+err_free_pdata:
+ kfree(d->spi_pdev->dev.platform_data);
+ d->spi_pdev->dev.platform_data = NULL;
+err_free_pdev:
+ platform_device_put(d->spi_pdev);
+err_free_d:
+ kfree(d);
+error:
+ return err;
+}
+
+static int gpiommc_remove(struct platform_device *pdev)
+{
+ struct gpiommc_device *d = platform_get_drvdata(pdev);
+ struct gpiommc_platform_data *pdata = d->pdev->dev.platform_data;
+
+ platform_device_unregister(d->spi_pdev);
+ printk(KERN_INFO PFX "GPIO based MMC-Card \"%s\" removed\n",
+ pdata->name);
+ platform_device_put(d->spi_pdev);
+
+ return 0;
+}
+
+#ifdef CONFIG_GPIOMMC_CONFIGFS
+
+/* A device that was created through configfs */
+struct gpiommc_configfs_device {
+ struct config_item item;
+ /* The platform device, after registration. */
+ struct platform_device *pdev;
+ /* The configuration */
+ struct gpiommc_platform_data pdata;
+};
+
+#define GPIO_INVALID -1
+
+static inline bool gpiommc_is_registered(struct gpiommc_configfs_device *dev)
+{
+ return (dev->pdev != NULL);
+}
+
+static inline struct gpiommc_configfs_device *ci_to_gpiommc(struct config_item *item)
+{
+ return item ? container_of(item, struct gpiommc_configfs_device, item) : NULL;
+}
+
+static struct configfs_attribute gpiommc_attr_DI = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "gpio_data_in",
+ .ca_mode = S_IRUGO | S_IWUSR,
+};
+
+static struct configfs_attribute gpiommc_attr_DO = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "gpio_data_out",
+ .ca_mode = S_IRUGO | S_IWUSR,
+};
+
+static struct configfs_attribute gpiommc_attr_CLK = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "gpio_clock",
+ .ca_mode = S_IRUGO | S_IWUSR,
+};
+
+static struct configfs_attribute gpiommc_attr_CS = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "gpio_chipselect",
+ .ca_mode = S_IRUGO | S_IWUSR,
+};
+
+static struct configfs_attribute gpiommc_attr_CS_activelow = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "gpio_chipselect_activelow",
+ .ca_mode = S_IRUGO | S_IWUSR,
+};
+
+static struct configfs_attribute gpiommc_attr_spimode = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "spi_mode",
+ .ca_mode = S_IRUGO | S_IWUSR,
+};
+
+static struct configfs_attribute gpiommc_attr_spidelay = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "spi_delay",
+ .ca_mode = S_IRUGO | S_IWUSR,
+};
+
+static struct configfs_attribute gpiommc_attr_max_bus_speed = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "max_bus_speed",
+ .ca_mode = S_IRUGO | S_IWUSR,
+};
+
+static struct configfs_attribute gpiommc_attr_register = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "register",
+ .ca_mode = S_IRUGO | S_IWUSR,
+};
+
+static struct configfs_attribute *gpiommc_config_attrs[] = {
+ &gpiommc_attr_DI,
+ &gpiommc_attr_DO,
+ &gpiommc_attr_CLK,
+ &gpiommc_attr_CS,
+ &gpiommc_attr_CS_activelow,
+ &gpiommc_attr_spimode,
+ &gpiommc_attr_spidelay,
+ &gpiommc_attr_max_bus_speed,
+ &gpiommc_attr_register,
+ NULL,
+};
+
+static ssize_t gpiommc_config_attr_show(struct config_item *item,
+ struct configfs_attribute *attr,
+ char *page)
+{
+ struct gpiommc_configfs_device *dev = ci_to_gpiommc(item);
+ ssize_t count = 0;
+ unsigned int gpio;
+ int err = 0;
+
+ if (attr == &gpiommc_attr_DI) {
+ gpio = dev->pdata.pins.gpio_di;
+ if (gpio == GPIO_INVALID)
+ count = snprintf(page, PAGE_SIZE, "not configured\n");
+ else
+ count = snprintf(page, PAGE_SIZE, "%u\n", gpio);
+ goto out;
+ }
+ if (attr == &gpiommc_attr_DO) {
+ gpio = dev->pdata.pins.gpio_do;
+ if (gpio == GPIO_INVALID)
+ count = snprintf(page, PAGE_SIZE, "not configured\n");
+ else
+ count = snprintf(page, PAGE_SIZE, "%u\n", gpio);
+ goto out;
+ }
+ if (attr == &gpiommc_attr_CLK) {
+ gpio = dev->pdata.pins.gpio_clk;
+ if (gpio == GPIO_INVALID)
+ count = snprintf(page, PAGE_SIZE, "not configured\n");
+ else
+ count = snprintf(page, PAGE_SIZE, "%u\n", gpio);
+ goto out;
+ }
+ if (attr == &gpiommc_attr_CS) {
+ gpio = dev->pdata.pins.gpio_cs;
+ if (gpio == GPIO_INVALID)
+ count = snprintf(page, PAGE_SIZE, "not configured\n");
+ else
+ count = snprintf(page, PAGE_SIZE, "%u\n", gpio);
+ goto out;
+ }
+ if (attr == &gpiommc_attr_CS_activelow) {
+ count = snprintf(page, PAGE_SIZE, "%u\n",
+ dev->pdata.pins.cs_activelow);
+ goto out;
+ }
+ if (attr == &gpiommc_attr_spimode) {
+ count = snprintf(page, PAGE_SIZE, "%u\n",
+ dev->pdata.mode);
+ goto out;
+ }
+ if (attr == &gpiommc_attr_spidelay) {
+ count = snprintf(page, PAGE_SIZE, "%u\n",
+ !dev->pdata.no_spi_delay);
+ goto out;
+ }
+ if (attr == &gpiommc_attr_max_bus_speed) {
+ count = snprintf(page, PAGE_SIZE, "%u\n",
+ dev->pdata.max_bus_speed);
+ goto out;
+ }
+ if (attr == &gpiommc_attr_register) {
+ count = snprintf(page, PAGE_SIZE, "%u\n",
+ gpiommc_is_registered(dev));
+ goto out;
+ }
+ WARN_ON(1);
+ err = -ENOSYS;
+out:
+ return err ? err : count;
+}
+
+static int gpiommc_do_register(struct gpiommc_configfs_device *dev,
+ const char *name)
+{
+ int err;
+
+ if (gpiommc_is_registered(dev))
+ return 0;
+
+ if (!gpio_is_valid(dev->pdata.pins.gpio_di) ||
+ !gpio_is_valid(dev->pdata.pins.gpio_do) ||
+ !gpio_is_valid(dev->pdata.pins.gpio_clk) ||
+ !gpio_is_valid(dev->pdata.pins.gpio_cs)) {
+ printk(KERN_ERR PFX
+ "configfs: Invalid GPIO pin number(s)\n");
+ return -EINVAL;
+ }
+
+ strlcpy(dev->pdata.name, name,
+ sizeof(dev->pdata.name));
+
+ dev->pdev = platform_device_alloc(GPIOMMC_PLATDEV_NAME,
+ gpiommc_next_id());
+ if (!dev->pdev)
+ return -ENOMEM;
+ err = platform_device_add_data(dev->pdev, &dev->pdata,
+ sizeof(dev->pdata));
+ if (err) {
+ platform_device_put(dev->pdev);
+ return err;
+ }
+ err = platform_device_add(dev->pdev);
+ if (err) {
+ platform_device_put(dev->pdev);
+ return err;
+ }
+
+ return 0;
+}
+
+static void gpiommc_do_unregister(struct gpiommc_configfs_device *dev)
+{
+ if (!gpiommc_is_registered(dev))
+ return;
+
+ platform_device_unregister(dev->pdev);
+ dev->pdev = NULL;
+}
+
+static ssize_t gpiommc_config_attr_store(struct config_item *item,
+ struct configfs_attribute *attr,
+ const char *page, size_t count)
+{
+ struct gpiommc_configfs_device *dev = ci_to_gpiommc(item);
+ int err = -EINVAL;
+ unsigned long data;
+
+ if (attr == &gpiommc_attr_register) {
+ err = strict_strtoul(page, 10, &data);
+ if (err)
+ goto out;
+ err = -EINVAL;
+ if (data == 1)
+ err = gpiommc_do_register(dev, item->ci_name);
+ if (data == 0) {
+ gpiommc_do_unregister(dev);
+ err = 0;
+ }
+ goto out;
+ }
+
+ if (gpiommc_is_registered(dev)) {
+ /* The rest of the config parameters can only be set
+ * as long as the device is not registered, yet. */
+ err = -EBUSY;
+ goto out;
+ }
+
+ if (attr == &gpiommc_attr_DI) {
+ err = strict_strtoul(page, 10, &data);
+ if (err)
+ goto out;
+ err = -EINVAL;
+ if (!gpio_is_valid(data))
+ goto out;
+ dev->pdata.pins.gpio_di = data;
+ err = 0;
+ goto out;
+ }
+ if (attr == &gpiommc_attr_DO) {
+ err = strict_strtoul(page, 10, &data);
+ if (err)
+ goto out;
+ err = -EINVAL;
+ if (!gpio_is_valid(data))
+ goto out;
+ dev->pdata.pins.gpio_do = data;
+ err = 0;
+ goto out;
+ }
+ if (attr == &gpiommc_attr_CLK) {
+ err = strict_strtoul(page, 10, &data);
+ if (err)
+ goto out;
+ err = -EINVAL;
+ if (!gpio_is_valid(data))
+ goto out;
+ dev->pdata.pins.gpio_clk = data;
+ err = 0;
+ goto out;
+ }
+ if (attr == &gpiommc_attr_CS) {
+ err = strict_strtoul(page, 10, &data);
+ if (err)
+ goto out;
+ err = -EINVAL;
+ if (!gpio_is_valid(data))
+ goto out;
+ dev->pdata.pins.gpio_cs = data;
+ err = 0;
+ goto out;
+ }
+ if (attr == &gpiommc_attr_CS_activelow) {
+ err = strict_strtoul(page, 10, &data);
+ if (err)
+ goto out;
+ err = -EINVAL;
+ if (data != 0 && data != 1)
+ goto out;
+ dev->pdata.pins.cs_activelow = data;
+ err = 0;
+ goto out;
+ }
+ if (attr == &gpiommc_attr_spimode) {
+ err = strict_strtoul(page, 10, &data);
+ if (err)
+ goto out;
+ err = -EINVAL;
+ switch (data) {
+ case 0:
+ dev->pdata.mode = SPI_MODE_0;
+ break;
+ case 1:
+ dev->pdata.mode = SPI_MODE_1;
+ break;
+ case 2:
+ dev->pdata.mode = SPI_MODE_2;
+ break;
+ case 3:
+ dev->pdata.mode = SPI_MODE_3;
+ break;
+ default:
+ goto out;
+ }
+ err = 0;
+ goto out;
+ }
+ if (attr == &gpiommc_attr_spidelay) {
+ err = strict_strtoul(page, 10, &data);
+ if (err)
+ goto out;
+ err = -EINVAL;
+ if (data != 0 && data != 1)
+ goto out;
+ dev->pdata.no_spi_delay = !data;
+ err = 0;
+ goto out;
+ }
+ if (attr == &gpiommc_attr_max_bus_speed) {
+ err = strict_strtoul(page, 10, &data);
+ if (err)
+ goto out;
+ err = -EINVAL;
+ if (data > UINT_MAX)
+ goto out;
+ dev->pdata.max_bus_speed = data;
+ err = 0;
+ goto out;
+ }
+ WARN_ON(1);
+ err = -ENOSYS;
+out:
+ return err ? err : count;
+}
+
+static void gpiommc_config_item_release(struct config_item *item)
+{
+ struct gpiommc_configfs_device *dev = ci_to_gpiommc(item);
+
+ kfree(dev);
+}
+
+static struct configfs_item_operations gpiommc_config_item_ops = {
+ .release = gpiommc_config_item_release,
+ .show_attribute = gpiommc_config_attr_show,
+ .store_attribute = gpiommc_config_attr_store,
+};
+
+static struct config_item_type gpiommc_dev_ci_type = {
+ .ct_item_ops = &gpiommc_config_item_ops,
+ .ct_attrs = gpiommc_config_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item *gpiommc_make_item(struct config_group *group,
+ const char *name)
+{
+ struct gpiommc_configfs_device *dev;
+
+ if (strlen(name) > GPIOMMC_MAX_NAMELEN) {
+ printk(KERN_ERR PFX "configfs: device name too long\n");
+ return NULL;
+ }
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ config_item_init_type_name(&dev->item, name,
+ &gpiommc_dev_ci_type);
+
+ /* Assign default configuration */
+ dev->pdata.pins.gpio_di = GPIO_INVALID;
+ dev->pdata.pins.gpio_do = GPIO_INVALID;
+ dev->pdata.pins.gpio_clk = GPIO_INVALID;
+ dev->pdata.pins.gpio_cs = GPIO_INVALID;
+ dev->pdata.pins.cs_activelow = 1;
+ dev->pdata.mode = SPI_MODE_0;
+ dev->pdata.no_spi_delay = 0;
+ dev->pdata.max_bus_speed = 5000000; /* 5 MHz */
+
+ return &(dev->item);
+}
+
+static void gpiommc_drop_item(struct config_group *group,
+ struct config_item *item)
+{
+ struct gpiommc_configfs_device *dev = ci_to_gpiommc(item);
+
+ gpiommc_do_unregister(dev);
+ kfree(dev);
+}
+
+static struct configfs_group_operations gpiommc_ct_group_ops = {
+ .make_item = gpiommc_make_item,
+ .drop_item = gpiommc_drop_item,
+};
+
+static struct config_item_type gpiommc_ci_type = {
+ .ct_group_ops = &gpiommc_ct_group_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct configfs_subsystem gpiommc_subsys = {
+ .su_group = {
+ .cg_item = {
+ .ci_namebuf = GPIOMMC_PLATDEV_NAME,
+ .ci_type = &gpiommc_ci_type,
+ },
+ },
+ .su_mutex = __MUTEX_INITIALIZER(gpiommc_subsys.su_mutex),
+};
+
+#endif /* CONFIG_GPIOMMC_CONFIGFS */
+
+static struct platform_driver gpiommc_plat_driver = {
+ .probe = gpiommc_probe,
+ .remove = gpiommc_remove,
+ .driver = {
+ .name = GPIOMMC_PLATDEV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+int gpiommc_next_id(void)
+{
+ static atomic_t counter = ATOMIC_INIT(-1);
+
+ return atomic_inc_return(&counter);
+}
+EXPORT_SYMBOL(gpiommc_next_id);
+
+static int __init gpiommc_modinit(void)
+{
+ int err;
+
+ err = platform_driver_register(&gpiommc_plat_driver);
+ if (err)
+ return err;
+
+#ifdef CONFIG_GPIOMMC_CONFIGFS
+ config_group_init(&gpiommc_subsys.su_group);
+ err = configfs_register_subsystem(&gpiommc_subsys);
+ if (err) {
+ platform_driver_unregister(&gpiommc_plat_driver);
+ return err;
+ }
+#endif /* CONFIG_GPIOMMC_CONFIGFS */
+
+ return 0;
+}
+module_init(gpiommc_modinit);
+
+static void __exit gpiommc_modexit(void)
+{
+#ifdef CONFIG_GPIOMMC_CONFIGFS
+ configfs_unregister_subsystem(&gpiommc_subsys);
+#endif
+ platform_driver_unregister(&gpiommc_plat_driver);
+}
+module_exit(gpiommc_modexit);
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -212,3 +212,28 @@ config MMC_TMIO
help
This provides support for the SD/MMC cell found in TC6393XB,
T7L66XB and also ipaq ASIC3
+
+config GPIOMMC
+ tristate "MMC/SD over GPIO-based SPI"
+ depends on MMC && MMC_SPI && SPI_GPIO
+ help
+ This driver hooks up the mmc_spi and spi_gpio modules so that
+ MMC/SD cards can be used on a GPIO based bus by bitbanging
+ the SPI protocol in software.
+
+ This driver provides a configfs interface to dynamically create
+ and destroy GPIO-based MMC/SD card devices. It also provides
+ a platform device interface API.
+ See Documentation/gpiommc.txt for details.
+
+ The module will be called gpiommc.
+
+ If unsure, say N.
+
+config GPIOMMC_CONFIGFS
+ bool
+ depends on GPIOMMC && CONFIGFS_FS
+ default y
+ help
+ This option automatically enables configfs support for gpiommc
+ if configfs is available.
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -27,4 +27,5 @@ endif
obj-$(CONFIG_MMC_S3C) += s3cmci.o
obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o
obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o
+obj-$(CONFIG_GPIOMMC) += gpiommc.o
--- /dev/null
+++ b/include/linux/mmc/gpiommc.h
@@ -0,0 +1,71 @@
+/*
+ * Device driver for MMC/SD cards driven over a GPIO bus.
+ *
+ * Copyright (c) 2008 Michael Buesch
+ *
+ * Licensed under the GNU/GPL version 2.
+ */
+#ifndef LINUX_GPIOMMC_H_
+#define LINUX_GPIOMMC_H_
+
+#include <linux/types.h>
+
+
+#define GPIOMMC_MAX_NAMELEN 15
+#define GPIOMMC_MAX_NAMELEN_STR __stringify(GPIOMMC_MAX_NAMELEN)
+
+/**
+ * struct gpiommc_pins - Hardware pin assignments
+ *
+ * @gpio_di: The GPIO number of the DATA IN pin
+ * @gpio_do: The GPIO number of the DATA OUT pin
+ * @gpio_clk: The GPIO number of the CLOCK pin
+ * @gpio_cs: The GPIO number of the CHIPSELECT pin
+ * @cs_activelow: If true, the chip is considered selected if @gpio_cs is low.
+ */
+struct gpiommc_pins {
+ unsigned int gpio_di;
+ unsigned int gpio_do;
+ unsigned int gpio_clk;
+ unsigned int gpio_cs;
+ bool cs_activelow;
+};
+
+/**
+ * struct gpiommc_platform_data - Platform data for a MMC-over-SPI-GPIO device.
+ *
+ * @name: The unique name string of the device.
+ * @pins: The hardware pin assignments.
+ * @mode: The hardware mode. This is either SPI_MODE_0,
+ * SPI_MODE_1, SPI_MODE_2 or SPI_MODE_3. See the SPI documentation.
+ * @no_spi_delay: Do not use delays in the lowlevel SPI bitbanging code.
+ * This is not standards compliant, but may be required for some
+ * embedded machines to gain reasonable speed.
+ * @max_bus_speed: The maximum speed of the SPI bus, in Hertz.
+ */
+struct gpiommc_platform_data {
+ char name[GPIOMMC_MAX_NAMELEN + 1];
+ struct gpiommc_pins pins;
+ u8 mode;
+ bool no_spi_delay;
+ unsigned int max_bus_speed;
+};
+
+/**
+ * GPIOMMC_PLATDEV_NAME - The platform device name string.
+ *
+ * The name string that has to be used for platform_device_alloc
+ * when allocating a gpiommc device.
+ */
+#define GPIOMMC_PLATDEV_NAME "gpiommc"
+
+/**
+ * gpiommc_next_id - Get another platform device ID number.
+ *
+ * This returns the next platform device ID number that has to be used
+ * for platform_device_alloc. The ID is opaque and should not be used for
+ * anything else.
+ */
+int gpiommc_next_id(void);
+
+#endif /* LINUX_GPIOMMC_H_ */
--- /dev/null
+++ b/Documentation/gpiommc.txt
@@ -0,0 +1,97 @@
+GPIOMMC - Driver for an MMC/SD card on a bitbanging GPIO SPI bus
+================================================================
+
+The gpiommc module hooks up the mmc_spi and spi_gpio modules for running an
+MMC or SD card on GPIO pins.
+
+Two interfaces for registering a new MMC/SD card device are provided:
+A static platform-device based mechanism and a dynamic configfs based interface.
+
+
+Registering devices via platform-device
+=======================================
+
+The platform-device interface is used for registering MMC/SD devices that are
+part of the hardware platform. This is most useful only for embedded machines
+with MMC/SD devices statically connected to the platform GPIO bus.
+
+The data structures are declared in <linux/mmc/gpiommc.h>.
+
+To register a new device, define an instance of struct gpiommc_platform_data.
+This structure holds any information about how the device is hooked up to the
+GPIO pins and what hardware modes the device supports. See the docbook-style
+documentation in the header file for more information on the struct fields.
+
+Then allocate a new instance of a platform device by doing:
+
+ pdev = platform_device_alloc(GPIOMMC_PLATDEV_NAME, gpiommc_next_id());
+
+This will allocate the platform device data structures and hook it up to the
+gpiommc driver.
+Then add the gpiommc_platform_data to the platform device.
+
+ err = platform_device_add_data(pdev, pdata, sizeof(struct gpiommc_platform_data));
+
+You may free the local instance of struct gpiommc_platform_data now. (So the
+struct may be allocated on the stack, too).
+Now simply register the platform device.
+
+ err = platform_device_add(pdev);
+
+Done. The gpiommc probe routine will be invoked now and you should see a kernel
+log message for the added device.
+
+
+Registering devices via configfs
+================================
+
+MMC/SD cards connected via GPIO often are a pretty dynamic thing, as for example
+selfmade hacks for soldering an MMC/SD card to standard GPIO pins on embedded
+hardware are a common situation.
+So we provide a dynamic interface to conveniently handle adding and removing
+devices from userspace, without the need to recompile the kernel.
+
+The "gpiommc" subdirectory at the configfs mountpoint is used for handling
+the dynamic configuration.
+
+To create a new device, it must first be allocated with mkdir.
+The following command will allocate a device named "my_mmc":
+ mkdir /config/gpiommc/my_mmc
+
+There are several configuration files available in the new
+/config/gpiommc/my_mmc/ directory:
+
+gpio_data_in = The SPI data-IN GPIO pin number.
+gpio_data_out = The SPI data-OUT GPIO pin number.
+gpio_clock = The SPI Clock GPIO pin number.
+gpio_chipselect = The SPI Chipselect GPIO pin number.
+gpio_chipselect_activelow = Boolean. If 0, Chipselect is active-HIGH.
+ If 1, Chipselect is active-LOW.
+spi_mode = The SPI data mode. Can be 0-3.
+spi_delay = Enable all delays in the lowlevel bitbanging.
+max_bus_speed = The maximum SPI bus speed. In Hertz.
+
+register = Not a configuration parameter.
+ Used to register the configured card
+ with the kernel.
+
+The device must first get configured and then registered by writing "1" to
+the "register" file.
+The configuration parameters "gpio_data_in", "gpio_data_out", "gpio_clock"
+and "gpio_chipselect" are essential and _must_ be configured before writing
+"1" to the "register" file. The registration will fail, otherwise.
+
+The default values for the other parameters are:
+gpio_chipselect_activelow = 1 (CS active-LOW)
+spi_mode = 0 (SPI_MODE_0)
+spi_delay = 1 (enabled)
+max_bus_speed = 5000000 (5 Mhz)
+
+Configuration values can not be changed after registration. To unregister
+the device, write a "0" to the "register" file. The configuration can be
+changed again after unregistering.
+
+To completely remove the device, simply rmdir the directory
+(/config/gpiommc/my_mmc in this example).
+There's no need to first unregister the device before removing it. That will
+be done automatically.
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1952,6 +1952,11 @@ L: linux-media@vger.kernel.org
T: git kernel.org:/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
S: Maintained
+GPIOMMC DRIVER
+P: Michael Buesch
+M: mb@bu3sch.de
+S: Maintained
+
HARDWARE MONITORING
L: lm-sensors@lm-sensors.org
W: http://www.lm-sensors.org/

View file

@ -0,0 +1,58 @@
The gpiommc configfs context structure needs locking, as configfs
does not lock access between files.
--- a/drivers/mmc/host/gpiommc.c
+++ b/drivers/mmc/host/gpiommc.c
@@ -143,6 +143,8 @@ struct gpiommc_configfs_device {
struct platform_device *pdev;
/* The configuration */
struct gpiommc_platform_data pdata;
+ /* Mutex to protect this structure */
+ struct mutex mutex;
};
#define GPIO_INVALID -1
@@ -233,6 +235,8 @@ static ssize_t gpiommc_config_attr_show(
unsigned int gpio;
int err = 0;
+ mutex_lock(&dev->mutex);
+
if (attr == &gpiommc_attr_DI) {
gpio = dev->pdata.pins.gpio_di;
if (gpio == GPIO_INVALID)
@@ -293,6 +297,8 @@ static ssize_t gpiommc_config_attr_show(
WARN_ON(1);
err = -ENOSYS;
out:
+ mutex_unlock(&dev->mutex);
+
return err ? err : count;
}
@@ -352,6 +358,8 @@ static ssize_t gpiommc_config_attr_store
int err = -EINVAL;
unsigned long data;
+ mutex_lock(&dev->mutex);
+
if (attr == &gpiommc_attr_register) {
err = strict_strtoul(page, 10, &data);
if (err)
@@ -477,6 +485,8 @@ static ssize_t gpiommc_config_attr_store
WARN_ON(1);
err = -ENOSYS;
out:
+ mutex_unlock(&dev->mutex);
+
return err ? err : count;
}
@@ -513,6 +523,7 @@ static struct config_item *gpiommc_make_
if (!dev)
return NULL;
+ mutex_init(&dev->mutex);
config_item_init_type_name(&dev->item, name,
&gpiommc_dev_ci_type);

View file

@ -0,0 +1,102 @@
--- a/drivers/char/cs5535_gpio.c
+++ b/drivers/char/cs5535_gpio.c
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/cdev.h>
+#include <linux/device.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/smp_lock.h>
@@ -48,6 +49,7 @@ static struct pci_device_id divil_pci[]
MODULE_DEVICE_TABLE(pci, divil_pci);
static struct cdev cs5535_gpio_cdev;
+static struct class *cs5535_gpio_class;
/* reserve 32 entries even though some aren't usable */
#define CS5535_GPIO_COUNT 32
@@ -66,9 +68,14 @@ static struct gpio_regmap rm[] =
{ 0x30, 0x00, '1', '0' }, /* GPIOx_READ_BACK / GPIOx_OUT_VAL */
{ 0x20, 0x20, 'I', 'i' }, /* GPIOx_IN_EN */
{ 0x04, 0x04, 'O', 'o' }, /* GPIOx_OUT_EN */
+ { 0x10, 0x10, 'A', 'a' }, /* GPIOx_OUT_AUX1_SEL */
+ { 0x14, 0x14, 'B', 'b' }, /* GPIOx_OUT_AUX2_SEL */
{ 0x08, 0x08, 't', 'T' }, /* GPIOx_OUT_OD_EN */
{ 0x18, 0x18, 'P', 'p' }, /* GPIOx_OUT_PU_EN */
{ 0x1c, 0x1c, 'D', 'd' }, /* GPIOx_OUT_PD_EN */
+ { 0x24, 0x24, 'N', 'n' }, /* GPIOx_IN_INV_EN */
+ { 0x0c, 0x0c, 'X', 'x' }, /* GPIOx_OUT_INV_EN */
+ { 0x00, 0x00, 'H', 'L' }, /* GPIOx_OUT_VAL */
};
@@ -177,7 +184,7 @@ static int __init cs5535_gpio_init(void)
{
dev_t dev_id;
u32 low, hi;
- int retval;
+ int retval, i;
if (pci_dev_present(divil_pci) == 0) {
printk(KERN_WARNING NAME ": DIVIL not found\n");
@@ -232,23 +239,54 @@ static int __init cs5535_gpio_init(void)
major = MAJOR(dev_id);
}
- if (retval) {
- release_region(gpio_base, CS5535_GPIO_SIZE);
- return -1;
- }
+ if (retval)
+ goto error;
printk(KERN_DEBUG NAME ": base=%#x mask=%#lx major=%d\n",
gpio_base, mask, major);
cdev_init(&cs5535_gpio_cdev, &cs5535_gpio_fops);
- cdev_add(&cs5535_gpio_cdev, dev_id, CS5535_GPIO_COUNT);
+ retval = cdev_add(&cs5535_gpio_cdev, dev_id, CS5535_GPIO_COUNT);
+ if (retval) {
+ kobject_put(&cs5535_gpio_cdev.kobj);
+ goto error_region;
+ }
+
+ cs5535_gpio_class = class_create(THIS_MODULE, "cs5535_gpio");
+ if (IS_ERR(cs5535_gpio_class)) {
+ printk(KERN_ERR "Error creating cs5535_gpio class\n");
+ cdev_del(&cs5535_gpio_cdev);
+ retval = PTR_ERR(cs5535_gpio_class);
+ goto error_region;
+ }
+
+ for (i = 0; i < CS5535_GPIO_COUNT; i++) {
+ if (mask & (1<<i)) {
+ device_create(cs5535_gpio_class, NULL, MKDEV(major, i), NULL, "cs5535_gpio%d", i);
+ }
+ }
return 0;
+
+error_region:
+ unregister_chrdev_region(dev_id, CS5535_GPIO_COUNT);
+error:
+ release_region(gpio_base, CS5535_GPIO_SIZE);
+ return retval;
}
static void __exit cs5535_gpio_cleanup(void)
{
dev_t dev_id = MKDEV(major, 0);
+ int i;
+
+ for (i = 0; i < CS5535_GPIO_COUNT; i++) {
+ if (mask & (1<<i)) {
+ device_destroy(cs5535_gpio_class, MKDEV(major, i));
+ }
+ }
+
+ class_destroy(cs5535_gpio_class);
cdev_del(&cs5535_gpio_cdev);
unregister_chrdev_region(dev_id, CS5535_GPIO_COUNT);

View file

@ -0,0 +1,103 @@
--- a/include/linux/netfilter/xt_sctp.h
+++ b/include/linux/netfilter/xt_sctp.h
@@ -37,54 +37,68 @@ struct xt_sctp_info {
#define SCTP_CHUNKMAP_SET(chunkmap, type) \
do { \
- (chunkmap)[type / bytes(u_int32_t)] |= \
+ chunkmap[type / bytes(u_int32_t)] |= \
1 << (type % bytes(u_int32_t)); \
} while (0)
#define SCTP_CHUNKMAP_CLEAR(chunkmap, type) \
do { \
- (chunkmap)[type / bytes(u_int32_t)] &= \
+ chunkmap[type / bytes(u_int32_t)] &= \
~(1 << (type % bytes(u_int32_t))); \
} while (0)
#define SCTP_CHUNKMAP_IS_SET(chunkmap, type) \
({ \
- ((chunkmap)[type / bytes (u_int32_t)] & \
+ (chunkmap[type / bytes (u_int32_t)] & \
(1 << (type % bytes (u_int32_t)))) ? 1: 0; \
})
-#define SCTP_CHUNKMAP_RESET(chunkmap) \
- memset((chunkmap), 0, sizeof(chunkmap))
+#define SCTP_CHUNKMAP_RESET(chunkmap) \
+ do { \
+ int i; \
+ for (i = 0; i < ARRAY_SIZE(chunkmap); i++) \
+ chunkmap[i] = 0; \
+ } while (0)
-#define SCTP_CHUNKMAP_SET_ALL(chunkmap) \
- memset((chunkmap), ~0U, sizeof(chunkmap))
+#define SCTP_CHUNKMAP_SET_ALL(chunkmap) \
+ do { \
+ int i; \
+ for (i = 0; i < ARRAY_SIZE(chunkmap); i++) \
+ chunkmap[i] = ~0; \
+ } while (0)
-#define SCTP_CHUNKMAP_COPY(destmap, srcmap) \
- memcpy((destmap), (srcmap), sizeof(srcmap))
+#define SCTP_CHUNKMAP_COPY(destmap, srcmap) \
+ do { \
+ int i; \
+ for (i = 0; i < ARRAY_SIZE(srcmap); i++) \
+ destmap[i] = srcmap[i]; \
+ } while (0)
+
+#define SCTP_CHUNKMAP_IS_CLEAR(chunkmap) \
+({ \
+ int i; \
+ int flag = 1; \
+ for (i = 0; i < ARRAY_SIZE(chunkmap); i++) { \
+ if (chunkmap[i]) { \
+ flag = 0; \
+ break; \
+ } \
+ } \
+ flag; \
+})
-#define SCTP_CHUNKMAP_IS_CLEAR(chunkmap) \
- __sctp_chunkmap_is_clear((chunkmap), ARRAY_SIZE(chunkmap))
-static inline bool
-__sctp_chunkmap_is_clear(const u_int32_t *chunkmap, unsigned int n)
-{
- unsigned int i;
- for (i = 0; i < n; ++i)
- if (chunkmap[i])
- return false;
- return true;
-}
-
-#define SCTP_CHUNKMAP_IS_ALL_SET(chunkmap) \
- __sctp_chunkmap_is_all_set((chunkmap), ARRAY_SIZE(chunkmap))
-static inline bool
-__sctp_chunkmap_is_all_set(const u_int32_t *chunkmap, unsigned int n)
-{
- unsigned int i;
- for (i = 0; i < n; ++i)
- if (chunkmap[i] != ~0U)
- return false;
- return true;
-}
+#define SCTP_CHUNKMAP_IS_ALL_SET(chunkmap) \
+({ \
+ int i; \
+ int flag = 1; \
+ for (i = 0; i < ARRAY_SIZE(chunkmap); i++) { \
+ if (chunkmap[i] != ~0) { \
+ flag = 0; \
+ break; \
+ } \
+ } \
+ flag; \
+})
#endif /* _XT_SCTP_H_ */

View file

@ -0,0 +1,524 @@
--- a/arch/powerpc/boot/crtsavres.S
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Special support for eabi and SVR4
- *
- * Copyright (C) 1995, 1996, 1998, 2000, 2001 Free Software Foundation, Inc.
- * Copyright 2008 Freescale Semiconductor, Inc.
- * Written By Michael Meissner
- *
- * Based on gcc/config/rs6000/crtsavres.asm from gcc
- *
- * This file 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, or (at your option) any
- * later version.
- *
- * In addition to the permissions in the GNU General Public License, the
- * Free Software Foundation gives you unlimited permission to link the
- * compiled version of this file with other programs, and to distribute
- * those programs without any restriction coming from the use of this
- * file. (The General Public License restrictions do apply in other
- * respects; for example, they cover modification of the file, and
- * distribution when not linked into another program.)
- *
- * This file 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; see the file COPYING. If not, write to
- * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- * As a special exception, if you link this library with files
- * compiled with GCC to produce an executable, this does not cause
- * the resulting executable to be covered by the GNU General Public License.
- * This exception does not however invalidate any other reasons why
- * the executable file might be covered by the GNU General Public License.
- */
-
- .file "crtsavres.S"
- .section ".text"
-
-/* On PowerPC64 Linux, these functions are provided by the linker. */
-#ifndef __powerpc64__
-
-#define _GLOBAL(name) \
- .type name,@function; \
- .globl name; \
-name:
-
-/* Routines for saving integer registers, called by the compiler. */
-/* Called with r11 pointing to the stack header word of the caller of the */
-/* function, just beyond the end of the integer save area. */
-
-_GLOBAL(_savegpr_14)
-_GLOBAL(_save32gpr_14)
- stw 14,-72(11) /* save gp registers */
-_GLOBAL(_savegpr_15)
-_GLOBAL(_save32gpr_15)
- stw 15,-68(11)
-_GLOBAL(_savegpr_16)
-_GLOBAL(_save32gpr_16)
- stw 16,-64(11)
-_GLOBAL(_savegpr_17)
-_GLOBAL(_save32gpr_17)
- stw 17,-60(11)
-_GLOBAL(_savegpr_18)
-_GLOBAL(_save32gpr_18)
- stw 18,-56(11)
-_GLOBAL(_savegpr_19)
-_GLOBAL(_save32gpr_19)
- stw 19,-52(11)
-_GLOBAL(_savegpr_20)
-_GLOBAL(_save32gpr_20)
- stw 20,-48(11)
-_GLOBAL(_savegpr_21)
-_GLOBAL(_save32gpr_21)
- stw 21,-44(11)
-_GLOBAL(_savegpr_22)
-_GLOBAL(_save32gpr_22)
- stw 22,-40(11)
-_GLOBAL(_savegpr_23)
-_GLOBAL(_save32gpr_23)
- stw 23,-36(11)
-_GLOBAL(_savegpr_24)
-_GLOBAL(_save32gpr_24)
- stw 24,-32(11)
-_GLOBAL(_savegpr_25)
-_GLOBAL(_save32gpr_25)
- stw 25,-28(11)
-_GLOBAL(_savegpr_26)
-_GLOBAL(_save32gpr_26)
- stw 26,-24(11)
-_GLOBAL(_savegpr_27)
-_GLOBAL(_save32gpr_27)
- stw 27,-20(11)
-_GLOBAL(_savegpr_28)
-_GLOBAL(_save32gpr_28)
- stw 28,-16(11)
-_GLOBAL(_savegpr_29)
-_GLOBAL(_save32gpr_29)
- stw 29,-12(11)
-_GLOBAL(_savegpr_30)
-_GLOBAL(_save32gpr_30)
- stw 30,-8(11)
-_GLOBAL(_savegpr_31)
-_GLOBAL(_save32gpr_31)
- stw 31,-4(11)
- blr
-
-/* Routines for restoring integer registers, called by the compiler. */
-/* Called with r11 pointing to the stack header word of the caller of the */
-/* function, just beyond the end of the integer restore area. */
-
-_GLOBAL(_restgpr_14)
-_GLOBAL(_rest32gpr_14)
- lwz 14,-72(11) /* restore gp registers */
-_GLOBAL(_restgpr_15)
-_GLOBAL(_rest32gpr_15)
- lwz 15,-68(11)
-_GLOBAL(_restgpr_16)
-_GLOBAL(_rest32gpr_16)
- lwz 16,-64(11)
-_GLOBAL(_restgpr_17)
-_GLOBAL(_rest32gpr_17)
- lwz 17,-60(11)
-_GLOBAL(_restgpr_18)
-_GLOBAL(_rest32gpr_18)
- lwz 18,-56(11)
-_GLOBAL(_restgpr_19)
-_GLOBAL(_rest32gpr_19)
- lwz 19,-52(11)
-_GLOBAL(_restgpr_20)
-_GLOBAL(_rest32gpr_20)
- lwz 20,-48(11)
-_GLOBAL(_restgpr_21)
-_GLOBAL(_rest32gpr_21)
- lwz 21,-44(11)
-_GLOBAL(_restgpr_22)
-_GLOBAL(_rest32gpr_22)
- lwz 22,-40(11)
-_GLOBAL(_restgpr_23)
-_GLOBAL(_rest32gpr_23)
- lwz 23,-36(11)
-_GLOBAL(_restgpr_24)
-_GLOBAL(_rest32gpr_24)
- lwz 24,-32(11)
-_GLOBAL(_restgpr_25)
-_GLOBAL(_rest32gpr_25)
- lwz 25,-28(11)
-_GLOBAL(_restgpr_26)
-_GLOBAL(_rest32gpr_26)
- lwz 26,-24(11)
-_GLOBAL(_restgpr_27)
-_GLOBAL(_rest32gpr_27)
- lwz 27,-20(11)
-_GLOBAL(_restgpr_28)
-_GLOBAL(_rest32gpr_28)
- lwz 28,-16(11)
-_GLOBAL(_restgpr_29)
-_GLOBAL(_rest32gpr_29)
- lwz 29,-12(11)
-_GLOBAL(_restgpr_30)
-_GLOBAL(_rest32gpr_30)
- lwz 30,-8(11)
-_GLOBAL(_restgpr_31)
-_GLOBAL(_rest32gpr_31)
- lwz 31,-4(11)
- blr
-
-/* Routines for restoring integer registers, called by the compiler. */
-/* Called with r11 pointing to the stack header word of the caller of the */
-/* function, just beyond the end of the integer restore area. */
-
-_GLOBAL(_restgpr_14_x)
-_GLOBAL(_rest32gpr_14_x)
- lwz 14,-72(11) /* restore gp registers */
-_GLOBAL(_restgpr_15_x)
-_GLOBAL(_rest32gpr_15_x)
- lwz 15,-68(11)
-_GLOBAL(_restgpr_16_x)
-_GLOBAL(_rest32gpr_16_x)
- lwz 16,-64(11)
-_GLOBAL(_restgpr_17_x)
-_GLOBAL(_rest32gpr_17_x)
- lwz 17,-60(11)
-_GLOBAL(_restgpr_18_x)
-_GLOBAL(_rest32gpr_18_x)
- lwz 18,-56(11)
-_GLOBAL(_restgpr_19_x)
-_GLOBAL(_rest32gpr_19_x)
- lwz 19,-52(11)
-_GLOBAL(_restgpr_20_x)
-_GLOBAL(_rest32gpr_20_x)
- lwz 20,-48(11)
-_GLOBAL(_restgpr_21_x)
-_GLOBAL(_rest32gpr_21_x)
- lwz 21,-44(11)
-_GLOBAL(_restgpr_22_x)
-_GLOBAL(_rest32gpr_22_x)
- lwz 22,-40(11)
-_GLOBAL(_restgpr_23_x)
-_GLOBAL(_rest32gpr_23_x)
- lwz 23,-36(11)
-_GLOBAL(_restgpr_24_x)
-_GLOBAL(_rest32gpr_24_x)
- lwz 24,-32(11)
-_GLOBAL(_restgpr_25_x)
-_GLOBAL(_rest32gpr_25_x)
- lwz 25,-28(11)
-_GLOBAL(_restgpr_26_x)
-_GLOBAL(_rest32gpr_26_x)
- lwz 26,-24(11)
-_GLOBAL(_restgpr_27_x)
-_GLOBAL(_rest32gpr_27_x)
- lwz 27,-20(11)
-_GLOBAL(_restgpr_28_x)
-_GLOBAL(_rest32gpr_28_x)
- lwz 28,-16(11)
-_GLOBAL(_restgpr_29_x)
-_GLOBAL(_rest32gpr_29_x)
- lwz 29,-12(11)
-_GLOBAL(_restgpr_30_x)
-_GLOBAL(_rest32gpr_30_x)
- lwz 30,-8(11)
-_GLOBAL(_restgpr_31_x)
-_GLOBAL(_rest32gpr_31_x)
- lwz 0,4(11)
- lwz 31,-4(11)
- mtlr 0
- mr 1,11
- blr
-#endif
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -54,7 +54,7 @@ $(addprefix $(obj)/,$(zlib) cuboot-c2k.o
$(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
src-libfdt := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
-src-wlib := string.S crt0.S crtsavres.S stdio.c main.c \
+src-wlib := string.S crt0.S stdio.c main.c \
$(addprefix libfdt/,$(src-libfdt)) libfdt-wrapper.c \
ns16550.c serial.c simple_alloc.c div64.S util.S \
gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \
--- a/arch/powerpc/kernel/prom_init_check.sh
+++ b/arch/powerpc/kernel/prom_init_check.sh
@@ -48,20 +48,6 @@ do
fi
done
- # ignore register save/restore funcitons
- if [ "${UNDEF:0:9}" = "_restgpr_" ]; then
- OK=1
- fi
- if [ "${UNDEF:0:11}" = "_rest32gpr_" ]; then
- OK=1
- fi
- if [ "${UNDEF:0:9}" = "_savegpr_" ]; then
- OK=1
- fi
- if [ "${UNDEF:0:11}" = "_save32gpr_" ]; then
- OK=1
- fi
-
if [ $OK -eq 0 ]; then
ERROR=1
echo "Error: External symbol '$UNDEF' referenced" \
--- a/arch/powerpc/lib/crtsavres.S
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Special support for eabi and SVR4
- *
- * Copyright (C) 1995, 1996, 1998, 2000, 2001 Free Software Foundation, Inc.
- * Copyright 2008 Freescale Semiconductor, Inc.
- * Written By Michael Meissner
- *
- * Based on gcc/config/rs6000/crtsavres.asm from gcc
- *
- * This file 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, or (at your option) any
- * later version.
- *
- * In addition to the permissions in the GNU General Public License, the
- * Free Software Foundation gives you unlimited permission to link the
- * compiled version of this file with other programs, and to distribute
- * those programs without any restriction coming from the use of this
- * file. (The General Public License restrictions do apply in other
- * respects; for example, they cover modification of the file, and
- * distribution when not linked into another program.)
- *
- * This file 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; see the file COPYING. If not, write to
- * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- * As a special exception, if you link this library with files
- * compiled with GCC to produce an executable, this does not cause
- * the resulting executable to be covered by the GNU General Public License.
- * This exception does not however invalidate any other reasons why
- * the executable file might be covered by the GNU General Public License.
- */
-
-#include <asm/ppc_asm.h>
-
- .file "crtsavres.S"
- .section ".text"
-
-#ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
-
-/* Routines for saving integer registers, called by the compiler. */
-/* Called with r11 pointing to the stack header word of the caller of the */
-/* function, just beyond the end of the integer save area. */
-
-_GLOBAL(_savegpr_14)
-_GLOBAL(_save32gpr_14)
- stw 14,-72(11) /* save gp registers */
-_GLOBAL(_savegpr_15)
-_GLOBAL(_save32gpr_15)
- stw 15,-68(11)
-_GLOBAL(_savegpr_16)
-_GLOBAL(_save32gpr_16)
- stw 16,-64(11)
-_GLOBAL(_savegpr_17)
-_GLOBAL(_save32gpr_17)
- stw 17,-60(11)
-_GLOBAL(_savegpr_18)
-_GLOBAL(_save32gpr_18)
- stw 18,-56(11)
-_GLOBAL(_savegpr_19)
-_GLOBAL(_save32gpr_19)
- stw 19,-52(11)
-_GLOBAL(_savegpr_20)
-_GLOBAL(_save32gpr_20)
- stw 20,-48(11)
-_GLOBAL(_savegpr_21)
-_GLOBAL(_save32gpr_21)
- stw 21,-44(11)
-_GLOBAL(_savegpr_22)
-_GLOBAL(_save32gpr_22)
- stw 22,-40(11)
-_GLOBAL(_savegpr_23)
-_GLOBAL(_save32gpr_23)
- stw 23,-36(11)
-_GLOBAL(_savegpr_24)
-_GLOBAL(_save32gpr_24)
- stw 24,-32(11)
-_GLOBAL(_savegpr_25)
-_GLOBAL(_save32gpr_25)
- stw 25,-28(11)
-_GLOBAL(_savegpr_26)
-_GLOBAL(_save32gpr_26)
- stw 26,-24(11)
-_GLOBAL(_savegpr_27)
-_GLOBAL(_save32gpr_27)
- stw 27,-20(11)
-_GLOBAL(_savegpr_28)
-_GLOBAL(_save32gpr_28)
- stw 28,-16(11)
-_GLOBAL(_savegpr_29)
-_GLOBAL(_save32gpr_29)
- stw 29,-12(11)
-_GLOBAL(_savegpr_30)
-_GLOBAL(_save32gpr_30)
- stw 30,-8(11)
-_GLOBAL(_savegpr_31)
-_GLOBAL(_save32gpr_31)
- stw 31,-4(11)
- blr
-
-/* Routines for restoring integer registers, called by the compiler. */
-/* Called with r11 pointing to the stack header word of the caller of the */
-/* function, just beyond the end of the integer restore area. */
-
-_GLOBAL(_restgpr_14)
-_GLOBAL(_rest32gpr_14)
- lwz 14,-72(11) /* restore gp registers */
-_GLOBAL(_restgpr_15)
-_GLOBAL(_rest32gpr_15)
- lwz 15,-68(11)
-_GLOBAL(_restgpr_16)
-_GLOBAL(_rest32gpr_16)
- lwz 16,-64(11)
-_GLOBAL(_restgpr_17)
-_GLOBAL(_rest32gpr_17)
- lwz 17,-60(11)
-_GLOBAL(_restgpr_18)
-_GLOBAL(_rest32gpr_18)
- lwz 18,-56(11)
-_GLOBAL(_restgpr_19)
-_GLOBAL(_rest32gpr_19)
- lwz 19,-52(11)
-_GLOBAL(_restgpr_20)
-_GLOBAL(_rest32gpr_20)
- lwz 20,-48(11)
-_GLOBAL(_restgpr_21)
-_GLOBAL(_rest32gpr_21)
- lwz 21,-44(11)
-_GLOBAL(_restgpr_22)
-_GLOBAL(_rest32gpr_22)
- lwz 22,-40(11)
-_GLOBAL(_restgpr_23)
-_GLOBAL(_rest32gpr_23)
- lwz 23,-36(11)
-_GLOBAL(_restgpr_24)
-_GLOBAL(_rest32gpr_24)
- lwz 24,-32(11)
-_GLOBAL(_restgpr_25)
-_GLOBAL(_rest32gpr_25)
- lwz 25,-28(11)
-_GLOBAL(_restgpr_26)
-_GLOBAL(_rest32gpr_26)
- lwz 26,-24(11)
-_GLOBAL(_restgpr_27)
-_GLOBAL(_rest32gpr_27)
- lwz 27,-20(11)
-_GLOBAL(_restgpr_28)
-_GLOBAL(_rest32gpr_28)
- lwz 28,-16(11)
-_GLOBAL(_restgpr_29)
-_GLOBAL(_rest32gpr_29)
- lwz 29,-12(11)
-_GLOBAL(_restgpr_30)
-_GLOBAL(_rest32gpr_30)
- lwz 30,-8(11)
-_GLOBAL(_restgpr_31)
-_GLOBAL(_rest32gpr_31)
- lwz 31,-4(11)
- blr
-
-/* Routines for restoring integer registers, called by the compiler. */
-/* Called with r11 pointing to the stack header word of the caller of the */
-/* function, just beyond the end of the integer restore area. */
-
-_GLOBAL(_restgpr_14_x)
-_GLOBAL(_rest32gpr_14_x)
- lwz 14,-72(11) /* restore gp registers */
-_GLOBAL(_restgpr_15_x)
-_GLOBAL(_rest32gpr_15_x)
- lwz 15,-68(11)
-_GLOBAL(_restgpr_16_x)
-_GLOBAL(_rest32gpr_16_x)
- lwz 16,-64(11)
-_GLOBAL(_restgpr_17_x)
-_GLOBAL(_rest32gpr_17_x)
- lwz 17,-60(11)
-_GLOBAL(_restgpr_18_x)
-_GLOBAL(_rest32gpr_18_x)
- lwz 18,-56(11)
-_GLOBAL(_restgpr_19_x)
-_GLOBAL(_rest32gpr_19_x)
- lwz 19,-52(11)
-_GLOBAL(_restgpr_20_x)
-_GLOBAL(_rest32gpr_20_x)
- lwz 20,-48(11)
-_GLOBAL(_restgpr_21_x)
-_GLOBAL(_rest32gpr_21_x)
- lwz 21,-44(11)
-_GLOBAL(_restgpr_22_x)
-_GLOBAL(_rest32gpr_22_x)
- lwz 22,-40(11)
-_GLOBAL(_restgpr_23_x)
-_GLOBAL(_rest32gpr_23_x)
- lwz 23,-36(11)
-_GLOBAL(_restgpr_24_x)
-_GLOBAL(_rest32gpr_24_x)
- lwz 24,-32(11)
-_GLOBAL(_restgpr_25_x)
-_GLOBAL(_rest32gpr_25_x)
- lwz 25,-28(11)
-_GLOBAL(_restgpr_26_x)
-_GLOBAL(_rest32gpr_26_x)
- lwz 26,-24(11)
-_GLOBAL(_restgpr_27_x)
-_GLOBAL(_rest32gpr_27_x)
- lwz 27,-20(11)
-_GLOBAL(_restgpr_28_x)
-_GLOBAL(_rest32gpr_28_x)
- lwz 28,-16(11)
-_GLOBAL(_restgpr_29_x)
-_GLOBAL(_rest32gpr_29_x)
- lwz 29,-12(11)
-_GLOBAL(_restgpr_30_x)
-_GLOBAL(_rest32gpr_30_x)
- lwz 30,-8(11)
-_GLOBAL(_restgpr_31_x)
-_GLOBAL(_rest32gpr_31_x)
- lwz 0,4(11)
- lwz 31,-4(11)
- mtlr 0
- mr 1,11
- blr
-#endif
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -11,7 +11,7 @@ CFLAGS_REMOVE_feature-fixups.o = -pg
obj-y := string.o alloc.o \
checksum_$(CONFIG_WORD_SIZE).o
-obj-$(CONFIG_PPC32) += div64.o copy_32.o crtsavres.o
+obj-$(CONFIG_PPC32) += div64.o copy_32.o
obj-$(CONFIG_HAS_IOMEM) += devres.o
obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o \
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -92,8 +92,6 @@ endif
else
KBUILD_CFLAGS += $(call cc-option,-mtune=power4)
endif
-else
-LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
endif
ifeq ($(CONFIG_TUNE_CELL),y)

View file

@ -0,0 +1,25 @@
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -734,6 +734,8 @@ config CRYPTO_ANSI_CPRNG
for cryptographic modules. Uses the Algorithm specified in
ANSI X9.31 A.2.4
+source "crypto/ocf/Kconfig"
+
source "drivers/crypto/Kconfig"
endif # if CRYPTO
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -80,6 +80,11 @@ obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_
obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
#
+# OCF
+#
+obj-$(CONFIG_OCF_OCF) += ocf/
+
+#
# generic algorithms and the async_tx api
#
obj-$(CONFIG_XOR_BLOCKS) += xor.o

View file

@ -0,0 +1,152 @@
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -129,6 +129,9 @@
* unsigned int value);
* void add_interrupt_randomness(int irq);
*
+ * void random_input_words(__u32 *buf, size_t wordcount, int ent_count)
+ * int random_input_wait(void);
+ *
* add_input_randomness() uses the input layer interrupt timing, as well as
* the event type information from the hardware.
*
@@ -140,6 +143,13 @@
* a better measure, since the timing of the disk interrupts are more
* unpredictable.
*
+ * random_input_words() just provides a raw block of entropy to the input
+ * pool, such as from a hardware entropy generator.
+ *
+ * random_input_wait() suspends the caller until such time as the
+ * entropy pool falls below the write threshold, and returns a count of how
+ * much entropy (in bits) is needed to sustain the pool.
+ *
* All of these routines try to estimate how many bits of randomness a
* particular randomness source. They do this by keeping track of the
* first and second order deltas of the event timings.
@@ -708,6 +718,61 @@ void add_disk_randomness(struct gendisk
}
#endif
+/*
+ * random_input_words - add bulk entropy to pool
+ *
+ * @buf: buffer to add
+ * @wordcount: number of __u32 words to add
+ * @ent_count: total amount of entropy (in bits) to credit
+ *
+ * this provides bulk input of entropy to the input pool
+ *
+ */
+void random_input_words(__u32 *buf, size_t wordcount, int ent_count)
+{
+ mix_pool_bytes(&input_pool, buf, wordcount*4);
+
+ credit_entropy_bits(&input_pool, ent_count);
+
+ DEBUG_ENT("crediting %d bits => %d\n",
+ ent_count, input_pool.entropy_count);
+ /*
+ * Wake up waiting processes if we have enough
+ * entropy.
+ */
+ if (input_pool.entropy_count >= random_read_wakeup_thresh)
+ wake_up_interruptible(&random_read_wait);
+}
+EXPORT_SYMBOL(random_input_words);
+
+/*
+ * random_input_wait - wait until random needs entropy
+ *
+ * this function sleeps until the /dev/random subsystem actually
+ * needs more entropy, and then return the amount of entropy
+ * that it would be nice to have added to the system.
+ */
+int random_input_wait(void)
+{
+ int count;
+
+ wait_event_interruptible(random_write_wait,
+ input_pool.entropy_count < random_write_wakeup_thresh);
+
+ count = random_write_wakeup_thresh - input_pool.entropy_count;
+
+ /* likely we got woken up due to a signal */
+ if (count <= 0) count = random_read_wakeup_thresh;
+
+ DEBUG_ENT("requesting %d bits from input_wait()er %d<%d\n",
+ count,
+ input_pool.entropy_count, random_write_wakeup_thresh);
+
+ return count;
+}
+EXPORT_SYMBOL(random_input_wait);
+
+
#define EXTRACT_SIZE 10
/*********************************************************************
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -140,6 +140,7 @@ SYSCALL_DEFINE1(dup, unsigned int, filde
}
return ret;
}
+EXPORT_SYMBOL(sys_dup);
#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC | O_DIRECT | O_NOATIME)
--- a/include/linux/miscdevice.h
+++ b/include/linux/miscdevice.h
@@ -12,6 +12,7 @@
#define APOLLO_MOUSE_MINOR 7
#define PC110PAD_MINOR 9
/*#define ADB_MOUSE_MINOR 10 FIXME OBSOLETE */
+#define CRYPTODEV_MINOR 70 /* /dev/crypto */
#define WATCHDOG_MINOR 130 /* Watchdog timer */
#define TEMP_MINOR 131 /* Temperature Sensor */
#define RTC_MINOR 135
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -34,6 +34,30 @@
/* Clear the entropy pool and associated counters. (Superuser only.) */
#define RNDCLEARPOOL _IO( 'R', 0x06 )
+#ifdef CONFIG_FIPS_RNG
+
+/* Size of seed value - equal to AES blocksize */
+#define AES_BLOCK_SIZE_BYTES 16
+#define SEED_SIZE_BYTES AES_BLOCK_SIZE_BYTES
+/* Size of AES key */
+#define KEY_SIZE_BYTES 16
+
+/* ioctl() structure used by FIPS 140-2 Tests */
+struct rand_fips_test {
+ unsigned char key[KEY_SIZE_BYTES]; /* Input */
+ unsigned char datetime[SEED_SIZE_BYTES]; /* Input */
+ unsigned char seed[SEED_SIZE_BYTES]; /* Input */
+ unsigned char result[SEED_SIZE_BYTES]; /* Output */
+};
+
+/* FIPS 140-2 RNG Variable Seed Test. (Superuser only.) */
+#define RNDFIPSVST _IOWR('R', 0x10, struct rand_fips_test)
+
+/* FIPS 140-2 RNG Monte Carlo Test. (Superuser only.) */
+#define RNDFIPSMCT _IOWR('R', 0x11, struct rand_fips_test)
+
+#endif /* #ifdef CONFIG_FIPS_RNG */
+
struct rand_pool_info {
int entropy_count;
int buf_size;
@@ -50,6 +74,10 @@ extern void add_input_randomness(unsigne
unsigned int value);
extern void add_interrupt_randomness(int irq);
+extern void random_input_words(__u32 *buf, size_t wordcount, int ent_count);
+extern int random_input_wait(void);
+#define HAS_RANDOM_INPUT_WAIT 1
+
extern void get_random_bytes(void *buf, int nbytes);
void generate_random_uuid(unsigned char uuid_out[16]);

View file

@ -0,0 +1,11 @@
--- a/crypto/ocf/cryptosoft.c
+++ b/crypto/ocf/cryptosoft.c
@@ -47,7 +47,7 @@
#include <linux/mm.h>
#include <linux/skbuff.h>
#include <linux/random.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include <cryptodev.h>
#include <uio.h>

View file

@ -0,0 +1,197 @@
--- a/crypto/ocf/random.c
+++ b/crypto/ocf/random.c
@@ -49,6 +49,7 @@
#include <linux/unistd.h>
#include <linux/poll.h>
#include <linux/random.h>
+#include <linux/kthread.h>
#include <cryptodev.h>
#ifdef CONFIG_OCF_FIPS
@@ -81,7 +82,7 @@ struct random_op {
static int random_proc(void *arg);
-static pid_t randomproc = (pid_t) -1;
+static struct task_struct *random_task;
static spinlock_t random_lock;
/*
@@ -141,13 +142,18 @@ crypto_rregister(
spin_lock_irqsave(&random_lock, flags);
list_add_tail(&rops->random_list, &random_ops);
if (!started) {
- randomproc = kernel_thread(random_proc, NULL, CLONE_FS|CLONE_FILES);
- if (randomproc < 0) {
- ret = randomproc;
+ struct task_struct *t;
+
+ t = kthread_create(random_proc, NULL, "ocf-random");
+ if (IS_ERR(t)) {
printk("crypto: crypto_rregister cannot start random thread; "
"error %d", ret);
- } else
+ ret = PTR_ERR(t);
+ } else {
+ random_task = t;
+ wake_up_process(t);
started = 1;
+ }
}
spin_unlock_irqrestore(&random_lock, flags);
@@ -172,7 +178,7 @@ crypto_runregister_all(u_int32_t driveri
spin_lock_irqsave(&random_lock, flags);
if (list_empty(&random_ops) && started)
- kill_proc(randomproc, SIGKILL, 1);
+ send_sig(SIGKILL, random_task, 1);
spin_unlock_irqrestore(&random_lock, flags);
return(0);
}
@@ -308,7 +314,7 @@ random_proc(void *arg)
bad_alloc:
spin_lock_irq(&random_lock);
- randomproc = (pid_t) -1;
+ random_task = NULL;
started = 0;
spin_unlock_irq(&random_lock);
--- a/crypto/ocf/crypto.c
+++ b/crypto/ocf/crypto.c
@@ -74,6 +74,7 @@ __FBSDID("$FreeBSD: src/sys/opencrypto/c
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/version.h>
+#include <linux/kthread.h>
#include <cryptodev.h>
/*
@@ -255,10 +256,10 @@ module_param(crypto_devallowsoft, int, 0
MODULE_PARM_DESC(crypto_devallowsoft,
"Enable/disable use of software crypto support");
-static pid_t cryptoproc = (pid_t) -1;
+static struct task_struct *crypto_task;
static struct completion cryptoproc_exited;
static DECLARE_WAIT_QUEUE_HEAD(cryptoproc_wait);
-static pid_t cryptoretproc = (pid_t) -1;
+static struct task_struct *cryptoret_task;
static struct completion cryptoretproc_exited;
static DECLARE_WAIT_QUEUE_HEAD(cryptoretproc_wait);
@@ -1401,7 +1402,7 @@ crypto_proc(void *arg)
wait_event_interruptible(cryptoproc_wait,
!(list_empty(&crp_q) || crypto_all_qblocked) ||
!(list_empty(&crp_kq) || crypto_all_kqblocked) ||
- cryptoproc == (pid_t) -1);
+ crypto_task == NULL);
crp_sleep = 0;
if (signal_pending (current)) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
@@ -1414,7 +1415,7 @@ crypto_proc(void *arg)
}
CRYPTO_Q_LOCK();
dprintk("%s - awake\n", __FUNCTION__);
- if (cryptoproc == (pid_t) -1)
+ if (crypto_task == NULL)
break;
cryptostats.cs_intrs++;
}
@@ -1470,7 +1471,7 @@ crypto_ret_proc(void *arg)
dprintk("%s - sleeping\n", __FUNCTION__);
CRYPTO_RETQ_UNLOCK();
wait_event_interruptible(cryptoretproc_wait,
- cryptoretproc == (pid_t) -1 ||
+ cryptoret_task == NULL ||
!list_empty(&crp_ret_q) ||
!list_empty(&crp_ret_kq));
if (signal_pending (current)) {
@@ -1484,7 +1485,7 @@ crypto_ret_proc(void *arg)
}
CRYPTO_RETQ_LOCK();
dprintk("%s - awake\n", __FUNCTION__);
- if (cryptoretproc == (pid_t) -1) {
+ if (cryptoret_task == NULL) {
dprintk("%s - EXITING!\n", __FUNCTION__);
break;
}
@@ -1597,6 +1598,7 @@ DB_SHOW_COMMAND(kcrypto, db_show_kcrypto
static int
crypto_init(void)
{
+ struct task_struct *t;
int error;
dprintk("%s(0x%x)\n", __FUNCTION__, (int) crypto_init);
@@ -1643,23 +1645,27 @@ crypto_init(void)
init_completion(&cryptoproc_exited);
init_completion(&cryptoretproc_exited);
- cryptoproc = 0; /* to avoid race condition where proc runs first */
- cryptoproc = kernel_thread(crypto_proc, NULL, CLONE_FS|CLONE_FILES);
- if (cryptoproc < 0) {
- error = cryptoproc;
+ crypto_task = NULL; /* to avoid race condition where proc runs first */
+ t = kthread_create(crypto_proc, NULL, "ocf-crypto");
+ if (IS_ERR(t)) {
+ error = PTR_ERR(t);
printk("crypto: crypto_init cannot start crypto thread; error %d",
error);
goto bad;
}
+ wake_up_process(t);
+ crypto_task = t;
- cryptoretproc = 0; /* to avoid race condition where proc runs first */
- cryptoretproc = kernel_thread(crypto_ret_proc, NULL, CLONE_FS|CLONE_FILES);
- if (cryptoretproc < 0) {
- error = cryptoretproc;
+ cryptoret_task = NULL; /* to avoid race condition where proc runs first */
+ t = kthread_create(crypto_ret_proc, NULL, "ocf-cryptoret");
+ if (IS_ERR(t)) {
+ error = PTR_ERR(t);
printk("crypto: crypto_init cannot start cryptoret thread; error %d",
error);
goto bad;
}
+ wake_up_process(t);
+ cryptoret_task = t;
return 0;
bad:
@@ -1671,7 +1677,7 @@ bad:
static void
crypto_exit(void)
{
- pid_t p;
+ struct task_struct *t;
unsigned long d_flags;
dprintk("%s()\n", __FUNCTION__);
@@ -1681,18 +1687,18 @@ crypto_exit(void)
*/
CRYPTO_DRIVER_LOCK();
- p = cryptoproc;
- cryptoproc = (pid_t) -1;
- kill_proc(p, SIGTERM, 1);
+ t = crypto_task;
+ crypto_task = NULL;
+ send_sig(SIGTERM, t, 1);
wake_up_interruptible(&cryptoproc_wait);
CRYPTO_DRIVER_UNLOCK();
wait_for_completion(&cryptoproc_exited);
CRYPTO_DRIVER_LOCK();
- p = cryptoretproc;
- cryptoretproc = (pid_t) -1;
- kill_proc(p, SIGTERM, 1);
+ t = cryptoret_task;
+ cryptoret_task = NULL;
+ send_sig(SIGTERM, t, 1);
wake_up_interruptible(&cryptoretproc_wait);
CRYPTO_DRIVER_UNLOCK();

View file

@ -0,0 +1,20 @@
--- a/drivers/ssb/Kconfig
+++ b/drivers/ssb/Kconfig
@@ -27,7 +27,7 @@ config SSB_SPROM
# Support for Block-I/O. SELECT this from the driver that needs it.
config SSB_BLOCKIO
- bool
+ bool "add SSB_BLOCKIO support"
depends on SSB
config SSB_PCIHOST_POSSIBLE
@@ -49,7 +49,7 @@ config SSB_PCIHOST
config SSB_B43_PCI_BRIDGE
bool
depends on SSB_PCIHOST
- default n
+ default y
config SSB_PCMCIAHOST_POSSIBLE
bool

View file

@ -0,0 +1,107 @@
--- a/drivers/ssb/pci.c
+++ b/drivers/ssb/pci.c
@@ -514,6 +514,7 @@ unsupported:
static int ssb_pci_sprom_get(struct ssb_bus *bus,
struct ssb_sprom *sprom)
{
+ const struct ssb_sprom *fallback;
int err = -ENOMEM;
u16 *buf;
@@ -533,12 +534,23 @@ static int ssb_pci_sprom_get(struct ssb_
bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
sprom_do_read(bus, buf);
err = sprom_check_crc(buf, bus->sprom_size);
- if (err)
+ if (err) {
+ /* All CRC attempts failed.
+ * Maybe there is no SPROM on the device?
+ * If we have a fallback, use that. */
+ fallback = ssb_get_fallback_sprom();
+ if (fallback) {
+ memcpy(sprom, fallback, sizeof(*sprom));
+ err = 0;
+ goto out_free;
+ }
ssb_printk(KERN_WARNING PFX "WARNING: Invalid"
" SPROM CRC (corrupt SPROM)\n");
+ }
}
err = sprom_extract(bus, sprom, buf, bus->sprom_size);
+out_free:
kfree(buf);
out:
return err;
--- a/drivers/ssb/sprom.c
+++ b/drivers/ssb/sprom.c
@@ -14,6 +14,9 @@
#include "ssb_private.h"
+static const struct ssb_sprom *fallback_sprom;
+
+
static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len,
size_t sprom_size_words)
{
@@ -131,3 +134,36 @@ out:
return res;
return err ? err : count;
}
+
+/**
+ * ssb_arch_set_fallback_sprom - Set a fallback SPROM for use if no SPROM is found.
+ *
+ * @sprom: The SPROM data structure to register.
+ *
+ * With this function the architecture implementation may register a fallback
+ * SPROM data structure. The fallback is only used for PCI based SSB devices,
+ * where no valid SPROM can be found in the shadow registers.
+ *
+ * This function is useful for weird architectures that have a half-assed SSB device
+ * hardwired to their PCI bus.
+ *
+ * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently
+ * don't use this fallback.
+ * Architectures must provide the SPROM for native SSB devices anyway,
+ * so the fallback also isn't used for native devices.
+ *
+ * This function is available for architecture code, only. So it is not exported.
+ */
+int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom)
+{
+ if (fallback_sprom)
+ return -EEXIST;
+ fallback_sprom = sprom;
+
+ return 0;
+}
+
+const struct ssb_sprom *ssb_get_fallback_sprom(void)
+{
+ return fallback_sprom;
+}
--- a/drivers/ssb/ssb_private.h
+++ b/drivers/ssb/ssb_private.h
@@ -131,6 +131,7 @@ ssize_t ssb_attr_sprom_store(struct ssb_
const char *buf, size_t count,
int (*sprom_check_crc)(const u16 *sprom, size_t size),
int (*sprom_write)(struct ssb_bus *bus, const u16 *sprom));
+extern const struct ssb_sprom *ssb_get_fallback_sprom(void);
/* core.c */
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -339,6 +339,10 @@ extern int ssb_bus_pcmciabus_register(st
extern void ssb_bus_unregister(struct ssb_bus *bus);
+/* Set a fallback SPROM.
+ * See kdoc at the function definition for complete documentation. */
+extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom);
+
/* Suspend a SSB bus.
* Call this from the parent bus suspend routine. */
extern int ssb_bus_suspend(struct ssb_bus *bus);

View file

@ -0,0 +1,23 @@
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -125,16 +125,16 @@ config REED_SOLOMON_DEC16
# Textsearch support is select'ed if needed
#
config TEXTSEARCH
- boolean
+ boolean "Textsearch support"
config TEXTSEARCH_KMP
- tristate
+ tristate "Textsearch KMP"
config TEXTSEARCH_BM
- tristate
+ tristate "Textsearch BM"
config TEXTSEARCH_FSM
- tristate
+ tristate "Textsearch FSM"
#
# plist support is select#ed if needed

View file

@ -0,0 +1,47 @@
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -30,7 +30,7 @@ config CRYPTO_FIPS
this is.
config CRYPTO_ALGAPI
- tristate
+ tristate "ALGAPI"
select CRYPTO_ALGAPI2
help
This option provides the API for cryptographic algorithms.
@@ -39,7 +39,7 @@ config CRYPTO_ALGAPI2
tristate
config CRYPTO_AEAD
- tristate
+ tristate "AEAD"
select CRYPTO_AEAD2
select CRYPTO_ALGAPI
@@ -48,7 +48,7 @@ config CRYPTO_AEAD2
select CRYPTO_ALGAPI2
config CRYPTO_BLKCIPHER
- tristate
+ tristate "BLKCIPHER"
select CRYPTO_BLKCIPHER2
select CRYPTO_ALGAPI
@@ -58,7 +58,7 @@ config CRYPTO_BLKCIPHER2
select CRYPTO_RNG2
config CRYPTO_HASH
- tristate
+ tristate "HASH"
select CRYPTO_HASH2
select CRYPTO_ALGAPI
@@ -67,7 +67,7 @@ config CRYPTO_HASH2
select CRYPTO_ALGAPI2
config CRYPTO_RNG
- tristate
+ tristate "RNG"
select CRYPTO_RNG2
select CRYPTO_ALGAPI

View file

@ -0,0 +1,114 @@
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2587,6 +2587,15 @@ int shmem_unuse(swp_entry_t entry, struc
/* common code */
+void shmem_set_file(struct vm_area_struct *vma, struct file *file)
+{
+ if (vma->vm_file)
+ fput(vma->vm_file);
+ vma->vm_file = file;
+ vma->vm_ops = &shmem_vm_ops;
+}
+EXPORT_SYMBOL_GPL(shmem_set_file);
+
/**
* shmem_file_setup - get an unlinked file living in tmpfs
* @name: name for dentry (to be seen in /proc/<pid>/maps
@@ -2665,10 +2674,7 @@ int shmem_zero_setup(struct vm_area_stru
if (IS_ERR(file))
return PTR_ERR(file);
- if (vma->vm_file)
- fput(vma->vm_file);
- vma->vm_file = file;
- vma->vm_ops = &shmem_vm_ops;
+ shmem_set_file(vma, file);
return 0;
}
--- a/fs/file.c
+++ b/fs/file.c
@@ -270,6 +270,7 @@ int expand_files(struct files_struct *fi
/* All good, so we try */
return expand_fdtable(files, nr);
}
+EXPORT_SYMBOL_GPL(expand_files);
static int count_open_files(struct fdtable *fdt)
{
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -516,6 +516,7 @@ struct files_struct *get_files_struct(st
return files;
}
+EXPORT_SYMBOL_GPL(get_files_struct);
void put_files_struct(struct files_struct *files)
{
@@ -535,6 +536,7 @@ void put_files_struct(struct files_struc
free_fdtable(fdt);
}
}
+EXPORT_SYMBOL_GPL(put_files_struct);
void reset_files_struct(struct files_struct *files)
{
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -158,6 +158,7 @@ void __put_task_struct(struct task_struc
if (!profile_handoff_task(tsk))
free_task(tsk);
}
+EXPORT_SYMBOL_GPL(__put_task_struct);
/*
* macro override instead of weak attribute alias, to workaround
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -5178,6 +5178,7 @@ int can_nice(const struct task_struct *p
return (nice_rlim <= p->signal->rlim[RLIMIT_NICE].rlim_cur ||
capable(CAP_SYS_NICE));
}
+EXPORT_SYMBOL_GPL(can_nice);
#ifdef __ARCH_WANT_SYS_NICE
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1063,6 +1063,7 @@ unsigned long zap_page_range(struct vm_a
tlb_finish_mmu(tlb, address, end);
return end;
}
+EXPORT_SYMBOL_GPL(zap_page_range);
/**
* zap_vma_ptes - remove ptes mapping the vma
@@ -2387,6 +2388,7 @@ int vmtruncate_range(struct inode *inode
return 0;
}
+EXPORT_SYMBOL_GPL(vmtruncate_range);
/*
* We enter with non-exclusive mmap_sem (to exclude vma changes,
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -1025,6 +1025,7 @@ void unmap_kernel_range(unsigned long ad
vunmap_page_range(addr, end);
flush_tlb_kernel_range(addr, end);
}
+EXPORT_SYMBOL_GPL(unmap_kernel_range);
int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages)
{
@@ -1138,6 +1139,7 @@ struct vm_struct *get_vm_area(unsigned l
return __get_vm_area_node(size, flags, VMALLOC_START, VMALLOC_END,
-1, GFP_KERNEL, __builtin_return_address(0));
}
+EXPORT_SYMBOL_GPL(get_vm_area);
struct vm_struct *get_vm_area_caller(unsigned long size, unsigned long flags,
void *caller)

View file

@ -0,0 +1,27 @@
--- a/arch/cris/include/arch-v10/arch/Kbuild
+++ b/arch/cris/include/arch-v10/arch/Kbuild
@@ -1,3 +1,5 @@
+header-y += elf.h
+header-y += ptrace.h
header-y += user.h
header-y += svinto.h
header-y += sv_addr_ag.h
--- a/arch/cris/include/asm/Kbuild
+++ b/arch/cris/include/asm/Kbuild
@@ -1,11 +1,14 @@
include include/asm-generic/Kbuild.asm
-header-y += arch-v10/
-header-y += arch-v32/
+header-y += ../arch-v10/arch/
+header-y += ../arch-v32/arch/
+header-y += elf.h
header-y += ethernet.h
+header-y += page.h
header-y += rtc.h
header-y += sync_serial.h
+header-y += user.h
unifdef-y += etraxgpio.h
unifdef-y += rs485.h

View file

@ -0,0 +1,14 @@
--- a/init/main.c
+++ b/init/main.c
@@ -821,10 +821,7 @@ static noinline int init_post(void)
printk(KERN_WARNING "Failed to execute %s. Attempting "
"defaults...\n", execute_command);
}
- run_init_process("/sbin/init");
- run_init_process("/etc/init");
- run_init_process("/bin/init");
- run_init_process("/bin/sh");
+ run_init_process("/etc/preinit");
panic("No init found. Try passing init= option to kernel.");
}