mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-11-03 14:34:27 -05:00 
			
		
		
		
	add preliminary 2.6.32 support
SVN-Revision: 18283
This commit is contained in:
		
							parent
							
								
									ab81d139c7
								
							
						
					
					
						commit
						3d4466cfd8
					
				
							
								
								
									
										55
									
								
								package/madwifi/patches/453-procps.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								package/madwifi/patches/453-procps.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,55 @@
 | 
			
		||||
--- a/net80211/ieee80211_linux.h	2009-10-04 22:27:05.528151949 +0300
 | 
			
		||||
+++ b/net80211/ieee80211_linux.h	2009-10-04 22:28:06.255777139 +0300
 | 
			
		||||
@@ -640,12 +640,24 @@
 | 
			
		||||
 	  void __user *buffer, size_t *lenp)
 | 
			
		||||
 #define	IEEE80211_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, lenp, ppos) \
 | 
			
		||||
 	proc_dointvec(ctl, write, filp, buffer, lenp)
 | 
			
		||||
-#else
 | 
			
		||||
+#define IEEE80211_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) \
 | 
			
		||||
+        proc_dostring(ctl, write, filp, buffer, lenp)
 | 
			
		||||
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
 | 
			
		||||
 #define	IEEE80211_SYSCTL_DECL(f, ctl, write, filp, buffer, lenp, ppos) \
 | 
			
		||||
 	f(ctl_table *ctl, int write, struct file *filp, \
 | 
			
		||||
 	  void __user *buffer, size_t *lenp, loff_t *ppos)
 | 
			
		||||
 #define	IEEE80211_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, lenp, ppos) \
 | 
			
		||||
 	proc_dointvec(ctl, write, filp, buffer, lenp, ppos)
 | 
			
		||||
+#define IEEE80211_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) \
 | 
			
		||||
+        proc_dostring(ctl, write, filp, buffer, lenp, ppos)
 | 
			
		||||
+#else /* Linux 2.6.32+ */
 | 
			
		||||
+#define	IEEE80211_SYSCTL_DECL(f, ctl, write, filp, buffer, lenp, ppos) \
 | 
			
		||||
+	f(ctl_table *ctl, int write, \
 | 
			
		||||
+	  void __user *buffer, size_t *lenp, loff_t *ppos)
 | 
			
		||||
+#define	IEEE80211_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, lenp, ppos) \
 | 
			
		||||
+	proc_dointvec(ctl, write, buffer, lenp, ppos)
 | 
			
		||||
+#define IEEE80211_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) \
 | 
			
		||||
+        proc_dostring(ctl, write, buffer, lenp, ppos)
 | 
			
		||||
 #endif
 | 
			
		||||
 
 | 
			
		||||
 void ieee80211_virtfs_latevattach(struct ieee80211vap *);
 | 
			
		||||
--- a/ath/if_athvar.h	2009-10-04 22:27:05.543151943 +0300
 | 
			
		||||
+++ b/ath/if_athvar.h	2009-10-04 22:27:40.115902053 +0300
 | 
			
		||||
@@ -173,14 +173,22 @@
 | 
			
		||||
 	proc_dointvec(ctl, write, filp, buffer, lenp)
 | 
			
		||||
 #define	ATH_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) \
 | 
			
		||||
 	proc_dostring(ctl, write, filp, buffer, lenp)
 | 
			
		||||
-#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) */
 | 
			
		||||
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
 | 
			
		||||
 #define	ATH_SYSCTL_DECL(f, ctl, write, filp, buffer, lenp, ppos) \
 | 
			
		||||
 	f(ctl_table *ctl, int write, struct file *filp, \
 | 
			
		||||
 	  void __user *buffer, size_t *lenp, loff_t *ppos)
 | 
			
		||||
 #define	ATH_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, lenp, ppos) \
 | 
			
		||||
 	proc_dointvec(ctl, write, filp, buffer, lenp, ppos)
 | 
			
		||||
+#define ATH_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) \
 | 
			
		||||
+        proc_dostring(ctl, write, filp, buffer, lenp, ppos)
 | 
			
		||||
+#else /* Linux 2.6.32+ */
 | 
			
		||||
+#define	ATH_SYSCTL_DECL(f, ctl, write, filp, buffer, lenp, ppos) \
 | 
			
		||||
+	f(ctl_table *ctl, int write, \
 | 
			
		||||
+	  void __user *buffer, size_t *lenp, loff_t *ppos)
 | 
			
		||||
+#define	ATH_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, lenp, ppos) \
 | 
			
		||||
+	proc_dointvec(ctl, write, buffer, lenp, ppos)
 | 
			
		||||
 #define	ATH_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) \
 | 
			
		||||
-	proc_dostring(ctl, write, filp, buffer, lenp, ppos)
 | 
			
		||||
+	proc_dostring(ctl, write, buffer, lenp, ppos)
 | 
			
		||||
 #endif
 | 
			
		||||
 
 | 
			
		||||
 #define	ATH_TIMEOUT	1000
 | 
			
		||||
							
								
								
									
										2666
									
								
								target/linux/generic-2.6/config-2.6.32
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2666
									
								
								target/linux/generic-2.6/config-2.6.32
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										201
									
								
								target/linux/generic-2.6/files-2.6.32/drivers/char/gpio_dev.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								target/linux/generic-2.6/files-2.6.32/drivers/char/gpio_dev.c
									
									
									
									
									
										Normal 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");
 | 
			
		||||
@ -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");
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										172
									
								
								target/linux/generic-2.6/files-2.6.32/drivers/leds/leds-alix.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								target/linux/generic-2.6/files-2.6.32/drivers/leds/leds-alix.c
									
									
									
									
									
										Normal 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");
 | 
			
		||||
 | 
			
		||||
@ -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");
 | 
			
		||||
@ -0,0 +1,454 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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;
 | 
			
		||||
	}
 | 
			
		||||
#ifdef CONFIG_COMPAT_NET_DEV_OPS
 | 
			
		||||
	dev_stats = trigger_data->net_dev->get_stats(trigger_data->net_dev);
 | 
			
		||||
#else
 | 
			
		||||
	dev_stats = trigger_data->net_dev->netdev_ops->ndo_get_stats(trigger_data->net_dev);
 | 
			
		||||
#endif
 | 
			
		||||
	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");
 | 
			
		||||
@ -0,0 +1,27 @@
 | 
			
		||||
#ifndef __GLAMO_ENGINE_H
 | 
			
		||||
#define __GLAMO_ENGINE_H
 | 
			
		||||
 | 
			
		||||
enum glamo_engine {
 | 
			
		||||
	GLAMO_ENGINE_CAPTURE = 0,
 | 
			
		||||
	GLAMO_ENGINE_ISP = 1,
 | 
			
		||||
	GLAMO_ENGINE_JPEG = 2,
 | 
			
		||||
	GLAMO_ENGINE_MPEG_ENC = 3,
 | 
			
		||||
	GLAMO_ENGINE_MPEG_DEC = 4,
 | 
			
		||||
	GLAMO_ENGINE_LCD = 5,
 | 
			
		||||
	GLAMO_ENGINE_CMDQ = 6,
 | 
			
		||||
	GLAMO_ENGINE_2D = 7,
 | 
			
		||||
	GLAMO_ENGINE_3D = 8,
 | 
			
		||||
	GLAMO_ENGINE_MMC = 9,
 | 
			
		||||
	GLAMO_ENGINE_MICROP0 = 10,
 | 
			
		||||
	GLAMO_ENGINE_RISC = 11,
 | 
			
		||||
	GLAMO_ENGINE_MICROP1_MPEG_ENC = 12,
 | 
			
		||||
	GLAMO_ENGINE_MICROP1_MPEG_DEC = 13,
 | 
			
		||||
#if 0
 | 
			
		||||
	GLAMO_ENGINE_H264_DEC = 14,
 | 
			
		||||
	GLAMO_ENGINE_RISC1 = 15,
 | 
			
		||||
	GLAMO_ENGINE_SPI = 16,
 | 
			
		||||
#endif
 | 
			
		||||
	__NUM_GLAMO_ENGINES
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -0,0 +1,35 @@
 | 
			
		||||
#ifndef _LINUX_GLAMOFB_H
 | 
			
		||||
#define _LINUX_GLAMOFB_H
 | 
			
		||||
 | 
			
		||||
#include <linux/fb.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __KERNEL__
 | 
			
		||||
 | 
			
		||||
struct glamo_core;
 | 
			
		||||
struct glamofb_handle;
 | 
			
		||||
 | 
			
		||||
struct glamo_fb_platform_data {
 | 
			
		||||
    int width, height;
 | 
			
		||||
 | 
			
		||||
    int num_modes;
 | 
			
		||||
    struct fb_videomode *modes;
 | 
			
		||||
 | 
			
		||||
    struct glamo_core *core;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int glamofb_cmd_mode(struct glamofb_handle *gfb, int on);
 | 
			
		||||
int glamofb_cmd_write(struct glamofb_handle *gfb, u_int16_t val);
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MFD_GLAMO
 | 
			
		||||
void glamo_lcm_reset(struct platform_device *pdev, int level);
 | 
			
		||||
#else
 | 
			
		||||
#define glamo_lcm_reset(...) do {} while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define GLAMOFB_ENGINE_ENABLE _IOW('F', 0x1, __u32)
 | 
			
		||||
#define GLAMOFB_ENGINE_DISABLE _IOW('F', 0x2, __u32)
 | 
			
		||||
#define GLAMOFB_ENGINE_RESET _IOW('F', 0x3, __u32)
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -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_ */
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
@ -0,0 +1,244 @@
 | 
			
		||||
From 6c4419d997d4431bb62e73475cd6b084e83efbd1 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Phillip Lougher <phillip@lougher.demon.co.uk>
 | 
			
		||||
Date: Tue, 22 Sep 2009 19:25:24 +0100
 | 
			
		||||
Subject: [PATCH] Squashfs: move zlib decompression wrapper code into a separate file
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Phillip Lougher <phillip@lougher.demon.co.uk>
 | 
			
		||||
---
 | 
			
		||||
 fs/squashfs/Makefile       |    2 +-
 | 
			
		||||
 fs/squashfs/block.c        |   74 ++----------------------------
 | 
			
		||||
 fs/squashfs/squashfs.h     |    4 ++
 | 
			
		||||
 fs/squashfs/zlib_wrapper.c |  109 ++++++++++++++++++++++++++++++++++++++++++++
 | 
			
		||||
 4 files changed, 118 insertions(+), 71 deletions(-)
 | 
			
		||||
 create mode 100644 fs/squashfs/zlib_wrapper.c
 | 
			
		||||
 | 
			
		||||
--- a/fs/squashfs/Makefile
 | 
			
		||||
+++ b/fs/squashfs/Makefile
 | 
			
		||||
@@ -4,4 +4,4 @@
 | 
			
		||||
 
 | 
			
		||||
 obj-$(CONFIG_SQUASHFS) += squashfs.o
 | 
			
		||||
 squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o
 | 
			
		||||
-squashfs-y += namei.o super.o symlink.o
 | 
			
		||||
+squashfs-y += namei.o super.o symlink.o zlib_wrapper.o
 | 
			
		||||
--- a/fs/squashfs/block.c
 | 
			
		||||
+++ b/fs/squashfs/block.c
 | 
			
		||||
@@ -29,7 +29,6 @@
 | 
			
		||||
 #include <linux/fs.h>
 | 
			
		||||
 #include <linux/vfs.h>
 | 
			
		||||
 #include <linux/slab.h>
 | 
			
		||||
-#include <linux/mutex.h>
 | 
			
		||||
 #include <linux/string.h>
 | 
			
		||||
 #include <linux/buffer_head.h>
 | 
			
		||||
 #include <linux/zlib.h>
 | 
			
		||||
@@ -153,72 +152,10 @@ int squashfs_read_data(struct super_bloc
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	if (compressed) {
 | 
			
		||||
-		int zlib_err = 0, zlib_init = 0;
 | 
			
		||||
-
 | 
			
		||||
-		/*
 | 
			
		||||
-		 * Uncompress block.
 | 
			
		||||
-		 */
 | 
			
		||||
-
 | 
			
		||||
-		mutex_lock(&msblk->read_data_mutex);
 | 
			
		||||
-
 | 
			
		||||
-		msblk->stream.avail_out = 0;
 | 
			
		||||
-		msblk->stream.avail_in = 0;
 | 
			
		||||
-
 | 
			
		||||
-		bytes = length;
 | 
			
		||||
-		do {
 | 
			
		||||
-			if (msblk->stream.avail_in == 0 && k < b) {
 | 
			
		||||
-				avail = min(bytes, msblk->devblksize - offset);
 | 
			
		||||
-				bytes -= avail;
 | 
			
		||||
-				wait_on_buffer(bh[k]);
 | 
			
		||||
-				if (!buffer_uptodate(bh[k]))
 | 
			
		||||
-					goto release_mutex;
 | 
			
		||||
-
 | 
			
		||||
-				if (avail == 0) {
 | 
			
		||||
-					offset = 0;
 | 
			
		||||
-					put_bh(bh[k++]);
 | 
			
		||||
-					continue;
 | 
			
		||||
-				}
 | 
			
		||||
-
 | 
			
		||||
-				msblk->stream.next_in = bh[k]->b_data + offset;
 | 
			
		||||
-				msblk->stream.avail_in = avail;
 | 
			
		||||
-				offset = 0;
 | 
			
		||||
-			}
 | 
			
		||||
-
 | 
			
		||||
-			if (msblk->stream.avail_out == 0 && page < pages) {
 | 
			
		||||
-				msblk->stream.next_out = buffer[page++];
 | 
			
		||||
-				msblk->stream.avail_out = PAGE_CACHE_SIZE;
 | 
			
		||||
-			}
 | 
			
		||||
-
 | 
			
		||||
-			if (!zlib_init) {
 | 
			
		||||
-				zlib_err = zlib_inflateInit(&msblk->stream);
 | 
			
		||||
-				if (zlib_err != Z_OK) {
 | 
			
		||||
-					ERROR("zlib_inflateInit returned"
 | 
			
		||||
-						" unexpected result 0x%x,"
 | 
			
		||||
-						" srclength %d\n", zlib_err,
 | 
			
		||||
-						srclength);
 | 
			
		||||
-					goto release_mutex;
 | 
			
		||||
-				}
 | 
			
		||||
-				zlib_init = 1;
 | 
			
		||||
-			}
 | 
			
		||||
-
 | 
			
		||||
-			zlib_err = zlib_inflate(&msblk->stream, Z_SYNC_FLUSH);
 | 
			
		||||
-
 | 
			
		||||
-			if (msblk->stream.avail_in == 0 && k < b)
 | 
			
		||||
-				put_bh(bh[k++]);
 | 
			
		||||
-		} while (zlib_err == Z_OK);
 | 
			
		||||
-
 | 
			
		||||
-		if (zlib_err != Z_STREAM_END) {
 | 
			
		||||
-			ERROR("zlib_inflate error, data probably corrupt\n");
 | 
			
		||||
-			goto release_mutex;
 | 
			
		||||
-		}
 | 
			
		||||
-
 | 
			
		||||
-		zlib_err = zlib_inflateEnd(&msblk->stream);
 | 
			
		||||
-		if (zlib_err != Z_OK) {
 | 
			
		||||
-			ERROR("zlib_inflate error, data probably corrupt\n");
 | 
			
		||||
-			goto release_mutex;
 | 
			
		||||
-		}
 | 
			
		||||
-		length = msblk->stream.total_out;
 | 
			
		||||
-		mutex_unlock(&msblk->read_data_mutex);
 | 
			
		||||
+		length = zlib_uncompress(msblk, buffer, bh, b, offset, length,
 | 
			
		||||
+			srclength, pages);
 | 
			
		||||
+		if (length < 0)
 | 
			
		||||
+			goto read_failure;
 | 
			
		||||
 	} else {
 | 
			
		||||
 		/*
 | 
			
		||||
 		 * Block is uncompressed.
 | 
			
		||||
@@ -255,9 +192,6 @@ int squashfs_read_data(struct super_bloc
 | 
			
		||||
 	kfree(bh);
 | 
			
		||||
 	return length;
 | 
			
		||||
 
 | 
			
		||||
-release_mutex:
 | 
			
		||||
-	mutex_unlock(&msblk->read_data_mutex);
 | 
			
		||||
-
 | 
			
		||||
 block_release:
 | 
			
		||||
 	for (; k < b; k++)
 | 
			
		||||
 		put_bh(bh[k]);
 | 
			
		||||
--- a/fs/squashfs/squashfs.h
 | 
			
		||||
+++ b/fs/squashfs/squashfs.h
 | 
			
		||||
@@ -70,6 +70,10 @@ extern struct inode *squashfs_iget(struc
 | 
			
		||||
 				unsigned int);
 | 
			
		||||
 extern int squashfs_read_inode(struct inode *, long long);
 | 
			
		||||
 
 | 
			
		||||
+/* zlib_wrapper.c */
 | 
			
		||||
+extern int zlib_uncompress(struct squashfs_sb_info *, void **,
 | 
			
		||||
+				struct buffer_head **, int, int, int, int, int);
 | 
			
		||||
+
 | 
			
		||||
 /*
 | 
			
		||||
  * Inodes and files operations
 | 
			
		||||
  */
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/fs/squashfs/zlib_wrapper.c
 | 
			
		||||
@@ -0,0 +1,109 @@
 | 
			
		||||
+/*
 | 
			
		||||
+ * Squashfs - a compressed read only filesystem for Linux
 | 
			
		||||
+ *
 | 
			
		||||
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
 | 
			
		||||
+ * Phillip Lougher <phillip@lougher.demon.co.uk>
 | 
			
		||||
+ *
 | 
			
		||||
+ * 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,
 | 
			
		||||
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | 
			
		||||
+ *
 | 
			
		||||
+ * zlib_wrapper.c
 | 
			
		||||
+ */
 | 
			
		||||
+
 | 
			
		||||
+
 | 
			
		||||
+#include <linux/mutex.h>
 | 
			
		||||
+#include <linux/buffer_head.h>
 | 
			
		||||
+#include <linux/zlib.h>
 | 
			
		||||
+
 | 
			
		||||
+#include "squashfs_fs.h"
 | 
			
		||||
+#include "squashfs_fs_sb.h"
 | 
			
		||||
+#include "squashfs_fs_i.h"
 | 
			
		||||
+#include "squashfs.h"
 | 
			
		||||
+
 | 
			
		||||
+int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
 | 
			
		||||
+	struct buffer_head **bh, int b, int offset, int length, int srclength,
 | 
			
		||||
+	int pages)
 | 
			
		||||
+{
 | 
			
		||||
+	int zlib_err = 0, zlib_init = 0;
 | 
			
		||||
+	int avail, bytes, k = 0, page = 0;
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&msblk->read_data_mutex);
 | 
			
		||||
+
 | 
			
		||||
+	msblk->stream.avail_out = 0;
 | 
			
		||||
+	msblk->stream.avail_in = 0;
 | 
			
		||||
+
 | 
			
		||||
+	bytes = length;
 | 
			
		||||
+	do {
 | 
			
		||||
+		if (msblk->stream.avail_in == 0 && k < b) {
 | 
			
		||||
+			avail = min(bytes, msblk->devblksize - offset);
 | 
			
		||||
+			bytes -= avail;
 | 
			
		||||
+			wait_on_buffer(bh[k]);
 | 
			
		||||
+			if (!buffer_uptodate(bh[k]))
 | 
			
		||||
+				goto release_mutex;
 | 
			
		||||
+
 | 
			
		||||
+			if (avail == 0) {
 | 
			
		||||
+				offset = 0;
 | 
			
		||||
+				put_bh(bh[k++]);
 | 
			
		||||
+				continue;
 | 
			
		||||
+			}
 | 
			
		||||
+
 | 
			
		||||
+			msblk->stream.next_in = bh[k]->b_data + offset;
 | 
			
		||||
+			msblk->stream.avail_in = avail;
 | 
			
		||||
+			offset = 0;
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
+		if (msblk->stream.avail_out == 0 && page < pages) {
 | 
			
		||||
+			msblk->stream.next_out = buffer[page++];
 | 
			
		||||
+			msblk->stream.avail_out = PAGE_CACHE_SIZE;
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
+		if (!zlib_init) {
 | 
			
		||||
+			zlib_err = zlib_inflateInit(&msblk->stream);
 | 
			
		||||
+			if (zlib_err != Z_OK) {
 | 
			
		||||
+				ERROR("zlib_inflateInit returned unexpected "
 | 
			
		||||
+					"result 0x%x, srclength %d\n",
 | 
			
		||||
+					zlib_err, srclength);
 | 
			
		||||
+				goto release_mutex;
 | 
			
		||||
+			}
 | 
			
		||||
+			zlib_init = 1;
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
+		zlib_err = zlib_inflate(&msblk->stream, Z_SYNC_FLUSH);
 | 
			
		||||
+
 | 
			
		||||
+		if (msblk->stream.avail_in == 0 && k < b)
 | 
			
		||||
+			put_bh(bh[k++]);
 | 
			
		||||
+	} while (zlib_err == Z_OK);
 | 
			
		||||
+
 | 
			
		||||
+	if (zlib_err != Z_STREAM_END) {
 | 
			
		||||
+		ERROR("zlib_inflate error, data probably corrupt\n");
 | 
			
		||||
+		goto release_mutex;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	zlib_err = zlib_inflateEnd(&msblk->stream);
 | 
			
		||||
+	if (zlib_err != Z_OK) {
 | 
			
		||||
+		ERROR("zlib_inflate error, data probably corrupt\n");
 | 
			
		||||
+		goto release_mutex;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	mutex_unlock(&msblk->read_data_mutex);
 | 
			
		||||
+	return msblk->stream.total_out;
 | 
			
		||||
+
 | 
			
		||||
+release_mutex:
 | 
			
		||||
+	mutex_unlock(&msblk->read_data_mutex);
 | 
			
		||||
+
 | 
			
		||||
+	for (; k < b; k++)
 | 
			
		||||
+		put_bh(bh[k]);
 | 
			
		||||
+
 | 
			
		||||
+	return -EIO;
 | 
			
		||||
+}
 | 
			
		||||
@ -0,0 +1,317 @@
 | 
			
		||||
From 37c44e85fd49676ec15ccaeea065662c1fbcda7d Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Phillip Lougher <phillip@lougher.demon.co.uk>
 | 
			
		||||
Date: Wed, 23 Sep 2009 19:04:49 +0100
 | 
			
		||||
Subject: [PATCH] Squashfs: Factor out remaining zlib dependencies into separate wrapper file
 | 
			
		||||
 | 
			
		||||
Move zlib buffer init/destroy code into separate wrapper file.  Also
 | 
			
		||||
make zlib z_stream field a void * removing the need to include zlib.h
 | 
			
		||||
for most files.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Phillip Lougher <phillip@lougher.demon.co.uk>
 | 
			
		||||
---
 | 
			
		||||
 fs/squashfs/block.c          |    1 -
 | 
			
		||||
 fs/squashfs/cache.c          |    1 -
 | 
			
		||||
 fs/squashfs/dir.c            |    1 -
 | 
			
		||||
 fs/squashfs/export.c         |    1 -
 | 
			
		||||
 fs/squashfs/file.c           |    1 -
 | 
			
		||||
 fs/squashfs/fragment.c       |    1 -
 | 
			
		||||
 fs/squashfs/id.c             |    1 -
 | 
			
		||||
 fs/squashfs/inode.c          |    1 -
 | 
			
		||||
 fs/squashfs/namei.c          |    1 -
 | 
			
		||||
 fs/squashfs/squashfs.h       |    2 +
 | 
			
		||||
 fs/squashfs/squashfs_fs_sb.h |    2 +-
 | 
			
		||||
 fs/squashfs/super.c          |   14 +++------
 | 
			
		||||
 fs/squashfs/symlink.c        |    1 -
 | 
			
		||||
 fs/squashfs/zlib_wrapper.c   |   56 ++++++++++++++++++++++++++++++++---------
 | 
			
		||||
 14 files changed, 51 insertions(+), 33 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/fs/squashfs/block.c
 | 
			
		||||
+++ b/fs/squashfs/block.c
 | 
			
		||||
@@ -31,7 +31,6 @@
 | 
			
		||||
 #include <linux/slab.h>
 | 
			
		||||
 #include <linux/string.h>
 | 
			
		||||
 #include <linux/buffer_head.h>
 | 
			
		||||
-#include <linux/zlib.h>
 | 
			
		||||
 
 | 
			
		||||
 #include "squashfs_fs.h"
 | 
			
		||||
 #include "squashfs_fs_sb.h"
 | 
			
		||||
--- a/fs/squashfs/cache.c
 | 
			
		||||
+++ b/fs/squashfs/cache.c
 | 
			
		||||
@@ -51,7 +51,6 @@
 | 
			
		||||
 #include <linux/sched.h>
 | 
			
		||||
 #include <linux/spinlock.h>
 | 
			
		||||
 #include <linux/wait.h>
 | 
			
		||||
-#include <linux/zlib.h>
 | 
			
		||||
 #include <linux/pagemap.h>
 | 
			
		||||
 
 | 
			
		||||
 #include "squashfs_fs.h"
 | 
			
		||||
--- a/fs/squashfs/dir.c
 | 
			
		||||
+++ b/fs/squashfs/dir.c
 | 
			
		||||
@@ -30,7 +30,6 @@
 | 
			
		||||
 #include <linux/fs.h>
 | 
			
		||||
 #include <linux/vfs.h>
 | 
			
		||||
 #include <linux/slab.h>
 | 
			
		||||
-#include <linux/zlib.h>
 | 
			
		||||
 
 | 
			
		||||
 #include "squashfs_fs.h"
 | 
			
		||||
 #include "squashfs_fs_sb.h"
 | 
			
		||||
--- a/fs/squashfs/export.c
 | 
			
		||||
+++ b/fs/squashfs/export.c
 | 
			
		||||
@@ -39,7 +39,6 @@
 | 
			
		||||
 #include <linux/vfs.h>
 | 
			
		||||
 #include <linux/dcache.h>
 | 
			
		||||
 #include <linux/exportfs.h>
 | 
			
		||||
-#include <linux/zlib.h>
 | 
			
		||||
 #include <linux/slab.h>
 | 
			
		||||
 
 | 
			
		||||
 #include "squashfs_fs.h"
 | 
			
		||||
--- a/fs/squashfs/file.c
 | 
			
		||||
+++ b/fs/squashfs/file.c
 | 
			
		||||
@@ -47,7 +47,6 @@
 | 
			
		||||
 #include <linux/string.h>
 | 
			
		||||
 #include <linux/pagemap.h>
 | 
			
		||||
 #include <linux/mutex.h>
 | 
			
		||||
-#include <linux/zlib.h>
 | 
			
		||||
 
 | 
			
		||||
 #include "squashfs_fs.h"
 | 
			
		||||
 #include "squashfs_fs_sb.h"
 | 
			
		||||
--- a/fs/squashfs/fragment.c
 | 
			
		||||
+++ b/fs/squashfs/fragment.c
 | 
			
		||||
@@ -36,7 +36,6 @@
 | 
			
		||||
 #include <linux/fs.h>
 | 
			
		||||
 #include <linux/vfs.h>
 | 
			
		||||
 #include <linux/slab.h>
 | 
			
		||||
-#include <linux/zlib.h>
 | 
			
		||||
 
 | 
			
		||||
 #include "squashfs_fs.h"
 | 
			
		||||
 #include "squashfs_fs_sb.h"
 | 
			
		||||
--- a/fs/squashfs/id.c
 | 
			
		||||
+++ b/fs/squashfs/id.c
 | 
			
		||||
@@ -34,7 +34,6 @@
 | 
			
		||||
 #include <linux/fs.h>
 | 
			
		||||
 #include <linux/vfs.h>
 | 
			
		||||
 #include <linux/slab.h>
 | 
			
		||||
-#include <linux/zlib.h>
 | 
			
		||||
 
 | 
			
		||||
 #include "squashfs_fs.h"
 | 
			
		||||
 #include "squashfs_fs_sb.h"
 | 
			
		||||
--- a/fs/squashfs/inode.c
 | 
			
		||||
+++ b/fs/squashfs/inode.c
 | 
			
		||||
@@ -40,7 +40,6 @@
 | 
			
		||||
 
 | 
			
		||||
 #include <linux/fs.h>
 | 
			
		||||
 #include <linux/vfs.h>
 | 
			
		||||
-#include <linux/zlib.h>
 | 
			
		||||
 
 | 
			
		||||
 #include "squashfs_fs.h"
 | 
			
		||||
 #include "squashfs_fs_sb.h"
 | 
			
		||||
--- a/fs/squashfs/namei.c
 | 
			
		||||
+++ b/fs/squashfs/namei.c
 | 
			
		||||
@@ -57,7 +57,6 @@
 | 
			
		||||
 #include <linux/slab.h>
 | 
			
		||||
 #include <linux/string.h>
 | 
			
		||||
 #include <linux/dcache.h>
 | 
			
		||||
-#include <linux/zlib.h>
 | 
			
		||||
 
 | 
			
		||||
 #include "squashfs_fs.h"
 | 
			
		||||
 #include "squashfs_fs_sb.h"
 | 
			
		||||
--- a/fs/squashfs/squashfs.h
 | 
			
		||||
+++ b/fs/squashfs/squashfs.h
 | 
			
		||||
@@ -71,6 +71,8 @@ extern struct inode *squashfs_iget(struc
 | 
			
		||||
 extern int squashfs_read_inode(struct inode *, long long);
 | 
			
		||||
 
 | 
			
		||||
 /* zlib_wrapper.c */
 | 
			
		||||
+extern void *zlib_init(void);
 | 
			
		||||
+extern void zlib_free(void *);
 | 
			
		||||
 extern int zlib_uncompress(struct squashfs_sb_info *, void **,
 | 
			
		||||
 				struct buffer_head **, int, int, int, int, int);
 | 
			
		||||
 
 | 
			
		||||
--- a/fs/squashfs/squashfs_fs_sb.h
 | 
			
		||||
+++ b/fs/squashfs/squashfs_fs_sb.h
 | 
			
		||||
@@ -64,7 +64,7 @@ struct squashfs_sb_info {
 | 
			
		||||
 	struct mutex		read_data_mutex;
 | 
			
		||||
 	struct mutex		meta_index_mutex;
 | 
			
		||||
 	struct meta_index	*meta_index;
 | 
			
		||||
-	z_stream		stream;
 | 
			
		||||
+	void			*stream;
 | 
			
		||||
 	__le64			*inode_lookup_table;
 | 
			
		||||
 	u64			inode_table;
 | 
			
		||||
 	u64			directory_table;
 | 
			
		||||
--- a/fs/squashfs/super.c
 | 
			
		||||
+++ b/fs/squashfs/super.c
 | 
			
		||||
@@ -35,7 +35,6 @@
 | 
			
		||||
 #include <linux/pagemap.h>
 | 
			
		||||
 #include <linux/init.h>
 | 
			
		||||
 #include <linux/module.h>
 | 
			
		||||
-#include <linux/zlib.h>
 | 
			
		||||
 #include <linux/magic.h>
 | 
			
		||||
 
 | 
			
		||||
 #include "squashfs_fs.h"
 | 
			
		||||
@@ -87,12 +86,9 @@ static int squashfs_fill_super(struct su
 | 
			
		||||
 	}
 | 
			
		||||
 	msblk = sb->s_fs_info;
 | 
			
		||||
 
 | 
			
		||||
-	msblk->stream.workspace = kmalloc(zlib_inflate_workspacesize(),
 | 
			
		||||
-		GFP_KERNEL);
 | 
			
		||||
-	if (msblk->stream.workspace == NULL) {
 | 
			
		||||
-		ERROR("Failed to allocate zlib workspace\n");
 | 
			
		||||
+	msblk->stream = zlib_init();
 | 
			
		||||
+	if (msblk->stream == NULL)
 | 
			
		||||
 		goto failure;
 | 
			
		||||
-	}
 | 
			
		||||
 
 | 
			
		||||
 	sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
 | 
			
		||||
 	if (sblk == NULL) {
 | 
			
		||||
@@ -292,17 +288,17 @@ failed_mount:
 | 
			
		||||
 	squashfs_cache_delete(msblk->block_cache);
 | 
			
		||||
 	squashfs_cache_delete(msblk->fragment_cache);
 | 
			
		||||
 	squashfs_cache_delete(msblk->read_page);
 | 
			
		||||
+	zlib_free(msblk->stream);
 | 
			
		||||
 	kfree(msblk->inode_lookup_table);
 | 
			
		||||
 	kfree(msblk->fragment_index);
 | 
			
		||||
 	kfree(msblk->id_table);
 | 
			
		||||
-	kfree(msblk->stream.workspace);
 | 
			
		||||
 	kfree(sb->s_fs_info);
 | 
			
		||||
 	sb->s_fs_info = NULL;
 | 
			
		||||
 	kfree(sblk);
 | 
			
		||||
 	return err;
 | 
			
		||||
 
 | 
			
		||||
 failure:
 | 
			
		||||
-	kfree(msblk->stream.workspace);
 | 
			
		||||
+	zlib_free(msblk->stream);
 | 
			
		||||
 	kfree(sb->s_fs_info);
 | 
			
		||||
 	sb->s_fs_info = NULL;
 | 
			
		||||
 	return -ENOMEM;
 | 
			
		||||
@@ -346,10 +342,10 @@ static void squashfs_put_super(struct su
 | 
			
		||||
 		squashfs_cache_delete(sbi->block_cache);
 | 
			
		||||
 		squashfs_cache_delete(sbi->fragment_cache);
 | 
			
		||||
 		squashfs_cache_delete(sbi->read_page);
 | 
			
		||||
+		zlib_free(sbi->stream);
 | 
			
		||||
 		kfree(sbi->id_table);
 | 
			
		||||
 		kfree(sbi->fragment_index);
 | 
			
		||||
 		kfree(sbi->meta_index);
 | 
			
		||||
-		kfree(sbi->stream.workspace);
 | 
			
		||||
 		kfree(sb->s_fs_info);
 | 
			
		||||
 		sb->s_fs_info = NULL;
 | 
			
		||||
 	}
 | 
			
		||||
--- a/fs/squashfs/symlink.c
 | 
			
		||||
+++ b/fs/squashfs/symlink.c
 | 
			
		||||
@@ -36,7 +36,6 @@
 | 
			
		||||
 #include <linux/slab.h>
 | 
			
		||||
 #include <linux/string.h>
 | 
			
		||||
 #include <linux/pagemap.h>
 | 
			
		||||
-#include <linux/zlib.h>
 | 
			
		||||
 
 | 
			
		||||
 #include "squashfs_fs.h"
 | 
			
		||||
 #include "squashfs_fs_sb.h"
 | 
			
		||||
--- a/fs/squashfs/zlib_wrapper.c
 | 
			
		||||
+++ b/fs/squashfs/zlib_wrapper.c
 | 
			
		||||
@@ -31,21 +31,51 @@
 | 
			
		||||
 #include "squashfs_fs_i.h"
 | 
			
		||||
 #include "squashfs.h"
 | 
			
		||||
 
 | 
			
		||||
+void *zlib_init()
 | 
			
		||||
+{
 | 
			
		||||
+	z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL);
 | 
			
		||||
+	if (stream == NULL)
 | 
			
		||||
+		goto failed;
 | 
			
		||||
+	stream->workspace = kmalloc(zlib_inflate_workspacesize(),
 | 
			
		||||
+		GFP_KERNEL);
 | 
			
		||||
+	if (stream->workspace == NULL)
 | 
			
		||||
+		goto failed;
 | 
			
		||||
+
 | 
			
		||||
+	return stream;
 | 
			
		||||
+
 | 
			
		||||
+failed:
 | 
			
		||||
+	ERROR("Failed to allocate zlib workspace\n");
 | 
			
		||||
+	kfree(stream);
 | 
			
		||||
+	return NULL;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+
 | 
			
		||||
+void zlib_free(void *strm)
 | 
			
		||||
+{
 | 
			
		||||
+	z_stream *stream = strm;
 | 
			
		||||
+
 | 
			
		||||
+	if (stream)
 | 
			
		||||
+		kfree(stream->workspace);
 | 
			
		||||
+	kfree(stream);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+
 | 
			
		||||
 int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
 | 
			
		||||
 	struct buffer_head **bh, int b, int offset, int length, int srclength,
 | 
			
		||||
 	int pages)
 | 
			
		||||
 {
 | 
			
		||||
 	int zlib_err = 0, zlib_init = 0;
 | 
			
		||||
 	int avail, bytes, k = 0, page = 0;
 | 
			
		||||
+	z_stream *stream = msblk->stream;
 | 
			
		||||
 
 | 
			
		||||
 	mutex_lock(&msblk->read_data_mutex);
 | 
			
		||||
 
 | 
			
		||||
-	msblk->stream.avail_out = 0;
 | 
			
		||||
-	msblk->stream.avail_in = 0;
 | 
			
		||||
+	stream->avail_out = 0;
 | 
			
		||||
+	stream->avail_in = 0;
 | 
			
		||||
 
 | 
			
		||||
 	bytes = length;
 | 
			
		||||
 	do {
 | 
			
		||||
-		if (msblk->stream.avail_in == 0 && k < b) {
 | 
			
		||||
+		if (stream->avail_in == 0 && k < b) {
 | 
			
		||||
 			avail = min(bytes, msblk->devblksize - offset);
 | 
			
		||||
 			bytes -= avail;
 | 
			
		||||
 			wait_on_buffer(bh[k]);
 | 
			
		||||
@@ -58,18 +88,18 @@ int zlib_uncompress(struct squashfs_sb_i
 | 
			
		||||
 				continue;
 | 
			
		||||
 			}
 | 
			
		||||
 
 | 
			
		||||
-			msblk->stream.next_in = bh[k]->b_data + offset;
 | 
			
		||||
-			msblk->stream.avail_in = avail;
 | 
			
		||||
+			stream->next_in = bh[k]->b_data + offset;
 | 
			
		||||
+			stream->avail_in = avail;
 | 
			
		||||
 			offset = 0;
 | 
			
		||||
 		}
 | 
			
		||||
 
 | 
			
		||||
-		if (msblk->stream.avail_out == 0 && page < pages) {
 | 
			
		||||
-			msblk->stream.next_out = buffer[page++];
 | 
			
		||||
-			msblk->stream.avail_out = PAGE_CACHE_SIZE;
 | 
			
		||||
+		if (stream->avail_out == 0 && page < pages) {
 | 
			
		||||
+			stream->next_out = buffer[page++];
 | 
			
		||||
+			stream->avail_out = PAGE_CACHE_SIZE;
 | 
			
		||||
 		}
 | 
			
		||||
 
 | 
			
		||||
 		if (!zlib_init) {
 | 
			
		||||
-			zlib_err = zlib_inflateInit(&msblk->stream);
 | 
			
		||||
+			zlib_err = zlib_inflateInit(stream);
 | 
			
		||||
 			if (zlib_err != Z_OK) {
 | 
			
		||||
 				ERROR("zlib_inflateInit returned unexpected "
 | 
			
		||||
 					"result 0x%x, srclength %d\n",
 | 
			
		||||
@@ -79,9 +109,9 @@ int zlib_uncompress(struct squashfs_sb_i
 | 
			
		||||
 			zlib_init = 1;
 | 
			
		||||
 		}
 | 
			
		||||
 
 | 
			
		||||
-		zlib_err = zlib_inflate(&msblk->stream, Z_SYNC_FLUSH);
 | 
			
		||||
+		zlib_err = zlib_inflate(stream, Z_SYNC_FLUSH);
 | 
			
		||||
 
 | 
			
		||||
-		if (msblk->stream.avail_in == 0 && k < b)
 | 
			
		||||
+		if (stream->avail_in == 0 && k < b)
 | 
			
		||||
 			put_bh(bh[k++]);
 | 
			
		||||
 	} while (zlib_err == Z_OK);
 | 
			
		||||
 
 | 
			
		||||
@@ -90,14 +120,14 @@ int zlib_uncompress(struct squashfs_sb_i
 | 
			
		||||
 		goto release_mutex;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
-	zlib_err = zlib_inflateEnd(&msblk->stream);
 | 
			
		||||
+	zlib_err = zlib_inflateEnd(stream);
 | 
			
		||||
 	if (zlib_err != Z_OK) {
 | 
			
		||||
 		ERROR("zlib_inflate error, data probably corrupt\n");
 | 
			
		||||
 		goto release_mutex;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	mutex_unlock(&msblk->read_data_mutex);
 | 
			
		||||
-	return msblk->stream.total_out;
 | 
			
		||||
+	return stream->total_out;
 | 
			
		||||
 
 | 
			
		||||
 release_mutex:
 | 
			
		||||
 	mutex_unlock(&msblk->read_data_mutex);
 | 
			
		||||
@ -0,0 +1,426 @@
 | 
			
		||||
From 327fbf47a419befc6bff74f3ca42d2b6f0841903 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Phillip Lougher <phillip@lougher.demon.co.uk>
 | 
			
		||||
Date: Tue, 6 Oct 2009 04:04:15 +0100
 | 
			
		||||
Subject: [PATCH] Squashfs: add a decompressor framework
 | 
			
		||||
 | 
			
		||||
This adds a decompressor framework which allows multiple compression
 | 
			
		||||
algorithms to be cleanly supported.
 | 
			
		||||
 | 
			
		||||
Also update zlib wrapper and other code to use the new framework.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Phillip Lougher <phillip@lougher.demon.co.uk>
 | 
			
		||||
---
 | 
			
		||||
 fs/squashfs/Makefile         |    2 +-
 | 
			
		||||
 fs/squashfs/block.c          |    6 ++--
 | 
			
		||||
 fs/squashfs/decompressor.c   |   58 ++++++++++++++++++++++++++++++++++++++++++
 | 
			
		||||
 fs/squashfs/decompressor.h   |   55 +++++++++++++++++++++++++++++++++++++++
 | 
			
		||||
 fs/squashfs/squashfs.h       |   14 +++++-----
 | 
			
		||||
 fs/squashfs/squashfs_fs_sb.h |   41 +++++++++++++++--------------
 | 
			
		||||
 fs/squashfs/super.c          |   45 ++++++++++++++++++-------------
 | 
			
		||||
 fs/squashfs/zlib_wrapper.c   |   17 ++++++++++--
 | 
			
		||||
 8 files changed, 185 insertions(+), 53 deletions(-)
 | 
			
		||||
 create mode 100644 fs/squashfs/decompressor.c
 | 
			
		||||
 create mode 100644 fs/squashfs/decompressor.h
 | 
			
		||||
 | 
			
		||||
--- a/fs/squashfs/Makefile
 | 
			
		||||
+++ b/fs/squashfs/Makefile
 | 
			
		||||
@@ -4,4 +4,4 @@
 | 
			
		||||
 
 | 
			
		||||
 obj-$(CONFIG_SQUASHFS) += squashfs.o
 | 
			
		||||
 squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o
 | 
			
		||||
-squashfs-y += namei.o super.o symlink.o zlib_wrapper.o
 | 
			
		||||
+squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o
 | 
			
		||||
--- a/fs/squashfs/block.c
 | 
			
		||||
+++ b/fs/squashfs/block.c
 | 
			
		||||
@@ -36,7 +36,7 @@
 | 
			
		||||
 #include "squashfs_fs_sb.h"
 | 
			
		||||
 #include "squashfs_fs_i.h"
 | 
			
		||||
 #include "squashfs.h"
 | 
			
		||||
-
 | 
			
		||||
+#include "decompressor.h"
 | 
			
		||||
 /*
 | 
			
		||||
  * Read the metadata block length, this is stored in the first two
 | 
			
		||||
  * bytes of the metadata block.
 | 
			
		||||
@@ -151,8 +151,8 @@ int squashfs_read_data(struct super_bloc
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	if (compressed) {
 | 
			
		||||
-		length = zlib_uncompress(msblk, buffer, bh, b, offset, length,
 | 
			
		||||
-			srclength, pages);
 | 
			
		||||
+		length = squashfs_decompress(msblk, buffer, bh, b, offset,
 | 
			
		||||
+			length, srclength, pages);
 | 
			
		||||
 		if (length < 0)
 | 
			
		||||
 			goto read_failure;
 | 
			
		||||
 	} else {
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/fs/squashfs/decompressor.c
 | 
			
		||||
@@ -0,0 +1,58 @@
 | 
			
		||||
+/*
 | 
			
		||||
+ * Squashfs - a compressed read only filesystem for Linux
 | 
			
		||||
+ *
 | 
			
		||||
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
 | 
			
		||||
+ * Phillip Lougher <phillip@lougher.demon.co.uk>
 | 
			
		||||
+ *
 | 
			
		||||
+ * 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,
 | 
			
		||||
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | 
			
		||||
+ *
 | 
			
		||||
+ * decompressor.c
 | 
			
		||||
+ */
 | 
			
		||||
+
 | 
			
		||||
+#include <linux/types.h>
 | 
			
		||||
+#include <linux/mutex.h>
 | 
			
		||||
+#include <linux/buffer_head.h>
 | 
			
		||||
+
 | 
			
		||||
+#include "squashfs_fs.h"
 | 
			
		||||
+#include "squashfs_fs_sb.h"
 | 
			
		||||
+#include "squashfs_fs_i.h"
 | 
			
		||||
+#include "decompressor.h"
 | 
			
		||||
+#include "squashfs.h"
 | 
			
		||||
+
 | 
			
		||||
+/*
 | 
			
		||||
+ * This file (and decompressor.h) implements a decompressor framework for
 | 
			
		||||
+ * Squashfs, allowing multiple decompressors to be easily supported
 | 
			
		||||
+ */
 | 
			
		||||
+
 | 
			
		||||
+static const struct squashfs_decompressor squashfs_unknown_comp_ops = {
 | 
			
		||||
+	NULL, NULL, NULL, 0, "unknown", 0
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+static const struct squashfs_decompressor *decompressor[] = {
 | 
			
		||||
+	&squashfs_zlib_comp_ops,
 | 
			
		||||
+	&squashfs_unknown_comp_ops
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+
 | 
			
		||||
+const struct squashfs_decompressor *squashfs_lookup_decompressor(int id)
 | 
			
		||||
+{
 | 
			
		||||
+	int i;
 | 
			
		||||
+
 | 
			
		||||
+	for (i = 0; decompressor[i]->id; i++)
 | 
			
		||||
+		if (id == decompressor[i]->id)
 | 
			
		||||
+			break;
 | 
			
		||||
+
 | 
			
		||||
+	return decompressor[i];
 | 
			
		||||
+}
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/fs/squashfs/decompressor.h
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
+#ifndef DECOMPRESSOR_H
 | 
			
		||||
+#define DECOMPRESSOR_H
 | 
			
		||||
+/*
 | 
			
		||||
+ * Squashfs - a compressed read only filesystem for Linux
 | 
			
		||||
+ *
 | 
			
		||||
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
 | 
			
		||||
+ * Phillip Lougher <phillip@lougher.demon.co.uk>
 | 
			
		||||
+ *
 | 
			
		||||
+ * 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,
 | 
			
		||||
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | 
			
		||||
+ *
 | 
			
		||||
+ * decompressor.h
 | 
			
		||||
+ */
 | 
			
		||||
+
 | 
			
		||||
+struct squashfs_decompressor {
 | 
			
		||||
+	void	*(*init)(void);
 | 
			
		||||
+	void	(*free)(void *);
 | 
			
		||||
+	int	(*decompress)(struct squashfs_sb_info *, void **,
 | 
			
		||||
+		struct buffer_head **, int, int, int, int, int);
 | 
			
		||||
+	int	id;
 | 
			
		||||
+	char	*name;
 | 
			
		||||
+	int	supported;
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+static inline void *squashfs_decompressor_init(struct squashfs_sb_info *msblk)
 | 
			
		||||
+{
 | 
			
		||||
+	return msblk->decompressor->init();
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static inline void squashfs_decompressor_free(struct squashfs_sb_info *msblk,
 | 
			
		||||
+	void *s)
 | 
			
		||||
+{
 | 
			
		||||
+	if (msblk->decompressor)
 | 
			
		||||
+		msblk->decompressor->free(s);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static inline int squashfs_decompress(struct squashfs_sb_info *msblk,
 | 
			
		||||
+	void **buffer, struct buffer_head **bh, int b, int offset, int length,
 | 
			
		||||
+	int srclength, int pages)
 | 
			
		||||
+{
 | 
			
		||||
+	return msblk->decompressor->decompress(msblk, buffer, bh, b, offset,
 | 
			
		||||
+		length, srclength, pages);
 | 
			
		||||
+}
 | 
			
		||||
+#endif
 | 
			
		||||
--- a/fs/squashfs/squashfs.h
 | 
			
		||||
+++ b/fs/squashfs/squashfs.h
 | 
			
		||||
@@ -51,6 +51,9 @@ extern struct squashfs_cache_entry *squa
 | 
			
		||||
 				u64, int);
 | 
			
		||||
 extern int squashfs_read_table(struct super_block *, void *, u64, int);
 | 
			
		||||
 
 | 
			
		||||
+/* decompressor.c */
 | 
			
		||||
+extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int);
 | 
			
		||||
+
 | 
			
		||||
 /* export.c */
 | 
			
		||||
 extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64,
 | 
			
		||||
 				unsigned int);
 | 
			
		||||
@@ -70,14 +73,8 @@ extern struct inode *squashfs_iget(struc
 | 
			
		||||
 				unsigned int);
 | 
			
		||||
 extern int squashfs_read_inode(struct inode *, long long);
 | 
			
		||||
 
 | 
			
		||||
-/* zlib_wrapper.c */
 | 
			
		||||
-extern void *zlib_init(void);
 | 
			
		||||
-extern void zlib_free(void *);
 | 
			
		||||
-extern int zlib_uncompress(struct squashfs_sb_info *, void **,
 | 
			
		||||
-				struct buffer_head **, int, int, int, int, int);
 | 
			
		||||
-
 | 
			
		||||
 /*
 | 
			
		||||
- * Inodes and files operations
 | 
			
		||||
+ * Inodes, files and decompressor operations
 | 
			
		||||
  */
 | 
			
		||||
 
 | 
			
		||||
 /* dir.c */
 | 
			
		||||
@@ -94,3 +91,6 @@ extern const struct inode_operations squ
 | 
			
		||||
 
 | 
			
		||||
 /* symlink.c */
 | 
			
		||||
 extern const struct address_space_operations squashfs_symlink_aops;
 | 
			
		||||
+
 | 
			
		||||
+/* zlib_wrapper.c */
 | 
			
		||||
+extern const struct squashfs_decompressor squashfs_zlib_comp_ops;
 | 
			
		||||
--- a/fs/squashfs/squashfs_fs_sb.h
 | 
			
		||||
+++ b/fs/squashfs/squashfs_fs_sb.h
 | 
			
		||||
@@ -52,25 +52,26 @@ struct squashfs_cache_entry {
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 struct squashfs_sb_info {
 | 
			
		||||
-	int			devblksize;
 | 
			
		||||
-	int			devblksize_log2;
 | 
			
		||||
-	struct squashfs_cache	*block_cache;
 | 
			
		||||
-	struct squashfs_cache	*fragment_cache;
 | 
			
		||||
-	struct squashfs_cache	*read_page;
 | 
			
		||||
-	int			next_meta_index;
 | 
			
		||||
-	__le64			*id_table;
 | 
			
		||||
-	__le64			*fragment_index;
 | 
			
		||||
-	unsigned int		*fragment_index_2;
 | 
			
		||||
-	struct mutex		read_data_mutex;
 | 
			
		||||
-	struct mutex		meta_index_mutex;
 | 
			
		||||
-	struct meta_index	*meta_index;
 | 
			
		||||
-	void			*stream;
 | 
			
		||||
-	__le64			*inode_lookup_table;
 | 
			
		||||
-	u64			inode_table;
 | 
			
		||||
-	u64			directory_table;
 | 
			
		||||
-	unsigned int		block_size;
 | 
			
		||||
-	unsigned short		block_log;
 | 
			
		||||
-	long long		bytes_used;
 | 
			
		||||
-	unsigned int		inodes;
 | 
			
		||||
+	const struct squashfs_decompressor	*decompressor;
 | 
			
		||||
+	int					devblksize;
 | 
			
		||||
+	int					devblksize_log2;
 | 
			
		||||
+	struct squashfs_cache			*block_cache;
 | 
			
		||||
+	struct squashfs_cache			*fragment_cache;
 | 
			
		||||
+	struct squashfs_cache			*read_page;
 | 
			
		||||
+	int					next_meta_index;
 | 
			
		||||
+	__le64					*id_table;
 | 
			
		||||
+	__le64					*fragment_index;
 | 
			
		||||
+	unsigned int				*fragment_index_2;
 | 
			
		||||
+	struct mutex				read_data_mutex;
 | 
			
		||||
+	struct mutex				meta_index_mutex;
 | 
			
		||||
+	struct meta_index			*meta_index;
 | 
			
		||||
+	void					*stream;
 | 
			
		||||
+	__le64					*inode_lookup_table;
 | 
			
		||||
+	u64					inode_table;
 | 
			
		||||
+	u64					directory_table;
 | 
			
		||||
+	unsigned int				block_size;
 | 
			
		||||
+	unsigned short				block_log;
 | 
			
		||||
+	long long				bytes_used;
 | 
			
		||||
+	unsigned int				inodes;
 | 
			
		||||
 };
 | 
			
		||||
 #endif
 | 
			
		||||
--- a/fs/squashfs/super.c
 | 
			
		||||
+++ b/fs/squashfs/super.c
 | 
			
		||||
@@ -41,27 +41,35 @@
 | 
			
		||||
 #include "squashfs_fs_sb.h"
 | 
			
		||||
 #include "squashfs_fs_i.h"
 | 
			
		||||
 #include "squashfs.h"
 | 
			
		||||
+#include "decompressor.h"
 | 
			
		||||
 
 | 
			
		||||
 static struct file_system_type squashfs_fs_type;
 | 
			
		||||
 static const struct super_operations squashfs_super_ops;
 | 
			
		||||
 
 | 
			
		||||
-static int supported_squashfs_filesystem(short major, short minor, short comp)
 | 
			
		||||
+static const struct squashfs_decompressor *supported_squashfs_filesystem(short
 | 
			
		||||
+	major, short minor, short id)
 | 
			
		||||
 {
 | 
			
		||||
+	const struct squashfs_decompressor *decompressor;
 | 
			
		||||
+
 | 
			
		||||
 	if (major < SQUASHFS_MAJOR) {
 | 
			
		||||
 		ERROR("Major/Minor mismatch, older Squashfs %d.%d "
 | 
			
		||||
 			"filesystems are unsupported\n", major, minor);
 | 
			
		||||
-		return -EINVAL;
 | 
			
		||||
+		return NULL;
 | 
			
		||||
 	} else if (major > SQUASHFS_MAJOR || minor > SQUASHFS_MINOR) {
 | 
			
		||||
 		ERROR("Major/Minor mismatch, trying to mount newer "
 | 
			
		||||
 			"%d.%d filesystem\n", major, minor);
 | 
			
		||||
 		ERROR("Please update your kernel\n");
 | 
			
		||||
-		return -EINVAL;
 | 
			
		||||
+		return NULL;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
-	if (comp != ZLIB_COMPRESSION)
 | 
			
		||||
-		return -EINVAL;
 | 
			
		||||
+	decompressor = squashfs_lookup_decompressor(id);
 | 
			
		||||
+	if (!decompressor->supported) {
 | 
			
		||||
+		ERROR("Filesystem uses \"%s\" compression. This is not "
 | 
			
		||||
+			"supported\n", decompressor->name);
 | 
			
		||||
+		return NULL;
 | 
			
		||||
+	}
 | 
			
		||||
 
 | 
			
		||||
-	return 0;
 | 
			
		||||
+	return decompressor;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
@@ -86,10 +94,6 @@ static int squashfs_fill_super(struct su
 | 
			
		||||
 	}
 | 
			
		||||
 	msblk = sb->s_fs_info;
 | 
			
		||||
 
 | 
			
		||||
-	msblk->stream = zlib_init();
 | 
			
		||||
-	if (msblk->stream == NULL)
 | 
			
		||||
-		goto failure;
 | 
			
		||||
-
 | 
			
		||||
 	sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
 | 
			
		||||
 	if (sblk == NULL) {
 | 
			
		||||
 		ERROR("Failed to allocate squashfs_super_block\n");
 | 
			
		||||
@@ -116,25 +120,25 @@ static int squashfs_fill_super(struct su
 | 
			
		||||
 		goto failed_mount;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
+	err = -EINVAL;
 | 
			
		||||
+
 | 
			
		||||
 	/* Check it is a SQUASHFS superblock */
 | 
			
		||||
 	sb->s_magic = le32_to_cpu(sblk->s_magic);
 | 
			
		||||
 	if (sb->s_magic != SQUASHFS_MAGIC) {
 | 
			
		||||
 		if (!silent)
 | 
			
		||||
 			ERROR("Can't find a SQUASHFS superblock on %s\n",
 | 
			
		||||
 						bdevname(sb->s_bdev, b));
 | 
			
		||||
-		err = -EINVAL;
 | 
			
		||||
 		goto failed_mount;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
-	/* Check the MAJOR & MINOR versions and compression type */
 | 
			
		||||
-	err = supported_squashfs_filesystem(le16_to_cpu(sblk->s_major),
 | 
			
		||||
+	/* Check the MAJOR & MINOR versions and lookup compression type */
 | 
			
		||||
+	msblk->decompressor = supported_squashfs_filesystem(
 | 
			
		||||
+			le16_to_cpu(sblk->s_major),
 | 
			
		||||
 			le16_to_cpu(sblk->s_minor),
 | 
			
		||||
 			le16_to_cpu(sblk->compression));
 | 
			
		||||
-	if (err < 0)
 | 
			
		||||
+	if (msblk->decompressor == NULL)
 | 
			
		||||
 		goto failed_mount;
 | 
			
		||||
 
 | 
			
		||||
-	err = -EINVAL;
 | 
			
		||||
-
 | 
			
		||||
 	/*
 | 
			
		||||
 	 * Check if there's xattrs in the filesystem.  These are not
 | 
			
		||||
 	 * supported in this version, so warn that they will be ignored.
 | 
			
		||||
@@ -201,6 +205,10 @@ static int squashfs_fill_super(struct su
 | 
			
		||||
 
 | 
			
		||||
 	err = -ENOMEM;
 | 
			
		||||
 
 | 
			
		||||
+	msblk->stream = squashfs_decompressor_init(msblk);
 | 
			
		||||
+	if (msblk->stream == NULL)
 | 
			
		||||
+		goto failed_mount;
 | 
			
		||||
+
 | 
			
		||||
 	msblk->block_cache = squashfs_cache_init("metadata",
 | 
			
		||||
 			SQUASHFS_CACHED_BLKS, SQUASHFS_METADATA_SIZE);
 | 
			
		||||
 	if (msblk->block_cache == NULL)
 | 
			
		||||
@@ -288,7 +296,7 @@ failed_mount:
 | 
			
		||||
 	squashfs_cache_delete(msblk->block_cache);
 | 
			
		||||
 	squashfs_cache_delete(msblk->fragment_cache);
 | 
			
		||||
 	squashfs_cache_delete(msblk->read_page);
 | 
			
		||||
-	zlib_free(msblk->stream);
 | 
			
		||||
+	squashfs_decompressor_free(msblk, msblk->stream);
 | 
			
		||||
 	kfree(msblk->inode_lookup_table);
 | 
			
		||||
 	kfree(msblk->fragment_index);
 | 
			
		||||
 	kfree(msblk->id_table);
 | 
			
		||||
@@ -298,7 +306,6 @@ failed_mount:
 | 
			
		||||
 	return err;
 | 
			
		||||
 
 | 
			
		||||
 failure:
 | 
			
		||||
-	zlib_free(msblk->stream);
 | 
			
		||||
 	kfree(sb->s_fs_info);
 | 
			
		||||
 	sb->s_fs_info = NULL;
 | 
			
		||||
 	return -ENOMEM;
 | 
			
		||||
@@ -342,7 +349,7 @@ static void squashfs_put_super(struct su
 | 
			
		||||
 		squashfs_cache_delete(sbi->block_cache);
 | 
			
		||||
 		squashfs_cache_delete(sbi->fragment_cache);
 | 
			
		||||
 		squashfs_cache_delete(sbi->read_page);
 | 
			
		||||
-		zlib_free(sbi->stream);
 | 
			
		||||
+		squashfs_decompressor_free(sbi, sbi->stream);
 | 
			
		||||
 		kfree(sbi->id_table);
 | 
			
		||||
 		kfree(sbi->fragment_index);
 | 
			
		||||
 		kfree(sbi->meta_index);
 | 
			
		||||
--- a/fs/squashfs/zlib_wrapper.c
 | 
			
		||||
+++ b/fs/squashfs/zlib_wrapper.c
 | 
			
		||||
@@ -30,8 +30,9 @@
 | 
			
		||||
 #include "squashfs_fs_sb.h"
 | 
			
		||||
 #include "squashfs_fs_i.h"
 | 
			
		||||
 #include "squashfs.h"
 | 
			
		||||
+#include "decompressor.h"
 | 
			
		||||
 
 | 
			
		||||
-void *zlib_init()
 | 
			
		||||
+static void *zlib_init(void)
 | 
			
		||||
 {
 | 
			
		||||
 	z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL);
 | 
			
		||||
 	if (stream == NULL)
 | 
			
		||||
@@ -50,7 +51,7 @@ failed:
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
-void zlib_free(void *strm)
 | 
			
		||||
+static void zlib_free(void *strm)
 | 
			
		||||
 {
 | 
			
		||||
 	z_stream *stream = strm;
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +61,7 @@ void zlib_free(void *strm)
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
-int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
 | 
			
		||||
+static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
 | 
			
		||||
 	struct buffer_head **bh, int b, int offset, int length, int srclength,
 | 
			
		||||
 	int pages)
 | 
			
		||||
 {
 | 
			
		||||
@@ -137,3 +138,13 @@ release_mutex:
 | 
			
		||||
 
 | 
			
		||||
 	return -EIO;
 | 
			
		||||
 }
 | 
			
		||||
+
 | 
			
		||||
+const struct squashfs_decompressor squashfs_zlib_comp_ops = {
 | 
			
		||||
+	.init = zlib_init,
 | 
			
		||||
+	.free = zlib_free,
 | 
			
		||||
+	.decompress = zlib_uncompress,
 | 
			
		||||
+	.id = ZLIB_COMPRESSION,
 | 
			
		||||
+	.name = "zlib",
 | 
			
		||||
+	.supported = 1
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
@ -0,0 +1,54 @@
 | 
			
		||||
From 1885ca0a1973944684f252094a703b7c80dfc974 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Phillip Lougher <phillip@lougher.demon.co.uk>
 | 
			
		||||
Date: Wed, 14 Oct 2009 03:58:11 +0100
 | 
			
		||||
Subject: [PATCH] Squashfs: add decompressor entries for lzma and lzo
 | 
			
		||||
 | 
			
		||||
Add knowledge of lzma/lzo compression formats to the decompressor
 | 
			
		||||
framework.  For now these are added as unsupported.  Without
 | 
			
		||||
these entries lzma/lzo compressed filesystems will be flagged as
 | 
			
		||||
having unknown compression which is undesirable.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Phillip Lougher <phillip@lougher.demon.co.uk>
 | 
			
		||||
---
 | 
			
		||||
 fs/squashfs/decompressor.c |   10 ++++++++++
 | 
			
		||||
 fs/squashfs/squashfs_fs.h  |    4 +++-
 | 
			
		||||
 2 files changed, 13 insertions(+), 1 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/fs/squashfs/decompressor.c
 | 
			
		||||
+++ b/fs/squashfs/decompressor.c
 | 
			
		||||
@@ -36,12 +36,22 @@
 | 
			
		||||
  * Squashfs, allowing multiple decompressors to be easily supported
 | 
			
		||||
  */
 | 
			
		||||
 
 | 
			
		||||
+static const struct squashfs_decompressor squashfs_lzma_unsupported_comp_ops = {
 | 
			
		||||
+	NULL, NULL, NULL, LZMA_COMPRESSION, "lzma", 0
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+static const struct squashfs_decompressor squashfs_lzo_unsupported_comp_ops = {
 | 
			
		||||
+	NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
 static const struct squashfs_decompressor squashfs_unknown_comp_ops = {
 | 
			
		||||
 	NULL, NULL, NULL, 0, "unknown", 0
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 static const struct squashfs_decompressor *decompressor[] = {
 | 
			
		||||
 	&squashfs_zlib_comp_ops,
 | 
			
		||||
+	&squashfs_lzma_unsupported_comp_ops,
 | 
			
		||||
+	&squashfs_lzo_unsupported_comp_ops,
 | 
			
		||||
 	&squashfs_unknown_comp_ops
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
--- a/fs/squashfs/squashfs_fs.h
 | 
			
		||||
+++ b/fs/squashfs/squashfs_fs.h
 | 
			
		||||
@@ -211,7 +211,9 @@ struct meta_index {
 | 
			
		||||
 /*
 | 
			
		||||
  * definitions for structures on disk
 | 
			
		||||
  */
 | 
			
		||||
-#define ZLIB_COMPRESSION	 1
 | 
			
		||||
+#define ZLIB_COMPRESSION	1
 | 
			
		||||
+#define LZMA_COMPRESSION	2
 | 
			
		||||
+#define LZO_COMPRESSION		3
 | 
			
		||||
 
 | 
			
		||||
 struct squashfs_super_block {
 | 
			
		||||
 	__le32			s_magic;
 | 
			
		||||
@ -0,0 +1,42 @@
 | 
			
		||||
From 5f393ede3ddb5dd4cc2a9f243182fac45f1ce10b Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Phillip Lougher <phillip@lougher.demon.co.uk>
 | 
			
		||||
Date: Wed, 14 Oct 2009 04:07:54 +0100
 | 
			
		||||
Subject: [PATCH] Squashfs: add an extra parameter to the decompressor init function
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Phillip Lougher <phillip@lougher.demon.co.uk>
 | 
			
		||||
---
 | 
			
		||||
 fs/squashfs/decompressor.h |    4 ++--
 | 
			
		||||
 fs/squashfs/zlib_wrapper.c |    2 +-
 | 
			
		||||
 2 files changed, 3 insertions(+), 3 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/fs/squashfs/decompressor.h
 | 
			
		||||
+++ b/fs/squashfs/decompressor.h
 | 
			
		||||
@@ -24,7 +24,7 @@
 | 
			
		||||
  */
 | 
			
		||||
 
 | 
			
		||||
 struct squashfs_decompressor {
 | 
			
		||||
-	void	*(*init)(void);
 | 
			
		||||
+	void	*(*init)(struct squashfs_sb_info *);
 | 
			
		||||
 	void	(*free)(void *);
 | 
			
		||||
 	int	(*decompress)(struct squashfs_sb_info *, void **,
 | 
			
		||||
 		struct buffer_head **, int, int, int, int, int);
 | 
			
		||||
@@ -35,7 +35,7 @@ struct squashfs_decompressor {
 | 
			
		||||
 
 | 
			
		||||
 static inline void *squashfs_decompressor_init(struct squashfs_sb_info *msblk)
 | 
			
		||||
 {
 | 
			
		||||
-	return msblk->decompressor->init();
 | 
			
		||||
+	return msblk->decompressor->init(msblk);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 static inline void squashfs_decompressor_free(struct squashfs_sb_info *msblk,
 | 
			
		||||
--- a/fs/squashfs/zlib_wrapper.c
 | 
			
		||||
+++ b/fs/squashfs/zlib_wrapper.c
 | 
			
		||||
@@ -32,7 +32,7 @@
 | 
			
		||||
 #include "squashfs.h"
 | 
			
		||||
 #include "decompressor.h"
 | 
			
		||||
 
 | 
			
		||||
-static void *zlib_init(void)
 | 
			
		||||
+static void *zlib_init(struct squashfs_sb_info *dummy)
 | 
			
		||||
 {
 | 
			
		||||
 	z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL);
 | 
			
		||||
 	if (stream == NULL)
 | 
			
		||||
@ -0,0 +1,216 @@
 | 
			
		||||
From f49e1efdd179d54e814ff2a8e8f469496583062c Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Phillip Lougher <phillip@lougher.demon.co.uk>
 | 
			
		||||
Date: Tue, 20 Oct 2009 10:54:36 +0100
 | 
			
		||||
Subject: [PATCH] Squashfs: add LZMA compression
 | 
			
		||||
 | 
			
		||||
Add support for LZMA compressed filesystems.  This is an initial
 | 
			
		||||
implementation.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Phillip Lougher <phillip@lougher.demon.co.uk>
 | 
			
		||||
---
 | 
			
		||||
 fs/squashfs/Kconfig        |    5 ++
 | 
			
		||||
 fs/squashfs/Makefile       |    1 +
 | 
			
		||||
 fs/squashfs/decompressor.c |    4 +
 | 
			
		||||
 fs/squashfs/lzma_wrapper.c |  151 ++++++++++++++++++++++++++++++++++++++++++++
 | 
			
		||||
 fs/squashfs/squashfs.h     |    3 +
 | 
			
		||||
 5 files changed, 164 insertions(+), 0 deletions(-)
 | 
			
		||||
 create mode 100644 fs/squashfs/lzma_wrapper.c
 | 
			
		||||
 | 
			
		||||
--- a/fs/squashfs/Kconfig
 | 
			
		||||
+++ b/fs/squashfs/Kconfig
 | 
			
		||||
@@ -26,6 +26,11 @@ config SQUASHFS
 | 
			
		||||
 
 | 
			
		||||
 	  If unsure, say N.
 | 
			
		||||
 
 | 
			
		||||
+config SQUASHFS_LZMA
 | 
			
		||||
+	bool "Include support for LZMA compressed file systems"
 | 
			
		||||
+	depends on SQUASHFS
 | 
			
		||||
+	select DECOMPRESS_LZMA
 | 
			
		||||
+
 | 
			
		||||
 config SQUASHFS_EMBEDDED
 | 
			
		||||
 
 | 
			
		||||
 	bool "Additional option for memory-constrained systems" 
 | 
			
		||||
--- a/fs/squashfs/Makefile
 | 
			
		||||
+++ b/fs/squashfs/Makefile
 | 
			
		||||
@@ -5,3 +5,4 @@
 | 
			
		||||
 obj-$(CONFIG_SQUASHFS) += squashfs.o
 | 
			
		||||
 squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o
 | 
			
		||||
 squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o
 | 
			
		||||
+squashfs-$(CONFIG_SQUASHFS_LZMA) += lzma_wrapper.o
 | 
			
		||||
--- a/fs/squashfs/decompressor.c
 | 
			
		||||
+++ b/fs/squashfs/decompressor.c
 | 
			
		||||
@@ -50,7 +50,11 @@ static const struct squashfs_decompresso
 | 
			
		||||
 
 | 
			
		||||
 static const struct squashfs_decompressor *decompressor[] = {
 | 
			
		||||
 	&squashfs_zlib_comp_ops,
 | 
			
		||||
+#ifdef CONFIG_SQUASHFS_LZMA
 | 
			
		||||
+	&squashfs_lzma_comp_ops,
 | 
			
		||||
+#else
 | 
			
		||||
 	&squashfs_lzma_unsupported_comp_ops,
 | 
			
		||||
+#endif
 | 
			
		||||
 	&squashfs_lzo_unsupported_comp_ops,
 | 
			
		||||
 	&squashfs_unknown_comp_ops
 | 
			
		||||
 };
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/fs/squashfs/lzma_wrapper.c
 | 
			
		||||
@@ -0,0 +1,151 @@
 | 
			
		||||
+/*
 | 
			
		||||
+ * Squashfs - a compressed read only filesystem for Linux
 | 
			
		||||
+ *
 | 
			
		||||
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
 | 
			
		||||
+ * Phillip Lougher <phillip@lougher.demon.co.uk>
 | 
			
		||||
+ *
 | 
			
		||||
+ * 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,
 | 
			
		||||
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | 
			
		||||
+ *
 | 
			
		||||
+ * lzma_wrapper.c
 | 
			
		||||
+ */
 | 
			
		||||
+
 | 
			
		||||
+#include <asm/unaligned.h>
 | 
			
		||||
+#include <linux/buffer_head.h>
 | 
			
		||||
+#include <linux/mutex.h>
 | 
			
		||||
+#include <linux/vmalloc.h>
 | 
			
		||||
+#include <linux/decompress/unlzma.h>
 | 
			
		||||
+
 | 
			
		||||
+#include "squashfs_fs.h"
 | 
			
		||||
+#include "squashfs_fs_sb.h"
 | 
			
		||||
+#include "squashfs_fs_i.h"
 | 
			
		||||
+#include "squashfs.h"
 | 
			
		||||
+#include "decompressor.h"
 | 
			
		||||
+
 | 
			
		||||
+struct squashfs_lzma {
 | 
			
		||||
+	void	*input;
 | 
			
		||||
+	void	*output;
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+/* decompress_unlzma.c is currently non re-entrant... */
 | 
			
		||||
+DEFINE_MUTEX(lzma_mutex);
 | 
			
		||||
+
 | 
			
		||||
+/* decompress_unlzma.c doesn't provide any context in its callbacks... */
 | 
			
		||||
+static int lzma_error;
 | 
			
		||||
+
 | 
			
		||||
+static void error(char *m)
 | 
			
		||||
+{
 | 
			
		||||
+	ERROR("unlzma error: %s\n", m);
 | 
			
		||||
+	lzma_error = 1;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+	
 | 
			
		||||
+static void *lzma_init(struct squashfs_sb_info *msblk)
 | 
			
		||||
+{
 | 
			
		||||
+	struct squashfs_lzma *stream = kzalloc(sizeof(*stream), GFP_KERNEL);
 | 
			
		||||
+	if (stream == NULL)
 | 
			
		||||
+		goto failed;
 | 
			
		||||
+	stream->input = vmalloc(msblk->block_size);
 | 
			
		||||
+	if (stream->input == NULL)
 | 
			
		||||
+		goto failed;
 | 
			
		||||
+	stream->output = vmalloc(msblk->block_size);
 | 
			
		||||
+	if (stream->output == NULL)
 | 
			
		||||
+		goto failed2;
 | 
			
		||||
+
 | 
			
		||||
+	return stream;
 | 
			
		||||
+
 | 
			
		||||
+failed2:
 | 
			
		||||
+	vfree(stream->input);
 | 
			
		||||
+failed:
 | 
			
		||||
+	ERROR("failed to allocate lzma workspace\n");
 | 
			
		||||
+	kfree(stream);
 | 
			
		||||
+	return NULL;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+
 | 
			
		||||
+static void lzma_free(void *strm)
 | 
			
		||||
+{
 | 
			
		||||
+	struct squashfs_lzma *stream = strm;
 | 
			
		||||
+
 | 
			
		||||
+	if (stream) {
 | 
			
		||||
+		vfree(stream->input);
 | 
			
		||||
+		vfree(stream->output);
 | 
			
		||||
+	}
 | 
			
		||||
+	kfree(stream);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+
 | 
			
		||||
+static int lzma_uncompress(struct squashfs_sb_info *msblk, void **buffer,
 | 
			
		||||
+	struct buffer_head **bh, int b, int offset, int length, int srclength,
 | 
			
		||||
+	int pages)
 | 
			
		||||
+{
 | 
			
		||||
+	struct squashfs_lzma *stream = msblk->stream;
 | 
			
		||||
+	void *buff = stream->input;
 | 
			
		||||
+	int avail, i, bytes = length, res;
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&lzma_mutex);
 | 
			
		||||
+
 | 
			
		||||
+	for (i = 0; i < b; i++) {
 | 
			
		||||
+		wait_on_buffer(bh[i]);
 | 
			
		||||
+		if (!buffer_uptodate(bh[i]))
 | 
			
		||||
+			goto block_release;
 | 
			
		||||
+
 | 
			
		||||
+		avail = min(bytes, msblk->devblksize - offset);
 | 
			
		||||
+		memcpy(buff, bh[i]->b_data + offset, avail);
 | 
			
		||||
+		buff += avail;
 | 
			
		||||
+		bytes -= avail;
 | 
			
		||||
+		offset = 0;
 | 
			
		||||
+		put_bh(bh[i]);
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	lzma_error = 0;
 | 
			
		||||
+	res = unlzma(stream->input, length, NULL, NULL, stream->output, NULL,
 | 
			
		||||
+							error);
 | 
			
		||||
+	if (res || lzma_error)
 | 
			
		||||
+		goto failed;
 | 
			
		||||
+
 | 
			
		||||
+	/* uncompressed size is stored in the LZMA header (5 byte offset) */
 | 
			
		||||
+	res = bytes = get_unaligned_le32(stream->input + 5);
 | 
			
		||||
+	for (i = 0, buff = stream->output; bytes && i < pages; i++) {
 | 
			
		||||
+		avail = min_t(int, bytes, PAGE_CACHE_SIZE);
 | 
			
		||||
+		memcpy(buffer[i], buff, avail);
 | 
			
		||||
+		buff += avail;
 | 
			
		||||
+		bytes -= avail;
 | 
			
		||||
+	}
 | 
			
		||||
+	if (bytes)
 | 
			
		||||
+		goto failed;
 | 
			
		||||
+
 | 
			
		||||
+	mutex_unlock(&lzma_mutex);
 | 
			
		||||
+	return res;
 | 
			
		||||
+
 | 
			
		||||
+block_release:
 | 
			
		||||
+	for (; i < b; i++)
 | 
			
		||||
+		put_bh(bh[i]);
 | 
			
		||||
+
 | 
			
		||||
+failed:
 | 
			
		||||
+	mutex_unlock(&lzma_mutex);
 | 
			
		||||
+
 | 
			
		||||
+	ERROR("lzma decompression failed, data probably corrupt\n");
 | 
			
		||||
+	return -EIO;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+const struct squashfs_decompressor squashfs_lzma_comp_ops = {
 | 
			
		||||
+	.init = lzma_init,
 | 
			
		||||
+	.free = lzma_free,
 | 
			
		||||
+	.decompress = lzma_uncompress,
 | 
			
		||||
+	.id = LZMA_COMPRESSION,
 | 
			
		||||
+	.name = "lzma",
 | 
			
		||||
+	.supported = 1
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
--- a/fs/squashfs/squashfs.h
 | 
			
		||||
+++ b/fs/squashfs/squashfs.h
 | 
			
		||||
@@ -94,3 +94,6 @@ extern const struct address_space_operat
 | 
			
		||||
 
 | 
			
		||||
 /* zlib_wrapper.c */
 | 
			
		||||
 extern const struct squashfs_decompressor squashfs_zlib_comp_ops;
 | 
			
		||||
+
 | 
			
		||||
+/* lzma wrapper.c */
 | 
			
		||||
+extern const struct squashfs_decompressor squashfs_lzma_comp_ops;
 | 
			
		||||
@ -0,0 +1,165 @@
 | 
			
		||||
From fdf23ed283bc6ef5c25076ce2065f892120ff556 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Phillip Lougher <phillip@lougher.demon.co.uk>
 | 
			
		||||
Date: Thu, 22 Oct 2009 04:57:38 +0100
 | 
			
		||||
Subject: [PATCH] Squashfs: Make unlzma available to non initramfs/initrd code
 | 
			
		||||
 | 
			
		||||
Add a config option DECOMPRESS_LZMA_NEEDED which allows subsystems to
 | 
			
		||||
specify they need the unlzma code.  Normally decompress_unlzma.c is
 | 
			
		||||
compiled with __init and unlzma is not exported to modules.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Phillip Lougher <phillip@lougher.demon.co.uk>
 | 
			
		||||
---
 | 
			
		||||
 fs/squashfs/Kconfig                   |    1 +
 | 
			
		||||
 include/linux/decompress/bunzip2_mm.h |   12 ++++++++++++
 | 
			
		||||
 include/linux/decompress/inflate_mm.h |   12 ++++++++++++
 | 
			
		||||
 include/linux/decompress/mm.h         |    3 ---
 | 
			
		||||
 include/linux/decompress/unlzma_mm.h  |   20 ++++++++++++++++++++
 | 
			
		||||
 lib/Kconfig                           |    3 +++
 | 
			
		||||
 lib/decompress_bunzip2.c              |    1 +
 | 
			
		||||
 lib/decompress_inflate.c              |    1 +
 | 
			
		||||
 lib/decompress_unlzma.c               |    5 ++++-
 | 
			
		||||
 9 files changed, 54 insertions(+), 4 deletions(-)
 | 
			
		||||
 create mode 100644 include/linux/decompress/bunzip2_mm.h
 | 
			
		||||
 create mode 100644 include/linux/decompress/inflate_mm.h
 | 
			
		||||
 create mode 100644 include/linux/decompress/unlzma_mm.h
 | 
			
		||||
 | 
			
		||||
--- a/fs/squashfs/Kconfig
 | 
			
		||||
+++ b/fs/squashfs/Kconfig
 | 
			
		||||
@@ -30,6 +30,7 @@ config SQUASHFS_LZMA
 | 
			
		||||
 	bool "Include support for LZMA compressed file systems"
 | 
			
		||||
 	depends on SQUASHFS
 | 
			
		||||
 	select DECOMPRESS_LZMA
 | 
			
		||||
+	select DECOMPRESS_LZMA_NEEDED
 | 
			
		||||
 
 | 
			
		||||
 config SQUASHFS_EMBEDDED
 | 
			
		||||
 
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/include/linux/decompress/bunzip2_mm.h
 | 
			
		||||
@@ -0,0 +1,12 @@
 | 
			
		||||
+#ifndef BUNZIP2_MM_H
 | 
			
		||||
+#define BUNZIP2_MM_H
 | 
			
		||||
+
 | 
			
		||||
+#ifdef STATIC
 | 
			
		||||
+/* Code active when included from pre-boot environment: */
 | 
			
		||||
+#define INIT
 | 
			
		||||
+#else
 | 
			
		||||
+/* Compile for initramfs/initrd code only */
 | 
			
		||||
+#define INIT __init
 | 
			
		||||
+#endif
 | 
			
		||||
+
 | 
			
		||||
+#endif
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/include/linux/decompress/inflate_mm.h
 | 
			
		||||
@@ -0,0 +1,12 @@
 | 
			
		||||
+#ifndef INFLATE_MM_H
 | 
			
		||||
+#define INFLATE_MM_H
 | 
			
		||||
+
 | 
			
		||||
+#ifdef STATIC
 | 
			
		||||
+/* Code active when included from pre-boot environment: */
 | 
			
		||||
+#define INIT
 | 
			
		||||
+#else
 | 
			
		||||
+/* Compile for initramfs/initrd code only */
 | 
			
		||||
+#define INIT __init
 | 
			
		||||
+#endif
 | 
			
		||||
+
 | 
			
		||||
+#endif
 | 
			
		||||
--- a/include/linux/decompress/mm.h
 | 
			
		||||
+++ b/include/linux/decompress/mm.h
 | 
			
		||||
@@ -53,8 +53,6 @@ static void free(void *where)
 | 
			
		||||
 
 | 
			
		||||
 #define set_error_fn(x)
 | 
			
		||||
 
 | 
			
		||||
-#define INIT
 | 
			
		||||
-
 | 
			
		||||
 #else /* STATIC */
 | 
			
		||||
 
 | 
			
		||||
 /* Code active when compiled standalone for use when loading ramdisk: */
 | 
			
		||||
@@ -77,7 +75,6 @@ static void free(void *where)
 | 
			
		||||
 static void(*error)(char *m);
 | 
			
		||||
 #define set_error_fn(x) error = x;
 | 
			
		||||
 
 | 
			
		||||
-#define INIT __init
 | 
			
		||||
 #define STATIC
 | 
			
		||||
 
 | 
			
		||||
 #include <linux/init.h>
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/include/linux/decompress/unlzma_mm.h
 | 
			
		||||
@@ -0,0 +1,20 @@
 | 
			
		||||
+#ifndef UNLZMA_MM_H
 | 
			
		||||
+#define UNLZMA_MM_H
 | 
			
		||||
+
 | 
			
		||||
+#ifdef STATIC
 | 
			
		||||
+
 | 
			
		||||
+/* Code active when included from pre-boot environment: */
 | 
			
		||||
+#define INIT
 | 
			
		||||
+
 | 
			
		||||
+#elif defined(CONFIG_DECOMPRESS_LZMA_NEEDED)
 | 
			
		||||
+
 | 
			
		||||
+/* Make it available to non initramfs/initrd code */
 | 
			
		||||
+#define INIT
 | 
			
		||||
+#include <linux/module.h>
 | 
			
		||||
+#else
 | 
			
		||||
+
 | 
			
		||||
+/* Compile for initramfs/initrd code only */
 | 
			
		||||
+#define INIT __init
 | 
			
		||||
+#endif
 | 
			
		||||
+
 | 
			
		||||
+#endif
 | 
			
		||||
--- a/lib/Kconfig
 | 
			
		||||
+++ b/lib/Kconfig
 | 
			
		||||
@@ -117,6 +117,9 @@ config DECOMPRESS_BZIP2
 | 
			
		||||
 config DECOMPRESS_LZMA
 | 
			
		||||
 	tristate
 | 
			
		||||
 
 | 
			
		||||
+config DECOMPRESS_LZMA_NEEDED
 | 
			
		||||
+	 boolean
 | 
			
		||||
+
 | 
			
		||||
 #
 | 
			
		||||
 # Generic allocator support is selected if needed
 | 
			
		||||
 #
 | 
			
		||||
--- a/lib/decompress_bunzip2.c
 | 
			
		||||
+++ b/lib/decompress_bunzip2.c
 | 
			
		||||
@@ -52,6 +52,7 @@
 | 
			
		||||
 #include <linux/slab.h>
 | 
			
		||||
 #endif /* STATIC */
 | 
			
		||||
 
 | 
			
		||||
+#include <linux/decompress/bunzip2_mm.h>
 | 
			
		||||
 #include <linux/decompress/mm.h>
 | 
			
		||||
 
 | 
			
		||||
 #ifndef INT_MAX
 | 
			
		||||
--- a/lib/decompress_inflate.c
 | 
			
		||||
+++ b/lib/decompress_inflate.c
 | 
			
		||||
@@ -23,6 +23,7 @@
 | 
			
		||||
 
 | 
			
		||||
 #endif /* STATIC */
 | 
			
		||||
 
 | 
			
		||||
+#include <linux/decompress/inflate_mm.h>
 | 
			
		||||
 #include <linux/decompress/mm.h>
 | 
			
		||||
 
 | 
			
		||||
 #define GZIP_IOBUF_SIZE (16*1024)
 | 
			
		||||
--- a/lib/decompress_unlzma.c
 | 
			
		||||
+++ b/lib/decompress_unlzma.c
 | 
			
		||||
@@ -36,6 +36,7 @@
 | 
			
		||||
 #include <linux/slab.h>
 | 
			
		||||
 #endif /* STATIC */
 | 
			
		||||
 
 | 
			
		||||
+#include <linux/decompress/unlzma_mm.h>
 | 
			
		||||
 #include <linux/decompress/mm.h>
 | 
			
		||||
 
 | 
			
		||||
 #define	MIN(a, b) (((a) < (b)) ? (a) : (b))
 | 
			
		||||
@@ -531,7 +532,7 @@ static inline void INIT process_bit1(str
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
-STATIC inline int INIT unlzma(unsigned char *buf, int in_len,
 | 
			
		||||
+STATIC int INIT unlzma(unsigned char *buf, int in_len,
 | 
			
		||||
 			      int(*fill)(void*, unsigned int),
 | 
			
		||||
 			      int(*flush)(void*, unsigned int),
 | 
			
		||||
 			      unsigned char *output,
 | 
			
		||||
@@ -664,4 +665,6 @@ STATIC int INIT decompress(unsigned char
 | 
			
		||||
 {
 | 
			
		||||
 	return unlzma(buf, in_len - 4, fill, flush, output, posp, error_fn);
 | 
			
		||||
 }
 | 
			
		||||
+#elif defined(CONFIG_DECOMPRESS_LZMA_NEEDED)
 | 
			
		||||
+EXPORT_SYMBOL(unlzma);
 | 
			
		||||
 #endif
 | 
			
		||||
							
								
								
									
										11
									
								
								target/linux/generic-2.6/patches-2.6.32/011-mips_boot.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								target/linux/generic-2.6/patches-2.6.32/011-mips_boot.patch
									
									
									
									
									
										Normal 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.
 | 
			
		||||
@ -0,0 +1,21 @@
 | 
			
		||||
--- a/Makefile
 | 
			
		||||
+++ b/Makefile
 | 
			
		||||
@@ -523,7 +523,7 @@ all: vmlinux
 | 
			
		||||
 ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
 | 
			
		||||
 KBUILD_CFLAGS	+= -Os
 | 
			
		||||
 else
 | 
			
		||||
-KBUILD_CFLAGS	+= -O2
 | 
			
		||||
+KBUILD_CFLAGS	+= -O2 -fno-reorder-blocks -fno-tree-ch
 | 
			
		||||
 endif
 | 
			
		||||
 
 | 
			
		||||
 include $(srctree)/arch/$(SRCARCH)/Makefile
 | 
			
		||||
@@ -561,6 +561,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,)
 | 
			
		||||
 
 | 
			
		||||
@ -0,0 +1,11 @@
 | 
			
		||||
--- a/arch/mips/include/asm/system.h
 | 
			
		||||
+++ b/arch/mips/include/asm/system.h
 | 
			
		||||
@@ -197,7 +197,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:
 | 
			
		||||
							
								
								
									
										36
									
								
								target/linux/generic-2.6/patches-2.6.32/014-samsung_flash
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								target/linux/generic-2.6/patches-2.6.32/014-samsung_flash
									
									
									
									
									
										Normal 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 */
 | 
			
		||||
@ -0,0 +1,168 @@
 | 
			
		||||
--- /dev/null
 | 
			
		||||
+++ b/include/asm-mips/mips_machine.h
 | 
			
		||||
@@ -0,0 +1,46 @@
 | 
			
		||||
+/*
 | 
			
		||||
+ *  Copyright (C) 2008-2009 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>
 | 
			
		||||
+
 | 
			
		||||
+struct mips_machine {
 | 
			
		||||
+	unsigned long		mach_type;
 | 
			
		||||
+	void			(*mach_setup)(void);
 | 
			
		||||
+	char			*mach_name;
 | 
			
		||||
+	struct list_head	list;
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
+void mips_machine_register(struct mips_machine *) __init;
 | 
			
		||||
+void mips_machine_setup(unsigned long machtype) __init;
 | 
			
		||||
+
 | 
			
		||||
+extern char *mips_machine_name;
 | 
			
		||||
+
 | 
			
		||||
+#define MIPS_MACHINE(_type, _name, _setup) 			\
 | 
			
		||||
+static char machine_name_##_type[] __initdata = _name;		\
 | 
			
		||||
+static struct mips_machine machine_##_type __initdata =		\
 | 
			
		||||
+{								\
 | 
			
		||||
+	.mach_type	= _type,				\
 | 
			
		||||
+	.mach_name	= machine_name_##_type,			\
 | 
			
		||||
+	.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,70 @@
 | 
			
		||||
+/*
 | 
			
		||||
+ *  Copyright (C) 2008-2009 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 <linux/mm.h>
 | 
			
		||||
+
 | 
			
		||||
+#include <asm/mips_machine.h>
 | 
			
		||||
+#include <asm/bootinfo.h>
 | 
			
		||||
+
 | 
			
		||||
+static struct list_head mips_machines __initdata =
 | 
			
		||||
+		LIST_HEAD_INIT(mips_machines);
 | 
			
		||||
+
 | 
			
		||||
+char *mips_machine_name = "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) {
 | 
			
		||||
+		char *name;
 | 
			
		||||
+		unsigned int len;
 | 
			
		||||
+
 | 
			
		||||
+		len = strlen(mach->mach_name);
 | 
			
		||||
+		name = kmalloc(len + 1, GFP_KERNEL);
 | 
			
		||||
+		if (name) {
 | 
			
		||||
+			strncpy(name, mach->mach_name,len);
 | 
			
		||||
+			name[len] = '\0';
 | 
			
		||||
+			mips_machine_name = name;
 | 
			
		||||
+		} else {
 | 
			
		||||
+			printk(KERN_WARNING "MIPS: no memory for machine_name\n");
 | 
			
		||||
+		}
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	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
 | 
			
		||||
@@ -87,6 +87,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
 | 
			
		||||
@@ -839,6 +839,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
 | 
			
		||||
@@ -12,6 +12,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;
 | 
			
		||||
 
 | 
			
		||||
@@ -31,8 +32,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",
 | 
			
		||||
@ -0,0 +1,28 @@
 | 
			
		||||
--- a/arch/mips/Kconfig
 | 
			
		||||
+++ b/arch/mips/Kconfig
 | 
			
		||||
@@ -842,6 +842,10 @@ config SYNC_R4K
 | 
			
		||||
 config MIPS_MACHINE
 | 
			
		||||
 	def_bool n
 | 
			
		||||
 
 | 
			
		||||
+config IMAGE_CMDLINE_HACK
 | 
			
		||||
+	bool "OpenWrt specific image command line hack"
 | 
			
		||||
+	default n
 | 
			
		||||
+
 | 
			
		||||
 config NO_IOPORT
 | 
			
		||||
 	def_bool n
 | 
			
		||||
 
 | 
			
		||||
--- a/arch/mips/kernel/head.S
 | 
			
		||||
+++ b/arch/mips/kernel/head.S
 | 
			
		||||
@@ -143,6 +143,12 @@ FEXPORT(__kernel_entry)
 | 
			
		||||
 	j	kernel_entry
 | 
			
		||||
 #endif
 | 
			
		||||
 
 | 
			
		||||
+#ifdef CONFIG_IMAGE_CMDLINE_HACK
 | 
			
		||||
+	.ascii	"CMDLINE:"
 | 
			
		||||
+EXPORT(__image_cmdline)
 | 
			
		||||
+	.fill	0x400
 | 
			
		||||
+#endif /* CONFIG_IMAGE_CMDLINE_HACK */
 | 
			
		||||
+
 | 
			
		||||
 	__REF
 | 
			
		||||
 
 | 
			
		||||
 NESTED(kernel_entry, 16, sp)			# kernel entry point
 | 
			
		||||
@ -0,0 +1,155 @@
 | 
			
		||||
MIPS: allow disabling the kernel FPU emulator
 | 
			
		||||
 | 
			
		||||
This patch allows turning off the in-kernel Algorithmics
 | 
			
		||||
FPU emulator support, which allows one to save a couple of
 | 
			
		||||
precious blocks on an embedded system.
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Florian Fainelli <florian@openwrt.org>
 | 
			
		||||
--
 | 
			
		||||
--- a/arch/mips/Kconfig
 | 
			
		||||
+++ b/arch/mips/Kconfig
 | 
			
		||||
@@ -827,6 +827,17 @@ config I8259
 | 
			
		||||
 config MIPS_BONITO64
 | 
			
		||||
 	bool
 | 
			
		||||
 
 | 
			
		||||
+config MIPS_FPU_EMU
 | 
			
		||||
+	bool
 | 
			
		||||
+	default n
 | 
			
		||||
+	help
 | 
			
		||||
+	   This option allows building a kernel with or without the Algorithmics
 | 
			
		||||
+	   FPU emulator enabled. Turning off this option results in a kernel which
 | 
			
		||||
+	   does not catch floating operations exceptions. Make sure that your toolchain
 | 
			
		||||
+	   is configured to enable software floating point emulation in that case.
 | 
			
		||||
+		
 | 
			
		||||
+	   If unsure say Y here.
 | 
			
		||||
+
 | 
			
		||||
 config MIPS_MSC
 | 
			
		||||
 	bool
 | 
			
		||||
 
 | 
			
		||||
--- a/arch/mips/math-emu/Makefile
 | 
			
		||||
+++ b/arch/mips/math-emu/Makefile
 | 
			
		||||
@@ -2,12 +2,14 @@
 | 
			
		||||
 # Makefile for the Linux/MIPS kernel FPU emulation.
 | 
			
		||||
 #
 | 
			
		||||
 
 | 
			
		||||
-obj-y	:= cp1emu.o ieee754m.o ieee754d.o ieee754dp.o ieee754sp.o ieee754.o \
 | 
			
		||||
+obj-y	:=	kernel_linkage.o dsemul.o cp1emu.o
 | 
			
		||||
+
 | 
			
		||||
+obj-$(CONFIG_MIPS_FPU_EMU)	+= ieee754m.o ieee754d.o ieee754dp.o ieee754sp.o ieee754.o \
 | 
			
		||||
 	   ieee754xcpt.o dp_frexp.o dp_modf.o dp_div.o dp_mul.o dp_sub.o \
 | 
			
		||||
 	   dp_add.o dp_fsp.o dp_cmp.o dp_logb.o dp_scalb.o dp_simple.o \
 | 
			
		||||
 	   dp_tint.o dp_fint.o dp_tlong.o dp_flong.o sp_frexp.o sp_modf.o \
 | 
			
		||||
 	   sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_logb.o \
 | 
			
		||||
 	   sp_scalb.o sp_simple.o sp_tint.o sp_fint.o sp_tlong.o sp_flong.o \
 | 
			
		||||
-	   dp_sqrt.o sp_sqrt.o kernel_linkage.o dsemul.o
 | 
			
		||||
+	   dp_sqrt.o sp_sqrt.o
 | 
			
		||||
 
 | 
			
		||||
 EXTRA_CFLAGS += -Werror
 | 
			
		||||
--- a/arch/mips/math-emu/cp1emu.c
 | 
			
		||||
+++ b/arch/mips/math-emu/cp1emu.c
 | 
			
		||||
@@ -56,6 +56,12 @@
 | 
			
		||||
 #endif
 | 
			
		||||
 #define __mips 4
 | 
			
		||||
 
 | 
			
		||||
+/* Further private data for which no space exists in mips_fpu_struct */
 | 
			
		||||
+
 | 
			
		||||
+struct mips_fpu_emulator_stats fpuemustats;
 | 
			
		||||
+
 | 
			
		||||
+#ifdef CONFIG_MIPS_FPU_EMU
 | 
			
		||||
+
 | 
			
		||||
 /* Function which emulates a floating point instruction. */
 | 
			
		||||
 
 | 
			
		||||
 static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *,
 | 
			
		||||
@@ -66,10 +72,6 @@ static int fpux_emu(struct pt_regs *,
 | 
			
		||||
 	struct mips_fpu_struct *, mips_instruction);
 | 
			
		||||
 #endif
 | 
			
		||||
 
 | 
			
		||||
-/* Further private data for which no space exists in mips_fpu_struct */
 | 
			
		||||
-
 | 
			
		||||
-struct mips_fpu_emulator_stats fpuemustats;
 | 
			
		||||
-
 | 
			
		||||
 /* Control registers */
 | 
			
		||||
 
 | 
			
		||||
 #define FPCREG_RID	0	/* $0  = revision id */
 | 
			
		||||
@@ -1273,6 +1275,13 @@ int fpu_emulator_cop1Handler(struct pt_r
 | 
			
		||||
 
 | 
			
		||||
 	return sig;
 | 
			
		||||
 }
 | 
			
		||||
+#else
 | 
			
		||||
+int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
 | 
			
		||||
+        int has_fpu)
 | 
			
		||||
+{
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+#endif /* CONFIG_MIPS_FPU_EMU */
 | 
			
		||||
 
 | 
			
		||||
 #ifdef CONFIG_DEBUG_FS
 | 
			
		||||
 extern struct dentry *mips_debugfs_dir;
 | 
			
		||||
--- a/arch/mips/math-emu/dsemul.c
 | 
			
		||||
+++ b/arch/mips/math-emu/dsemul.c
 | 
			
		||||
@@ -109,6 +109,7 @@ int mips_dsemul(struct pt_regs *regs, mi
 | 
			
		||||
 	return SIGILL;		/* force out of emulation loop */
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+#ifdef CONFIG_MIPS_FPU_EMU
 | 
			
		||||
 int do_dsemulret(struct pt_regs *xcp)
 | 
			
		||||
 {
 | 
			
		||||
 	struct emuframe __user *fr;
 | 
			
		||||
@@ -165,3 +166,9 @@ int do_dsemulret(struct pt_regs *xcp)
 | 
			
		||||
 
 | 
			
		||||
 	return 1;
 | 
			
		||||
 }
 | 
			
		||||
+#else
 | 
			
		||||
+int do_dsemulret(struct pt_regs *xcp)
 | 
			
		||||
+{
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+#endif /* CONFIG_MIPS_FPU_EMU */
 | 
			
		||||
--- a/arch/mips/math-emu/kernel_linkage.c
 | 
			
		||||
+++ b/arch/mips/math-emu/kernel_linkage.c
 | 
			
		||||
@@ -29,6 +29,7 @@
 | 
			
		||||
 
 | 
			
		||||
 #define SIGNALLING_NAN 0x7ff800007ff80000LL
 | 
			
		||||
 
 | 
			
		||||
+#ifdef CONFIG_MIPS_FPU_EMU
 | 
			
		||||
 void fpu_emulator_init_fpu(void)
 | 
			
		||||
 {
 | 
			
		||||
 	static int first = 1;
 | 
			
		||||
@@ -112,4 +113,36 @@ int fpu_emulator_restore_context32(struc
 | 
			
		||||
 
 | 
			
		||||
 	return err;
 | 
			
		||||
 }
 | 
			
		||||
-#endif
 | 
			
		||||
+#endif	/* CONFIG_64BIT */
 | 
			
		||||
+#else
 | 
			
		||||
+
 | 
			
		||||
+void fpu_emulator_init_fpu(void)
 | 
			
		||||
+{
 | 
			
		||||
+	printk(KERN_INFO "FPU emulator disabled, make sure your toolchain"
 | 
			
		||||
+		"was compiled with software floating point support (soft-float)\n");
 | 
			
		||||
+	return;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+int fpu_emulator_save_context(struct sigcontext __user *sc)
 | 
			
		||||
+{
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+int fpu_emulator_restore_context(struct sigcontext __user *sc)
 | 
			
		||||
+{
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+int fpu_emulator_save_context32(struct sigcontext32 __user *sc)
 | 
			
		||||
+{
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+int fpu_emulator_restore_context32(struct sigcontext32 __user *sc)
 | 
			
		||||
+{
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+#ifdef CONFIG_64BIT
 | 
			
		||||
+#endif	/* CONFIG_64BIT */
 | 
			
		||||
+#endif /* CONFIG_MIPS_FPU_EMU */
 | 
			
		||||
@ -0,0 +1,331 @@
 | 
			
		||||
--- a/arch/mips/Makefile
 | 
			
		||||
+++ b/arch/mips/Makefile
 | 
			
		||||
@@ -83,7 +83,7 @@ all-$(CONFIG_BOOT_ELF64)	:= $(vmlinux-64
 | 
			
		||||
 cflags-y			+= -G 0 -mno-abicalls -fno-pic -pipe
 | 
			
		||||
 cflags-y			+= -msoft-float
 | 
			
		||||
 LDFLAGS_vmlinux			+= -G 0 -static -n -nostdlib
 | 
			
		||||
-MODFLAGS			+= -mlong-calls
 | 
			
		||||
+MODFLAGS			+= -mno-long-calls
 | 
			
		||||
 
 | 
			
		||||
 cflags-y += -ffreestanding
 | 
			
		||||
 
 | 
			
		||||
--- a/arch/mips/include/asm/module.h
 | 
			
		||||
+++ b/arch/mips/include/asm/module.h
 | 
			
		||||
@@ -9,6 +9,11 @@ struct mod_arch_specific {
 | 
			
		||||
 	struct list_head dbe_list;
 | 
			
		||||
 	const struct exception_table_entry *dbe_start;
 | 
			
		||||
 	const struct exception_table_entry *dbe_end;
 | 
			
		||||
+
 | 
			
		||||
+	void *plt_tbl;
 | 
			
		||||
+	unsigned int core_plt_offset;
 | 
			
		||||
+	unsigned int core_plt_size;
 | 
			
		||||
+	unsigned int init_plt_offset;
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 typedef uint8_t Elf64_Byte;		/* Type for a 8-bit quantity.  */
 | 
			
		||||
--- a/arch/mips/kernel/module.c
 | 
			
		||||
+++ b/arch/mips/kernel/module.c
 | 
			
		||||
@@ -43,6 +43,117 @@ static struct mips_hi16 *mips_hi16_list;
 | 
			
		||||
 static LIST_HEAD(dbe_list);
 | 
			
		||||
 static DEFINE_SPINLOCK(dbe_lock);
 | 
			
		||||
 
 | 
			
		||||
+/*
 | 
			
		||||
+ * Get the potential max trampolines size required of the init and
 | 
			
		||||
+ * non-init sections. Only used if we cannot find enough contiguous
 | 
			
		||||
+ * physically mapped memory to put the module into.
 | 
			
		||||
+ */
 | 
			
		||||
+static unsigned int
 | 
			
		||||
+get_plt_size(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
 | 
			
		||||
+             const char *secstrings, unsigned int symindex, bool is_init)
 | 
			
		||||
+{
 | 
			
		||||
+	unsigned long ret = 0;
 | 
			
		||||
+	unsigned int i, j;
 | 
			
		||||
+	Elf_Sym *syms;
 | 
			
		||||
+
 | 
			
		||||
+	/* Everything marked ALLOC (this includes the exported symbols) */
 | 
			
		||||
+	for (i = 1; i < hdr->e_shnum; ++i) {
 | 
			
		||||
+		unsigned int info = sechdrs[i].sh_info;
 | 
			
		||||
+
 | 
			
		||||
+		if (sechdrs[i].sh_type != SHT_REL
 | 
			
		||||
+		    && sechdrs[i].sh_type != SHT_RELA)
 | 
			
		||||
+			continue;
 | 
			
		||||
+
 | 
			
		||||
+		/* Not a valid relocation section? */
 | 
			
		||||
+		if (info >= hdr->e_shnum)
 | 
			
		||||
+			continue;
 | 
			
		||||
+
 | 
			
		||||
+		/* Don't bother with non-allocated sections */
 | 
			
		||||
+		if (!(sechdrs[info].sh_flags & SHF_ALLOC))
 | 
			
		||||
+			continue;
 | 
			
		||||
+
 | 
			
		||||
+		/* If it's called *.init*, and we're not init, we're
 | 
			
		||||
+                   not interested */
 | 
			
		||||
+		if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0)
 | 
			
		||||
+		    != is_init)
 | 
			
		||||
+			continue;
 | 
			
		||||
+
 | 
			
		||||
+		syms = (Elf_Sym *) sechdrs[symindex].sh_addr;
 | 
			
		||||
+		if (sechdrs[i].sh_type == SHT_REL) {
 | 
			
		||||
+			Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr;
 | 
			
		||||
+			unsigned int size = sechdrs[i].sh_size / sizeof(*rel);
 | 
			
		||||
+
 | 
			
		||||
+			for (j = 0; j < size; ++j) {
 | 
			
		||||
+				Elf_Sym *sym;
 | 
			
		||||
+
 | 
			
		||||
+				if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26)
 | 
			
		||||
+					continue;
 | 
			
		||||
+
 | 
			
		||||
+				sym = syms + ELF_MIPS_R_SYM(rel[j]);
 | 
			
		||||
+				if (!is_init && sym->st_shndx != SHN_UNDEF)
 | 
			
		||||
+					continue;
 | 
			
		||||
+
 | 
			
		||||
+				ret += 4 * sizeof(int);
 | 
			
		||||
+			}
 | 
			
		||||
+		} else {
 | 
			
		||||
+			Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr;
 | 
			
		||||
+			unsigned int size = sechdrs[i].sh_size / sizeof(*rela);
 | 
			
		||||
+
 | 
			
		||||
+			for (j = 0; j < size; ++j) {
 | 
			
		||||
+				Elf_Sym *sym;
 | 
			
		||||
+
 | 
			
		||||
+				if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26)
 | 
			
		||||
+					continue;
 | 
			
		||||
+
 | 
			
		||||
+				sym = syms + ELF_MIPS_R_SYM(rela[j]);
 | 
			
		||||
+				if (!is_init && sym->st_shndx != SHN_UNDEF)
 | 
			
		||||
+					continue;
 | 
			
		||||
+
 | 
			
		||||
+				ret += 4 * sizeof(int);
 | 
			
		||||
+			}
 | 
			
		||||
+		}
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	return ret;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+#ifndef MODULE_START
 | 
			
		||||
+static void *alloc_phys(unsigned long size)
 | 
			
		||||
+{
 | 
			
		||||
+	unsigned order;
 | 
			
		||||
+	struct page *page;
 | 
			
		||||
+	struct page *p;
 | 
			
		||||
+
 | 
			
		||||
+	size = PAGE_ALIGN(size);
 | 
			
		||||
+	order = get_order(size);
 | 
			
		||||
+
 | 
			
		||||
+	page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN |
 | 
			
		||||
+			__GFP_THISNODE, order);
 | 
			
		||||
+	if (!page)
 | 
			
		||||
+		return NULL;
 | 
			
		||||
+
 | 
			
		||||
+	split_page(page, order);
 | 
			
		||||
+
 | 
			
		||||
+	for (p = page + (size >> PAGE_SHIFT); p < page + (1 << order); ++p)
 | 
			
		||||
+		__free_page(p);
 | 
			
		||||
+
 | 
			
		||||
+	return page_address(page);
 | 
			
		||||
+}
 | 
			
		||||
+#endif
 | 
			
		||||
+
 | 
			
		||||
+static void free_phys(void *ptr, unsigned long size)
 | 
			
		||||
+{
 | 
			
		||||
+	struct page *page;
 | 
			
		||||
+	struct page *end;
 | 
			
		||||
+
 | 
			
		||||
+	page = virt_to_page(ptr);
 | 
			
		||||
+	end = page + (PAGE_ALIGN(size) >> PAGE_SHIFT);
 | 
			
		||||
+
 | 
			
		||||
+	for (; page < end; ++page)
 | 
			
		||||
+		__free_page(page);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+
 | 
			
		||||
 void *module_alloc(unsigned long size)
 | 
			
		||||
 {
 | 
			
		||||
 #ifdef MODULE_START
 | 
			
		||||
@@ -58,21 +169,68 @@ void *module_alloc(unsigned long size)
 | 
			
		||||
 
 | 
			
		||||
 	return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL);
 | 
			
		||||
 #else
 | 
			
		||||
+	void *ptr;
 | 
			
		||||
+
 | 
			
		||||
 	if (size == 0)
 | 
			
		||||
 		return NULL;
 | 
			
		||||
-	return vmalloc(size);
 | 
			
		||||
+
 | 
			
		||||
+	ptr = alloc_phys(size);
 | 
			
		||||
+
 | 
			
		||||
+	/* If we failed to allocate physically contiguous memory,
 | 
			
		||||
+	 * fall back to regular vmalloc. The module loader code will
 | 
			
		||||
+	 * create jump tables to handle long jumps */
 | 
			
		||||
+	if (!ptr)
 | 
			
		||||
+		return vmalloc(size);
 | 
			
		||||
+
 | 
			
		||||
+	return ptr;
 | 
			
		||||
+#endif
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static inline bool is_phys_addr(void *ptr)
 | 
			
		||||
+{
 | 
			
		||||
+#ifdef CONFIG_64BIT
 | 
			
		||||
+	return (KSEGX((unsigned long)ptr) == CKSEG0);
 | 
			
		||||
+#else
 | 
			
		||||
+	return (KSEGX(ptr) == KSEG0);
 | 
			
		||||
 #endif
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 /* Free memory returned from module_alloc */
 | 
			
		||||
 void module_free(struct module *mod, void *module_region)
 | 
			
		||||
 {
 | 
			
		||||
-	vfree(module_region);
 | 
			
		||||
+	if (is_phys_addr(module_region)) {
 | 
			
		||||
+		if (mod->module_init == module_region)
 | 
			
		||||
+			free_phys(module_region, mod->init_size);
 | 
			
		||||
+		else if (mod->module_core == module_region)
 | 
			
		||||
+			free_phys(module_region, mod->core_size);
 | 
			
		||||
+		else
 | 
			
		||||
+			BUG();
 | 
			
		||||
+	} else {
 | 
			
		||||
+		vfree(module_region);
 | 
			
		||||
+	}
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
 | 
			
		||||
 			      char *secstrings, struct module *mod)
 | 
			
		||||
 {
 | 
			
		||||
+	unsigned int symindex = 0;
 | 
			
		||||
+	unsigned int core_size, init_size;
 | 
			
		||||
+	int i;
 | 
			
		||||
+
 | 
			
		||||
+	for (i = 1; i < hdr->e_shnum; i++)
 | 
			
		||||
+		if (sechdrs[i].sh_type == SHT_SYMTAB)
 | 
			
		||||
+			symindex = i;
 | 
			
		||||
+
 | 
			
		||||
+	core_size = get_plt_size(hdr, sechdrs, secstrings, symindex, false);
 | 
			
		||||
+	init_size = get_plt_size(hdr, sechdrs, secstrings, symindex, true);
 | 
			
		||||
+
 | 
			
		||||
+	mod->arch.core_plt_offset = 0;
 | 
			
		||||
+	mod->arch.core_plt_size = core_size;
 | 
			
		||||
+	mod->arch.init_plt_offset = core_size;
 | 
			
		||||
+	mod->arch.plt_tbl = kmalloc(core_size + init_size, GFP_KERNEL);
 | 
			
		||||
+	if (!mod->arch.plt_tbl)
 | 
			
		||||
+		return -ENOMEM;
 | 
			
		||||
+
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -95,28 +253,40 @@ static int apply_r_mips_32_rela(struct m
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v)
 | 
			
		||||
+static Elf_Addr add_plt_entry_to(unsigned *plt_offset,
 | 
			
		||||
+				 void *start, Elf_Addr v)
 | 
			
		||||
 {
 | 
			
		||||
-	if (v % 4) {
 | 
			
		||||
-		pr_err("module %s: dangerous R_MIPS_26 REL relocation\n",
 | 
			
		||||
-		       me->name);
 | 
			
		||||
-		return -ENOEXEC;
 | 
			
		||||
-	}
 | 
			
		||||
+	unsigned *tramp = start + *plt_offset;
 | 
			
		||||
+	*plt_offset += 4 * sizeof(int);
 | 
			
		||||
 
 | 
			
		||||
-	if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
 | 
			
		||||
-		printk(KERN_ERR
 | 
			
		||||
-		       "module %s: relocation overflow\n",
 | 
			
		||||
-		       me->name);
 | 
			
		||||
-		return -ENOEXEC;
 | 
			
		||||
-	}
 | 
			
		||||
+	/* adjust carry for addiu */
 | 
			
		||||
+	if (v & 0x00008000)
 | 
			
		||||
+		v += 0x10000;
 | 
			
		||||
+
 | 
			
		||||
+	tramp[0] = 0x3c190000 | (v >> 16);      /* lui t9, hi16 */
 | 
			
		||||
+	tramp[1] = 0x27390000 | (v & 0xffff);   /* addiu t9, t9, lo16 */
 | 
			
		||||
+	tramp[2] = 0x03200008;                  /* jr t9 */
 | 
			
		||||
+	tramp[3] = 0x00000000;                  /* nop */
 | 
			
		||||
 
 | 
			
		||||
-	*location = (*location & ~0x03ffffff) |
 | 
			
		||||
-	            ((*location + (v >> 2)) & 0x03ffffff);
 | 
			
		||||
+	return (Elf_Addr) tramp;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v)
 | 
			
		||||
+{
 | 
			
		||||
+	if (location >= me->module_core &&
 | 
			
		||||
+	    location < me->module_core + me->core_size)
 | 
			
		||||
+		return add_plt_entry_to(&me->arch.core_plt_offset,
 | 
			
		||||
+				me->arch.plt_tbl, v);
 | 
			
		||||
+
 | 
			
		||||
+	if (location >= me->module_init &&
 | 
			
		||||
+	    location < me->module_init + me->init_size)
 | 
			
		||||
+		return add_plt_entry_to(&me->arch.init_plt_offset,
 | 
			
		||||
+				me->arch.plt_tbl, v);
 | 
			
		||||
 
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
-static int apply_r_mips_26_rela(struct module *me, u32 *location, Elf_Addr v)
 | 
			
		||||
+static int set_r_mips_26(struct module *me, u32 *location, u32 ofs, Elf_Addr v)
 | 
			
		||||
 {
 | 
			
		||||
 	if (v % 4) {
 | 
			
		||||
 		pr_err("module %s: dangerous R_MIPS_26 RELArelocation\n",
 | 
			
		||||
@@ -125,17 +295,31 @@ static int apply_r_mips_26_rela(struct m
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
 | 
			
		||||
-		printk(KERN_ERR
 | 
			
		||||
+	    v = add_plt_entry(me, location, v + (ofs << 2));
 | 
			
		||||
+		if (!v) {
 | 
			
		||||
+			printk(KERN_ERR
 | 
			
		||||
 		       "module %s: relocation overflow\n",
 | 
			
		||||
 		       me->name);
 | 
			
		||||
-		return -ENOEXEC;
 | 
			
		||||
+			return -ENOEXEC;
 | 
			
		||||
+		}
 | 
			
		||||
+		ofs = 0;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
-	*location = (*location & ~0x03ffffff) | ((v >> 2) & 0x03ffffff);
 | 
			
		||||
+	*location = (*location & ~0x03ffffff) | ((ofs + (v >> 2)) & 0x03ffffff);
 | 
			
		||||
 
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v)
 | 
			
		||||
+{
 | 
			
		||||
+	return set_r_mips_26(me, location, *location & 0x03ffffff, v);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int apply_r_mips_26_rela(struct module *me, u32 *location, Elf_Addr v)
 | 
			
		||||
+{
 | 
			
		||||
+	return set_r_mips_26(me, location, 0, v);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 static int apply_r_mips_hi16_rel(struct module *me, u32 *location, Elf_Addr v)
 | 
			
		||||
 {
 | 
			
		||||
 	struct mips_hi16 *n;
 | 
			
		||||
@@ -400,11 +584,23 @@ int module_finalize(const Elf_Ehdr *hdr,
 | 
			
		||||
 		list_add(&me->arch.dbe_list, &dbe_list);
 | 
			
		||||
 		spin_unlock_irq(&dbe_lock);
 | 
			
		||||
 	}
 | 
			
		||||
+
 | 
			
		||||
+	/* Get rid of the fixup trampoline if we're running the module
 | 
			
		||||
+	 * from physically mapped address space */
 | 
			
		||||
+	if (me->arch.core_plt_offset == 0 &&
 | 
			
		||||
+	    me->arch.init_plt_offset == me->arch.core_plt_size &&
 | 
			
		||||
+	    is_phys_addr(me->module_core)) {
 | 
			
		||||
+		kfree(me->arch.plt_tbl);
 | 
			
		||||
+		me->arch.plt_tbl = NULL;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 void module_arch_cleanup(struct module *mod)
 | 
			
		||||
 {
 | 
			
		||||
+	if (mod->arch.plt_tbl)
 | 
			
		||||
+		kfree(mod->arch.plt_tbl);
 | 
			
		||||
 	spin_lock_irq(&dbe_lock);
 | 
			
		||||
 	list_del(&mod->arch.dbe_list);
 | 
			
		||||
 	spin_unlock_irq(&dbe_lock);
 | 
			
		||||
							
								
								
									
										115
									
								
								target/linux/generic-2.6/patches-2.6.32/028-module_exports.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								target/linux/generic-2.6/patches-2.6.32/028-module_exports.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,115 @@
 | 
			
		||||
--- a/include/asm-generic/vmlinux.lds.h
 | 
			
		||||
+++ b/include/asm-generic/vmlinux.lds.h
 | 
			
		||||
@@ -52,6 +52,27 @@
 | 
			
		||||
 #define LOAD_OFFSET 0
 | 
			
		||||
 #endif
 | 
			
		||||
 
 | 
			
		||||
+#ifndef SYMTAB_KEEP_STR
 | 
			
		||||
+#define SYMTAB_KEEP_STR *(__ksymtab_strings.*)
 | 
			
		||||
+#define SYMTAB_DISCARD_STR
 | 
			
		||||
+#else
 | 
			
		||||
+#define SYMTAB_DISCARD_STR *(__ksymtab_strings.*)
 | 
			
		||||
+#endif
 | 
			
		||||
+
 | 
			
		||||
+#ifndef SYMTAB_KEEP
 | 
			
		||||
+#define SYMTAB_KEEP *(__ksymtab.*)
 | 
			
		||||
+#define SYMTAB_DISCARD
 | 
			
		||||
+#else
 | 
			
		||||
+#define SYMTAB_DISCARD *(__ksymtab.*)
 | 
			
		||||
+#endif
 | 
			
		||||
+
 | 
			
		||||
+#ifndef SYMTAB_KEEP_GPL
 | 
			
		||||
+#define SYMTAB_KEEP_GPL *(__ksymtab_gpl.*)
 | 
			
		||||
+#define SYMTAB_DISCARD_GPL
 | 
			
		||||
+#else
 | 
			
		||||
+#define SYMTAB_DISCARD_GPL *(__ksymtab_gpl.*)
 | 
			
		||||
+#endif
 | 
			
		||||
+
 | 
			
		||||
 #ifndef VMLINUX_SYMBOL
 | 
			
		||||
 #define VMLINUX_SYMBOL(_sym_) _sym_
 | 
			
		||||
 #endif
 | 
			
		||||
@@ -254,35 +275,35 @@
 | 
			
		||||
 	/* Kernel symbol table: Normal symbols */			\
 | 
			
		||||
 	__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\
 | 
			
		||||
 		VMLINUX_SYMBOL(__start___ksymtab) = .;			\
 | 
			
		||||
-		*(__ksymtab)						\
 | 
			
		||||
+		SYMTAB_KEEP						\
 | 
			
		||||
 		VMLINUX_SYMBOL(__stop___ksymtab) = .;			\
 | 
			
		||||
 	}								\
 | 
			
		||||
 									\
 | 
			
		||||
 	/* Kernel symbol table: GPL-only symbols */			\
 | 
			
		||||
 	__ksymtab_gpl     : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) {	\
 | 
			
		||||
 		VMLINUX_SYMBOL(__start___ksymtab_gpl) = .;		\
 | 
			
		||||
-		*(__ksymtab_gpl)					\
 | 
			
		||||
+		SYMTAB_KEEP_GPL						\
 | 
			
		||||
 		VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .;		\
 | 
			
		||||
 	}								\
 | 
			
		||||
 									\
 | 
			
		||||
 	/* Kernel symbol table: Normal unused symbols */		\
 | 
			
		||||
 	__ksymtab_unused  : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) {	\
 | 
			
		||||
 		VMLINUX_SYMBOL(__start___ksymtab_unused) = .;		\
 | 
			
		||||
-		*(__ksymtab_unused)					\
 | 
			
		||||
+		*(__ksymtab_unused.*)					\
 | 
			
		||||
 		VMLINUX_SYMBOL(__stop___ksymtab_unused) = .;		\
 | 
			
		||||
 	}								\
 | 
			
		||||
 									\
 | 
			
		||||
 	/* Kernel symbol table: GPL-only unused symbols */		\
 | 
			
		||||
 	__ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \
 | 
			
		||||
 		VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .;	\
 | 
			
		||||
-		*(__ksymtab_unused_gpl)					\
 | 
			
		||||
+		*(__ksymtab_unused_gpl.*)				\
 | 
			
		||||
 		VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .;	\
 | 
			
		||||
 	}								\
 | 
			
		||||
 									\
 | 
			
		||||
 	/* Kernel symbol table: GPL-future-only symbols */		\
 | 
			
		||||
 	__ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
 | 
			
		||||
 		VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .;	\
 | 
			
		||||
-		*(__ksymtab_gpl_future)					\
 | 
			
		||||
+		*(__ksymtab_gpl_future.*)				\
 | 
			
		||||
 		VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .;	\
 | 
			
		||||
 	}								\
 | 
			
		||||
 									\
 | 
			
		||||
@@ -323,7 +344,13 @@
 | 
			
		||||
 									\
 | 
			
		||||
 	/* Kernel symbol table: strings */				\
 | 
			
		||||
         __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {	\
 | 
			
		||||
-		*(__ksymtab_strings)					\
 | 
			
		||||
+		SYMTAB_KEEP_STR						\
 | 
			
		||||
+	}								\
 | 
			
		||||
+									\
 | 
			
		||||
+	/DISCARD/ : {							\
 | 
			
		||||
+		SYMTAB_DISCARD						\
 | 
			
		||||
+		SYMTAB_DISCARD_GPL					\
 | 
			
		||||
+		SYMTAB_DISCARD_STR					\
 | 
			
		||||
 	}								\
 | 
			
		||||
 									\
 | 
			
		||||
 	/* __*init sections */						\
 | 
			
		||||
--- a/include/linux/module.h
 | 
			
		||||
+++ b/include/linux/module.h
 | 
			
		||||
@@ -192,16 +192,24 @@ void *__symbol_get_gpl(const char *symbo
 | 
			
		||||
 #define __CRC_SYMBOL(sym, sec)
 | 
			
		||||
 #endif
 | 
			
		||||
 
 | 
			
		||||
+#ifdef MODULE
 | 
			
		||||
+#define __EXPORT_SUFFIX(sym)
 | 
			
		||||
+#else
 | 
			
		||||
+#define __EXPORT_SUFFIX(sym) "." #sym
 | 
			
		||||
+#endif
 | 
			
		||||
+
 | 
			
		||||
 /* For every exported symbol, place a struct in the __ksymtab section */
 | 
			
		||||
 #define __EXPORT_SYMBOL(sym, sec)				\
 | 
			
		||||
 	extern typeof(sym) sym;					\
 | 
			
		||||
 	__CRC_SYMBOL(sym, sec)					\
 | 
			
		||||
 	static const char __kstrtab_##sym[]			\
 | 
			
		||||
-	__attribute__((section("__ksymtab_strings"), aligned(1))) \
 | 
			
		||||
+	__attribute__((section("__ksymtab_strings"		\
 | 
			
		||||
+	  __EXPORT_SUFFIX(sym)), aligned(1)))			\
 | 
			
		||||
 	= MODULE_SYMBOL_PREFIX #sym;                    	\
 | 
			
		||||
 	static const struct kernel_symbol __ksymtab_##sym	\
 | 
			
		||||
 	__used							\
 | 
			
		||||
-	__attribute__((section("__ksymtab" sec), unused))	\
 | 
			
		||||
+	__attribute__((section("__ksymtab" sec			\
 | 
			
		||||
+	  __EXPORT_SUFFIX(sym)), unused))			\
 | 
			
		||||
 	= { (unsigned long)&sym, __kstrtab_##sym }
 | 
			
		||||
 
 | 
			
		||||
 #define EXPORT_SYMBOL(sym)					\
 | 
			
		||||
@ -0,0 +1,13 @@
 | 
			
		||||
--- a/arch/arm/kernel/module.c
 | 
			
		||||
+++ b/arch/arm/kernel/module.c
 | 
			
		||||
@@ -121,6 +121,10 @@ apply_relocate(Elf32_Shdr *sechdrs, cons
 | 
			
		||||
 			return -ENOEXEC;
 | 
			
		||||
 		}
 | 
			
		||||
 
 | 
			
		||||
+		if ((IS_ERR_VALUE(sym->st_value) || !sym->st_value) &&
 | 
			
		||||
+		    ELF_ST_BIND(sym->st_info) == STB_WEAK)
 | 
			
		||||
+			continue;
 | 
			
		||||
+
 | 
			
		||||
 		loc = dstsec->sh_addr + rel->r_offset;
 | 
			
		||||
 
 | 
			
		||||
 		switch (ELF32_R_TYPE(rel->r_info)) {
 | 
			
		||||
@ -0,0 +1,43 @@
 | 
			
		||||
--- a/drivers/pci/Kconfig
 | 
			
		||||
+++ b/drivers/pci/Kconfig
 | 
			
		||||
@@ -51,6 +51,12 @@ config PCI_STUB
 | 
			
		||||
 
 | 
			
		||||
 	  When in doubt, say N.
 | 
			
		||||
 
 | 
			
		||||
+config PCI_DISABLE_COMMON_QUIRKS
 | 
			
		||||
+	bool "PCI disable common quirks"
 | 
			
		||||
+	depends on PCI
 | 
			
		||||
+	help
 | 
			
		||||
+	  If you don't know what to do here, say N.
 | 
			
		||||
+
 | 
			
		||||
 config HT_IRQ
 | 
			
		||||
 	bool "Interrupts on hypertransport devices"
 | 
			
		||||
 	default y
 | 
			
		||||
--- a/drivers/pci/quirks.c
 | 
			
		||||
+++ b/drivers/pci/quirks.c
 | 
			
		||||
@@ -96,6 +96,7 @@ static void __devinit quirk_resource_ali
 | 
			
		||||
 }
 | 
			
		||||
 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_resource_alignment);
 | 
			
		||||
 
 | 
			
		||||
+#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
 | 
			
		||||
 /* The Mellanox Tavor device gives false positive parity errors
 | 
			
		||||
  * Mark this device with a broken_parity_status, to allow
 | 
			
		||||
  * PCI scanning code to "skip" this now blacklisted device.
 | 
			
		||||
@@ -1884,7 +1885,9 @@ static void __devinit fixup_rev1_53c810(
 | 
			
		||||
 	}
 | 
			
		||||
 }
 | 
			
		||||
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1_53c810);
 | 
			
		||||
+#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */
 | 
			
		||||
 
 | 
			
		||||
+#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
 | 
			
		||||
 /* Enable 1k I/O space granularity on the Intel P64H2 */
 | 
			
		||||
 static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev)
 | 
			
		||||
 {
 | 
			
		||||
@@ -2515,6 +2518,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I
 | 
			
		||||
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x150d, quirk_i82576_sriov);
 | 
			
		||||
 
 | 
			
		||||
 #endif	/* CONFIG_PCI_IOV */
 | 
			
		||||
+#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */
 | 
			
		||||
 
 | 
			
		||||
 static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
 | 
			
		||||
 			  struct pci_fixup *end)
 | 
			
		||||
@ -0,0 +1,226 @@
 | 
			
		||||
GCC 4.4.x looks to be adding support for generating out-of-line register
 | 
			
		||||
saves/restores based on:
 | 
			
		||||
 | 
			
		||||
http://gcc.gnu.org/ml/gcc-patches/2008-04/msg01678.html
 | 
			
		||||
 | 
			
		||||
This breaks the kernel build as we'd have to link with libgcc to get the
 | 
			
		||||
implementation of the register save/restores.
 | 
			
		||||
 | 
			
		||||
To workaround this issue, we just stole the save/restore code from gcc
 | 
			
		||||
and simplified it down for our needs (integer only).  We only do this if
 | 
			
		||||
PPC32 as gcc makes believe the linker on ppc64 will deal with this and
 | 
			
		||||
only if CONFIG_CC_OPTIMIZE_FOR_SIZE is set (thus -Os).
 | 
			
		||||
 | 
			
		||||
Signed-off-by: Kumar Gala <[EMAIL PROTECTED]>
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
If someone using cutting edge toolchains for ppc64 could test and make
 | 
			
		||||
sure if we enable CONFIG_CC_OPTIMIZE_FOR_SIZE things work that would be
 | 
			
		||||
nice.
 | 
			
		||||
 | 
			
		||||
- k
 | 
			
		||||
 | 
			
		||||
 arch/powerpc/kernel/misc_32.S   |   77 +++++++++++++++++++++++++++
 | 
			
		||||
 arch/powerpc/kernel/ppc_ksyms.c |  111 +++++++++++++++++++++++++++++++++++++++
 | 
			
		||||
 2 files changed, 188 insertions(+), 0 deletions(-)
 | 
			
		||||
 | 
			
		||||
--- a/arch/powerpc/kernel/misc_32.S
 | 
			
		||||
+++ b/arch/powerpc/kernel/misc_32.S
 | 
			
		||||
@@ -820,3 +820,80 @@ relocate_new_kernel_end:
 | 
			
		||||
 relocate_new_kernel_size:
 | 
			
		||||
 	.long relocate_new_kernel_end - relocate_new_kernel
 | 
			
		||||
 #endif
 | 
			
		||||
+
 | 
			
		||||
+#if defined(CONFIG_PPC32) && defined(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)   stw     14,-72(11)      /* save gp registers */
 | 
			
		||||
+_GLOBAL(_savegpr_15)   stw     15,-68(11)
 | 
			
		||||
+_GLOBAL(_savegpr_16)   stw     16,-64(11)
 | 
			
		||||
+_GLOBAL(_savegpr_17)   stw     17,-60(11)
 | 
			
		||||
+_GLOBAL(_savegpr_18)   stw     18,-56(11)
 | 
			
		||||
+_GLOBAL(_savegpr_19)   stw     19,-52(11)
 | 
			
		||||
+_GLOBAL(_savegpr_20)   stw     20,-48(11)
 | 
			
		||||
+_GLOBAL(_savegpr_21)   stw     21,-44(11)
 | 
			
		||||
+_GLOBAL(_savegpr_22)   stw     22,-40(11)
 | 
			
		||||
+_GLOBAL(_savegpr_23)   stw     23,-36(11)
 | 
			
		||||
+_GLOBAL(_savegpr_24)   stw     24,-32(11)
 | 
			
		||||
+_GLOBAL(_savegpr_25)   stw     25,-28(11)
 | 
			
		||||
+_GLOBAL(_savegpr_26)   stw     26,-24(11)
 | 
			
		||||
+_GLOBAL(_savegpr_27)   stw     27,-20(11)
 | 
			
		||||
+_GLOBAL(_savegpr_28)   stw     28,-16(11)
 | 
			
		||||
+_GLOBAL(_savegpr_29)   stw     29,-12(11)
 | 
			
		||||
+_GLOBAL(_savegpr_30)   stw     30,-8(11)
 | 
			
		||||
+_GLOBAL(_savegpr_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)   lwz     14,-72(11)      /* restore gp registers */
 | 
			
		||||
+_GLOBAL(_restgpr_15)   lwz     15,-68(11)
 | 
			
		||||
+_GLOBAL(_restgpr_16)   lwz     16,-64(11)
 | 
			
		||||
+_GLOBAL(_restgpr_17)   lwz     17,-60(11)
 | 
			
		||||
+_GLOBAL(_restgpr_18)   lwz     18,-56(11)
 | 
			
		||||
+_GLOBAL(_restgpr_19)   lwz     19,-52(11)
 | 
			
		||||
+_GLOBAL(_restgpr_20)   lwz     20,-48(11)
 | 
			
		||||
+_GLOBAL(_restgpr_21)   lwz     21,-44(11)
 | 
			
		||||
+_GLOBAL(_restgpr_22)   lwz     22,-40(11)
 | 
			
		||||
+_GLOBAL(_restgpr_23)   lwz     23,-36(11)
 | 
			
		||||
+_GLOBAL(_restgpr_24)   lwz     24,-32(11)
 | 
			
		||||
+_GLOBAL(_restgpr_25)   lwz     25,-28(11)
 | 
			
		||||
+_GLOBAL(_restgpr_26)   lwz     26,-24(11)
 | 
			
		||||
+_GLOBAL(_restgpr_27)   lwz     27,-20(11)
 | 
			
		||||
+_GLOBAL(_restgpr_28)   lwz     28,-16(11)
 | 
			
		||||
+_GLOBAL(_restgpr_29)   lwz     29,-12(11)
 | 
			
		||||
+_GLOBAL(_restgpr_30)   lwz     30,-8(11)
 | 
			
		||||
+_GLOBAL(_restgpr_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) lwz     14,-72(11)      /* restore gp registers */
 | 
			
		||||
+_GLOBAL(_restgpr_15_x) lwz     15,-68(11)
 | 
			
		||||
+_GLOBAL(_restgpr_16_x) lwz     16,-64(11)
 | 
			
		||||
+_GLOBAL(_restgpr_17_x) lwz     17,-60(11)
 | 
			
		||||
+_GLOBAL(_restgpr_18_x) lwz     18,-56(11)
 | 
			
		||||
+_GLOBAL(_restgpr_19_x) lwz     19,-52(11)
 | 
			
		||||
+_GLOBAL(_restgpr_20_x) lwz     20,-48(11)
 | 
			
		||||
+_GLOBAL(_restgpr_21_x) lwz     21,-44(11)
 | 
			
		||||
+_GLOBAL(_restgpr_22_x) lwz     22,-40(11)
 | 
			
		||||
+_GLOBAL(_restgpr_23_x) lwz     23,-36(11)
 | 
			
		||||
+_GLOBAL(_restgpr_24_x) lwz     24,-32(11)
 | 
			
		||||
+_GLOBAL(_restgpr_25_x) lwz     25,-28(11)
 | 
			
		||||
+_GLOBAL(_restgpr_26_x) lwz     26,-24(11)
 | 
			
		||||
+_GLOBAL(_restgpr_27_x) lwz     27,-20(11)
 | 
			
		||||
+_GLOBAL(_restgpr_28_x) lwz     28,-16(11)
 | 
			
		||||
+_GLOBAL(_restgpr_29_x) lwz     29,-12(11)
 | 
			
		||||
+_GLOBAL(_restgpr_30_x) lwz     30,-8(11)
 | 
			
		||||
+_GLOBAL(_restgpr_31_x) lwz     0,4(11)
 | 
			
		||||
+                       lwz     31,-4(11)
 | 
			
		||||
+                       mtlr    0
 | 
			
		||||
+                       mr      1,11
 | 
			
		||||
+                       blr
 | 
			
		||||
+#endif
 | 
			
		||||
--- a/arch/powerpc/kernel/ppc_ksyms.c
 | 
			
		||||
+++ b/arch/powerpc/kernel/ppc_ksyms.c
 | 
			
		||||
@@ -188,3 +188,114 @@ EXPORT_SYMBOL(__mtdcr);
 | 
			
		||||
 EXPORT_SYMBOL(__mfdcr);
 | 
			
		||||
 #endif
 | 
			
		||||
 EXPORT_SYMBOL(empty_zero_page);
 | 
			
		||||
+
 | 
			
		||||
+#if defined(CONFIG_PPC32) && defined(CONFIG_CC_OPTIMIZE_FOR_SIZE)
 | 
			
		||||
+void _savegpr_14(void);
 | 
			
		||||
+void _savegpr_15(void);
 | 
			
		||||
+void _savegpr_16(void);
 | 
			
		||||
+void _savegpr_17(void);
 | 
			
		||||
+void _savegpr_18(void);
 | 
			
		||||
+void _savegpr_19(void);
 | 
			
		||||
+void _savegpr_20(void);
 | 
			
		||||
+void _savegpr_21(void);
 | 
			
		||||
+void _savegpr_22(void);
 | 
			
		||||
+void _savegpr_23(void);
 | 
			
		||||
+void _savegpr_24(void);
 | 
			
		||||
+void _savegpr_25(void);
 | 
			
		||||
+void _savegpr_26(void);
 | 
			
		||||
+void _savegpr_27(void);
 | 
			
		||||
+void _savegpr_28(void);
 | 
			
		||||
+void _savegpr_29(void);
 | 
			
		||||
+void _savegpr_30(void);
 | 
			
		||||
+void _savegpr_31(void);
 | 
			
		||||
+void _restgpr_14(void);
 | 
			
		||||
+void _restgpr_15(void);
 | 
			
		||||
+void _restgpr_16(void);
 | 
			
		||||
+void _restgpr_17(void);
 | 
			
		||||
+void _restgpr_18(void);
 | 
			
		||||
+void _restgpr_19(void);
 | 
			
		||||
+void _restgpr_20(void);
 | 
			
		||||
+void _restgpr_21(void);
 | 
			
		||||
+void _restgpr_22(void);
 | 
			
		||||
+void _restgpr_23(void);
 | 
			
		||||
+void _restgpr_24(void);
 | 
			
		||||
+void _restgpr_25(void);
 | 
			
		||||
+void _restgpr_26(void);
 | 
			
		||||
+void _restgpr_27(void);
 | 
			
		||||
+void _restgpr_28(void);
 | 
			
		||||
+void _restgpr_29(void);
 | 
			
		||||
+void _restgpr_30(void);
 | 
			
		||||
+void _restgpr_31(void);
 | 
			
		||||
+void _restgpr_14_x(void);
 | 
			
		||||
+void _restgpr_15_x(void);
 | 
			
		||||
+void _restgpr_16_x(void);
 | 
			
		||||
+void _restgpr_17_x(void);
 | 
			
		||||
+void _restgpr_18_x(void);
 | 
			
		||||
+void _restgpr_19_x(void);
 | 
			
		||||
+void _restgpr_20_x(void);
 | 
			
		||||
+void _restgpr_21_x(void);
 | 
			
		||||
+void _restgpr_22_x(void);
 | 
			
		||||
+void _restgpr_23_x(void);
 | 
			
		||||
+void _restgpr_24_x(void);
 | 
			
		||||
+void _restgpr_25_x(void);
 | 
			
		||||
+void _restgpr_26_x(void);
 | 
			
		||||
+void _restgpr_27_x(void);
 | 
			
		||||
+void _restgpr_28_x(void);
 | 
			
		||||
+void _restgpr_29_x(void);
 | 
			
		||||
+void _restgpr_30_x(void);
 | 
			
		||||
+void _restgpr_31_x(void);
 | 
			
		||||
+EXPORT_SYMBOL(_savegpr_14);
 | 
			
		||||
+EXPORT_SYMBOL(_savegpr_15);
 | 
			
		||||
+EXPORT_SYMBOL(_savegpr_16);
 | 
			
		||||
+EXPORT_SYMBOL(_savegpr_17);
 | 
			
		||||
+EXPORT_SYMBOL(_savegpr_18);
 | 
			
		||||
+EXPORT_SYMBOL(_savegpr_19);
 | 
			
		||||
+EXPORT_SYMBOL(_savegpr_20);
 | 
			
		||||
+EXPORT_SYMBOL(_savegpr_21);
 | 
			
		||||
+EXPORT_SYMBOL(_savegpr_22);
 | 
			
		||||
+EXPORT_SYMBOL(_savegpr_23);
 | 
			
		||||
+EXPORT_SYMBOL(_savegpr_24);
 | 
			
		||||
+EXPORT_SYMBOL(_savegpr_25);
 | 
			
		||||
+EXPORT_SYMBOL(_savegpr_26);
 | 
			
		||||
+EXPORT_SYMBOL(_savegpr_27);
 | 
			
		||||
+EXPORT_SYMBOL(_savegpr_28);
 | 
			
		||||
+EXPORT_SYMBOL(_savegpr_29);
 | 
			
		||||
+EXPORT_SYMBOL(_savegpr_30);
 | 
			
		||||
+EXPORT_SYMBOL(_savegpr_31);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_14);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_15);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_16);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_17);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_18);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_19);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_20);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_21);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_22);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_23);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_24);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_25);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_26);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_27);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_28);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_29);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_30);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_31);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_14_x);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_15_x);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_16_x);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_17_x);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_18_x);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_19_x);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_20_x);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_21_x);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_22_x);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_23_x);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_24_x);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_25_x);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_26_x);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_27_x);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_28_x);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_29_x);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_30_x);
 | 
			
		||||
+EXPORT_SYMBOL(_restgpr_31_x);
 | 
			
		||||
+#endif /* CONFIG_PPC32 && CONFIG_CC_OPTIMIZE_FOR_SIZE */
 | 
			
		||||
							
								
								
									
										110
									
								
								target/linux/generic-2.6/patches-2.6.32/060-block2mtd_init.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								target/linux/generic-2.6/patches-2.6.32/060-block2mtd_init.patch
									
									
									
									
									
										Normal 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)
 | 
			
		||||
 {
 | 
			
		||||
							
								
								
									
										624
									
								
								target/linux/generic-2.6/patches-2.6.32/065-rootfs_split.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										624
									
								
								target/linux/generic-2.6/patches-2.6.32/065-rootfs_split.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,624 @@
 | 
			
		||||
--- a/drivers/mtd/Kconfig
 | 
			
		||||
+++ b/drivers/mtd/Kconfig
 | 
			
		||||
@@ -53,6 +53,16 @@ config MTD_PARTITIONS
 | 
			
		||||
 	  devices. Partitioning on NFTL 'devices' is a different - that's the
 | 
			
		||||
 	  'normal' form of partitioning used on a block device.
 | 
			
		||||
 
 | 
			
		||||
+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);
 | 
			
		||||
@@ -35,7 +37,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
 | 
			
		||||
@@ -503,6 +505,150 @@ 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)
 | 
			
		||||
+{
 | 
			
		||||
+	struct squashfs_super_block sb;
 | 
			
		||||
+	int len, ret;
 | 
			
		||||
+
 | 
			
		||||
+	ret = master->read(master, offset, sizeof(sb), &len, (void *) &sb);
 | 
			
		||||
+	if (ret || (len != sizeof(sb))) {
 | 
			
		||||
+		printk(KERN_ALERT "split_squashfs: error occured while reading "
 | 
			
		||||
+			"from \"%s\"\n", master->name);
 | 
			
		||||
+		return -EINVAL;
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	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 (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) le64_to_cpu(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)
 | 
			
		||||
+{
 | 
			
		||||
+	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, 0, 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;
 | 
			
		||||
+
 | 
			
		||||
+		return split_rootfs_data(part->master, &part->mtd, &tpart);
 | 
			
		||||
+	} 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
 | 
			
		||||
@@ -518,7 +664,7 @@ int add_mtd_partitions(struct mtd_info *
 | 
			
		||||
 {
 | 
			
		||||
 	struct mtd_part *slave;
 | 
			
		||||
 	uint64_t cur_offset = 0;
 | 
			
		||||
-	int i;
 | 
			
		||||
+	int i, ret;
 | 
			
		||||
 
 | 
			
		||||
 	printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
 | 
			
		||||
 
 | 
			
		||||
@@ -526,6 +672,21 @@ int add_mtd_partitions(struct mtd_info *
 | 
			
		||||
 		slave = add_one_partition(master, parts + i, i, cur_offset);
 | 
			
		||||
 		if (!slave)
 | 
			
		||||
 			return -ENOMEM;
 | 
			
		||||
+
 | 
			
		||||
+		if (!strcmp(parts[i].name, "rootfs")) {
 | 
			
		||||
+#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]);
 | 
			
		||||
+			/* if (ret == 0)
 | 
			
		||||
+				j++; */
 | 
			
		||||
+#endif
 | 
			
		||||
+		}
 | 
			
		||||
 		cur_offset = slave->offset + slave->mtd.size;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
@@ -533,6 +694,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
 | 
			
		||||
@@ -18,6 +18,7 @@
 | 
			
		||||
 
 | 
			
		||||
 #include <linux/mtd/mtd.h>
 | 
			
		||||
 #include <linux/mtd/compatmac.h>
 | 
			
		||||
+#include <linux/mtd/partitions.h>
 | 
			
		||||
 
 | 
			
		||||
 #include <asm/uaccess.h>
 | 
			
		||||
 
 | 
			
		||||
@@ -814,6 +815,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
 | 
			
		||||
@@ -101,6 +101,7 @@ struct mtd_oob_ops {
 | 
			
		||||
 	uint8_t		*oobbuf;
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
+struct mtd_info;
 | 
			
		||||
 struct mtd_info {
 | 
			
		||||
 	u_char type;
 | 
			
		||||
 	uint32_t flags;
 | 
			
		||||
@@ -241,6 +242,9 @@ struct mtd_info {
 | 
			
		||||
 	struct device dev;
 | 
			
		||||
 	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,12 +34,14 @@
 | 
			
		||||
  * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK).
 | 
			
		||||
  */
 | 
			
		||||
 
 | 
			
		||||
+struct mtd_partition;
 | 
			
		||||
 struct mtd_partition {
 | 
			
		||||
 	char *name;			/* identifier string */
 | 
			
		||||
 	uint64_t size;			/* partition size */
 | 
			
		||||
 	uint64_t offset;		/* offset within the master MTD space */
 | 
			
		||||
 	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)*/
 | 
			
		||||
+	int (*refresh_partition)(struct mtd_info *);
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 #define MTDPART_OFS_NXTBLK	(-2)
 | 
			
		||||
@@ -51,6 +53,7 @@ struct mtd_info;
 | 
			
		||||
 
 | 
			
		||||
 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
 | 
			
		||||
@@ -110,6 +110,7 @@ struct otp_info {
 | 
			
		||||
 #define MEMERASE64		_IOW('M', 20, struct erase_info_user64)
 | 
			
		||||
 #define MEMWRITEOOB64		_IOWR('M', 21, struct mtd_oob_buf64)
 | 
			
		||||
 #define MEMREADOOB64		_IOWR('M', 22, struct mtd_oob_buf64)
 | 
			
		||||
+#define MTDREFRESH		_IO('M', 23)
 | 
			
		||||
 
 | 
			
		||||
 /*
 | 
			
		||||
  * Obsolete legacy interface. Keep it in order not to break userspace
 | 
			
		||||
@ -0,0 +1,10 @@
 | 
			
		||||
--- a/drivers/mtd/devices/block2mtd.c
 | 
			
		||||
+++ b/drivers/mtd/devices/block2mtd.c
 | 
			
		||||
@@ -268,6 +268,7 @@ static int _open_bdev(struct block2mtd_d
 | 
			
		||||
 		/* We might not have rootfs mounted at this point. Try
 | 
			
		||||
 		   to resolve the device name by other means. */
 | 
			
		||||
 
 | 
			
		||||
+		wait_for_device_probe();
 | 
			
		||||
 		dev_t devt = name_to_dev_t(dev->devname);
 | 
			
		||||
 		if (devt) {
 | 
			
		||||
 			bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ);
 | 
			
		||||
@ -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);
 | 
			
		||||
@ -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:
 | 
			
		||||
@ -0,0 +1,32 @@
 | 
			
		||||
--- a/include/linux/mtd/nand.h
 | 
			
		||||
+++ b/include/linux/mtd/nand.h
 | 
			
		||||
@@ -576,6 +576,7 @@ struct platform_nand_chip {
 | 
			
		||||
 	int			chip_delay;
 | 
			
		||||
 	unsigned int		options;
 | 
			
		||||
 	const char		**part_probe_types;
 | 
			
		||||
+	int			(*chip_fixup)(struct mtd_info *mtd);
 | 
			
		||||
 	void			(*set_parts)(uint64_t size,
 | 
			
		||||
 					struct platform_nand_chip *chip);
 | 
			
		||||
 	void			*priv;
 | 
			
		||||
--- a/drivers/mtd/nand/plat_nand.c
 | 
			
		||||
+++ b/drivers/mtd/nand/plat_nand.c
 | 
			
		||||
@@ -80,7 +80,18 @@ static int __devinit plat_nand_probe(str
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	/* 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;
 | 
			
		||||
 	}
 | 
			
		||||
@ -0,0 +1,35 @@
 | 
			
		||||
--- a/drivers/mtd/Kconfig
 | 
			
		||||
+++ b/drivers/mtd/Kconfig
 | 
			
		||||
@@ -181,6 +181,22 @@ config MTD_AR7_PARTS
 | 
			
		||||
 	---help---
 | 
			
		||||
 	  TI AR7 partitioning support
 | 
			
		||||
 
 | 
			
		||||
+config MTD_MYLOADER_PARTS
 | 
			
		||||
+	tristate "MyLoader partition parsing"
 | 
			
		||||
+	depends on MTD_PARTITIONS && (ADM5120 || ATHEROS_AR231X || 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
 | 
			
		||||
@ -0,0 +1,18 @@
 | 
			
		||||
--- a/include/linux/mtd/partitions.h
 | 
			
		||||
+++ b/include/linux/mtd/partitions.h
 | 
			
		||||
@@ -33,6 +33,7 @@
 | 
			
		||||
  * Note: writeable partitions require their size and offset be
 | 
			
		||||
  * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK).
 | 
			
		||||
  */
 | 
			
		||||
+struct mtd_info;
 | 
			
		||||
 
 | 
			
		||||
 struct mtd_partition;
 | 
			
		||||
 struct mtd_partition {
 | 
			
		||||
@@ -49,7 +50,6 @@ struct mtd_partition {
 | 
			
		||||
 #define MTDPART_SIZ_FULL	(0)
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
-struct mtd_info;
 | 
			
		||||
 
 | 
			
		||||
 int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
 | 
			
		||||
 int del_mtd_partitions(struct mtd_info *);
 | 
			
		||||
@ -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(unsigned char *b
 | 
			
		||||
 	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
											
										
									
								
							@ -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){
 | 
			
		||||
@ -0,0 +1,121 @@
 | 
			
		||||
--- 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,
 | 
			
		||||
@@ -138,13 +141,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;
 | 
			
		||||
@@ -154,6 +179,8 @@ ip_checkentry(const struct ipt_ip *ip)
 | 
			
		||||
 			 ip->invflags & ~IPT_INV_MASK);
 | 
			
		||||
 		return false;
 | 
			
		||||
 	}
 | 
			
		||||
+
 | 
			
		||||
+#undef FWINV
 | 
			
		||||
 	return true;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -196,7 +223,6 @@ static inline bool unconditional(const s
 | 
			
		||||
 	static const struct ipt_ip uncond;
 | 
			
		||||
 
 | 
			
		||||
 	return memcmp(ip, &uncond, sizeof(uncond)) == 0;
 | 
			
		||||
-#undef FWINV
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
 | 
			
		||||
@@ -321,8 +347,28 @@ ipt_do_table(struct sk_buff *skb,
 | 
			
		||||
 	struct xt_match_param mtpar;
 | 
			
		||||
 	struct xt_target_param tgpar;
 | 
			
		||||
 
 | 
			
		||||
-	/* Initialization */
 | 
			
		||||
 	ip = ip_hdr(skb);
 | 
			
		||||
+
 | 
			
		||||
+	IP_NF_ASSERT(table->valid_hooks & (1 << hook));
 | 
			
		||||
+	xt_info_rdlock_bh();
 | 
			
		||||
+	private = table->private;
 | 
			
		||||
+	table_base = 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);
 | 
			
		||||
+					xt_info_rdunlock_bh();
 | 
			
		||||
+					return (unsigned)(-v) - 1;
 | 
			
		||||
+				}
 | 
			
		||||
+			}
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	/* Initialization */
 | 
			
		||||
 	indev = in ? in->name : nulldevname;
 | 
			
		||||
 	outdev = out ? out->name : nulldevname;
 | 
			
		||||
 	/* We handle fragments by dealing with the first fragment as
 | 
			
		||||
@@ -339,13 +385,6 @@ ipt_do_table(struct sk_buff *skb,
 | 
			
		||||
 	mtpar.family  = tgpar.family = NFPROTO_IPV4;
 | 
			
		||||
 	mtpar.hooknum = tgpar.hooknum = hook;
 | 
			
		||||
 
 | 
			
		||||
-	IP_NF_ASSERT(table->valid_hooks & (1 << hook));
 | 
			
		||||
-	xt_info_rdlock_bh();
 | 
			
		||||
-	private = table->private;
 | 
			
		||||
-	table_base = 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]);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1260
									
								
								target/linux/generic-2.6/patches-2.6.32/150-netfilter_imq.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1260
									
								
								target/linux/generic-2.6/patches-2.6.32/150-netfilter_imq.patch
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -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
 | 
			
		||||
@@ -505,7 +504,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
 | 
			
		||||
							
								
								
									
										1366
									
								
								target/linux/generic-2.6/patches-2.6.32/190-netfilter_rtsp.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1366
									
								
								target/linux/generic-2.6/patches-2.6.32/190-netfilter_rtsp.patch
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										793
									
								
								target/linux/generic-2.6/patches-2.6.32/200-sched_esfq.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										793
									
								
								target/linux/generic-2.6/patches-2.6.32/200-sched_esfq.patch
									
									
									
									
									
										Normal 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(skb);
 | 
			
		||||
+		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");
 | 
			
		||||
							
								
								
									
										227
									
								
								target/linux/generic-2.6/patches-2.6.32/201-jhash3.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								target/linux/generic-2.6/patches-2.6.32/201-jhash3.patch
									
									
									
									
									
										Normal 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 */
 | 
			
		||||
@ -0,0 +1,12 @@
 | 
			
		||||
--- a/arch/mips/Makefile
 | 
			
		||||
+++ b/arch/mips/Makefile
 | 
			
		||||
@@ -624,6 +624,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/
 | 
			
		||||
 
 | 
			
		||||
@ -0,0 +1,13 @@
 | 
			
		||||
--- a/include/linux/slab.h
 | 
			
		||||
+++ b/include/linux/slab.h
 | 
			
		||||
@@ -124,8 +124,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)
 | 
			
		||||
@ -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;
 | 
			
		||||
@ -0,0 +1,56 @@
 | 
			
		||||
--- a/include/linux/skbuff.h
 | 
			
		||||
+++ b/include/linux/skbuff.h
 | 
			
		||||
@@ -1383,11 +1383,18 @@ static inline int skb_network_offset(con
 | 
			
		||||
  *
 | 
			
		||||
  * Various parts of the networking layer expect at least 32 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	32
 | 
			
		||||
 #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)
 | 
			
		||||
@@ -1477,9 +1484,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;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -1552,7 +1559,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
 | 
			
		||||
@@ -336,9 +336,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;
 | 
			
		||||
@ -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 */
 | 
			
		||||
							
								
								
									
										7780
									
								
								target/linux/generic-2.6/patches-2.6.32/209-mini_fo.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7780
									
								
								target/linux/generic-2.6/patches-2.6.32/209-mini_fo.patch
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -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);
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
@ -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;
 | 
			
		||||
@ -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) */
 | 
			
		||||
@ -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);
 | 
			
		||||
@ -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");
 | 
			
		||||
							
								
								
									
										157
									
								
								target/linux/generic-2.6/patches-2.6.32/215-mini_fo_2.6.30.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								target/linux/generic-2.6/patches-2.6.32/215-mini_fo_2.6.30.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,157 @@
 | 
			
		||||
--- a/fs/mini_fo/aux.c
 | 
			
		||||
+++ b/fs/mini_fo/aux.c
 | 
			
		||||
@@ -86,8 +86,10 @@ int get_neg_sto_dentry(dentry_t *dentry)
 | 
			
		||||
 	len = dentry->d_name.len;
 | 
			
		||||
 	name = dentry->d_name.name;
 | 
			
		||||
 
 | 
			
		||||
+	mutex_lock(&dtohd2(dentry->d_parent)->d_inode->i_mutex);
 | 
			
		||||
 	dtohd2(dentry) =
 | 
			
		||||
 		lookup_one_len(name, dtohd2(dentry->d_parent), len);
 | 
			
		||||
+	mutex_unlock(&dtohd2(dentry->d_parent)->d_inode->i_mutex);
 | 
			
		||||
 
 | 
			
		||||
  out:
 | 
			
		||||
 	return err;
 | 
			
		||||
@@ -426,7 +428,9 @@ int build_sto_structure(dentry_t *dir, d
 | 
			
		||||
 		const unsigned char *name;
 | 
			
		||||
 		len = dtohd(dentry)->d_name.len;
 | 
			
		||||
 		name = dtohd(dentry)->d_name.name;
 | 
			
		||||
+		mutex_lock(&dtohd2(dir)->d_inode->i_mutex);
 | 
			
		||||
 		hidden_sto_dentry = lookup_one_len(name, dtohd2(dir), len);
 | 
			
		||||
+		mutex_unlock(&dtohd2(dir)->d_inode->i_mutex);
 | 
			
		||||
 		dtohd2(dentry) = hidden_sto_dentry;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
--- a/fs/mini_fo/inode.c
 | 
			
		||||
+++ b/fs/mini_fo/inode.c
 | 
			
		||||
@@ -113,17 +113,23 @@ mini_fo_lookup(inode_t *dir, dentry_t *d
 | 
			
		||||
 		hidden_dir_dentry = hidden_dentry->d_parent;
 | 
			
		||||
 		kfree(bpath);
 | 
			
		||||
 	}
 | 
			
		||||
-	else if(hidden_dir_dentry && hidden_dir_dentry->d_inode)
 | 
			
		||||
+	else if(hidden_dir_dentry && hidden_dir_dentry->d_inode) {
 | 
			
		||||
+		mutex_lock(&hidden_dir_dentry->d_inode->i_mutex);
 | 
			
		||||
 		hidden_dentry =
 | 
			
		||||
 			lookup_one_len(name, hidden_dir_dentry, namelen);
 | 
			
		||||
-	else
 | 
			
		||||
+		mutex_unlock(&hidden_dir_dentry->d_inode->i_mutex);
 | 
			
		||||
+	} else {
 | 
			
		||||
 		hidden_dentry = NULL;
 | 
			
		||||
+	}
 | 
			
		||||
 
 | 
			
		||||
-	if(hidden_sto_dir_dentry && hidden_sto_dir_dentry->d_inode)
 | 
			
		||||
+	if(hidden_sto_dir_dentry && hidden_sto_dir_dentry->d_inode) {
 | 
			
		||||
+		mutex_lock(&hidden_sto_dir_dentry->d_inode->i_mutex);
 | 
			
		||||
 		hidden_sto_dentry =
 | 
			
		||||
 			lookup_one_len(name, hidden_sto_dir_dentry, namelen);
 | 
			
		||||
-	else
 | 
			
		||||
+		mutex_unlock(&hidden_sto_dir_dentry->d_inode->i_mutex);
 | 
			
		||||
+	} else {
 | 
			
		||||
 		hidden_sto_dentry =  NULL;
 | 
			
		||||
+	}
 | 
			
		||||
 
 | 
			
		||||
 	/* catch error in lookup */
 | 
			
		||||
 	if (IS_ERR(hidden_dentry) || IS_ERR(hidden_sto_dentry)) {
 | 
			
		||||
@@ -553,9 +559,11 @@ mini_fo_rmdir(inode_t *dir, dentry_t *de
 | 
			
		||||
 #endif
 | 
			
		||||
 
 | 
			
		||||
 		/* Delete an old WOL file contained in the storage dir */
 | 
			
		||||
+		mutex_lock(&hidden_sto_dentry->d_inode->i_mutex);
 | 
			
		||||
 		meta_dentry = lookup_one_len(META_FILENAME,
 | 
			
		||||
 					     hidden_sto_dentry,
 | 
			
		||||
 					     strlen(META_FILENAME));
 | 
			
		||||
+		mutex_unlock(&hidden_sto_dentry->d_inode->i_mutex);
 | 
			
		||||
 		if(meta_dentry->d_inode) {
 | 
			
		||||
 			err = vfs_unlink(hidden_sto_dentry->d_inode, meta_dentry);
 | 
			
		||||
 			dput(meta_dentry);
 | 
			
		||||
@@ -643,9 +651,11 @@ mini_fo_rmdir(inode_t *dir, dentry_t *de
 | 
			
		||||
 #endif
 | 
			
		||||
 
 | 
			
		||||
 		/* Delete an old WOL file contained in the storage dir */
 | 
			
		||||
+		mutex_lock(&hidden_sto_dentry->d_inode->i_mutex);
 | 
			
		||||
 		meta_dentry = lookup_one_len(META_FILENAME,
 | 
			
		||||
 					     hidden_sto_dentry,
 | 
			
		||||
 					     strlen(META_FILENAME));
 | 
			
		||||
+		mutex_unlock(&hidden_sto_dentry->d_inode->i_mutex);
 | 
			
		||||
 		if(meta_dentry->d_inode) {
 | 
			
		||||
 			/* is this necessary? dget(meta_dentry); */
 | 
			
		||||
 			err = vfs_unlink(hidden_sto_dentry->d_inode,
 | 
			
		||||
@@ -688,9 +698,11 @@ mini_fo_rmdir(inode_t *dir, dentry_t *de
 | 
			
		||||
 #endif
 | 
			
		||||
 
 | 
			
		||||
 		/* Delete an old WOL file contained in the storage dir */
 | 
			
		||||
+		mutex_lock(&hidden_sto_dentry->d_inode->i_mutex);
 | 
			
		||||
 		meta_dentry = lookup_one_len(META_FILENAME,
 | 
			
		||||
 					     hidden_sto_dentry,
 | 
			
		||||
 					     strlen(META_FILENAME));
 | 
			
		||||
+		mutex_unlock(&hidden_sto_dentry->d_inode->i_mutex);
 | 
			
		||||
 		if(meta_dentry->d_inode) {
 | 
			
		||||
 			/* is this necessary? dget(meta_dentry); */
 | 
			
		||||
 			err = vfs_unlink(hidden_sto_dentry->d_inode,
 | 
			
		||||
--- a/fs/mini_fo/meta.c
 | 
			
		||||
+++ b/fs/mini_fo/meta.c
 | 
			
		||||
@@ -43,9 +43,11 @@ int meta_build_lists(dentry_t *dentry)
 | 
			
		||||
 
 | 
			
		||||
   	/* might there be a META-file? */
 | 
			
		||||
 	if(dtohd2(dentry) && dtohd2(dentry)->d_inode) {
 | 
			
		||||
+		mutex_lock(&dtohd2(dentry)->d_inode->i_mutex);
 | 
			
		||||
 		meta_dentry = lookup_one_len(META_FILENAME,
 | 
			
		||||
 					     dtohd2(dentry),
 | 
			
		||||
 					     strlen(META_FILENAME));
 | 
			
		||||
+		mutex_unlock(&dtohd2(dentry)->d_inode->i_mutex);
 | 
			
		||||
 		if(!meta_dentry->d_inode) {
 | 
			
		||||
 			dput(meta_dentry);
 | 
			
		||||
 			goto out_ok;
 | 
			
		||||
@@ -426,8 +428,11 @@ int meta_write_d_entry(dentry_t *dentry,
 | 
			
		||||
 			goto out;
 | 
			
		||||
                 }
 | 
			
		||||
         }
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&dtohd2(dentry)->d_inode->i_mutex);
 | 
			
		||||
 	meta_dentry = lookup_one_len(META_FILENAME,
 | 
			
		||||
 				     dtohd2(dentry), strlen (META_FILENAME));
 | 
			
		||||
+	mutex_unlock(&dtohd2(dentry)->d_inode->i_mutex);
 | 
			
		||||
 
 | 
			
		||||
 	/* We need to create a META-file */
 | 
			
		||||
         if(!meta_dentry->d_inode) {
 | 
			
		||||
@@ -527,9 +532,13 @@ int meta_write_r_entry(dentry_t *dentry,
 | 
			
		||||
 			goto out;
 | 
			
		||||
                 }
 | 
			
		||||
         }
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&dtohd2(dentry)->d_inode->i_mutex);
 | 
			
		||||
 	meta_dentry = lookup_one_len(META_FILENAME,
 | 
			
		||||
 				     dtohd2(dentry),
 | 
			
		||||
 				     strlen (META_FILENAME));
 | 
			
		||||
+	mutex_unlock(&dtohd2(dentry)->d_inode->i_mutex);
 | 
			
		||||
+
 | 
			
		||||
         if(!meta_dentry->d_inode) {
 | 
			
		||||
                 /* We need to create a META-file */
 | 
			
		||||
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 | 
			
		||||
@@ -641,9 +650,13 @@ int meta_sync_d_list(dentry_t *dentry, i
 | 
			
		||||
 			goto out;
 | 
			
		||||
                 }
 | 
			
		||||
         }
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&dtohd2(dentry)->d_inode->i_mutex);
 | 
			
		||||
 	meta_dentry = lookup_one_len(META_FILENAME,
 | 
			
		||||
 				     dtohd2(dentry),
 | 
			
		||||
 				     strlen(META_FILENAME));
 | 
			
		||||
+	mutex_unlock(&dtohd2(dentry)->d_inode->i_mutex);
 | 
			
		||||
+
 | 
			
		||||
         if(!meta_dentry->d_inode) {
 | 
			
		||||
                 /* We need to create a META-file */
 | 
			
		||||
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 | 
			
		||||
@@ -784,9 +797,13 @@ int meta_sync_r_list(dentry_t *dentry, i
 | 
			
		||||
 			goto out;
 | 
			
		||||
                 }
 | 
			
		||||
         }
 | 
			
		||||
+
 | 
			
		||||
+	mutex_lock(&dtohd2(dentry)->d_inode->i_mutex);
 | 
			
		||||
 	meta_dentry = lookup_one_len(META_FILENAME,
 | 
			
		||||
 				     dtohd2(dentry),
 | 
			
		||||
 				     strlen(META_FILENAME));
 | 
			
		||||
+	mutex_unlock(&dtohd2(dentry)->d_inode->i_mutex);
 | 
			
		||||
+
 | 
			
		||||
         if(!meta_dentry->d_inode) {
 | 
			
		||||
                 /* We need to create a META-file */
 | 
			
		||||
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 | 
			
		||||
@ -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
 | 
			
		||||
  *
 | 
			
		||||
@@ -201,9 +214,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;
 | 
			
		||||
@ -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
 | 
			
		||||
@ -0,0 +1,11 @@
 | 
			
		||||
--- a/fs/binfmt_elf.c
 | 
			
		||||
+++ b/fs/binfmt_elf.c
 | 
			
		||||
@@ -1193,7 +1193,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.
 | 
			
		||||
@ -0,0 +1,146 @@
 | 
			
		||||
--- a/drivers/mtd/mtdpart.c
 | 
			
		||||
+++ b/drivers/mtd/mtdpart.c
 | 
			
		||||
@@ -21,6 +21,8 @@
 | 
			
		||||
 #include <linux/root_dev.h>
 | 
			
		||||
 #include <linux/magic.h>
 | 
			
		||||
 
 | 
			
		||||
+#define MTD_ERASE_PARTIAL	0x8000 /* partition only covers parts of an erase block */
 | 
			
		||||
+
 | 
			
		||||
 /* Our partition linked list */
 | 
			
		||||
 static LIST_HEAD(mtd_partitions);
 | 
			
		||||
 
 | 
			
		||||
@@ -226,13 +228,60 @@ static int part_erase(struct mtd_info *m
 | 
			
		||||
 		return -EROFS;
 | 
			
		||||
 	if (instr->addr >= mtd->size)
 | 
			
		||||
 		return -EINVAL;
 | 
			
		||||
+
 | 
			
		||||
+	instr->partial_start = false;
 | 
			
		||||
+	if (mtd->flags & MTD_ERASE_PARTIAL) {
 | 
			
		||||
+		size_t readlen = 0;
 | 
			
		||||
+		u64 mtd_ofs;
 | 
			
		||||
+
 | 
			
		||||
+		instr->erase_buf = kmalloc(part->master->erasesize, GFP_ATOMIC);
 | 
			
		||||
+		if (!instr->erase_buf)
 | 
			
		||||
+			return -ENOMEM;
 | 
			
		||||
+
 | 
			
		||||
+		mtd_ofs = part->offset + instr->addr;
 | 
			
		||||
+		instr->erase_buf_ofs = do_div(mtd_ofs, part->master->erasesize);
 | 
			
		||||
+
 | 
			
		||||
+		if (instr->erase_buf_ofs > 0) {
 | 
			
		||||
+			instr->addr -= instr->erase_buf_ofs;
 | 
			
		||||
+			ret = part->master->read(part->master,
 | 
			
		||||
+				instr->addr + part->offset,
 | 
			
		||||
+				part->master->erasesize,
 | 
			
		||||
+				&readlen, instr->erase_buf);
 | 
			
		||||
+
 | 
			
		||||
+			instr->partial_start = true;
 | 
			
		||||
+		} else {
 | 
			
		||||
+			mtd_ofs = part->offset + part->mtd.size;
 | 
			
		||||
+			instr->erase_buf_ofs = part->master->erasesize -
 | 
			
		||||
+				do_div(mtd_ofs, part->master->erasesize);
 | 
			
		||||
+
 | 
			
		||||
+			if (instr->erase_buf_ofs > 0) {
 | 
			
		||||
+				instr->len += instr->erase_buf_ofs;
 | 
			
		||||
+				ret = part->master->read(part->master,
 | 
			
		||||
+					part->offset + instr->addr +
 | 
			
		||||
+					instr->len - part->master->erasesize,
 | 
			
		||||
+					part->master->erasesize, &readlen,
 | 
			
		||||
+					instr->erase_buf);
 | 
			
		||||
+			} else {
 | 
			
		||||
+				ret = 0;
 | 
			
		||||
+			}
 | 
			
		||||
+		}
 | 
			
		||||
+		if (ret < 0) {
 | 
			
		||||
+			kfree(instr->erase_buf);
 | 
			
		||||
+			return ret;
 | 
			
		||||
+		}
 | 
			
		||||
+
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
 	instr->addr += part->offset;
 | 
			
		||||
 	ret = part->master->erase(part->master, instr);
 | 
			
		||||
 	if (ret) {
 | 
			
		||||
 		if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
 | 
			
		||||
 			instr->fail_addr -= part->offset;
 | 
			
		||||
 		instr->addr -= part->offset;
 | 
			
		||||
+		if (mtd->flags & MTD_ERASE_PARTIAL)
 | 
			
		||||
+			kfree(instr->erase_buf);
 | 
			
		||||
 	}
 | 
			
		||||
+
 | 
			
		||||
 	return ret;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -240,7 +289,25 @@ void mtd_erase_callback(struct erase_inf
 | 
			
		||||
 {
 | 
			
		||||
 	if (instr->mtd->erase == part_erase) {
 | 
			
		||||
 		struct mtd_part *part = PART(instr->mtd);
 | 
			
		||||
+		size_t wrlen = 0;
 | 
			
		||||
 
 | 
			
		||||
+		if (instr->mtd->flags & MTD_ERASE_PARTIAL) {
 | 
			
		||||
+			if (instr->partial_start) {
 | 
			
		||||
+				part->master->write(part->master,
 | 
			
		||||
+					instr->addr, instr->erase_buf_ofs,
 | 
			
		||||
+					&wrlen, instr->erase_buf);
 | 
			
		||||
+				instr->addr += instr->erase_buf_ofs;
 | 
			
		||||
+			} else {
 | 
			
		||||
+				instr->len -= instr->erase_buf_ofs;
 | 
			
		||||
+				part->master->write(part->master,
 | 
			
		||||
+					instr->addr + instr->len,
 | 
			
		||||
+					instr->erase_buf_ofs, &wrlen,
 | 
			
		||||
+					instr->erase_buf +
 | 
			
		||||
+					part->master->erasesize -
 | 
			
		||||
+					instr->erase_buf_ofs);
 | 
			
		||||
+			}
 | 
			
		||||
+			kfree(instr->erase_buf);
 | 
			
		||||
+		}
 | 
			
		||||
 		if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
 | 
			
		||||
 			instr->fail_addr -= part->offset;
 | 
			
		||||
 		instr->addr -= part->offset;
 | 
			
		||||
@@ -473,18 +540,24 @@ static struct mtd_part *add_one_partitio
 | 
			
		||||
 	if ((slave->mtd.flags & MTD_WRITEABLE) &&
 | 
			
		||||
 	    mtd_mod_by_eb(slave->offset, &slave->mtd)) {
 | 
			
		||||
 		/* Doesn't start on a boundary of major erase size */
 | 
			
		||||
-		/* FIXME: Let it be writable if it is on a boundary of
 | 
			
		||||
-		 * _minor_ erase size though */
 | 
			
		||||
-		slave->mtd.flags &= ~MTD_WRITEABLE;
 | 
			
		||||
-		printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
 | 
			
		||||
-			part->name);
 | 
			
		||||
+		slave->mtd.flags |= MTD_ERASE_PARTIAL;
 | 
			
		||||
+		if (((u32) slave->mtd.size) > master->erasesize)
 | 
			
		||||
+			slave->mtd.flags &= ~MTD_WRITEABLE;
 | 
			
		||||
+		else
 | 
			
		||||
+			slave->mtd.erasesize = slave->mtd.size;
 | 
			
		||||
 	}
 | 
			
		||||
 	if ((slave->mtd.flags & MTD_WRITEABLE) &&
 | 
			
		||||
-	    mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) {
 | 
			
		||||
-		slave->mtd.flags &= ~MTD_WRITEABLE;
 | 
			
		||||
-		printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
 | 
			
		||||
-			part->name);
 | 
			
		||||
-	}
 | 
			
		||||
+	    mtd_mod_by_eb(slave->offset + slave->mtd.size, &slave->mtd)) {
 | 
			
		||||
+		slave->mtd.flags |= MTD_ERASE_PARTIAL;
 | 
			
		||||
+
 | 
			
		||||
+		if ((u32) slave->mtd.size > master->erasesize)
 | 
			
		||||
+			slave->mtd.flags &= ~MTD_WRITEABLE;
 | 
			
		||||
+		else
 | 
			
		||||
+			slave->mtd.erasesize = slave->mtd.size;
 | 
			
		||||
+	}
 | 
			
		||||
+	if ((slave->mtd.flags & (MTD_ERASE_PARTIAL|MTD_WRITEABLE)) == MTD_ERASE_PARTIAL)
 | 
			
		||||
+		printk(KERN_WARNING"mtd: partition \"%s\" must either start or end on erase block boundary or be smaller than an erase block -- forcing read-only\n",
 | 
			
		||||
+				part->name);
 | 
			
		||||
 
 | 
			
		||||
 	slave->mtd.ecclayout = master->ecclayout;
 | 
			
		||||
 	if (master->block_isbad) {
 | 
			
		||||
--- a/include/linux/mtd/mtd.h
 | 
			
		||||
+++ b/include/linux/mtd/mtd.h
 | 
			
		||||
@@ -46,6 +46,10 @@ struct erase_info {
 | 
			
		||||
 	u_long priv;
 | 
			
		||||
 	u_char state;
 | 
			
		||||
 	struct erase_info *next;
 | 
			
		||||
+
 | 
			
		||||
+	u8 *erase_buf;
 | 
			
		||||
+	u32 erase_buf_ofs;
 | 
			
		||||
+	bool partial_start;
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 struct mtd_erase_region_info {
 | 
			
		||||
							
								
								
									
										5203
									
								
								target/linux/generic-2.6/patches-2.6.32/230-union_mounts.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5203
									
								
								target/linux/generic-2.6/patches-2.6.32/230-union_mounts.patch
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
--- a/fs/namespace.c
 | 
			
		||||
+++ b/fs/namespace.c
 | 
			
		||||
@@ -1550,7 +1550,7 @@ static int do_loopback(struct path *path
 | 
			
		||||
 	if (!mnt)
 | 
			
		||||
 		goto out;
 | 
			
		||||
 
 | 
			
		||||
-	err = check_union_mnt(&old_path, mnt, mnt_flags);
 | 
			
		||||
+	err = check_union_mnt(path, mnt, mnt_flags);
 | 
			
		||||
 	if (err)
 | 
			
		||||
 		goto out;
 | 
			
		||||
 
 | 
			
		||||
@ -0,0 +1,11 @@
 | 
			
		||||
--- a/include/linux/union.h
 | 
			
		||||
+++ b/include/linux/union.h
 | 
			
		||||
@@ -77,7 +77,7 @@ extern int union_permission(struct path 
 | 
			
		||||
 #define __union_copyup(x, y, z)		({ BUG(); (0); })
 | 
			
		||||
 #define union_copyup(x, y)		({ (0); })
 | 
			
		||||
 #define union_copyup_dir(x)		({ BUG(); (0); })
 | 
			
		||||
-#define union_permission(x, y)		inode_permission(x->dentry->d_inode, y)
 | 
			
		||||
+#define union_permission(x, y)		inode_permission((x)->dentry->d_inode, y)
 | 
			
		||||
 
 | 
			
		||||
 #endif	/* CONFIG_UNION_MOUNT */
 | 
			
		||||
 #endif	/* __KERNEL__ */
 | 
			
		||||
@ -0,0 +1,186 @@
 | 
			
		||||
--- a/fs/jffs2/dir.c
 | 
			
		||||
+++ b/fs/jffs2/dir.c
 | 
			
		||||
@@ -34,6 +34,9 @@ static int jffs2_mknod (struct inode *,s
 | 
			
		||||
 static int jffs2_rename (struct inode *, struct dentry *,
 | 
			
		||||
 			 struct inode *, struct dentry *);
 | 
			
		||||
 
 | 
			
		||||
+static int jffs2_whiteout (struct inode *, struct dentry *, struct dentry *);
 | 
			
		||||
+static int jffs2_fallthru (struct inode *, struct dentry *);
 | 
			
		||||
+
 | 
			
		||||
 const struct file_operations jffs2_dir_operations =
 | 
			
		||||
 {
 | 
			
		||||
 	.read =		generic_read_dir,
 | 
			
		||||
@@ -55,6 +58,8 @@ const struct inode_operations jffs2_dir_
 | 
			
		||||
 	.rmdir =	jffs2_rmdir,
 | 
			
		||||
 	.mknod =	jffs2_mknod,
 | 
			
		||||
 	.rename =	jffs2_rename,
 | 
			
		||||
+	.fallthru =     jffs2_fallthru,
 | 
			
		||||
+	.whiteout =     jffs2_whiteout,
 | 
			
		||||
 	.check_acl =	jffs2_check_acl,
 | 
			
		||||
 	.setattr =	jffs2_setattr,
 | 
			
		||||
 	.setxattr =	jffs2_setxattr,
 | 
			
		||||
@@ -98,8 +103,21 @@ static struct dentry *jffs2_lookup(struc
 | 
			
		||||
 			fd = fd_list;
 | 
			
		||||
 		}
 | 
			
		||||
 	}
 | 
			
		||||
-	if (fd)
 | 
			
		||||
-		ino = fd->ino;
 | 
			
		||||
+	if (fd) {
 | 
			
		||||
+		spin_lock(&target->d_lock);
 | 
			
		||||
+		switch(fd->type) {
 | 
			
		||||
+		case DT_WHT:
 | 
			
		||||
+			target->d_flags |= DCACHE_WHITEOUT;
 | 
			
		||||
+			break;
 | 
			
		||||
+		case DT_UNKNOWN:
 | 
			
		||||
+			target->d_flags |= DCACHE_FALLTHRU;
 | 
			
		||||
+			break;
 | 
			
		||||
+		default:
 | 
			
		||||
+			ino = fd->ino;
 | 
			
		||||
+			break;
 | 
			
		||||
+		}
 | 
			
		||||
+		spin_unlock(&target->d_lock);
 | 
			
		||||
+	}
 | 
			
		||||
 	mutex_unlock(&dir_f->sem);
 | 
			
		||||
 	if (ino) {
 | 
			
		||||
 		inode = jffs2_iget(dir_i->i_sb, ino);
 | 
			
		||||
@@ -155,7 +173,9 @@ static int jffs2_readdir(struct file *fi
 | 
			
		||||
 				  fd->name, fd->ino, fd->type, curofs, offset));
 | 
			
		||||
 			continue;
 | 
			
		||||
 		}
 | 
			
		||||
-		if (!fd->ino) {
 | 
			
		||||
+		if (fd->type == DT_UNKNOWN)
 | 
			
		||||
+			fd->ino = 100; /* XXX: arbitrary */
 | 
			
		||||
+		else if (!fd->ino && (fd->type != DT_WHT)) {
 | 
			
		||||
 			D2(printk(KERN_DEBUG "Skipping deletion dirent \"%s\"\n", fd->name));
 | 
			
		||||
 			offset++;
 | 
			
		||||
 			continue;
 | 
			
		||||
@@ -498,6 +518,11 @@ static int jffs2_mkdir (struct inode *di
 | 
			
		||||
 		return PTR_ERR(inode);
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
+	if (dentry->d_flags & DCACHE_WHITEOUT) {
 | 
			
		||||
+		inode->i_flags |= S_OPAQUE;
 | 
			
		||||
+		ri->flags = cpu_to_je16(JFFS2_INO_FLAG_OPAQUE);
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
 	inode->i_op = &jffs2_dir_inode_operations;
 | 
			
		||||
 	inode->i_fop = &jffs2_dir_operations;
 | 
			
		||||
 
 | 
			
		||||
@@ -779,6 +804,82 @@ static int jffs2_mknod (struct inode *di
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static int jffs2_fallthru (struct inode *dir, struct dentry *dentry)
 | 
			
		||||
+{
 | 
			
		||||
+	struct jffs2_sb_info *c = JFFS2_SB_INFO(dir->i_sb);
 | 
			
		||||
+	uint32_t now;
 | 
			
		||||
+	int ret;
 | 
			
		||||
+
 | 
			
		||||
+	now = get_seconds();
 | 
			
		||||
+	ret = jffs2_do_link(c, JFFS2_INODE_INFO(dir), 0, DT_UNKNOWN,
 | 
			
		||||
+			    dentry->d_name.name, dentry->d_name.len, now);
 | 
			
		||||
+	if (ret)
 | 
			
		||||
+		return ret;
 | 
			
		||||
+
 | 
			
		||||
+	d_instantiate(dentry, NULL);
 | 
			
		||||
+	spin_lock(&dentry->d_lock);
 | 
			
		||||
+	dentry->d_flags |= DCACHE_FALLTHRU;
 | 
			
		||||
+	spin_unlock(&dentry->d_lock);
 | 
			
		||||
+
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static int jffs2_whiteout (struct inode *dir, struct dentry *old_dentry,
 | 
			
		||||
+			   struct dentry *new_dentry)
 | 
			
		||||
+{
 | 
			
		||||
+	struct jffs2_sb_info *c = JFFS2_SB_INFO(dir->i_sb);
 | 
			
		||||
+	struct jffs2_inode_info *victim_f = NULL;
 | 
			
		||||
+	uint32_t now;
 | 
			
		||||
+	int ret;
 | 
			
		||||
+
 | 
			
		||||
+	/* If it's a directory, then check whether it is really empty
 | 
			
		||||
+	 */
 | 
			
		||||
+	if (new_dentry->d_inode) {
 | 
			
		||||
+		victim_f = JFFS2_INODE_INFO(old_dentry->d_inode);
 | 
			
		||||
+		if (S_ISDIR(old_dentry->d_inode->i_mode)) {
 | 
			
		||||
+			struct jffs2_full_dirent *fd;
 | 
			
		||||
+
 | 
			
		||||
+			mutex_lock(&victim_f->sem);
 | 
			
		||||
+			for (fd = victim_f->dents; fd; fd = fd->next) {
 | 
			
		||||
+				if (fd->ino) {
 | 
			
		||||
+					mutex_unlock(&victim_f->sem);
 | 
			
		||||
+					return -ENOTEMPTY;
 | 
			
		||||
+				}
 | 
			
		||||
+			}
 | 
			
		||||
+			mutex_unlock(&victim_f->sem);
 | 
			
		||||
+		}
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	now = get_seconds();
 | 
			
		||||
+	ret = jffs2_do_link(c, JFFS2_INODE_INFO(dir), 0, DT_WHT,
 | 
			
		||||
+			    new_dentry->d_name.name, new_dentry->d_name.len, now);
 | 
			
		||||
+	if (ret)
 | 
			
		||||
+		return ret;
 | 
			
		||||
+
 | 
			
		||||
+	spin_lock(&new_dentry->d_lock);
 | 
			
		||||
+	new_dentry->d_flags &= ~DCACHE_FALLTHRU;
 | 
			
		||||
+	new_dentry->d_flags |= DCACHE_WHITEOUT;
 | 
			
		||||
+	spin_unlock(&new_dentry->d_lock);
 | 
			
		||||
+	d_add(new_dentry, NULL);
 | 
			
		||||
+
 | 
			
		||||
+	if (victim_f) {
 | 
			
		||||
+		/* There was a victim. Kill it off nicely */
 | 
			
		||||
+		drop_nlink(old_dentry->d_inode);
 | 
			
		||||
+		/* Don't oops if the victim was a dirent pointing to an
 | 
			
		||||
+		   inode which didn't exist. */
 | 
			
		||||
+		if (victim_f->inocache) {
 | 
			
		||||
+			mutex_lock(&victim_f->sem);
 | 
			
		||||
+			if (S_ISDIR(old_dentry->d_inode->i_mode))
 | 
			
		||||
+				victim_f->inocache->pino_nlink = 0;
 | 
			
		||||
+			else
 | 
			
		||||
+				victim_f->inocache->pino_nlink--;
 | 
			
		||||
+			mutex_unlock(&victim_f->sem);
 | 
			
		||||
+		}
 | 
			
		||||
+	}
 | 
			
		||||
+
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
 | 
			
		||||
 			 struct inode *new_dir_i, struct dentry *new_dentry)
 | 
			
		||||
 {
 | 
			
		||||
--- a/fs/jffs2/fs.c
 | 
			
		||||
+++ b/fs/jffs2/fs.c
 | 
			
		||||
@@ -301,6 +301,10 @@ struct inode *jffs2_iget(struct super_bl
 | 
			
		||||
 
 | 
			
		||||
 		inode->i_op = &jffs2_dir_inode_operations;
 | 
			
		||||
 		inode->i_fop = &jffs2_dir_operations;
 | 
			
		||||
+
 | 
			
		||||
+		if (je16_to_cpu(latest_node.flags) & JFFS2_INO_FLAG_OPAQUE)
 | 
			
		||||
+			inode->i_flags |= S_OPAQUE;
 | 
			
		||||
+
 | 
			
		||||
 		break;
 | 
			
		||||
 	}
 | 
			
		||||
 	case S_IFREG:
 | 
			
		||||
--- a/fs/jffs2/super.c
 | 
			
		||||
+++ b/fs/jffs2/super.c
 | 
			
		||||
@@ -172,7 +172,7 @@ static int jffs2_fill_super(struct super
 | 
			
		||||
 
 | 
			
		||||
 	sb->s_op = &jffs2_super_operations;
 | 
			
		||||
 	sb->s_export_op = &jffs2_export_ops;
 | 
			
		||||
-	sb->s_flags = sb->s_flags | MS_NOATIME;
 | 
			
		||||
+	sb->s_flags = sb->s_flags | MS_NOATIME | MS_WHITEOUT;
 | 
			
		||||
 	sb->s_xattr = jffs2_xattr_handlers;
 | 
			
		||||
 #ifdef CONFIG_JFFS2_FS_POSIX_ACL
 | 
			
		||||
 	sb->s_flags |= MS_POSIXACL;
 | 
			
		||||
--- a/include/linux/jffs2.h
 | 
			
		||||
+++ b/include/linux/jffs2.h
 | 
			
		||||
@@ -87,6 +87,8 @@
 | 
			
		||||
 #define JFFS2_INO_FLAG_USERCOMPR  2	/* User has requested a specific
 | 
			
		||||
 					   compression type */
 | 
			
		||||
 
 | 
			
		||||
+#define JFFS2_INO_FLAG_OPAQUE     4	/* Directory is opaque (for union mounts) */
 | 
			
		||||
+
 | 
			
		||||
 
 | 
			
		||||
 /* These can go once we've made sure we've caught all uses without
 | 
			
		||||
    byteswapping */
 | 
			
		||||
@ -0,0 +1,30 @@
 | 
			
		||||
--- a/fs/union.c
 | 
			
		||||
+++ b/fs/union.c
 | 
			
		||||
@@ -842,10 +842,8 @@ static int union_copyup_dir_one(void *bu
 | 
			
		||||
 	/* Lookup this entry in the topmost directory */
 | 
			
		||||
 	dentry = lookup_one_len(name, topmost_dentry, namlen);
 | 
			
		||||
 
 | 
			
		||||
-	if (IS_ERR(dentry)) {
 | 
			
		||||
-		printk(KERN_INFO "error looking up %s\n", dentry->d_name.name);
 | 
			
		||||
+	if (IS_ERR(dentry))
 | 
			
		||||
 		goto out;
 | 
			
		||||
-	}
 | 
			
		||||
 
 | 
			
		||||
 	/*
 | 
			
		||||
 	 * If the entry already exists, one of the following is true:
 | 
			
		||||
@@ -857,7 +855,6 @@ static int union_copyup_dir_one(void *bu
 | 
			
		||||
 	 */
 | 
			
		||||
 	if (dentry->d_inode || d_is_whiteout(dentry) ||
 | 
			
		||||
 	    d_is_fallthru(dentry)) {
 | 
			
		||||
-		printk(KERN_INFO "skipping copy of %s\n", dentry->d_name.name);
 | 
			
		||||
 		goto out_dput;
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
@@ -867,7 +864,6 @@ static int union_copyup_dir_one(void *bu
 | 
			
		||||
 	 * used, so each file system must implement its own way of
 | 
			
		||||
 	 * storing a fallthru entry.
 | 
			
		||||
 	 */
 | 
			
		||||
-	printk(KERN_INFO "creating fallthru for %s\n", dentry->d_name.name);
 | 
			
		||||
 	err = topmost_dentry->d_inode->i_op->fallthru(topmost_dentry->d_inode,
 | 
			
		||||
 						      dentry);
 | 
			
		||||
 	/* FIXME */
 | 
			
		||||
@ -0,0 +1,117 @@
 | 
			
		||||
--- a/fs/namespace.c
 | 
			
		||||
+++ b/fs/namespace.c
 | 
			
		||||
@@ -1656,8 +1656,10 @@ static int do_move_mount(struct path *pa
 | 
			
		||||
 
 | 
			
		||||
 	/* moving to or from a union mount is not supported */
 | 
			
		||||
 	err = -EINVAL;
 | 
			
		||||
+#if 0
 | 
			
		||||
 	if (IS_MNT_UNION(path->mnt))
 | 
			
		||||
 		goto exit;
 | 
			
		||||
+#endif
 | 
			
		||||
 	if (IS_MNT_UNION(old_path.mnt))
 | 
			
		||||
 		goto exit;
 | 
			
		||||
 
 | 
			
		||||
--- a/fs/union.c
 | 
			
		||||
+++ b/fs/union.c
 | 
			
		||||
@@ -260,8 +260,6 @@ int append_to_union(struct vfsmount *mnt
 | 
			
		||||
 	spin_lock(&union_lock);
 | 
			
		||||
 	um = union_lookup(dentry, mnt);
 | 
			
		||||
 	if (um) {
 | 
			
		||||
-		BUG_ON((um->u_next.dentry != dest_dentry) ||
 | 
			
		||||
-		       (um->u_next.mnt != dest_mnt));
 | 
			
		||||
 		spin_unlock(&union_lock);
 | 
			
		||||
 		union_put(this);
 | 
			
		||||
 		return 0;
 | 
			
		||||
@@ -274,6 +272,23 @@ int append_to_union(struct vfsmount *mnt
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+int follow_union_mountpoint(struct path *path)
 | 
			
		||||
+{
 | 
			
		||||
+	struct path new_path = *path;
 | 
			
		||||
+
 | 
			
		||||
+	path_get(&new_path);
 | 
			
		||||
+	while (follow_union_down(&new_path)) {
 | 
			
		||||
+		if (new_path.dentry != new_path.mnt->mnt_root)
 | 
			
		||||
+			continue;
 | 
			
		||||
+
 | 
			
		||||
+		path_put(path);
 | 
			
		||||
+		*path = new_path;
 | 
			
		||||
+		return 1;
 | 
			
		||||
+	}
 | 
			
		||||
+	path_put(&new_path);
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 /*
 | 
			
		||||
  * follow_union_down - follow the union stack one layer down
 | 
			
		||||
  *
 | 
			
		||||
--- a/include/linux/union.h
 | 
			
		||||
+++ b/include/linux/union.h
 | 
			
		||||
@@ -47,6 +47,7 @@ extern int append_to_union(struct vfsmou
 | 
			
		||||
 			   struct vfsmount *, struct dentry *);
 | 
			
		||||
 extern int follow_union_down(struct path *);
 | 
			
		||||
 extern int follow_union_mount(struct path *);
 | 
			
		||||
+extern int follow_union_mountpoint(struct path *path);
 | 
			
		||||
 extern void __d_drop_unions(struct dentry *);
 | 
			
		||||
 extern void shrink_d_unions(struct dentry *);
 | 
			
		||||
 extern void __shrink_d_unions(struct dentry *, struct list_head *);
 | 
			
		||||
@@ -68,6 +69,7 @@ extern int union_permission(struct path 
 | 
			
		||||
 #define append_to_union(x1, y1, x2, y2)	({ BUG(); (0); })
 | 
			
		||||
 #define follow_union_down(x)		({ (0); })
 | 
			
		||||
 #define follow_union_mount(x)	({ (0); })
 | 
			
		||||
+#define follow_union_mountpoint(x)	({ (0); })
 | 
			
		||||
 #define __d_drop_unions(x)		do { } while (0)
 | 
			
		||||
 #define shrink_d_unions(x)		do { } while (0)
 | 
			
		||||
 #define __shrink_d_unions(x,y)		do { } while (0)
 | 
			
		||||
--- a/fs/namei.c
 | 
			
		||||
+++ b/fs/namei.c
 | 
			
		||||
@@ -626,6 +626,9 @@ static int cache_lookup_union(struct nam
 | 
			
		||||
 		    !S_ISDIR(path->dentry->d_inode->i_mode))
 | 
			
		||||
 			goto out;
 | 
			
		||||
 
 | 
			
		||||
+		if (follow_union_mountpoint(path))
 | 
			
		||||
+			goto out;
 | 
			
		||||
+
 | 
			
		||||
 		/* Build the union stack for this part */
 | 
			
		||||
 		res = __cache_lookup_build_union(nd, name, path);
 | 
			
		||||
 		if (res) {
 | 
			
		||||
@@ -892,6 +895,9 @@ static int real_lookup_union(struct name
 | 
			
		||||
 	    !S_ISDIR(path->dentry->d_inode->i_mode))
 | 
			
		||||
 		goto out;
 | 
			
		||||
 
 | 
			
		||||
+	if (follow_union_mountpoint(path))
 | 
			
		||||
+		goto out;
 | 
			
		||||
+
 | 
			
		||||
 	/* Build the union stack for this part */
 | 
			
		||||
 	res = __real_lookup_build_union(nd, name, path);
 | 
			
		||||
 	if (res) {
 | 
			
		||||
@@ -1813,6 +1819,9 @@ int hash_lookup_union(struct nameidata *
 | 
			
		||||
 	    !S_ISDIR(path->dentry->d_inode->i_mode))
 | 
			
		||||
 		goto out;
 | 
			
		||||
 
 | 
			
		||||
+	if (follow_union_mountpoint(path))
 | 
			
		||||
+		goto out;
 | 
			
		||||
+
 | 
			
		||||
 	/* Build the union stack for this part */
 | 
			
		||||
 	res = __hash_lookup_build_union(nd, name, path);
 | 
			
		||||
 	if (res) {
 | 
			
		||||
--- a/fs/readdir.c
 | 
			
		||||
+++ b/fs/readdir.c
 | 
			
		||||
@@ -17,6 +17,7 @@
 | 
			
		||||
 #include <linux/syscalls.h>
 | 
			
		||||
 #include <linux/unistd.h>
 | 
			
		||||
 #include <linux/union.h>
 | 
			
		||||
+#include <linux/mount.h>
 | 
			
		||||
 
 | 
			
		||||
 #include <asm/uaccess.h>
 | 
			
		||||
 
 | 
			
		||||
@@ -45,7 +46,7 @@ int vfs_readdir(struct file *file, filld
 | 
			
		||||
 		 * below this one in the union stack.
 | 
			
		||||
 		 */
 | 
			
		||||
 		if (is_unionized(file->f_path.dentry, file->f_path.mnt) &&
 | 
			
		||||
-		    !IS_OPAQUE(inode)) {
 | 
			
		||||
+		    !IS_OPAQUE(inode) && IS_MNT_UNION(file->f_path.mnt)) {
 | 
			
		||||
 			res = union_copyup_dir(&file->f_path);
 | 
			
		||||
 			if (res)
 | 
			
		||||
 				goto out_unlock;
 | 
			
		||||
@ -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 */
 | 
			
		||||
 
 | 
			
		||||
@@ -48,6 +50,7 @@ struct sockaddr_ll
 | 
			
		||||
 #define PACKET_RESERVE			12
 | 
			
		||||
 #define PACKET_TX_RING			13
 | 
			
		||||
 #define PACKET_LOSS			14
 | 
			
		||||
+#define PACKET_RECV_TYPE		15
 | 
			
		||||
 
 | 
			
		||||
 struct tpacket_stats
 | 
			
		||||
 {
 | 
			
		||||
--- a/net/packet/af_packet.c
 | 
			
		||||
+++ b/net/packet/af_packet.c
 | 
			
		||||
@@ -204,6 +204,7 @@ struct packet_sock {
 | 
			
		||||
 	unsigned int		tp_reserve;
 | 
			
		||||
 	unsigned int		tp_loss:1;
 | 
			
		||||
 #endif
 | 
			
		||||
+	unsigned int		pkt_type;
 | 
			
		||||
 };
 | 
			
		||||
 
 | 
			
		||||
 struct packet_skb_cb {
 | 
			
		||||
@@ -342,6 +343,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
 | 
			
		||||
@@ -349,6 +351,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
 | 
			
		||||
@@ -361,7 +364,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))
 | 
			
		||||
@@ -545,12 +548,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;
 | 
			
		||||
 
 | 
			
		||||
@@ -667,12 +670,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;
 | 
			
		||||
 
 | 
			
		||||
@@ -1384,6 +1387,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;
 | 
			
		||||
@@ -1731,6 +1735,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:
 | 
			
		||||
@@ -1876,6 +1890,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))
 | 
			
		||||
@ -0,0 +1,20 @@
 | 
			
		||||
--- a/drivers/net/pppoe.c
 | 
			
		||||
+++ b/drivers/net/pppoe.c
 | 
			
		||||
@@ -863,7 +863,7 @@ static int pppoe_sendmsg(struct kiocb *i
 | 
			
		||||
 		goto end;
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
-	skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32,
 | 
			
		||||
+	skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32 + NET_SKB_PAD,
 | 
			
		||||
 			   0, GFP_KERNEL);
 | 
			
		||||
 	if (!skb) {
 | 
			
		||||
 		error = -ENOMEM;
 | 
			
		||||
@@ -871,7 +871,7 @@ static int pppoe_sendmsg(struct kiocb *i
 | 
			
		||||
 	}
 | 
			
		||||
 
 | 
			
		||||
 	/* Reserve space for headers. */
 | 
			
		||||
-	skb_reserve(skb, dev->hard_header_len);
 | 
			
		||||
+	skb_reserve(skb, dev->hard_header_len + NET_SKB_PAD);
 | 
			
		||||
 	skb_reset_network_header(skb);
 | 
			
		||||
 
 | 
			
		||||
 	skb->dev = dev;
 | 
			
		||||
@ -0,0 +1,144 @@
 | 
			
		||||
--- a/net/sched/sch_generic.c
 | 
			
		||||
+++ b/net/sched/sch_generic.c
 | 
			
		||||
@@ -391,16 +391,50 @@ static const u8 prio2band[TC_PRIO_MAX+1]
 | 
			
		||||
 
 | 
			
		||||
 #define PFIFO_FAST_BANDS 3
 | 
			
		||||
 
 | 
			
		||||
+struct pfifo_fast_sched_data {
 | 
			
		||||
+	struct tcf_proto *filter_list;
 | 
			
		||||
+	struct sk_buff_head list[PFIFO_FAST_BANDS];
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
 static inline struct sk_buff_head *prio2list(struct sk_buff *skb,
 | 
			
		||||
 					     struct Qdisc *qdisc)
 | 
			
		||||
 {
 | 
			
		||||
-	struct sk_buff_head *list = qdisc_priv(qdisc);
 | 
			
		||||
+	struct pfifo_fast_sched_data *q = qdisc_priv(qdisc);
 | 
			
		||||
+	struct sk_buff_head *list = q->list;
 | 
			
		||||
 	return list + prio2band[skb->priority & TC_PRIO_MAX];
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static int pfifo_fast_filter(struct sk_buff *skb, struct Qdisc* qdisc)
 | 
			
		||||
+{
 | 
			
		||||
+#ifdef CONFIG_NET_CLS_ACT
 | 
			
		||||
+	struct pfifo_fast_sched_data *q = qdisc_priv(qdisc);
 | 
			
		||||
+	int result = 0, ret = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
 | 
			
		||||
+	struct tcf_result res;
 | 
			
		||||
+
 | 
			
		||||
+	if (q->filter_list != NULL)
 | 
			
		||||
+		result = tc_classify(skb, q->filter_list, &res);
 | 
			
		||||
+	if (result >= 0) {
 | 
			
		||||
+		switch (result) {
 | 
			
		||||
+		case TC_ACT_STOLEN:
 | 
			
		||||
+		case TC_ACT_QUEUED:
 | 
			
		||||
+			ret = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN;
 | 
			
		||||
+		case TC_ACT_SHOT:
 | 
			
		||||
+			kfree_skb(skb);
 | 
			
		||||
+			return ret;
 | 
			
		||||
+		}
 | 
			
		||||
+	}
 | 
			
		||||
+#endif
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
 static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc* qdisc)
 | 
			
		||||
 {
 | 
			
		||||
 	struct sk_buff_head *list = prio2list(skb, qdisc);
 | 
			
		||||
+	int ret;
 | 
			
		||||
+
 | 
			
		||||
+	ret = pfifo_fast_filter(skb, qdisc);
 | 
			
		||||
+	if (ret)
 | 
			
		||||
+		return ret;
 | 
			
		||||
 
 | 
			
		||||
 	if (skb_queue_len(list) < qdisc_dev(qdisc)->tx_queue_len) {
 | 
			
		||||
 		qdisc->q.qlen++;
 | 
			
		||||
@@ -412,8 +446,9 @@ static int pfifo_fast_enqueue(struct sk_
 | 
			
		||||
 
 | 
			
		||||
 static struct sk_buff *pfifo_fast_dequeue(struct Qdisc* qdisc)
 | 
			
		||||
 {
 | 
			
		||||
+	struct pfifo_fast_sched_data *q = qdisc_priv(qdisc);
 | 
			
		||||
+	struct sk_buff_head *list = q->list;
 | 
			
		||||
 	int prio;
 | 
			
		||||
-	struct sk_buff_head *list = qdisc_priv(qdisc);
 | 
			
		||||
 
 | 
			
		||||
 	for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) {
 | 
			
		||||
 		if (!skb_queue_empty(list + prio)) {
 | 
			
		||||
@@ -440,8 +475,9 @@ static struct sk_buff *pfifo_fast_peek(s
 | 
			
		||||
 
 | 
			
		||||
 static void pfifo_fast_reset(struct Qdisc* qdisc)
 | 
			
		||||
 {
 | 
			
		||||
+	struct pfifo_fast_sched_data *q = qdisc_priv(qdisc);
 | 
			
		||||
+	struct sk_buff_head *list = q->list;
 | 
			
		||||
 	int prio;
 | 
			
		||||
-	struct sk_buff_head *list = qdisc_priv(qdisc);
 | 
			
		||||
 
 | 
			
		||||
 	for (prio = 0; prio < PFIFO_FAST_BANDS; prio++)
 | 
			
		||||
 		__qdisc_reset_queue(qdisc, list + prio);
 | 
			
		||||
@@ -464,8 +500,9 @@ nla_put_failure:
 | 
			
		||||
 
 | 
			
		||||
 static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt)
 | 
			
		||||
 {
 | 
			
		||||
+	struct pfifo_fast_sched_data *q = qdisc_priv(qdisc);
 | 
			
		||||
+	struct sk_buff_head *list = q->list;
 | 
			
		||||
 	int prio;
 | 
			
		||||
-	struct sk_buff_head *list = qdisc_priv(qdisc);
 | 
			
		||||
 
 | 
			
		||||
 	for (prio = 0; prio < PFIFO_FAST_BANDS; prio++)
 | 
			
		||||
 		skb_queue_head_init(list + prio);
 | 
			
		||||
@@ -473,9 +510,36 @@ static int pfifo_fast_init(struct Qdisc 
 | 
			
		||||
 	return 0;
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+static int pfifo_fast_change_class(struct Qdisc *qdisc, u32 classid, u32 parentid,
 | 
			
		||||
+			    struct nlattr **tca, unsigned long *arg)
 | 
			
		||||
+{
 | 
			
		||||
+	return -EOPNOTSUPP;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static unsigned long pfifo_fast_get(struct Qdisc *qdisc, u32 classid)
 | 
			
		||||
+{
 | 
			
		||||
+	return 0;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static struct tcf_proto **pfifo_fast_find_tcf(struct Qdisc *qdisc, unsigned long cl)
 | 
			
		||||
+{
 | 
			
		||||
+	struct pfifo_fast_sched_data *q = qdisc_priv(qdisc);
 | 
			
		||||
+
 | 
			
		||||
+	if (cl)
 | 
			
		||||
+		return NULL;
 | 
			
		||||
+	return &q->filter_list;
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static const struct Qdisc_class_ops pfifo_fast_class_ops = {
 | 
			
		||||
+	.get		=	pfifo_fast_get,
 | 
			
		||||
+	.change		=	pfifo_fast_change_class,
 | 
			
		||||
+	.tcf_chain	=	pfifo_fast_find_tcf,
 | 
			
		||||
+};
 | 
			
		||||
+
 | 
			
		||||
 static struct Qdisc_ops pfifo_fast_ops __read_mostly = {
 | 
			
		||||
 	.id		=	"pfifo_fast",
 | 
			
		||||
-	.priv_size	=	PFIFO_FAST_BANDS * sizeof(struct sk_buff_head),
 | 
			
		||||
+	.cl_ops		=	&pfifo_fast_class_ops,
 | 
			
		||||
+	.priv_size	=	sizeof(struct pfifo_fast_sched_data),
 | 
			
		||||
 	.enqueue	=	pfifo_fast_enqueue,
 | 
			
		||||
 	.dequeue	=	pfifo_fast_dequeue,
 | 
			
		||||
 	.peek		=	pfifo_fast_peek,
 | 
			
		||||
@@ -757,3 +821,18 @@ void dev_shutdown(struct net_device *dev
 | 
			
		||||
 	shutdown_scheduler_queue(dev, &dev->rx_queue, &noop_qdisc);
 | 
			
		||||
 	WARN_ON(timer_pending(&dev->watchdog_timer));
 | 
			
		||||
 }
 | 
			
		||||
+
 | 
			
		||||
+#ifdef CONFIG_NET_SCHED
 | 
			
		||||
+static int __init sch_generic_init(void)
 | 
			
		||||
+{
 | 
			
		||||
+	return register_qdisc(&pfifo_fast_ops);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+static void __exit sch_generic_exit(void)
 | 
			
		||||
+{
 | 
			
		||||
+	unregister_qdisc(&pfifo_fast_ops);
 | 
			
		||||
+}
 | 
			
		||||
+
 | 
			
		||||
+module_init(sch_generic_init)
 | 
			
		||||
+module_exit(sch_generic_exit)
 | 
			
		||||
+#endif
 | 
			
		||||
@ -0,0 +1,18 @@
 | 
			
		||||
--- a/drivers/leds/Kconfig
 | 
			
		||||
+++ b/drivers/leds/Kconfig
 | 
			
		||||
@@ -304,4 +304,8 @@ config LEDS_TRIGGER_DEFAULT_ON
 | 
			
		||||
 comment "iptables trigger is under Netfilter config (LED target)"
 | 
			
		||||
 	depends on LEDS_TRIGGERS
 | 
			
		||||
 
 | 
			
		||||
+config LEDS_TRIGGER_MORSE
 | 
			
		||||
+	tristate "LED Morse Trigger"
 | 
			
		||||
+	depends on LEDS_TRIGGERS
 | 
			
		||||
+
 | 
			
		||||
 endif # NEW_LEDS
 | 
			
		||||
--- a/drivers/leds/Makefile
 | 
			
		||||
+++ b/drivers/leds/Makefile
 | 
			
		||||
@@ -40,3 +40,4 @@ obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT)	+= 
 | 
			
		||||
 obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT)	+= ledtrig-backlight.o
 | 
			
		||||
 obj-$(CONFIG_LEDS_TRIGGER_GPIO)		+= ledtrig-gpio.o
 | 
			
		||||
 obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON)	+= ledtrig-default-on.o
 | 
			
		||||
+obj-$(CONFIG_LEDS_TRIGGER_MORSE)	+= ledtrig-morse.o
 | 
			
		||||
@ -0,0 +1,21 @@
 | 
			
		||||
--- a/drivers/leds/Kconfig
 | 
			
		||||
+++ b/drivers/leds/Kconfig
 | 
			
		||||
@@ -308,4 +308,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
 | 
			
		||||
@@ -41,3 +41,4 @@ obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT)	+= 
 | 
			
		||||
 obj-$(CONFIG_LEDS_TRIGGER_GPIO)		+= ledtrig-gpio.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
 | 
			
		||||
@ -0,0 +1,31 @@
 | 
			
		||||
--- a/drivers/input/misc/Kconfig
 | 
			
		||||
+++ b/drivers/input/misc/Kconfig
 | 
			
		||||
@@ -316,4 +316,20 @@ config INPUT_PCAP
 | 
			
		||||
 	  To compile this driver as a module, choose M here: the
 | 
			
		||||
 	  module will be called pcap_keys.
 | 
			
		||||
 
 | 
			
		||||
+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
 | 
			
		||||
@@ -30,4 +30,5 @@ obj-$(CONFIG_INPUT_WINBOND_CIR)		+= winb
 | 
			
		||||
 obj-$(CONFIG_INPUT_WISTRON_BTNS)	+= wistron_btns.o
 | 
			
		||||
 obj-$(CONFIG_INPUT_WM831X_ON)		+= wm831x-on.o
 | 
			
		||||
 obj-$(CONFIG_INPUT_YEALINK)		+= yealink.o
 | 
			
		||||
+obj-$(CONFIG_INPUT_GPIO_BUTTONS)	+= gpio_buttons.o
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										27
									
								
								target/linux/generic-2.6/patches-2.6.32/420-gpiodev.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								target/linux/generic-2.6/patches-2.6.32/420-gpiodev.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
--- a/drivers/char/Kconfig
 | 
			
		||||
+++ b/drivers/char/Kconfig
 | 
			
		||||
@@ -1029,6 +1029,14 @@ 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 RAW_DRIVER
 | 
			
		||||
 	tristate "RAW driver (/dev/raw/rawN)"
 | 
			
		||||
 	depends on BLOCK
 | 
			
		||||
--- a/drivers/char/Makefile
 | 
			
		||||
+++ b/drivers/char/Makefile
 | 
			
		||||
@@ -96,6 +96,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_TB0219)	+= tb0219.o
 | 
			
		||||
 obj-$(CONFIG_TELCLOCK)		+= tlclk.o
 | 
			
		||||
 
 | 
			
		||||
@ -0,0 +1,17 @@
 | 
			
		||||
--- a/include/scsi/scsi.h
 | 
			
		||||
+++ b/include/scsi/scsi.h
 | 
			
		||||
@@ -145,10 +145,10 @@ struct scsi_cmnd;
 | 
			
		||||
 
 | 
			
		||||
 /* defined in T10 SCSI Primary Commands-2 (SPC2) */
 | 
			
		||||
 struct scsi_varlen_cdb_hdr {
 | 
			
		||||
-	u8 opcode;        /* opcode always == VARIABLE_LENGTH_CMD */
 | 
			
		||||
-	u8 control;
 | 
			
		||||
-	u8 misc[5];
 | 
			
		||||
-	u8 additional_cdb_length;         /* total cdb length - 8 */
 | 
			
		||||
+	__u8 opcode;        /* opcode always == VARIABLE_LENGTH_CMD */
 | 
			
		||||
+	__u8 control;
 | 
			
		||||
+	__u8 misc[5];
 | 
			
		||||
+	__u8 additional_cdb_length;         /* total cdb length - 8 */
 | 
			
		||||
 	__be16 service_action;
 | 
			
		||||
 	/* service specific data follows */
 | 
			
		||||
 };
 | 
			
		||||
@ -0,0 +1,17 @@
 | 
			
		||||
--- a/fs/Kconfig
 | 
			
		||||
+++ b/fs/Kconfig
 | 
			
		||||
@@ -44,6 +44,7 @@ source "fs/gfs2/Kconfig"
 | 
			
		||||
 source "fs/ocfs2/Kconfig"
 | 
			
		||||
 source "fs/btrfs/Kconfig"
 | 
			
		||||
 source "fs/nilfs2/Kconfig"
 | 
			
		||||
+source "fs/yaffs2/Kconfig"
 | 
			
		||||
 
 | 
			
		||||
 endif # BLOCK
 | 
			
		||||
 
 | 
			
		||||
--- a/fs/Makefile
 | 
			
		||||
+++ b/fs/Makefile
 | 
			
		||||
@@ -126,3 +126,4 @@ obj-$(CONFIG_OCFS2_FS)		+= ocfs2/
 | 
			
		||||
 obj-$(CONFIG_BTRFS_FS)		+= btrfs/
 | 
			
		||||
 obj-$(CONFIG_GFS2_FS)           += gfs2/
 | 
			
		||||
 obj-$(CONFIG_EXOFS_FS)          += exofs/
 | 
			
		||||
+obj-$(CONFIG_YAFFS_FS)		+= yaffs2/
 | 
			
		||||
							
								
								
									
										12344
									
								
								target/linux/generic-2.6/patches-2.6.32/511-yaffs-cvs-2009-04-24.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12344
									
								
								target/linux/generic-2.6/patches-2.6.32/511-yaffs-cvs-2009-04-24.patch
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -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
 | 
			
		||||
@@ -352,8 +396,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);
 | 
			
		||||
@@ -468,7 +512,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
 | 
			
		||||
@@ -489,6 +489,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);
 | 
			
		||||
@ -0,0 +1,24 @@
 | 
			
		||||
--- a/drivers/net/phy/Kconfig
 | 
			
		||||
+++ b/drivers/net/phy/Kconfig
 | 
			
		||||
@@ -88,6 +88,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
 | 
			
		||||
@@ -13,6 +13,7 @@ obj-$(CONFIG_VITESSE_PHY)	+= vitesse.o
 | 
			
		||||
 obj-$(CONFIG_BROADCOM_PHY)	+= broadcom.o
 | 
			
		||||
 obj-$(CONFIG_BCM63XX_PHY)	+= bcm63xx.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
 | 
			
		||||
@ -0,0 +1,63 @@
 | 
			
		||||
--- a/drivers/net/phy/phy_device.c
 | 
			
		||||
+++ b/drivers/net/phy/phy_device.c
 | 
			
		||||
@@ -146,6 +146,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;
 | 
			
		||||
@@ -175,6 +187,8 @@ struct phy_device* phy_device_create(str
 | 
			
		||||
 	dev_set_name(&dev->dev, PHY_ID_FMT, bus->id, addr);
 | 
			
		||||
 
 | 
			
		||||
 	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
 | 
			
		||||
@@ -325,6 +325,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
 | 
			
		||||
@@ -807,6 +807,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())
 | 
			
		||||
							
								
								
									
										25
									
								
								target/linux/generic-2.6/patches-2.6.32/650-swconfig.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								target/linux/generic-2.6/patches-2.6.32/650-swconfig.patch
									
									
									
									
									
										Normal 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
 | 
			
		||||
@ -0,0 +1,22 @@
 | 
			
		||||
--- a/drivers/net/phy/Kconfig
 | 
			
		||||
+++ b/drivers/net/phy/Kconfig
 | 
			
		||||
@@ -99,6 +99,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
 | 
			
		||||
@@ -15,6 +15,7 @@ obj-$(CONFIG_BROADCOM_PHY)	+= broadcom.o
 | 
			
		||||
 obj-$(CONFIG_BCM63XX_PHY)	+= bcm63xx.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
 | 
			
		||||
							
								
								
									
										23
									
								
								target/linux/generic-2.6/patches-2.6.32/670-phy_ip175c.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								target/linux/generic-2.6/patches-2.6.32/670-phy_ip175c.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
--- a/drivers/net/phy/Kconfig
 | 
			
		||||
+++ b/drivers/net/phy/Kconfig
 | 
			
		||||
@@ -102,6 +102,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
 | 
			
		||||
@@ -16,6 +16,7 @@ obj-$(CONFIG_BCM63XX_PHY)	+= bcm63xx.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
 | 
			
		||||
							
								
								
									
										23
									
								
								target/linux/generic-2.6/patches-2.6.32/680-phy_ar8216.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								target/linux/generic-2.6/patches-2.6.32/680-phy_ar8216.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
--- a/drivers/net/phy/Kconfig
 | 
			
		||||
+++ b/drivers/net/phy/Kconfig
 | 
			
		||||
@@ -106,6 +106,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
 | 
			
		||||
@@ -18,6 +18,7 @@ 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_AR8216_PHY)	+= ar8216.o
 | 
			
		||||
 obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
 | 
			
		||||
 obj-$(CONFIG_FIXED_PHY)		+= fixed.o
 | 
			
		||||
 obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
 | 
			
		||||
@ -0,0 +1,23 @@
 | 
			
		||||
--- a/drivers/net/phy/Kconfig
 | 
			
		||||
+++ b/drivers/net/phy/Kconfig
 | 
			
		||||
@@ -110,6 +110,10 @@ config AR8216_PHY
 | 
			
		||||
 	tristate "Driver for Atheros AR8216 switches"
 | 
			
		||||
 	select SWCONFIG
 | 
			
		||||
 
 | 
			
		||||
+config RTL8306_PHY
 | 
			
		||||
+	tristate "Driver for Realtek RTL8306S 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
 | 
			
		||||
@@ -19,6 +19,7 @@ obj-$(CONFIG_MVSWITCH_PHY)	+= mvswitch.o
 | 
			
		||||
 obj-$(CONFIG_IP175C_PHY)	+= ip175c.o
 | 
			
		||||
 obj-$(CONFIG_REALTEK_PHY)	+= realtek.o
 | 
			
		||||
 obj-$(CONFIG_AR8216_PHY)	+= ar8216.o
 | 
			
		||||
+obj-$(CONFIG_RTL8306_PHY)	+= rtl8306.o
 | 
			
		||||
 obj-$(CONFIG_LSI_ET1011C_PHY)	+= et1011c.o
 | 
			
		||||
 obj-$(CONFIG_FIXED_PHY)		+= fixed.o
 | 
			
		||||
 obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
 | 
			
		||||
							
								
								
									
										250
									
								
								target/linux/generic-2.6/patches-2.6.32/700-rtc7301.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										250
									
								
								target/linux/generic-2.6/patches-2.6.32/700-rtc7301.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,250 @@
 | 
			
		||||
--- a/drivers/rtc/Kconfig
 | 
			
		||||
+++ b/drivers/rtc/Kconfig
 | 
			
		||||
@@ -574,6 +574,15 @@ config RTC_DRV_AB3100
 | 
			
		||||
 	  support. This chip contains a battery- and capacitor-backed RTC.
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
+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
 | 
			
		||||
@@ -67,6 +67,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_RX8025)	+= rtc-rx8025.o
 | 
			
		||||
 obj-$(CONFIG_RTC_DRV_RX8581)	+= rtc-rx8581.o
 | 
			
		||||
 obj-$(CONFIG_RTC_DRV_S35390A)	+= rtc-s35390a.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);
 | 
			
		||||
@ -0,0 +1,21 @@
 | 
			
		||||
--- a/include/linux/fb.h
 | 
			
		||||
+++ b/include/linux/fb.h
 | 
			
		||||
@@ -124,6 +124,7 @@ struct dentry;
 | 
			
		||||
 #define FB_ACCEL_TRIDENT_BLADE3D 52	/* Trident Blade3D		*/
 | 
			
		||||
 #define FB_ACCEL_TRIDENT_BLADEXP 53	/* Trident BladeXP		*/
 | 
			
		||||
 #define FB_ACCEL_CIRRUS_ALPINE   53	/* Cirrus Logic 543x/544x/5480	*/
 | 
			
		||||
+#define FB_ACCEL_GLAMO		50	/* SMedia Glamo                 */
 | 
			
		||||
 #define FB_ACCEL_NEOMAGIC_NM2070 90	/* NeoMagic NM2070              */
 | 
			
		||||
 #define FB_ACCEL_NEOMAGIC_NM2090 91	/* NeoMagic NM2090              */
 | 
			
		||||
 #define FB_ACCEL_NEOMAGIC_NM2093 92	/* NeoMagic NM2093              */
 | 
			
		||||
--- a/include/linux/Kbuild
 | 
			
		||||
+++ b/include/linux/Kbuild
 | 
			
		||||
@@ -76,6 +76,8 @@ header-y += genetlink.h
 | 
			
		||||
 header-y += gen_stats.h
 | 
			
		||||
 header-y += gfs2_ondisk.h
 | 
			
		||||
 header-y += gigaset_dev.h
 | 
			
		||||
+header-y += glamofb.h
 | 
			
		||||
+header-y += glamo-engine.h
 | 
			
		||||
 header-y += hysdn_if.h
 | 
			
		||||
 header-y += i2o-dev.h
 | 
			
		||||
 header-y += i8k.h
 | 
			
		||||
@ -0,0 +1,25 @@
 | 
			
		||||
--- a/drivers/usb/serial/usb-serial.c
 | 
			
		||||
+++ b/drivers/usb/serial/usb-serial.c
 | 
			
		||||
@@ -61,6 +61,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];
 | 
			
		||||
@@ -942,7 +943,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);
 | 
			
		||||
@@ -1386,3 +1387,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");
 | 
			
		||||
@ -0,0 +1,11 @@
 | 
			
		||||
--- a/init/main.c
 | 
			
		||||
+++ b/init/main.c
 | 
			
		||||
@@ -819,7 +819,7 @@ static noinline int init_post(void)
 | 
			
		||||
 	printk(KERN_INFO"Running BFS CPU scheduler v0.302 by Con Kolivas.\n");
 | 
			
		||||
 
 | 
			
		||||
 	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);
 | 
			
		||||
@ -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
 | 
			
		||||
 
 | 
			
		||||
 #ifndef ARRAY_SIZE
 | 
			
		||||
 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
 | 
			
		||||
--- a/scripts/kconfig/Makefile
 | 
			
		||||
+++ b/scripts/kconfig/Makefile
 | 
			
		||||
@@ -129,6 +129,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>
 | 
			
		||||
+#if !(defined(__APPLE__) || defined(__CYGWIN__))
 | 
			
		||||
 #include <elf.h>
 | 
			
		||||
+#else
 | 
			
		||||
+#include "../../../../../tools/sstrip/include/elf.h"
 | 
			
		||||
+#endif
 | 
			
		||||
 
 | 
			
		||||
 #include "elfconfig.h"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										154
									
								
								target/linux/generic-2.6/patches-2.6.32/903-hostap_txpower.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								target/linux/generic-2.6/patches-2.6.32/903-hostap_txpower.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,154 @@
 | 
			
		||||
--- a/drivers/net/wireless/hostap/hostap_ap.c
 | 
			
		||||
+++ b/drivers/net/wireless/hostap/hostap_ap.c
 | 
			
		||||
@@ -2335,13 +2335,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;
 | 
			
		||||
@@ -2407,13 +2407,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
 | 
			
		||||
@@ -932,6 +932,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
 | 
			
		||||
@@ -432,6 +432,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
 | 
			
		||||
@@ -1476,23 +1476,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;
 | 
			
		||||
 }
 | 
			
		||||
@@ -4056,3 +4053,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);
 | 
			
		||||
@ -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
 | 
			
		||||
							
								
								
									
										10
									
								
								target/linux/generic-2.6/patches-2.6.32/905-i386_build.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								target/linux/generic-2.6/patches-2.6.32/905-i386_build.patch
									
									
									
									
									
										Normal 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>
 | 
			
		||||
@ -0,0 +1,60 @@
 | 
			
		||||
Fix spi-gpio for hotplug.
 | 
			
		||||
 | 
			
		||||
--mb
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--- a/drivers/spi/spi_gpio.c
 | 
			
		||||
+++ b/drivers/spi/spi_gpio.c
 | 
			
		||||
@@ -218,7 +218,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;
 | 
			
		||||
 
 | 
			
		||||
@@ -232,7 +232,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;
 | 
			
		||||
@@ -261,7 +261,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;
 | 
			
		||||
@@ -317,7 +317,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;
 | 
			
		||||
@@ -344,12 +344,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);
 | 
			
		||||
 
 | 
			
		||||
@ -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>
 | 
			
		||||
@ -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 i.MX SPI controllers"
 | 
			
		||||
 	depends on ARCH_MXC
 | 
			
		||||
--- 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
 | 
			
		||||
							
								
								
									
										843
									
								
								target/linux/generic-2.6/patches-2.6.32/922-gpiommc.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										843
									
								
								target/linux/generic-2.6/patches-2.6.32/922-gpiommc.patch
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,843 @@
 | 
			
		||||
--- /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
 | 
			
		||||
@@ -334,6 +334,31 @@ config MMC_TMIO
 | 
			
		||||
 	  This provides support for the SD/MMC cell found in TC6393XB,
 | 
			
		||||
 	  T7L66XB and also HTC 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.
 | 
			
		||||
+
 | 
			
		||||
 config MMC_CB710
 | 
			
		||||
 	tristate "ENE CB710 MMC/SD Interface support"
 | 
			
		||||
 	depends on PCI
 | 
			
		||||
--- a/drivers/mmc/host/Makefile
 | 
			
		||||
+++ b/drivers/mmc/host/Makefile
 | 
			
		||||
@@ -34,6 +34,7 @@ obj-$(CONFIG_MMC_SDRICOH_CS)	+= sdricoh_
 | 
			
		||||
 obj-$(CONFIG_MMC_TMIO)		+= tmio_mmc.o
 | 
			
		||||
 obj-$(CONFIG_MMC_CB710)	+= cb710-mmc.o
 | 
			
		||||
 obj-$(CONFIG_MMC_VIA_SDMMC)	+= via-sdmmc.o
 | 
			
		||||
+obj-$(CONFIG_GPIOMMC)		+= gpiommc.o
 | 
			
		||||
 
 | 
			
		||||
 ifeq ($(CONFIG_CB710_DEBUG),y)
 | 
			
		||||
 	CFLAGS-cb710-mmc	+= -DDEBUG
 | 
			
		||||
--- /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
 | 
			
		||||
@@ -2354,6 +2354,11 @@ T:	git git://git.kernel.org/pub/scm/linu
 | 
			
		||||
 S:	Maintained
 | 
			
		||||
 F:	drivers/media/video/gspca/
 | 
			
		||||
 
 | 
			
		||||
+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/
 | 
			
		||||
@ -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);
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user