mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 3/3] kconfig: linux.pot for all arch
@ 2005-07-10 20:01 Egry Gábor
  2005-08-08  9:12 ` [PATCH] spi dmitry pervushin
  0 siblings, 1 reply; 15+ messages in thread
From: Egry Gábor @ 2005-07-10 20:01 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Linux Kernel Mailing List, Arnaldo Carvalho de Melo


The 'make update-po-config' creates the .pot file for the
default arch. This patch enhances it with all arch.

Signed-off-by: Egry Gabor <gaboregry@t-online.hu>

---

 Makefile |   16 ++++++++++++++--
 1 files changed, 14 insertions(+), 2 deletions(-)

diff -Nru linux-2.6.13-rc2/scripts/kconfig/Makefile
linux-2.6.13-rc2-i18n-kconfig/scripts/kconfig/Makefile
--- linux-2.6.13-rc2/scripts/kconfig/Makefile	2005-07-09
12:16:04.000000000 +0200
+++ linux-2.6.13-rc2-i18n-kconfig/scripts/kconfig/Makefile	2005-07-10
21:13:00.000000000 +0200
@@ -27,8 +27,20 @@
 	xgettext --default-domain=linux \
           --add-comments --keyword=_ --keyword=N_ \
           --files-from=scripts/kconfig/POTFILES.in \
-	-o scripts/kconfig/linux.pot
-	scripts/kconfig/kxgettext arch/$(ARCH)/Kconfig >>
scripts/kconfig/linux.pot
+          --output scripts/kconfig/config.pot
+	$(Q)ln -fs Kconfig_i386 arch/um/Kconfig_arch
+	$(Q)for i in `ls arch/`; \
+	do \
+	  scripts/kconfig/kxgettext arch/$$i/Kconfig \
+	    | msguniq -o scripts/kconfig/linux_$${i}.pot; \
+	done
+	$(Q)msgcat scripts/kconfig/config.pot \
+	  `find scripts/kconfig/ -type f -name linux_*.pot` \
+	  --output scripts/kconfig/linux_raw.pot
+	$(Q)msguniq --sort-by-file scripts/kconfig/linux_raw.pot \
+	    --output scripts/kconfig/linux.pot
+	$(Q)rm -f arch/um/Kconfig_arch
+	$(Q)rm -f scripts/kconfig/linux_*.pot scripts/kconfig/config.pot
 
 .PHONY: randconfig allyesconfig allnoconfig allmodconfig defconfig
 



^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH] spi
  2005-07-10 20:01 [PATCH 3/3] kconfig: linux.pot for all arch Egry Gábor
@ 2005-08-08  9:12 ` dmitry pervushin
  2005-08-08 10:41   ` Jiri Slaby
                     ` (4 more replies)
  0 siblings, 5 replies; 15+ messages in thread
From: dmitry pervushin @ 2005-08-08  9:12 UTC (permalink / raw)
  To: Linux Kernel Mailing List

Hello all, 


Here is the spi core patch (slightly redesigned again). Now it operates
with three abstractions:
a) the spi bus, which is registered in system and is resposible for
general things like registering devices on it, handling PM events for
entire bus, providing bus-wide operations;
b) the spi device, which is responsible for interactions between the
device and the bus (selecting/deselecting device) and PM events for the
specifi device;
c) the driver, which is attached to spi devices and (possibly) provide
interface to the upper level like block device interface. The spi-dev is
the good starting point for people who does not want anything but simple
character device access.
The new abstraction is the spi bus, which functionality was represented
by spi_device structure.

Especially for Greg K-H: yes, I ran this code through sparse :), thank
you.

Signed-off-by: dmitry pervushin <dpervushin@gmail.com>

Kernel-version: 2.6.12

This patch is to provide SPI support on linux

 drivers/Kconfig          |    2
 drivers/Makefile         |    1
 drivers/spi/Kconfig      |   33 ++++
 drivers/spi/Makefile     |   12 +
 drivers/spi/spi-core.c   |  327 +++++++++++++++++++++++++++++++++++++++++++++++ 
 drivers/spi/spi-dev.c    |  303 +++++++++++++++++++++++++++++++++++++++++++
 drivers/spi/spi_locals.h |   10 +
 include/linux/spi.h      |  148 +++++++++++++++++++++
 8 files changed, 836 insertions(+)

Index: linux-2.6.10/drivers/Kconfig
===================================================================
--- linux-2.6.10.orig/drivers/Kconfig	2005-07-15 06:56:55.000000000 +0000
+++ linux-2.6.10/drivers/Kconfig	2005-07-15 06:57:39.000000000 +0000
@@ -42,6 +42,8 @@
 
 source "drivers/i2c/Kconfig"
 
+source "drivers/spi/Kconfig"
+
 source "drivers/w1/Kconfig"
 
 source "drivers/misc/Kconfig"
Index: linux-2.6.10/drivers/Makefile
===================================================================
--- linux-2.6.10.orig/drivers/Makefile	2005-07-15 06:57:21.000000000 +0000
+++ linux-2.6.10/drivers/Makefile	2005-07-15 06:59:04.000000000 +0000
@@ -67,1 +67,2 @@
 obj-$(CONFIG_MMC)		+= mmc/
+obj-$(CONFIG_SPI)               += spi/
Index: linux-2.6.10/drivers/spi/Kconfig
===================================================================
--- linux-2.6.10.orig/drivers/spi/Kconfig	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.10/drivers/spi/Kconfig	2005-07-15 06:57:39.000000000 +0000
@@ -0,0 +1,33 @@
+#
+# SPI device configuration
+#
+menu "SPI support"
+
+config SPI
+	default Y
+	tristate "SPI support"
+        default false
+	help
+	  Say Y if you need to enable SPI support on your kernel
+
+config SPI_DEBUG
+	bool "SPI debug output" 
+	depends on SPI 
+	default false 
+	help 
+          Say Y there if you'd like to see debug output from SPI drivers.
+	  If unsure, say N
+	
+config SPI_CHARDEV
+	default Y
+	tristate "SPI device interface"
+	depends on SPI
+	help
+	  Say Y here to use spi-* device files, usually found in the /dev
+	  directory on your system.  They make it possible to have user-space
+	  programs use the SPI bus. 
+	  This support is also available as a module.  If so, the module 
+	  will be called spi-dev.
+
+endmenu
+
Index: linux-2.6.10/drivers/spi/Makefile
===================================================================
--- linux-2.6.10.orig/drivers/spi/Makefile	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.10/drivers/spi/Makefile	2005-07-15 06:57:39.000000000 +0000
@@ -0,0 +1,12 @@
+#
+# Makefile for the kernel spi bus driver.
+#
+
+obj-$(CONFIG_SPI) += spi-core.o helpers.o
+
+obj-$(CONFIG_SPI_CHARDEV) += spi-dev.o
+
+ifeq ($(CONFIG_SPI_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
+
Index: linux-2.6.10/drivers/spi/spi-core.c
===================================================================
--- linux-2.6.10.orig/drivers/spi/spi-core.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.10/drivers/spi/spi-core.c	2005-07-15 06:57:39.000000000 +0000
@@ -0,0 +1,327 @@
+/*
+ *  linux/drivers/spi/spi-core.c
+ *
+ *  Copyright (C) 2005 MontaVista Software
+ *  Author: dmitry pervushin <dpervushin@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/proc_fs.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
+
+#include <linux/spi.h>
+
+#include "spi_locals.h"
+
+static LIST_HEAD( spi_busses );
+
+int spi_bus_match(struct device *dev, struct device_driver *driver)
+{
+	struct spi_driver *spidrv = SPI_DRV(driver);
+	struct spi_device *spidev = SPI_DEV(dev);
+	char **id;
+	int found = 0;
+
+	if (NULL == dev || NULL == driver) {
+		printk(KERN_ERR
+		       "%s: error - both dev and driver should not be NULL !\n",
+		       __FUNCTION__);
+		found = 0;
+		goto spi_match_done;
+	}
+
+	if (NULL == spidrv->supported_ids) {
+		printk
+		    ("%s: driver has no ids of devices to support, assuming ALL\n",
+		     __FUNCTION__);
+		found = 1;
+		goto spi_match_done;
+	}
+
+	id = *spidrv->supported_ids;
+	while (*id) {
+		pr_debug
+		    ("Verifying driver's supported id of '%s' against '%s'\n",
+		     *id, spidev->dev.bus_id);
+		if (0 == strncmp(*id, SPI_ID_ANY, strlen(SPI_ID_ANY))) {
+			pr_debug
+			    ("The driver (%p) can be attached to any device (%p)\n",
+			     driver, dev);
+			found = 1;
+			goto spi_match_done;
+		}
+		if (0 == strcmp(*id, spidev->dev.bus_id)) {
+			pr_debug("Done, driver (%p) match the device '%p'\n",
+				 driver, dev);
+			found = 1;
+			goto spi_match_done;
+		}
+		++id;
+	}
+
+	pr_debug("%s: no match\n ", __FUNCTION__);
+	found = 0;
+spi_match_done:	
+	return found;
+}
+
+int spi_bus_register( struct spi_bus* bus, char* name )
+{
+	int err = -EINVAL;
+	static int count = 0;
+	char busname[ BUS_ID_SIZE ];
+	char fullname[ BUS_ID_SIZE ];
+
+	ENTER();	
+	if( bus ) {
+		init_MUTEX( &bus->lock );
+
+		bus->platform_device.name = NULL;
+		bus->the_bus.name = NULL;
+
+		strncpy( busname, name ? name : "SPI", sizeof( busname ) );
+		bus->platform_device.id = count++ % 100;
+		sprintf( fullname, "%s_%02d", busname, bus->platform_device.id);
+		bus->the_bus.name = kmalloc( strlen( fullname )+1, GFP_KERNEL );
+		if( bus->the_bus.name ) {
+			strcpy( bus->the_bus.name, fullname );
+		}
+
+		err = bus_register( &bus->the_bus );
+		if( err ) {
+			goto out;
+		}
+		list_add_tail( &bus->bus_list, &spi_busses );
+		bus->platform_device.name = kmalloc( strlen( busname )+1, GFP_KERNEL );
+		if( bus->platform_device.name ) {
+			strcpy( bus->platform_device.name, busname );
+		}
+		err = platform_device_register( &bus->platform_device );
+	}
+out:
+	if( err ) {
+		if( bus->the_bus.name ) {
+			kfree( bus->the_bus.name );
+		}
+		if( bus->platform_device.name ) {
+			kfree( bus->platform_device.name );
+		}
+		/* TODO: platform_device_unregister */
+	}
+	return err;
+}
+
+void spi_bus_unregister( struct spi_bus* bus )
+{
+	if( bus ) {
+		platform_device_unregister( &bus->platform_device );
+		if( bus->platform_device.name ) {
+			kfree( bus->platform_device.name );
+		}
+		bus_unregister( &bus->the_bus );
+		if( bus->the_bus.name ) {
+			kfree( bus->the_bus.name );
+		}
+		list_del_init( &bus->bus_list );
+	}
+}
+
+/**
+ * spi_add_adapter - register a new SPI bus adapter
+ * @spidev: spi_device structure for the registering adapter
+ *
+ * Make the adapter available for use by clients using name adap->name.
+ * The adap->adapters list is initialised by this function.
+ *
+ * Returns error code ( 0 on success ) ;
+ */
+struct spi_bus* spi_bus_find( char* id )
+{
+	struct bus_type* the_bus = find_bus( id );
+
+	return the_bus ? container_of( the_bus, struct spi_bus, the_bus ) : NULL;
+}
+
+EXPORT_SYMBOL( spi_bus_find );
+int spi_device_add( struct spi_bus* bus, struct spi_device *dev, char* name)
+{
+	int err;
+
+	memset(&dev->dev, 0, sizeof(dev->dev));
+
+	if (dev->dev.parent == NULL)
+		dev->dev.parent = &platform_bus;
+	if( name ) {
+		strncpy( dev->dev.bus_id, name, sizeof( dev->dev.bus_id ) );
+	} else {
+		snprintf( dev->dev.bus_id, sizeof( dev->dev.bus_id ), "DEV%p_%s", dev, bus->the_bus.name );
+	}
+	dev->dev.bus = &bus->the_bus;
+	init_MUTEX( &dev->lock );
+
+	err = device_register(&dev->dev);
+	pr_debug("device_register (%p) status = %d\n", &dev->dev, err);
+	return err;
+}
+
+/**
+ * spi_del_adapter - unregister a SPI bus adapter
+ * @dev: spi_device structure to unregister
+ *
+ * Remove an adapter from the list of available SPI Bus adapters.
+ *
+ * Returns error code (0 on success);
+ */
+
+void spi_device_del(struct spi_device *dev)
+{
+	device_unregister(&dev->dev);
+}
+
+int spi_do_probe( struct device* dev, void* device_driver )
+{
+	struct device_driver* drv = device_driver;
+	
+	if( dev->bus->match && !dev->bus->match( dev, drv ) ) {
+		goto do_probe_out;
+	}
+	if( drv->probe ) {
+		if( 0 == drv->probe( dev ) ) {
+			dev->driver = drv;
+			device_bind_driver( dev );
+		}	
+	}
+do_probe_out:	
+	return 0;
+}
+int spi_driver_add( struct spi_driver* drv )
+{
+	int err;
+	struct list_head* entry;
+       
+	err = driver_register( &drv->driver );
+	if( err ) {
+		goto out;
+	}
+
+	err = kobject_set_name(&drv->driver.kobj, "%s", drv->driver.name);
+	if( err ) {
+		goto out;
+	}
+	err = kobject_register(&drv->driver.kobj);
+	if( err ) {
+		goto out;
+	}
+	list_for_each( entry, &spi_busses ) {
+		struct spi_bus* bus = container_of( entry, struct spi_bus, bus_list );
+		bus_for_each_dev( &bus->the_bus, NULL, &drv->driver, spi_do_probe );
+	}
+	module_add_driver( drv->driver.owner, &drv->driver );
+out:
+	return err;	
+}
+
+void spi_driver_del( struct spi_driver* drv )
+{
+	driver_unregister( &drv->driver );
+}
+/**
+ * spi_transfer - transfer information on an SPI bus
+ * @adap: adapter structure to perform transfer on
+ * @msgs: array of spi_msg structures describing transfer
+ * @num: number of spi_msg structures
+ *
+ * Transfer the specified messages to/from a device on the SPI bus.
+ *
+ * Returns number of messages successfully transferred, otherwise negative
+ * error code.
+ */
+int spi_transfer(struct spi_device *dev, struct spi_msg msgs[], int num)
+{
+	int ret = -ENOSYS;
+	struct spi_bus* bus;
+
+	bus = TO_SPI_BUS( dev->dev.bus );
+
+	if (bus->xfer) {
+		down( &dev->lock );
+		ret = bus->xfer(bus, dev, msgs, num, 0);
+		up(&dev->lock);
+	}
+	return ret;
+}
+
+/**
+ * spi_write - send data to a device on an SPI bus
+ * @client: registered client structure
+ * @addr: SPI bus address
+ * @buf: buffer for bytes to send
+ * @len: number of bytes to send
+ *
+ * Send len bytes pointed to by buf to device address addr on the SPI bus
+ * described by client.
+ *
+ * Returns the number of bytes transferred, or negative error code.
+ */
+int spi_write(struct spi_device *dev, int addr, const char *buf, int len)
+{
+	struct spi_msg msg;
+	int ret;
+
+	msg.addr = addr;
+	msg.flags = 0;
+	msg.buf = (char *)buf;
+	msg.len = len;
+
+	ret = spi_transfer(dev, &msg, 1);
+	return ret == 1 ? len : ret;
+}
+
+/**
+ * spi_read - receive data from a device on an SPI bus
+ * @client: registered client structure
+ * @addr: SPI bus address
+ * @buf: buffer for bytes to receive
+ * @len: number of bytes to receive
+ *
+ * Receive len bytes from device address addr on the SPI bus described by
+ * client to a buffer pointed to by buf.
+ *
+ * Returns the number of bytes transferred, or negative error code.
+ */
+int spi_read(struct spi_device *dev, int addr, char *buf, int len)
+{
+	struct spi_msg msg;
+	int ret;
+
+	msg.addr = addr;
+	msg.flags = SPI_M_RD;
+	msg.buf = buf;
+	msg.len = len;
+
+	ret = spi_transfer(dev, &msg, 1);
+	return ret == 1 ? len : ret;
+}
+
+MODULE_LICENSE( "GPL" );
+MODULE_AUTHOR( "dmitry pervushin <dpervushin@ru.mvista.com>" );
+
+EXPORT_SYMBOL_GPL(spi_driver_add);
+EXPORT_SYMBOL_GPL(spi_driver_del);
+EXPORT_SYMBOL_GPL(spi_device_add);
+EXPORT_SYMBOL_GPL(spi_device_del);
+EXPORT_SYMBOL_GPL(spi_bus_match);
+EXPORT_SYMBOL_GPL(spi_transfer);
+EXPORT_SYMBOL_GPL(spi_write);
+EXPORT_SYMBOL_GPL(spi_read);
Index: linux-2.6.10/drivers/spi/spi-dev.c
===================================================================
--- linux-2.6.10.orig/drivers/spi/spi-dev.c	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.10/drivers/spi/spi-dev.c	2005-07-15 06:57:39.000000000 +0000
@@ -0,0 +1,303 @@
+/*#ifdef CONFIG_DEVFS_FS	
+
+    spi-dev.c - spi-bus driver, char device interface  
+
+    Copyright (C) 2005 MontaVista Software
+    Author: dmitry pervushin <dpervushin@ru.mvista.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* Adapted from i2c-dev module by Jamey Hicks <jamey.hicks@compaq.com> */
+
+/* Note that this is a complete rewrite of Simon Vogl's i2c-dev module.
+   But I have used so much of his original code and ideas that it seems
+   only fair to recognize him as co-author -- Frodo */
+
+/* The devfs code is contributed by Philipp Matthias Hahn 
+   <pmhahn@titan.lahn.de> */
+
+/* Modifications to allow work with current spi-core by 
+   Andrey Ivolgin <aivolgin@ru.mvista.com>, Sep 2004
+ */
+
+/* devfs code corrected to support automatic device addition/deletion
+   by Vitaly Wool <vwool@ru.mvista.com> (C) 2004 MontaVista Software, Inc. 
+ */
+
+/* $Id: common_spi_core-2.patch,v 1.1.2.6 2005/07/15 07:24:40 tpoynor Exp $ */
+
+#include <linux/init.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/smp_lock.h>
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/spi.h>
+#include "spi_locals.h"
+
+#define SPI_TRANSFER_MAX	65535
+
+/* struct file_operations changed too often in the 2.1 series for nice code */
+
+static ssize_t spidev_read(struct file *file, char *buf, size_t count,
+			   loff_t * offset);
+static ssize_t spidev_write(struct file *file, const char *buf, size_t count,
+			    loff_t * offset);
+
+static int spidev_open(struct inode *inode, struct file *file);
+static int spidev_release(struct inode *inode, struct file *file);
+static int __init spidev_init(void);
+
+static void spidev_cleanup(void);
+
+static int spidev_probe(struct device *dev);
+static int spidev_remove(struct device *dev);
+
+static struct file_operations spidev_fops = {
+	.owner = THIS_MODULE,
+	.llseek = no_llseek,
+	.read = spidev_read,
+	.write = spidev_write,
+	.open = spidev_open,
+	.release = spidev_release,
+};
+
+static struct class_simple *spidev_class;
+
+static struct spi_driver spidev_driver = {
+	.owner = THIS_MODULE,
+	.driver = {
+		   .name = "generic_spi",
+		   .probe = spidev_probe,
+		   .remove = spidev_remove,
+		   },
+	.supported_ids = NULL,
+	.minor = 0,
+};
+
+static int spidev_probe(struct device *dev)
+{
+	struct spidev_driver_data *drvdata;
+
+	if (NULL == dev) {
+		printk(KERN_ERR "%s: probing the NULL device!\n", __FUNCTION__);
+		return -EFAULT;
+	}
+
+	drvdata = kmalloc(sizeof(struct spidev_driver_data), GFP_KERNEL);
+	if (NULL == drvdata) {
+		pr_debug("%s: allocating drvdata failed\n", __FUNCTION__);
+		return -ENOMEM;
+	}
+
+	drvdata->minor = spidev_driver.minor++;
+	pr_debug("%s: setting device's(%p) minor to %d\n",
+		 __FUNCTION__, dev, drvdata->minor);
+	dev_set_drvdata(dev, drvdata);
+
+	class_simple_device_add( spidev_class, 
+			 MKDEV( SPI_MAJOR, drvdata->minor ),
+		         NULL, "spi%d", drvdata->minor );
+
+	pr_debug("%s: Registered as minor %d\n", __FUNCTION__, drvdata->minor);
+	return 0;
+}
+
+static int spidev_remove(struct device *dev)
+{
+	struct spidev_driver_data *drvdata;
+
+	if (NULL == dev) {
+		printk(KERN_ERR "%s: removing the NULL device\n", __FUNCTION__);
+	}
+
+	drvdata = (struct spidev_driver_data *) dev_get_drvdata(dev);
+	if (NULL == drvdata) {
+		pr_debug("%s: oops, drvdata is NULL !\n", __FUNCTION__);
+		return -ENODEV;
+	}
+	class_simple_device_remove( MKDEV( SPI_MAJOR, drvdata->minor ) );
+	kfree(drvdata);
+	pr_debug("%s: device removed\n", __FUNCTION__);
+	return 0;
+}
+
+static ssize_t spidev_read(struct file *file, char *buf, size_t count,
+			   loff_t * offset)
+{
+	char *tmp;
+	int ret;
+	struct spi_device *dev = (struct spi_device *)file->private_data;
+	unsigned long (*cpy_to_user) (void *to_user, const void *from,
+				      unsigned long len);
+	void *(*alloc) (size_t, int);
+	void (*free) (const void *);
+
+	if (count > SPI_TRANSFER_MAX)
+		count = SPI_TRANSFER_MAX;
+
+	cpy_to_user = dev->copy_to_user ? dev->copy_to_user : copy_to_user;
+	alloc = dev->alloc ? dev->alloc : kmalloc;
+	free = dev->free ? dev->free : kfree;
+
+	/* copy user space data to kernel space. */
+	tmp = alloc(count, GFP_KERNEL);
+	if (tmp == NULL)
+		return -ENOMEM;
+
+	ret = spi_read( dev, 0, tmp, count);
+	if (ret >= 0)
+		ret = cpy_to_user(buf, tmp, count) ? -EFAULT : ret;
+	free(tmp);
+	return ret;
+}
+
+static ssize_t spidev_write(struct file *file, const char *buf, size_t count,
+			    loff_t * offset)
+{
+	int ret;
+	char *tmp;
+	struct spi_device *dev = (struct spi_device *)file->private_data;
+	unsigned long (*cpy_from_user) (void *to, const void *from_user,
+					unsigned long len);
+	void *(*alloc) (size_t, int);
+	void (*free) (const void *);
+
+	if (count > SPI_TRANSFER_MAX)
+		count = SPI_TRANSFER_MAX;
+
+	cpy_from_user =
+	    dev->copy_from_user ? dev->copy_from_user : copy_from_user;
+	alloc = dev->alloc ? dev->alloc : kmalloc;
+	free = dev->free ? dev->free : kfree;
+
+	/* copy user space data to kernel space. */
+	tmp = alloc(count, GFP_KERNEL);
+	if (tmp == NULL)
+		return -ENOMEM;
+
+	if (cpy_from_user(tmp, buf, count)) {
+		free(tmp);
+		return -EFAULT;
+	}
+
+	pr_debug("spi-%d writing %d bytes.\n", MINOR(file->f_dentry->d_inode->i_rdev), count);
+	ret = spi_write( dev, 0, tmp, count);
+	free(tmp);
+	return ret;
+}
+
+struct spidev_openclose {
+	unsigned int minor;
+	struct file *file;
+};
+
+static int spidev_do_open(struct device *the_dev, void *context)
+{
+	struct spidev_openclose *o = (struct spidev_openclose *) context;
+	struct spi_device *dev = SPI_DEV(the_dev);
+	struct spidev_driver_data *drvdata;
+
+	drvdata = (struct spidev_driver_data *) dev_get_drvdata(the_dev);
+	if (NULL == drvdata) {
+		pr_debug("%s: oops, drvdata is NULL !\n", __FUNCTION__);
+		return 0;
+	}
+
+	pr_debug("drvdata->minor = %d vs %d\n", drvdata->minor, o->minor);
+	if (drvdata->minor == o->minor) {
+		get_device(&dev->dev);
+		o->file->private_data = dev;
+		return 1;
+	}
+	return 0;
+}
+
+int spidev_open(struct inode *inode, struct file *file)
+{
+	struct spidev_openclose o;
+	int status;
+
+	o.minor = iminor(inode);
+	o.file = file;
+	status = driver_for_each_dev(&spidev_driver.driver, &o, spidev_do_open);
+	if (status == 0) {
+		status = -ENODEV;
+	}
+	return status < 0 ? status : 0;
+}
+
+static int spidev_release(struct inode *inode, struct file *file)
+{
+	struct spi_device *dev = file->private_data;
+
+	if (dev) {
+		put_device(&dev->dev);
+	}
+	file->private_data = NULL;
+
+	return 0;
+}
+
+static int __init spidev_init(void)
+{
+	int res;
+
+	if (0 != (res = register_chrdev(SPI_MAJOR, "spi", &spidev_fops))) {
+		goto out;
+	}
+
+	spidev_class = class_simple_create(THIS_MODULE, "spi" );
+	if ( IS_ERR( spidev_class)) {
+		printk( KERN_ERR"%s: error creating class\n", __FUNCTION__ );
+		res = -EINVAL;
+		goto out_unreg;
+	}
+
+	if (0 != (res = spi_driver_add(&spidev_driver))) {
+		goto out_unreg;
+	}
+	
+	printk( "SPI /dev entries driver.\n" );
+
+	return 0;
+
+      out_unreg:
+	unregister_chrdev(SPI_MAJOR, "spi");
+      out:
+	printk(KERN_ERR "%s: Driver initialization failed\n", __FILE__);
+	return res;
+}
+
+static void spidev_cleanup(void)
+{
+	spi_driver_del(&spidev_driver);
+	class_simple_destroy( spidev_class );
+	unregister_chrdev(SPI_MAJOR, "spi");
+}
+
+MODULE_AUTHOR( "dmitry pervushin <dpervushin@ru.mvista.com>" );
+MODULE_DESCRIPTION("SPI /dev entries driver");
+MODULE_LICENSE("GPL");
+
+module_init(spidev_init);
+module_exit(spidev_cleanup);
Index: linux-2.6.10/drivers/spi/spi_locals.h
===================================================================
--- linux-2.6.10.orig/drivers/spi/spi_locals.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.10/drivers/spi/spi_locals.h	2005-07-15 06:57:39.000000000 +0000
@@ -0,0 +1,10 @@
+#ifndef __SPI_LOCAL_H
+#define __SPI_LOCAL_H
+
+#define SPI_DRV( n ) container_of( n, struct spi_driver, driver )
+#define SPI_DEV( n ) container_of( n, struct spi_device, dev )
+
+#define ENTER() pr_debug( "%s: ENTERed\n", __FUNCTION__ )
+#define LEAVE() pr_debug( "%s: LEFT OUT\n", __FUNCTION__ )
+
+#endif				/* __SPI_LOCAL_H */
Index: linux-2.6.10/include/linux/spi.h
===================================================================
--- linux-2.6.10.orig/include/linux/spi.h	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.10/include/linux/spi.h	2005-07-15 06:57:39.000000000 +0000
@@ -0,0 +1,148 @@
+/*
+ *  linux/include/linux/spi/spi.h
+ *
+ *  Copyright (C) 2005 MontaVista Software
+ *  Author: dmitry pervushin <dpervushin@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * Derived from l3.h by Jamey Hicks
+ */
+#ifndef SPI_H
+#define SPI_H
+
+#include <linux/types.h>
+
+struct spi_msg {
+	unsigned char addr;	/* slave address        */
+	unsigned char flags;
+#define SPI_M_RD	0x01
+#define SPI_M_WR	0x02	/**< Write mode flag */
+#define SPI_M_CSREL	0x04	/**< CS release level at end of the frame  */
+#define SPI_M_CS	0x08	/**< CS active level at begining of frame ( default low ) */
+#define SPI_M_CPOL	0x10	/**< Clock polarity */
+#define SPI_M_CPHA	0x20	/**< Clock Phase */
+#define SPI_M_NOADDR	0x80
+
+	unsigned short len;	/* msg length           */
+	unsigned char *buf;	/* pointer to msg data  */
+	unsigned long clock;
+};
+
+
+#define SPI_MAJOR	98
+
+struct spi_driver;
+struct spi_device;
+struct spi_bus;
+
+int spi_bus_register( struct spi_bus*, char* name );
+void spi_bus_unregister( struct spi_bus* );
+struct spi_bus* spi_bus_find( char* id );
+
+int spi_device_add( struct spi_bus*, struct spi_device*, char* name );
+void spi_device_del( struct spi_device* );
+
+int spi_driver_add( struct spi_driver* );
+void spi_driver_del( struct spi_driver* );
+
+struct spi_ops {
+	int (*open) (struct spi_driver *);
+	int (*command) (struct spi_driver *, int cmd, void *arg);
+	void (*close) (struct spi_driver *);
+};
+
+#define SPI_ID_ANY "* ANY *"
+
+struct spi_driver {
+	struct spi_ops *ops;
+	struct module *owner;
+	struct device_driver driver;
+	unsigned int minor;
+	char *(*supported_ids)[];
+};
+
+#define TO_SPI_BUS( bus ) container_of( bus, struct spi_bus, the_bus )
+#define TO_SPI_BUS_PLDEV( dev ) container_of( dev, struct spi_bus, platform_device )
+struct spi_bus
+{
+	struct bus_type the_bus;
+	struct platform_device platform_device;
+	struct list_head bus_list;
+	struct semaphore lock;
+	int (*xfer)( struct spi_bus* this, struct spi_device* device, struct spi_msg msgs[], int num, int flags );
+	int (*chip_cs)( int op, void* context );
+	struct resource *rsrc;
+};
+
+#define SPI_DEVICE( dev ) container_of( dev, struct spi_device, dev )
+struct spi_device {
+
+	void* bus_data;
+	void* drv_data;
+
+	struct semaphore lock;
+
+	void (*select)( int op, struct spi_device* this );
+
+	void *(*alloc) (size_t, int);
+	void (*free) (const void *);
+	unsigned long (*copy_from_user) (void *to, const void *from_user,
+					 unsigned long len);
+	unsigned long (*copy_to_user) (void *to_user, const void *from,
+				       unsigned long len);
+	
+	struct device dev;
+};
+
+struct spidev_driver_data {
+	unsigned int minor;
+	void *private_data;
+};
+
+/**
+ * spi_command - send a command to a SPI device driver
+ * @client: registered client structure
+ * @cmd: device driver command
+ * @arg: device driver arguments
+ *
+ * Ask the SPI device driver to perform some function.  Further information
+ * should be sought from the device driver in question.
+ *
+ * Returns negative error code on failure.
+ */
+static inline int spi_command(struct spi_driver *clnt, int cmd, void *arg)
+{
+	struct spi_ops *ops = clnt->ops;
+	int ret = -EINVAL;
+
+	if (ops && ops->command)
+		ret = ops->command(clnt, cmd, arg);
+
+	return ret;
+}
+
+static inline int spi_open(struct spi_driver *clnt)
+{
+	struct spi_ops *ops = clnt->ops;
+	int ret = 0;
+
+	if (ops && ops->open)
+		ret = ops->open(clnt);
+	return ret;
+}
+
+static inline void spi_close(struct spi_driver *clnt)
+{
+	struct spi_ops *ops = clnt->ops;
+	if (ops && ops->close)
+		ops->close(clnt);
+}
+
+extern int spi_write(struct spi_device *dev, int addr, const char *buf, int len);
+extern int spi_read(struct spi_device *dev, int addr, char *buf, int len);
+
+
+#endif				/* SPI_H */



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] spi
  2005-08-08  9:12 ` [PATCH] spi dmitry pervushin
@ 2005-08-08 10:41   ` Jiri Slaby
  2005-08-08 13:16   ` Mark Underwood
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 15+ messages in thread
From: Jiri Slaby @ 2005-08-08 10:41 UTC (permalink / raw)
  To: dmitry pervushin; +Cc: Linux Kernel Mailing List

dmitry pervushin napsal(a):

>Index: linux-2.6.10/drivers/spi/Makefile
>===================================================================
>--- linux-2.6.10.orig/drivers/spi/Makefile	1970-01-01 00:00:00.000000000 +0000
>+++ linux-2.6.10/drivers/spi/Makefile	2005-07-15 06:57:39.000000000 +0000
>@@ -0,0 +1,12 @@
>+#
>+# Makefile for the kernel spi bus driver.
>+#
>+
>+obj-$(CONFIG_SPI) += spi-core.o helpers.o
>  
>
But where are helpers?

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] spi
  2005-08-08  9:12 ` [PATCH] spi dmitry pervushin
  2005-08-08 10:41   ` Jiri Slaby
@ 2005-08-08 13:16   ` Mark Underwood
  2005-08-08 16:41     ` dmitry pervushin
  2005-08-08 14:55   ` Greg KH
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 15+ messages in thread
From: Mark Underwood @ 2005-08-08 13:16 UTC (permalink / raw)
  To: dmitry pervushin, Linux Kernel Mailing List


--- dmitry pervushin <dpervushin@gmail.com> wrote:

> Hello all, 
> 
> 
> Here is the spi core patch (slightly redesigned
> again). Now it operates
> with three abstractions:
> a) the spi bus, which is registered in system and is
> resposible for
> general things like registering devices on it,
> handling PM events for
> entire bus, providing bus-wide operations;
> b) the spi device, which is responsible for
> interactions between the
> device and the bus (selecting/deselecting device)
> and PM events for the
> specifi device;
> c) the driver, which is attached to spi devices and
> (possibly) provide
> interface to the upper level like block device
> interface. The spi-dev is
> the good starting point for people who does not want
> anything but simple
> character device access.
> The new abstraction is the spi bus, which
> functionality was represented
> by spi_device structure.
> 
> Especially for Greg K-H: yes, I ran this code
> through sparse :), thank
> you.
> 

Please can we have an example client driver as it
would aid understanding :-). But in the mean time.

-= snip =-

+/**
+ * spi_add_adapter - register a new SPI bus adapter
+ * @spidev: spi_device structure for the registering
adapter
+ *
+ * Make the adapter available for use by clients
using name 
adap->name.
+ * The adap->adapters list is initialised by this
function.
+ *
+ * Returns error code ( 0 on success ) ;
+ */
+struct spi_bus* spi_bus_find( char* id )
+{
+	struct bus_type* the_bus = find_bus( id );
+
+	return the_bus ? container_of( the_bus, struct
spi_bus, the_bus ) : 
NULL;
+}

Eh? The comment is for spi_add_adapter but the
function is spi_bus_find! Where is spi_add_adapter?

-= snip =-


+/**
+ * spi_del_adapter - unregister a SPI bus adapter
+ * @dev: spi_device structure to unregister
+ *
+ * Remove an adapter from the list of available SPI
Bus adapters.
+ *
+ * Returns error code (0 on success);
+ */
+
+void spi_device_del(struct spi_device *dev)
+{
+	device_unregister(&dev->dev);
+}

Eh? The comment is for spi_del_adapter but the
function is spi_device_del! Where is spi_del_adapter?

-= snip =-

+/**
+ * spi_transfer - transfer information on an SPI bus
+ * @adap: adapter structure to perform transfer on
+ * @msgs: array of spi_msg structures describing
transfer
+ * @num: number of spi_msg structures
+ *
+ * Transfer the specified messages to/from a device
on the SPI bus.
+ *
+ * Returns number of messages successfully
transferred, otherwise 
negative
+ * error code.
+ */
+int spi_transfer(struct spi_device *dev, struct
spi_msg msgs[], int 
num)
+{
+	int ret = -ENOSYS;
+	struct spi_bus* bus;
+
+	bus = TO_SPI_BUS( dev->dev.bus );
+
+	if (bus->xfer) {
+		down( &dev->lock );
+		ret = bus->xfer(bus, dev, msgs, num, 0);
+		up(&dev->lock);
+	}
+	return ret;
+}

Surely this should be locked with bus lock?

-= snip =-

Some other comments:
1) I think you need to fix some of your comments
especially those describing how the interfaces work.
2) I take it spi adaptor drivers now use
spi_bus_register/spi_bus_unregister?
3) Different clients on one bus will want to run at
different speeds, how will you handle this?
3) This subsystem can only handle small transfers like
I2C. SPI peripherals like SPI Ethernet devices will
have to do lots of large transfers and with your
current subsystem the device will be forced to wait
until its transfer has finished (as well as other
clients) when it might have other important work to
do.

Best Regards,

Mark


	
	
		
___________________________________________________________ 
Yahoo! Messenger - NEW crystal clear PC to PC calling worldwide with voicemail http://uk.messenger.yahoo.com

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] spi
  2005-08-08  9:12 ` [PATCH] spi dmitry pervushin
  2005-08-08 10:41   ` Jiri Slaby
  2005-08-08 13:16   ` Mark Underwood
@ 2005-08-08 14:55   ` Greg KH
  2005-08-08 17:35     ` Marcel Holtmann
  2005-08-08 22:58   ` Andrew Morton
  2005-08-10 13:10   ` Pavel Machek
  4 siblings, 1 reply; 15+ messages in thread
From: Greg KH @ 2005-08-08 14:55 UTC (permalink / raw)
  To: dmitry pervushin; +Cc: Linux Kernel Mailing List

On Mon, Aug 08, 2005 at 01:12:18PM +0400, dmitry pervushin wrote:
> +config SPI
> +	default Y
> +	tristate "SPI support"
> +        default false
> +	help
> +	  Say Y if you need to enable SPI support on your kernel

What about the "the module will be called..." text for this?

> +obj-$(CONFIG_SPI) += spi-core.o helpers.o

Hm, this will not build :(

> +static LIST_HEAD( spi_busses );

No spaces after ( or before ) please.  You do this all over the place in
the code, please fix it up.

> +	if (NULL == dev || NULL == driver) {

Put the variable on the left side, gcc will complain if you incorrectly
put a "=" instead of a "==" here, which is all that you are defending
against with this style.


> +		printk(KERN_ERR
> +		       "%s: error - both dev and driver should not be NULL !\n",
> +		       __FUNCTION__);
> +		found = 0;
> +		goto spi_match_done;
> +	}
> +
> +	if (NULL == spidrv->supported_ids) {
> +		printk
> +		    ("%s: driver has no ids of devices to support, assuming ALL\n",
> +		     __FUNCTION__);

No KERN_ level here.  Also, please use dev_dbg() and friends if you
possibly can, it's much better for log messages.

> +int spi_bus_register( struct spi_bus* bus, char* name )
> +{
> +	int err = -EINVAL;
> +	static int count = 0;
> +	char busname[ BUS_ID_SIZE ];
> +	char fullname[ BUS_ID_SIZE ];
> +
> +	ENTER();	

Tracing?  ick, not really needed...

> +	if( bus ) {
> +		init_MUTEX( &bus->lock );
> +
> +		bus->platform_device.name = NULL;
> +		bus->the_bus.name = NULL;
> +
> +		strncpy( busname, name ? name : "SPI", sizeof( busname ) );
> +		bus->platform_device.id = count++ % 100;
> +		sprintf( fullname, "%s_%02d", busname, bus->platform_device.id);
> +		bus->the_bus.name = kmalloc( strlen( fullname )+1, GFP_KERNEL );
> +		if( bus->the_bus.name ) {
> +			strcpy( bus->the_bus.name, fullname );
> +		}
> +

{ } are not needed for 1 line if statements.

> +/**
> + * spi_add_adapter - register a new SPI bus adapter
> + * @spidev: spi_device structure for the registering adapter
> + *
> + * Make the adapter available for use by clients using name adap->name.
> + * The adap->adapters list is initialised by this function.
> + *
> + * Returns error code ( 0 on success ) ;
> + */
> +struct spi_bus* spi_bus_find( char* id )

Wrong comment.

> +{
> +	struct bus_type* the_bus = find_bus( id );
> +
> +	return the_bus ? container_of( the_bus, struct spi_bus, the_bus ) : NULL;
> +}
> +
> +EXPORT_SYMBOL( spi_bus_find );

EXPORT_SYMBOL_GPL ?


> +int spi_device_add( struct spi_bus* bus, struct spi_device *dev, char* name)

No space between that and the next function?

No comment for a public function ike this?

> +/**
> + * spi_del_adapter - unregister a SPI bus adapter
> + * @dev: spi_device structure to unregister
> + *
> + * Remove an adapter from the list of available SPI Bus adapters.
> + *
> + * Returns error code (0 on success);
> + */
> +
> +void spi_device_del(struct spi_device *dev)

Again, comments out of sync with the code.

> +void spi_driver_del( struct spi_driver* drv )
> +{
> +	driver_unregister( &drv->driver );
> +}
> +/**
> + * spi_transfer - transfer information on an SPI bus

Please, just 1 line of whitespace between functions, not none.

> +/**
> + * spi_write - send data to a device on an SPI bus
> + * @client: registered client structure
> + * @addr: SPI bus address
> + * @buf: buffer for bytes to send
> + * @len: number of bytes to send
> + *
> + * Send len bytes pointed to by buf to device address addr on the SPI bus
> + * described by client.
> + *
> + * Returns the number of bytes transferred, or negative error code.
> + */
> +int spi_write(struct spi_device *dev, int addr, const char *buf, int len)

Comment doesn't match function.  You will catch all of these errors if
you add the files to the kernel api docbook document.

> ===================================================================
> --- linux-2.6.10.orig/drivers/spi/spi-dev.c	1970-01-01 00:00:00.000000000 +0000
> +++ linux-2.6.10/drivers/spi/spi-dev.c	2005-07-15 06:57:39.000000000 +0000
> @@ -0,0 +1,303 @@
> +/*#ifdef CONFIG_DEVFS_FS	

What's with the #ifdef here?

> +
> +/* $Id: common_spi_core-2.patch,v 1.1.2.6 2005/07/15 07:24:40 tpoynor Exp $ */

No CVS ids in kernel code please.

> +/* struct file_operations changed too often in the 2.1 series for nice code */

I don't think this comment is necessary anymore :)

> +static ssize_t spidev_read(struct file *file, char *buf, size_t count,
> +			   loff_t * offset);
> +static ssize_t spidev_write(struct file *file, const char *buf, size_t count,
> +			    loff_t * offset);

You didn't run this through sparse :(

That's enough to start with...

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] spi
  2005-08-08 13:16   ` Mark Underwood
@ 2005-08-08 16:41     ` dmitry pervushin
  2005-08-08 18:51       ` Mark Underwood
  0 siblings, 1 reply; 15+ messages in thread
From: dmitry pervushin @ 2005-08-08 16:41 UTC (permalink / raw)
  To: Mark Underwood; +Cc: Linux Kernel Mailing List


> Surely this should be locked with bus lock?
Why not ? Until the transfer on device is not finished, the bus will be
locked. Otherwise, the another device (on the same bus) might want to
transfer something...
> 
> -= snip =-
> 
> Some other comments:
> 1) I think you need to fix some of your comments
> especially those describing how the interfaces work.
> 2) I take it spi adaptor drivers now use
> spi_bus_register/spi_bus_unregister?
> 3) Different clients on one bus will want to run at
> different speeds, how will you handle this?
> 3) This subsystem can only handle small transfers like
> I2C. SPI peripherals like SPI Ethernet devices will
> have to do lots of large transfers and with your
> current subsystem the device will be forced to wait
> until its transfer has finished (as well as other
> clients) when it might have other important work to
> do.
Hmm.. In the sample (it needs some polishing!), the bus initiates the
DMA transfers and waits for completion on it. Do you want to have
something like state machine (the function that will be called upon the
end of transfer ?)


 Kconfig             |   12 +
 Makefile            |    7
 pnxalloc.c          |   70 ++++++
 pnxalloc.h          |    9
 spi-pnx010x_atmel.c |   91 ++++++++
 spipnx-resources.h  |  138 ++++++++++++
 spipnx.c            |  581 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 
 spipnx.h            |  309 +++++++++++++++++++++++++++
 8 files changed, 1455 insertions(+)

Index: linux-2.6.10/drivers/spi/spipnx-resources.h
===================================================================
--- /dev/null
+++ linux-2.6.10/drivers/spi/spipnx-resources.h
@@ -0,0 +1,138 @@
+#ifdef CONFIG_MACH_PNX0106_GH450
+struct resource spipnx_010x_resources_0[] = 
+{
+	{ 
+	  .start = BLAS_SPI0_BASE, 
+	  .end = BLAS_SPI0_BASE + SZ_4K, 
+	  .flags = IORESOURCE_MEM,
+	}, { 
+	  .start = SPI0_FIFO_DMA_SLAVE_NR, 
+	  .flags = IORESOURCE_DMA,
+	},
+	/*
+	 * Note that the clocks are shutdown in this order and resumed
+	 * in the opposite order.
+	 */
+       	{ 
+	  .start = CGU_SWITCHBOX_BLAS_SPI0_PCLK_ID, 
+	  .flags = IORESOURCE_CLOCK_ID,
+	}, {
+	  .start = CGU_SWITCHBOX_BLAS_SPI0_PCLK_GAT_ID,
+	  .flags = IORESOURCE_CLOCK_ID,
+	}, {
+	  .start = CGU_SWITCHBOX_BLAS_SPI0_FIFO_PCLK_ID,
+	  .flags = IORESOURCE_CLOCK_ID,
+	}, { 
+	   .start = CGU_SWITCHBOX_BLAS_SPI0_DUMMY_VPBCLK_ID, 
+	  .flags = IORESOURCE_CLOCK_ID,
+	}, {
+	  .start = VH_INTC_INT_NUM_BLAS_SPI0_INT, 
+	  .flags =  IORESOURCE_IRQ,
+	}, {
+	   .flags = 0,
+	}
+};
+
+struct resource spipnx_010x_resources_1[] = 
+{
+	{ 
+	  .start = BLAS_SPI1_BASE, 
+	  .end = BLAS_SPI1_BASE + SZ_4K, 
+	  .flags = IORESOURCE_MEM,
+	}, { 
+	  .start = SPI1_FIFO_DMA_SLAVE_NR, 
+	  .flags = IORESOURCE_DMA,
+	}, 
+	/*
+	 * Note that the clocks are shutdown in this order and resumed
+	 * in the opposite order.
+	 */
+	{ 
+	  .start = CGU_SWITCHBOX_BLAS_SPI1_PCLK_ID, 
+	  .flags = IORESOURCE_CLOCK_ID,
+	}, { 
+	   .start = CGU_SWITCHBOX_BLAS_SPI1_PCLK_GAT_ID,
+	   .flags = IORESOURCE_CLOCK_ID,
+	}, { 
+	  .start = CGU_SWITCHBOX_BLAS_SPI1_FIFO_PCLK_ID,
+	  .flags = IORESOURCE_CLOCK_ID,
+	}, {
+	   .start = CGU_SWITCHBOX_BLAS_SPI1_DUMMY_VPBCLK_ID, 
+	  .flags = IORESOURCE_CLOCK_ID,
+	}, {
+	  .start = VH_INTC_INT_NUM_BLAS_SPI1_INT, 
+	  .flags =  IORESOURCE_IRQ,
+	}, {
+	   .flags = 0,
+	}
+};
+#endif
+
+#ifdef CONFIG_MACH_PNX0105_GH448
+struct resource spipnx_010x_resources[] = 
+{
+	{ 
+	  .start = BLAS_SPI_BASE, 
+	  .end = BLAS_SPI_BASE + SZ_4K, 
+	  .flags = IORESOURCE_MEM,
+	}, { 
+	  .start = BLAS_SPI_DMA_SLAVE_NR, 
+	  .flags = IORESOURCE_DMA,
+	}, 
+	/*
+	 * Note that the clocks are shutdown in this order and resumed
+	 * in the opposite order.
+	 */
+	{
+	   .start =  CGU_SWITCHBOX_BLAS_SPI_PCLK_ID,
+	   .flags = IORESOURCE_CLOCK_ID,
+	}, {
+	   .start = CGU_SWITCHBOX_BLAS_SPI_PCLK_GAT_ID,
+	   .flags = IORESOURCE_CLOCK_ID,
+	}, {
+	   .start = CGU_SWITCHBOX_BLAS_SPI_FIFO_PCLK_ID,
+	   .flags = IORESOURCE_CLOCK_ID,
+	}, { 
+	  .start = VH_INTC_INT_NUM_BLAS_SPI_INT, 
+	  .flags =  IORESOURCE_IRQ,
+	}, {
+	   .flags = 0,
+	}
+};
+#endif
+
+#ifdef CONFIG_ARCH_PNX4008
+struct resource spipnx_4008_resources_0[] = 
+{
+	{ 	      
+	  .start = PNX4008_SPI1_BASE, 
+	  .end = PNX4008_SPI1_BASE + SZ_4K, 
+	  .flags = IORESOURCE_MEM,
+	}, { 
+	  .start = 11 /* SPI1_DMA_PERIPHERAL_ID */, 
+	  .flags = IORESOURCE_DMA,
+	}, { 
+	  .start = SPI1_INT, 
+	  .flags =  IORESOURCE_IRQ,
+	}, {
+	   .flags = 0,
+	}
+};
+
+struct resource spipnx_4008_resources_1[] = 
+{
+	{ 	      
+	  .start = PNX4008_SPI2_BASE, 
+	  .end = PNX4008_SPI2_BASE + SZ_4K, 
+	  .flags = IORESOURCE_MEM,
+	}, { 
+	  .start = 12 /* SPI2_DMA_PERIPHERAL_ID */, 
+	  .flags = IORESOURCE_DMA,
+	}, { 
+	  .start = SPI2_INT, 
+	  .flags =  IORESOURCE_IRQ,
+	}, {
+	   .flags = 0,
+	}
+};
+#endif
Index: linux-2.6.10/drivers/spi/spipnx.c
===================================================================
--- /dev/null
+++ linux-2.6.10/drivers/spi/spipnx.c
@@ -0,0 +1,581 @@
+/*
+ * drivers/spi/spi-pnx.c
+ *
+ * SPI support for PNX 010x/4008 boards.
+ *
+ * Author: dmitry pervushin <dpervushin@ru.mvista.com>
+ * Based on Dennis Kovalev's <dkovalev@ru.mvista.com> bus driver for pnx010x
+ *
+ * 2004 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#define CONFIG_ARCH_PNX4008_R2
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/spi.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/dma.h>
+
+#if defined(CONFIG_ARCH_PNX010X)
+#include <asm/arch/sdma.h>
+#include <asm/arch/cgu.h>
+#include <vhal/cgu_switchbox.h>
+#endif
+
+#if defined (CONFIG_ARCH_PNX4008)
+#include <asm/arch/dma.h>
+#include <asm/arch/gpio.h>
+#endif
+
+#define IORESOURCE_CLOCK_ID 0x80000000
+#include "spipnx.h"
+#include "spipnx-resources.h"
+#include "spi_locals.h"
+
+
+#define SPIPNX_BUS_TAG "spipnx"
+
+extern int spi_bus_match(struct device *dev, struct device_driver *driver);
+static int spipnx_interrupt( int irq, void* context, struct pt_regs* regs );
+static void spipnx_spi_init( struct spipnx_bus* );
+static int spipnx_xfer_nondma( struct spi_bus* bus, struct spi_device* device, struct spi_msg msgs[], int len, int flags );
+static int spipnx_xfer_dma( struct spi_bus* bus, struct spi_device* device, struct spi_msg msgs[], int len, int flags );
+static int spipnx_xfer( struct spi_bus* bus, struct spi_device* device, struct spi_msg msgs[], int len, int flags );
+static int spipnx_probe( struct device* dev );
+static int spipnx_remove( struct device* dev );
+static int spipnx_suspend(struct device *dev, u32 state, u32 level);
+static int spipnx_resume(struct device *dev, u32 level);
+
+struct bus_type spipnx_template = 
+{
+	.match = spi_bus_match,
+};
+
+struct device_driver spipnx_platform_driver = {
+	.bus = &platform_bus_type,
+	.name = SPIPNX_BUS_TAG,
+	.probe = spipnx_probe,
+	.remove = spipnx_remove,
+	.suspend = spipnx_suspend,
+	.resume = spipnx_resume,
+};
+
+
+static void spipnx_bus_set_mode( struct spipnx_bus* bus, int mode )
+{
+	bus->dma_mode = mode;
+}
+
+struct spipnx_bus spipnx_busses[] = 
+{
+#if defined( CONFIG_MACH_PNX0105_GH448 )
+	[0] = { 
+		.bus = { .rsrc = spipnx_010x_resources },
+		.set_mode = spipnx_bus_set_mode,
+		.state = SPIPNX_STATE_UNINITIALIZED,
+	},
+#elif defined( CONFIG_MACH_PNX0106_GH450 )	
+	[0] = { 
+		.bus = { .rsrc = spipnx_010x_resources_0 },
+		.set_mode = spipnx_bus_set_mode,
+		.state = SPIPNX_STATE_UNINITIALIZED,
+	},
+	[1] = { 
+		.bus = { .rsrc = spipnx_010x_resources_1 },
+		.set_mode = spipnx_bus_set_mode,
+		.state = SPIPNX_STATE_UNINITIALIZED,
+	},
+#elif defined( CONFIG_ARCH_PNX4008 )
+	[0] = { 
+		.bus = { .rsrc = spipnx_4008_resources_0 },
+		.set_mode = spipnx_bus_set_mode,
+		.state = SPIPNX_STATE_UNINITIALIZED,
+	},
+	[1] = { 
+		.bus = { .rsrc = spipnx_4008_resources_1 },
+		.set_mode = spipnx_bus_set_mode,
+		.state = SPIPNX_STATE_UNINITIALIZED,
+	},
+#endif
+};
+
+static void spipnx_free_hardware( struct spipnx_bus* pnx_bus )
+{
+	struct spi_bus *bus = &pnx_bus->bus;
+	struct resource* rsrc = bus->rsrc;
+	
+	down( &bus->lock );
+	for( rsrc = bus->rsrc; rsrc->flags; rsrc ++ ) {
+		if( rsrc->flags & IORESOURCE_IRQ ) {
+			free_irq( rsrc->start, bus->the_bus.name );
+		}
+		else if( rsrc->flags & IORESOURCE_MEM ) {
+			pnx_bus->spi_regs = ioremap( rsrc->start, SZ_4K );
+			release_mem_region( 
+					rsrc->start,
+					rsrc->end - rsrc->start + 1 );
+		}
+		else if( rsrc->flags & IORESOURCE_DMA ) {
+			spipnx_release_dma( pnx_bus );
+		}
+	}
+	up( &bus->lock );
+}
+int spipnx_request_hardware( struct spipnx_bus* pnx_bus )
+{	
+	struct spi_bus *bus = &pnx_bus->bus;
+	int err = 0;
+	struct resource* rsrc;
+	int* clk = pnx_bus->clk_id;
+	
+	down( &bus->lock );
+	pnx_bus->clk_id_num = 0;
+	for( rsrc = bus->rsrc; rsrc->flags; rsrc ++ ) {
+		if( rsrc->flags & IORESOURCE_IRQ ) {
+			pnx_bus->spi_regs->ier = 0;
+			if( !request_irq( 
+					rsrc->start, 
+					spipnx_interrupt,
+					SA_INTERRUPT,
+					bus->the_bus.name,
+					pnx_bus ) ) {
+				err = -ENODEV;
+			}
+		}
+		else if( rsrc->flags & IORESOURCE_MEM ) {
+			pnx_bus->phys_data_reg = (void*)rsrc->start + SPIPNX_DATA;
+			pnx_bus->spi_regs = ioremap( rsrc->start, SZ_4K );
+			if( NULL == request_mem_region( 
+					rsrc->start, 
+					rsrc->end - rsrc->start + 1, 
+					bus->the_bus.name ) ) {
+				err = -ENODEV;
+			}
+		}
+		else if( rsrc->flags & IORESOURCE_DMA ) {
+			pnx_bus->slave_nr = rsrc->start;
+			err = spipnx_request_dma( pnx_bus );
+		}
+		else if( rsrc->flags & IORESOURCE_CLOCK_ID ) {
+			if( pnx_bus->clk_id_num >= ARRAY_SIZE( pnx_bus->clk_id )) {
+				printk( KERN_ERR"%s: too many clocks defined\n", __FUNCTION__ );
+				err = -ENODEV;
+			} else {
+				*clk++ = rsrc->start;
+				pnx_bus->clk_id_num++;
+			}
+		}
+		else {
+			printk( "Unknown resource type 0x%08lx\n", rsrc->flags );
+		}
+	}
+	up( &bus->lock );
+	return err;
+}
+
+void spipnx_set_mode( struct spi_bus* bus, int mode )
+{
+	struct spipnx_bus* spipnx = TO_SPIPNX_BUS( bus );
+
+	down( &bus->lock );	
+	if( bus && spipnx->set_mode ) 
+		spipnx->set_mode( spipnx, mode );
+	up( &bus->lock );
+}
+
+int __init spipnx_init( void )
+{
+	int i;
+	int status;
+	
+	printk( "SPI bus driver for PNX010x\n" );
+	spipnx_platform_driver.name = SPIPNX_BUS_TAG;
+	for( i = 0; i < ARRAY_SIZE( spipnx_busses ); i ++ ) {
+		spipnx_busses[ i ].bus.the_bus = spipnx_template;
+		spipnx_busses[ i ].bus.xfer = spipnx_xfer;
+		spipnx_busses[ i ].dma_mode = 0;
+		spipnx_busses[ i ].dma_channel = -1;
+		status = spi_bus_register( &spipnx_busses[ i ].bus, SPIPNX_BUS_TAG );
+		if( status ) {
+			printk( "SPI Bus#%d cannot be registered: error %d\n", i, status );
+			continue;
+		}
+		spipnx_request_hardware( &spipnx_busses[ i ] );
+		spipnx_busses[ i ].state = SPIPNX_STATE_READY;
+	}
+	driver_register( &spipnx_platform_driver );
+	return 0;	
+}
+
+void __exit spipnx_cleanup( void )
+{
+	int i;
+	
+	driver_unregister( &spipnx_platform_driver );
+	for( i = 0; i < ARRAY_SIZE( spipnx_busses );  i ++ ) {
+		spipnx_busses[ i ].state = SPIPNX_STATE_UNINITIALIZED;
+		spi_bus_unregister( &spipnx_busses[ i ].bus );
+		spipnx_free_hardware( &spipnx_busses[ i ] );
+	}
+}
+
+static irqreturn_t spipnx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct spipnx_bus *bus = dev_id;
+	unsigned int i_stat = bus->spi_regs->stat;
+	unsigned int ier = bus->spi_regs->ier;
+
+	if ((i_stat & SPIPNX_STAT_EOT) &&
+	    (ier & SPIPNX_IER_EOT)) {
+		bus->spi_regs->ier &= ~SPIPNX_IER_EOT;
+		complete(&bus->op_complete);
+	}
+	if ((i_stat & SPIPNX_STAT_THR) &&
+	    (ier & SPIPNX_IER_THR)) {
+		bus->spi_regs->ier &= ~SPIPNX_IER_THR;
+		complete(&bus->threshold);
+	}
+	bus->spi_regs->stat |= SPIPNX_STAT_CLRINT;	/*     clear interrupt   */
+	bus->spi_regs->timer_status = 0L;
+
+	return IRQ_HANDLED;
+}
+
+static void spipnx_spi_init( struct spipnx_bus* bus)
+{
+	bus->spi_regs->global = SPIPNX_GLOBAL_RESET_SPI |
+	                        SPIPNX_GLOBAL_SPI_ON;	
+	mdelay(5);
+	bus->spi_regs->global = SPIPNX_GLOBAL_SPI_ON;
+	bus->spi_regs->con =
+		SPIPNX_CON_MS | SPIPNX_CLOCK;
+	bus->spi_regs->con |= SPIPNX_CON_BIDIR | ( 7<<9 );
+#ifdef CONFIG_ARCH_PNX4008	
+	bus->spi_regs->stat |= SPIPNX_STAT_CLRINT;
+	bus->spi_regs->con |= SPI_CON_SPI_MODE0 |  SPI_CON_RATE_13 | SPI_CON_THR; 
+#endif	
+}
+
+void  spipnx_default_cs( int type, struct spi_device* device )
+{
+#ifdef CONFIG_MACH_PNX0105_GH448
+	unsigned reg;
+	
+	switch( type ) 
+	{
+	case SELECT:
+	    reg = gpio_read_reg(PADMUX1_MODE0);
+	    gpio_write_reg((reg & ~GPIO_PIN_SPI_CE), PADMUX1_MODE0);
+	    break;
+	case UNSELECT:
+	    reg = gpio_read_reg(PADMUX1_MODE0);
+	    gpio_write_reg(reg | GPIO_PIN_SPI_CE, PADMUX1_MODE0);
+	    break;
+	}
+#endif
+}
+
+static int spipnx_xfer_nondma(struct spi_bus *spibus, struct spi_device* dev, struct spi_msg msgs[],
+			int num, int flags )
+{
+	struct spi_msg *pmsg;
+	int i, j, bptr;
+	raw_spinlock_t lock;
+	void (*chip_cs) ( int type, struct spi_device *device ) = dev->select ? dev->select : spipnx_default_cs;
+	struct spipnx_bus* bus = TO_SPIPNX_BUS( spibus );
+
+	pr_debug("Non-SDMA processing %d messages ...\n", num);
+
+	chip_cs(SELECT, dev );
+	bus->spi_regs->con |= SPIPNX_CON_THR; 
+
+	for (i = 0; i < num; i++) {
+		pmsg = &msgs[i];
+		
+		chip_cs( SPIMSG_FLAGS | ( pmsg->flags & SPI_M_CS ), dev );
+		if (pmsg->flags & SPI_M_RD) {	
+			/*  here we have to read data */
+			chip_cs(BEFORE_READ, dev );
+			bptr = 0;
+			init_completion(&bus->op_complete);
+			bus->spi_regs->frm = 0x0000FFFF & (pmsg->len);	
+			bus->spi_regs->con &= ~SPIPNX_CON_RXTX; 
+			bus->spi_regs->con |= SPIPNX_CON_SHIFT_OFF; 
+			bus->spi_regs->ier = SPIPNX_IER_EOT; 
+			bus->spi_regs->dat = 0x00;
+
+			while (bptr < pmsg->len) {
+				if ((pmsg->len) - bptr > FIFO_CHUNK_SIZE) {	/*  if there's data left for another  */
+					init_completion(&bus->threshold);	/*  init wait queue for another chunk */
+					spin_lock_irq(&lock);
+					bus->spi_regs->ier |= SPIPNX_IER_THR; 	/*  chunk, then enable THR interrupt  */
+					spin_unlock_irq(&lock);
+					wait_for_completion(&bus->threshold);
+				} else {
+					wait_for_completion(&bus->op_complete);
+				}
+				for (j = bptr;
+				     j <
+				     (((pmsg->len) - bptr <
+				       FIFO_CHUNK_SIZE) ? (pmsg->len) : (bptr +
+									 FIFO_CHUNK_SIZE));
+				     j++)
+					pmsg->buf[j] = bus->spi_regs->dat;
+				bptr +=
+				    ((pmsg->len) - bptr <
+				     FIFO_CHUNK_SIZE) ? (pmsg->len -
+							 bptr) :
+				    FIFO_CHUNK_SIZE;
+			}
+			pr_debug("[i]:SPI_M_RD: %x\n", *pmsg->buf);
+			chip_cs(AFTER_READ, dev);
+		} 
+		else if( pmsg->flags & SPI_M_WR ) {
+			/*  now we have to transmit data        */
+			chip_cs(BEFORE_WRITE, dev);
+			bus->spi_regs->con |= SPIPNX_CON_RXTX;
+			bus->spi_regs->frm = 0x0000FFFF & (pmsg->len);
+			bptr = 0;
+			init_completion(&bus->op_complete);
+			bus->spi_regs->ier = SPIPNX_IER_EOT;
+
+			while (bptr < pmsg->len) {
+				for (j = bptr;
+				     j <
+				     (((pmsg->len) - bptr <
+				       FIFO_CHUNK_SIZE) ? (pmsg->len) : (bptr +
+									 FIFO_CHUNK_SIZE));
+				     j++) {
+					bus->spi_regs->dat = pmsg->buf[j];
+				}
+				if ((pmsg->len) - bptr > FIFO_CHUNK_SIZE) {
+					init_completion(&bus->threshold);
+					spin_lock_irq(&lock);
+					bus->spi_regs->ier |= SPIPNX_IER_THR;
+					spin_unlock_irq(&lock);
+					wait_for_completion(&bus->threshold);
+				}
+				bptr +=
+				    ((pmsg->len) - bptr <
+				     FIFO_CHUNK_SIZE) ? (pmsg->len -
+							 bptr) :
+				    FIFO_CHUNK_SIZE;
+			}
+			wait_for_completion(&bus->op_complete);
+			pr_debug("[i]:SPI_M_WR: %x\n", *pmsg->buf);
+			chip_cs(AFTER_WRITE, dev);
+		}
+		chip_cs( SPIMSG_FLAGS | ( pmsg->flags & SPI_M_CSREL ), dev );
+	}	
+	chip_cs(UNSELECT, dev);
+	bus->spi_regs->ier &= ~SPIPNX_IER_EOT;
+
+	return num;
+}
+
+int spipnx_xfer_dma(struct spi_bus *spibus, struct spi_device* dev, struct spi_msg msgs[], int num, int flags)
+{
+	struct spi_msg *pmsg;
+	int i;
+	spi_pnx_msg_buff_t *buff;
+	void (*chip_cs) (int type, struct spi_device *device) = dev->select ? dev->select : spipnx_default_cs;
+	struct spipnx_bus *bus = TO_SPIPNX_BUS( spibus );
+
+	pr_debug("SDMA processing %d messages ...\n", num);
+
+	chip_cs(SELECT, dev);
+
+	for (i = 0; i < num; i++) {
+		pmsg = &msgs[i];
+		buff = (spi_pnx_msg_buff_t *) pmsg->buf;
+		pr_debug("SDMA processing [%d] message ...\n", i);
+
+		chip_cs( SPIMSG_FLAGS | ( pmsg->flags & SPI_M_CS ), dev );
+
+		if (pmsg->flags & SPI_M_RD) {
+			chip_cs(BEFORE_READ, dev);
+
+			init_completion(&bus->op_complete);
+			bus->spi_regs->con &= ~SPIPNX_CON_RXTX; 
+			bus->spi_regs->con |= SPIPNX_CON_SHIFT_OFF; 
+			bus->spi_regs->frm = 0x0000FFFF & (pmsg->len);
+			bus->spi_regs->ier = SPIPNX_IER_EOT; 
+
+			bus->spi_regs->dat = 0;
+			while (!
+			       (bus->spi_regs->
+				stat & SPIPNX_STAT_THR)) {
+					cpu_relax();
+			}
+			spipnx_setup_dma( bus, DMA_MODE_READ, buff,  pmsg->len  );
+			spipnx_start_dma( bus->dma_channel ); 
+			wait_for_completion(&bus->op_complete);
+			spipnx_stop_dma( bus->dma_channel ); 
+			pr_debug("[i]:SPI_M_RD: %x\n", *buff->io_buffer);
+			chip_cs(AFTER_READ, dev);
+		} else {
+			chip_cs(BEFORE_WRITE, dev );
+			bus->spi_regs->con |= SPIPNX_CON_RXTX; 
+			bus->spi_regs->frm = 0x0000FFFF & (pmsg->len);
+			bus->spi_regs->con &= ~SPIPNX_CON_SHIFT_OFF; 
+
+			spipnx_setup_dma( bus, DMA_MODE_WRITE, buff, pmsg->len );
+			bus->spi_regs->ier = SPIPNX_IER_EOT; 
+			init_completion(&bus->op_complete);
+			spipnx_start_dma( bus->dma_channel );
+			wait_for_completion(&bus->op_complete);
+			spipnx_stop_dma( bus->dma_channel);
+			pr_debug("[i]:SPI_M_WR: %x\n", *buff->io_buffer);
+			chip_cs(AFTER_WRITE, dev);
+		}
+		chip_cs( SPIMSG_FLAGS | ( pmsg->flags & SPI_M_CSREL ), dev );
+	}
+	chip_cs(UNSELECT, dev );
+
+	return num;
+}
+
+int spipnx_xfer(struct spi_bus *spibus, struct spi_device* dev, struct spi_msg msgs[], int num, int flags)
+{
+	int  i;
+	struct spi_msg *pmsg;
+	struct spipnx_bus* bus = TO_SPIPNX_BUS( spibus );
+	int status;
+
+	down( &spibus->lock );
+	if( !SPIPNX_IS_READY( bus ) ) {
+		status = -EIO;
+		goto unlock_and_out;
+	}
+	pr_debug("processing %d messages ...\n", num);
+	for (i = 0; i < num; i++) {
+		pmsg = &msgs[i];
+		if ((pmsg->len >= 0xFFFF) || (!pmsg->buf))
+			return -EINVAL;
+		pr_debug("%d) %c - %d bytes\n", i, pmsg->flags ? 'R' : 'W',
+			 pmsg->len);
+	}
+#ifdef CONFIG_ARCH_PNX010X		
+	if (bus->dma_mode) {
+		bus->sdma_config.transfer_size = SDMA_TRANSFER_BYTE;
+		bus->sdma_config.invert_endian = SDMA_INVERT_ENDIAN_NO;
+		bus->sdma_config.companion_channel = 0;
+		bus->sdma_config.companion_enable = SDMA_COMPANION_DISABLE;
+		bus->sdma_config.circular_buffer = SDMA_CIRC_BUF_DISABLE;
+	}
+#endif
+	spipnx_spi_init( bus );
+
+	status =  bus->dma_mode ? 
+		spipnx_xfer_dma( spibus, dev, msgs, num, flags) : 
+		spipnx_xfer_nondma( spibus, dev, msgs, num, flags );
+unlock_and_out:	
+	up( &spibus->lock );
+	return status;
+}
+
+static int spipnx_probe( struct device* dev )
+{
+	struct platform_device *pldev = to_platform_device( dev );
+
+	if( strncmp( pldev->name, SPIPNX_BUS_TAG, strlen( SPIPNX_BUS_TAG ) ) != 0 ) {
+		return -ENODEV;
+	}
+	spipnx_resume( dev, RESUME_POWER_ON );
+	spipnx_resume( dev, RESUME_ENABLE );
+	return 0;
+}
+
+static int spipnx_remove( struct device* dev )
+{
+	spipnx_suspend( dev, SUSPEND_DISABLE, 0 );
+	spipnx_suspend( dev, SUSPEND_POWER_DOWN, 0 );
+	return 0;
+}
+
+static int spipnx_suspend(struct device *dev, u32 state, u32 level)
+{
+	int err = 0;
+#ifdef CONFIG_PM
+	int c;
+	struct platform_device* pldev = to_platform_device(dev);
+	struct spi_bus *spibus = TO_SPI_BUS_PLDEV( pldev );
+	struct spipnx_bus* bus = TO_SPIPNX_BUS( spibus );
+
+	down( &spibus->lock );
+	switch (level) 
+	{
+	case SUSPEND_DISABLE:
+		spipnx_release_dma( bus );
+		bus->state = SPIPNX_STATE_SUSPENDED;              
+		break;
+	case SUSPEND_SAVE_STATE:
+		break;
+	case SUSPEND_POWER_DOWN:
+		for( c = 0; c < bus->clk_id_num; c ++ ) {
+		    cgu_set_clock_run( bus->clk_id[ c ], 0 );
+		}
+		break;
+	}
+	up( &spibus->lock );
+#endif
+	return err;
+}
+
+static int spipnx_resume(struct device *dev, u32 level)
+{
+	int err = 0;
+#ifdef CONFIG_PM
+	int c;
+	struct platform_device* pldev = to_platform_device(dev);
+	struct spi_bus *spibus = TO_SPI_BUS_PLDEV( pldev );
+	struct spipnx_bus* bus = TO_SPIPNX_BUS( spibus );
+
+	down( &spibus->lock );	
+	switch (level) 
+	{
+	case RESUME_POWER_ON:
+		for( c = bus->clk_id_num - 1; c >= 0; c -- ) {
+			cgu_set_clock_run(bus->clk_id[ c ], 1);
+		}
+		break;
+	case RESUME_RESTORE_STATE:
+		break;
+	case RESUME_ENABLE:
+		spipnx_request_dma( bus );
+		bus->state = SPIPNX_STATE_READY;
+		break;
+	}
+	up( &spibus->lock );
+#endif				/* CONFIG_PM */
+	return err;
+}
+
+
+EXPORT_SYMBOL_GPL( spipnx_set_mode );
+MODULE_AUTHOR("dmitry pervushin <dpervushin@ru.mvista.com>");
+MODULE_DESCRIPTION("SPI driver for Philips' PNX boards");
+MODULE_LICENSE("GPL");
+module_init(spipnx_init);
+module_exit(spipnx_cleanup);
Index: linux-2.6.10/drivers/spi/spi-pnx010x_atmel.c
===================================================================
--- /dev/null
+++ linux-2.6.10/drivers/spi/spi-pnx010x_atmel.c
@@ -0,0 +1,91 @@
+/*
+ * drivers/spi/spi-pnx010x_atmel.c
+ *
+ * Provides Atmel SPI chip support for pnx010x.
+ *
+ * Author: Dennis Kovalev <dkovalev@ru.mvista.com>
+ *
+ * 2004 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/spi.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+// #include <asm/arch/sdma.h>
+
+#include "spipnx.h"
+#include "spi_locals.h"
+#include "pnxalloc.h"
+
+static int mode = 0;
+static int sdma_mode = 0;
+static char* spi_bus_atmel = "spipnx_00"; 
+MODULE_PARM( sdma_mode, "i" );
+MODULE_PARM( spi_bus_atmel, "s" );
+
+static struct spi_device atmel = {
+	.alloc = NULL,
+	.free = NULL,
+	.copy_from_user = NULL,
+	.copy_to_user = NULL,
+};
+
+int __init atmel_init( void )
+{
+        struct spi_bus* bus = spi_bus_find( spi_bus_atmel );
+        int err;
+
+        if( NULL == bus ) {
+                err = -ENODEV;
+                goto out;
+	}
+				
+	if (sdma_mode) {
+		atmel.alloc = pnx_memory_alloc;
+		atmel.free = pnx_memory_free;
+		atmel.copy_from_user = pnx_copy_from_user;
+		atmel.copy_to_user = pnx_copy_to_user;
+		spipnx_set_mode( bus, 1 );
+	}
+	
+	err = spi_device_add( bus, &atmel, "atmel" );
+	if( err ) {
+		goto out;
+	}
+	printk( "ATMEL driver for the SPI bus loaded.\n" );
+out:
+	if( err ) {
+		printk( "ATMEL driver for the SPI bus: error = %d\n", err );
+	}
+	return err;
+}
+
+void __exit atmel_exit( void )
+{
+	spi_device_del( &atmel );
+}
+
+module_init( atmel_init );
+module_exit( atmel_exit );
+
Index: linux-2.6.10/drivers/spi/spipnx.h
===================================================================
--- /dev/null
+++ linux-2.6.10/drivers/spi/spipnx.h
@@ -0,0 +1,309 @@
+/*
+ * SPI support for pnx010x.
+ *
+ * Author: Dennis Kovalev <dkovalev@ru.mvista.com>
+ *
+ * 2004 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+//#ifndef CONFIG_ARCH_PNX010X
+//#error This driver cannot be run on non-pnx010x
+//#endif
+
+#ifndef _SPI_PNX_BUS_DRIVER
+#define _SPI_PNX_BUS_DRIVER
+
+#include <asm/arch/platform.h>
+#include <asm/arch/dma.h>
+#include <asm/dma.h>
+
+
+
+#if defined (CONFIG_ARCH_PNX010X)
+#include <vhal/spi_pnx0105.h>
+#include <vhal/ioconf.h>
+#elif defined( CONFIG_ARCH_PNX4008)
+typedef volatile struct  {
+        u32 global ;			/* 0x000             */
+        u32 con ;			/* 0x004             */
+        u32 frm ;			/* 0x008             */
+        u32 ier ;			/* 0x00C             */
+        u32 stat ;			/* 0x010             */
+        u32 dat ;			/* 0x014             */
+        u32 dat_msk ;		/* 0x018             */
+        u32 mask ;			/* 0x01C             */
+        u32 addr ;			/* 0x020             */
+    	u32 _d0[(SPI_ADR_OFFSET_TIMER_CTRL_REG - (SPI_ADR_OFFSET_ADDR + sizeof( u32))) / sizeof( u32 )];
+        u32 timer_ctrl ;		/* 0x400             */
+        u32 timer_count ;		/* 0x404             */
+        u32 timer_status ;		/* 0x408             */
+} vhblas_spiregs, *pvhblas_spiregs;
+#endif
+
+#if defined( CONFIG_ARCH_PNX010X )
+#define SPIPNX_STAT_EOT (1 << VH_BLASSPI_STAT_REG_SPI_EOT_POS )
+#define SPIPNX_STAT_THR (1 << VH_BLASSPI_STAT_REG_SPI_THR_POS )
+#define SPIPNX_IER_EOT  (1 << VH_BLASSPI_IER_REG_SPI_INTEOT_POS )
+#define SPIPNX_IER_THR  (1 << VH_BLASSPI_IER_REG_SPI_INTTHR_POS )
+#define SPIPNX_STAT_CLRINT (1 << VH_BLASSPI_STAT_REG_SPI_INTCLR_POS )
+#define SPIPNX_GLOBAL_RESET_SPI (1 << VH_BLASSPI_GLOBAL_REG_BLRES_SPI_POS)
+#define SPIPNX_GLOBAL_SPI_ON (1 << VH_BLASSPI_GLOBAL_REG_SPI_ON_POS)
+#define SPIPNX_CON_MS (1 << VH_BLASSPI_CON_REG_MS_POS)
+#define SPIPNX_CON_BIDIR (1 << VH_BLASSPI_CON_REG_SPI_BIDIR_POS) 
+#define SPIPNX_CON_RXTX VH_BLASSPI_CON_REG_RXTX_MSK 
+#define SPIPNX_CON_THR  (1 << VH_BLASSPI_CON_REG_THR_POS)
+#define SPIPNX_CON_SHIFT_OFF (1 << VH_BLASSPI_CON_REG_SHIFT_OFF_POS)
+#define SPIPNX_DATA  VH_BLASSPI_ADDR_REG
+#define SPIPNX_CLOCK SPI_CLOCK
+
+#elif defined( CONFIG_ARCH_PNX4008 )
+#define SPIPNX_STAT_EOT SPI_STAT_SPI_EOT
+#define SPIPNX_STAT_THR SPI_STAT_SPI_THR
+#define SPIPNX_IER_EOT SPI_IER_SPI_INTEOT
+#define SPIPNX_IER_THR SPI_IER_SPI_INTTHR
+#define SPIPNX_STAT_CLRINT SPI_STAT_SPI_INTCLR
+
+#define SPIPNX_GLOBAL_RESET_SPI SPI_GLOBAL_BLRES_SPI
+#define SPIPNX_GLOBAL_SPI_ON 	SPI_GLOBAL_SPI_ON
+#define SPIPNX_CON_MS		SPI_CON_MS
+#define SPIPNX_CON_BIDIR	SPI_CON_SPI_BIDIR
+#define SPIPNX_CON_RXTX		SPI_CON_RxTx
+#define SPIPNX_CON_THR		SPI_CON_THR
+#define SPIPNX_CON_SHIFT_OFF	SPI_CON_SHIFT_OFF
+#define SPIPNX_DATA		SPI_ADR_OFFSET_DAT
+#define SPI_PNX4008_CLOCK_IN  104000000
+#define SPI_PNX4008_CLOCK 2670000
+#define SPIPNX_CLOCK ((((SPI_PNX4008_CLOCK_IN / SPI_PNX4008_CLOCK) - 2) / 2) & SPI_CON_RATE_MASK )
+#endif
+
+/* exports */
+extern void spipnx_set_mode( struct spi_bus* bus, int mode );
+
+/* structures */
+#define TO_SPIPNX_BUS(spipnx) container_of( spipnx, struct spipnx_bus, bus )
+struct spipnx_bus 
+{
+	int dma_mode;
+	void (*set_mode)( struct spipnx_bus* this, int dma );
+	struct spi_bus bus;
+	void* phys_data_reg;	
+	int dma_channel;
+#ifdef CONFIG_ARCH_PNX010X
+	sdma_setup_t sdma_setup;
+	sdma_config_t sdma_config;
+#endif	
+ 	vhblas_spiregs*	spi_regs;
+	int slave_nr;
+	int clk_id[ 4 ];
+	int clk_id_num;
+	int sdma_use_count;
+	struct completion threshold;
+	struct completion op_complete;
+	int state;
+};
+#define SPIPNX_STATE_UNINITIALIZED 0
+#define SPIPNX_STATE_READY         1
+#define SPIPNX_STATE_SUSPENDED     2
+
+#define SPIPNX_IS_READY( bus )  ( (bus)->state == SPIPNX_STATE_READY )
+
+typedef enum {
+	SELECT = 0,
+	UNSELECT,
+	INIT,
+	BEFORE_READ,
+	AFTER_READ,
+	BEFORE_WRITE,
+	AFTER_WRITE,
+} spi_pnx010x_cb_type_t;
+#define SPIMSG_FLAGS 0x80
+
+typedef struct {
+	char *io_buffer;
+	dma_addr_t dma_buffer;
+	size_t size;
+} spi_pnx_msg_buff_t;
+
+static inline int spipnx_request_dma ( struct spipnx_bus* bus )
+{
+ 	int err;
+	
+	if( bus->dma_channel != -1 ) {
+		err = bus->dma_channel;
+		goto out;
+	}
+#if defined ( CONFIG_ARCH_PNX010X )
+      	err = sdma_request_channel( bus->bus.the_bus.name, NULL, NULL );
+#elif defined( CONFIG_ARCH_PNX4008 )
+	err = pnx4008_request_channel( bus->bus.the_bus.name, -1, NULL, NULL );
+#endif
+	if( err >= 0 ) {
+		bus->dma_channel = err;
+	}
+out:	
+	return err < 0 ? err : 0;
+}
+
+static inline void spipnx_release_dma( struct spipnx_bus* bus )
+{
+	if( bus->dma_channel >= 0 ) {
+#if defined ( CONFIG_ARCH_PNX010X )
+	      	sdma_release_channel( bus->dma_channel );
+#elif defined( CONFIG_ARCH_PNX4008 )
+		pnx4008_free_channel( bus->dma_channel );
+#endif	
+	}
+	bus->dma_channel = -1;
+}
+
+static inline void spipnx_start_dma( int dma_channel ) 
+{
+#if defined( CONFIG_ARCH_PNX010X )
+	sdma_start_channel( dma_channel );
+#elif defined( CONFIG_ARCH_PNX4008 )
+	pnx4008_dma_ch_enable( dma_channel );
+#else
+#warning spipnx_start_dma does nothing
+	dma_channel = dma_channel;
+#endif	
+}
+
+static inline void spipnx_stop_dma( int dma_channel )
+{
+#if defined( CONFIG_ARCH_PNX010X )
+	sdma_stop_channel( dma_channel );
+#elif defined( CONFIG_ARCH_PNX4008 )
+	pnx4008_dma_ch_disable( dma_channel );
+#else
+#warning spipnx_stop_dma does nothing
+	dma_channel = dma_channel;
+#endif	
+}
+
+static inline int spipnx_setup_dma( struct spipnx_bus* bus, int mode, spi_pnx_msg_buff_t* buff, int len )
+{
+	int err = 0;
+
+#if defined( CONFIG_ARCH_PNX010X )
+	if( mode == DMA_MODE_READ ) {
+		bus->sdma_setup.src_address =  
+			    (unsigned int)bus->phys_data_reg;
+		bus->sdma_setup.dest_address =
+			    (unsigned int)buff->dma_buffer;
+		bus->sdma_setup.trans_length = len;
+		bus->sdma_config.write_slave_nr = MEMORY_DMA_SLAVE_NR;
+		bus->sdma_config.read_slave_nr = bus->slave_nr;
+	}
+	else if( mode == DMA_MODE_WRITE ) {
+		bus->sdma_setup.dest_address =  
+			    (unsigned int)bus->phys_data_reg;
+		bus->sdma_setup.src_address =
+			    (unsigned int)buff->dma_buffer;
+		bus->sdma_setup.trans_length = len;
+		bus->sdma_config.read_slave_nr = MEMORY_DMA_SLAVE_NR;
+		bus->sdma_config.write_slave_nr = bus->slave_nr;
+	}
+	else {
+		err = -EINVAL;
+		goto out;	
+	}
+	err = sdma_pack_config(&bus->sdma_config,
+			 &bus->sdma_setup.packed_config);
+	if( err ) {
+		goto out;
+	}
+	err = sdma_prog_channel(bus->dma_channel, &bus->sdma_setup);
+#elif defined( CONFIG_ARCH_PNX4008 )
+        pnx4008_dma_config_t cfg;
+	pnx4008_dma_ch_config_t ch_cfg;
+        pnx4008_dma_ch_ctrl_t ch_ctrl;
+
+	memset( &cfg, 0, sizeof( cfg ) );
+
+	if( mode == DMA_MODE_READ ) {
+ 	        cfg.dest_addr = buff->dma_buffer;
+		cfg.src_addr = (u32)bus->phys_data_reg;
+	        ch_cfg.flow_cntrl = FC_PER2MEM_DMA;
+		ch_cfg.src_per = bus->slave_nr;
+		ch_cfg.dest_per = 0;
+		ch_ctrl.di = 1;
+	        ch_ctrl.si = 0;
+	}
+	else if ( mode == DMA_MODE_WRITE ) {
+ 	        cfg.src_addr = buff->dma_buffer;
+		cfg.dest_addr = (u32)bus->phys_data_reg;
+	        ch_cfg.flow_cntrl = FC_MEM2PER_DMA;
+		ch_cfg.dest_per = bus->slave_nr;
+		ch_cfg.src_per = 0;
+		ch_ctrl.di = 0;
+	        ch_ctrl.si = 1;
+	}
+	else {
+		err = -EINVAL;
+	}
+
+	ch_cfg.halt = 0;
+        ch_cfg.active = 1;
+	ch_cfg.lock = 0;
+	ch_cfg.itc = 1;
+	ch_cfg.ie = 1;
+        ch_ctrl.tc_mask = 1;
+        ch_ctrl.cacheable = 0;
+        ch_ctrl.bufferable = 0;
+        ch_ctrl.priv_mode = 1;
+	ch_ctrl.dest_ahb1 = 0;
+	ch_ctrl.src_ahb1 = 0;
+	ch_ctrl.dwidth = WIDTH_BYTE;
+        ch_ctrl.swidth = WIDTH_BYTE;
+        ch_ctrl.dbsize = 1;
+        ch_ctrl.sbsize = 1;
+        ch_ctrl.tr_size = len;
+        if( 0 > ( err = pnx4008_dma_pack_config(&ch_cfg, &cfg.ch_cfg) ) ) {
+		goto out;
+	}
+        if( 0 > ( err = pnx4008_dma_pack_control(&ch_ctrl, &cfg.ch_ctrl) ) ) {
+		goto out;
+	}
+        err = pnx4008_config_channel( bus->dma_channel, &cfg);
+#endif
+out:
+	return err;
+}
+
+#define IORESOURCE_CLOCK_ID 0x80000000
+#define FIFO_CHUNK_SIZE		56
+#define SPI_RECEIVE                        0
+#define SPI_TRANSMIT                       1
+
+#define SPI_ENDIAN_SWAP_NO                 0
+#define SPI_ENDIAN_SWAP_YES                1
+
+#if defined( CONFIG_ARCH_PNX010X )
+#define SPI_CLOCK		0x10
+
+/*  GPIO related definitions  */
+#define PADMUX1_PINS		(IOCONF_PNX0105_PADMUX0 + VH_IOCONF_REG_PINS)
+#define PADMUX1_MODE0		(IOCONF_PNX0105_PADMUX0 + VH_IOCONF_REG_MODE0)
+#define PADMUX1_MODE0SET	(IOCONF_PNX0105_PADMUX0 + VH_IOCONF_REG_MODE0_SET)
+#define PADMUX1_MODE0RESET	(IOCONF_PNX0105_PADMUX0 + VH_IOCONF_REG_MODE0_RESET)
+#define PADMUX1_MODE1		(IOCONF_PNX0105_PADMUX0 + VH_IOCONF_REG_MODE1)
+#define PADMUX1_MODE1SET	(IOCONF_PNX0105_PADMUX0 + VH_IOCONF_REG_MODE1_SET)
+#define PADMUX1_MODE1RESET	(IOCONF_PNX0105_PADMUX0 + VH_IOCONF_REG_MODE1_RESET)
+
+#define GPIO_PIN_SPI_CE			(1<<VH_IOCONF_PNX0105_PADMUX1_MSPI_CE_POS)
+#define PADMUX1_BASE_ADDR		IO_ADDRESS(IOCONF_BASE)
+
+#define GPIO_PIN_SPI_CE			(1<<VH_IOCONF_PNX0105_PADMUX1_MSPI_CE_POS)
+#define PADMUX1_BASE_ADDR		IO_ADDRESS(IOCONF_BASE)
+
+#define gpio_write_reg(val,reg)		writel (val, PADMUX1_BASE_ADDR + reg)
+#define gpio_read_reg(reg)		readl (PADMUX1_BASE_ADDR + reg)
+#endif
+
+#endif // __SPI_PNX_BUS_DRIVER
+
+
+
Index: linux-2.6.10/drivers/spi/pnxalloc.c
===================================================================
--- /dev/null
+++ linux-2.6.10/drivers/spi/pnxalloc.c
@@ -0,0 +1,70 @@
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <asm/uaccess.h>
+#include <asm/dma.h>
+
+#include <linux/spi.h>
+
+#include "spipnx.h"
+#include "pnxalloc.h"
+
+void *pnx_memory_alloc(size_t size, int base)
+{
+	spi_pnx_msg_buff_t *buff;
+
+	buff = (spi_pnx_msg_buff_t *) kmalloc(sizeof(spi_pnx_msg_buff_t), base);
+	buff->size = size;
+	buff->io_buffer =
+	    dma_alloc_coherent(NULL, size, &buff->dma_buffer, base);
+
+	pr_debug
+	    ("%s:allocated memory(%p) for io_buffer = %p dma_buffer = %08x\n",
+	     __FUNCTION__, buff, buff->io_buffer, buff->dma_buffer);
+
+	return (void *)buff;
+}
+
+void pnx_memory_free(const void *data)
+{
+	spi_pnx_msg_buff_t *buff;
+
+	buff = (spi_pnx_msg_buff_t *) data;
+	pr_debug("%s:deleted memory(%p) for io_buffer = %p dma_buffer = %08x\n",
+		 __FUNCTION__, buff, buff->io_buffer, buff->dma_buffer);
+
+	dma_free_coherent(NULL, buff->size, buff->io_buffer, buff->dma_buffer);
+	kfree(buff);
+}
+
+unsigned long pnx_copy_from_user(void *to, const void *from_user,
+				 unsigned long len)
+{
+	spi_pnx_msg_buff_t *buff;
+	int ret;
+
+	buff = (spi_pnx_msg_buff_t *) to;
+	ret = copy_from_user(buff->io_buffer, from_user, len);
+
+	return ret;
+}
+
+unsigned long pnx_copy_to_user(void *to_user, const void *from,
+			       unsigned long len)
+{
+	spi_pnx_msg_buff_t *buff;
+	int ret;
+
+	buff = (spi_pnx_msg_buff_t *) from;
+	ret = copy_to_user(to_user, buff->io_buffer, len);
+
+	return ret;
+}
+
+EXPORT_SYMBOL( pnx_copy_to_user );
+EXPORT_SYMBOL( pnx_copy_from_user );
+EXPORT_SYMBOL( pnx_memory_alloc );
+EXPORT_SYMBOL( pnx_memory_free );
Index: linux-2.6.10/drivers/spi/pnxalloc.h
===================================================================
--- /dev/null
+++ linux-2.6.10/drivers/spi/pnxalloc.h
@@ -0,0 +1,9 @@
+#ifndef __PNX_ALLOC_H
+#define __PNX_ALLOC_H
+void *pnx_memory_alloc(size_t size, int base);
+void pnx_memory_free(const void *data);
+unsigned long pnx_copy_from_user(void *to, const void *from_user,
+				 unsigned long len);
+unsigned long pnx_copy_to_user(void *to_user, const void *from,
+			       unsigned long len);
+#endif
Index: linux-2.6.10/drivers/spi/Kconfig
===================================================================
--- linux-2.6.10.orig/drivers/spi/Kconfig
+++ linux-2.6.10/drivers/spi/Kconfig
@@ -29,5 +29,17 @@
 	  This support is also available as a module.  If so, the module 
 	  will be called spi-dev.
 
+config SPI_PNX
+	tristate "PNX SPI bus support"
+	depends on SPI
+
+config SPI_PNX010X_ATMEL
+	tristate "Atmel Flash chip on PNX010x SPI support"
+	depends on SPI_PNX && ARCH_PNX010X
+
+config SPI_PNX4008_EEPROM
+	tristate "Dummy EEPROM driver"
+	depends on SPI_PNX && ARCH_PNX4008
+
 endmenu
 
Index: linux-2.6.10/drivers/spi/Makefile
===================================================================
--- linux-2.6.10.orig/drivers/spi/Makefile
+++ linux-2.6.10/drivers/spi/Makefile
@@ -4,6 +4,13 @@
 
 obj-$(CONFIG_SPI) += spi-core.o helpers.o
 
+obj-$(CONFIG_SPI_PNX)            += spipnx.o 
+obj-$(CONFIG_SPI_PNX010X_ATMEL)  += spi-pnx010x_atmel.o 
+
+obj-$(CONFIG_ARCH_PNX4008)       += pnxalloc.o
+obj-$(CONFIG_ARCH_PNX010X)       += pnxalloc.o
+
 obj-$(CONFIG_SPI_CHARDEV) += spi-dev.o
 
 ifeq ($(CONFIG_SPI_DEBUG),y)



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] spi
  2005-08-08 14:55   ` Greg KH
@ 2005-08-08 17:35     ` Marcel Holtmann
  2005-08-08 17:47       ` Marc Singer
  0 siblings, 1 reply; 15+ messages in thread
From: Marcel Holtmann @ 2005-08-08 17:35 UTC (permalink / raw)
  To: Greg KH; +Cc: dmitry pervushin, Linux Kernel Mailing List

Hi Greg,

> No spaces after ( or before ) please.  You do this all over the place in
> the code, please fix it up.
> 
> > +	if (NULL == dev || NULL == driver) {
> 
> Put the variable on the left side, gcc will complain if you incorrectly
> put a "=" instead of a "==" here, which is all that you are defending
> against with this style.

I think in this case the preferred way is

	if (!dev || !driver) {

Regards

Marcel



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] spi
  2005-08-08 17:35     ` Marcel Holtmann
@ 2005-08-08 17:47       ` Marc Singer
  2005-08-09 17:54         ` Andy Isaacson
  0 siblings, 1 reply; 15+ messages in thread
From: Marc Singer @ 2005-08-08 17:47 UTC (permalink / raw)
  To: Marcel Holtmann, Linux Kernel Mailing List

On Mon, Aug 08, 2005 at 07:35:36PM +0200, Marcel Holtmann wrote:
> > > +	if (NULL == dev || NULL == driver) {
> > 
> > Put the variable on the left side, gcc will complain if you incorrectly
> > put a "=" instead of a "==" here, which is all that you are defending
> > against with this style.
> 
> I think in this case the preferred way is
> 
> 	if (!dev || !driver) {
> 

That's not a guaranteed equivalence in the C standard.  Null pointers
may not be zero.  I don't think we have any targets that work this
way, however there is nothing wrong with explicitly testing for NULL.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] spi
  2005-08-08 16:41     ` dmitry pervushin
@ 2005-08-08 18:51       ` Mark Underwood
  0 siblings, 0 replies; 15+ messages in thread
From: Mark Underwood @ 2005-08-08 18:51 UTC (permalink / raw)
  To: dmitry pervushin; +Cc: Linux Kernel Mailing List


--- dmitry pervushin <dpervushin@gmail.com> wrote:

> 
> > Surely this should be locked with bus lock?
> Why not ? Until the transfer on device is not
> finished, the bus will be
> locked. Otherwise, the another device (on the same
> bus) might want to
> transfer something...

OK. My confusion was that we are also working on a SPI
subsystem which works in a different way.
Our SPI subsystem works much like the USB subsystem in
that drivers can queue up transfers and they will get
a callback when the transfer is complete.
Actually I think we have 4 modes of operation which
also allows transfers to be done in interrupt context,
with callback, wait for completion or high priority
(used to transfer high priority messages by bypassing
the transfer queue). I'll see if I can submit a patch
to the mailing list as I know its not only ideas but
code that counts ;-).


> > 
> > -= snip =-
> > 
> > Some other comments:
> > 1) I think you need to fix some of your comments
> > especially those describing how the interfaces
> work.
> > 2) I take it spi adaptor drivers now use
> > spi_bus_register/spi_bus_unregister?
> > 3) Different clients on one bus will want to run
> at
> > different speeds, how will you handle this?
> > 3) This subsystem can only handle small transfers
> like
> > I2C. SPI peripherals like SPI Ethernet devices
> will
> > have to do lots of large transfers and with your
> > current subsystem the device will be forced to
> wait
> > until its transfer has finished (as well as other
> > clients) when it might have other important work
> to
> > do.
> Hmm.. In the sample (it needs some polishing!), the
> bus initiates the
> DMA transfers and waits for completion on it. Do you
> want to have
> something like state machine (the function that will
> be called upon the
> end of transfer ?)

Yes, please see above.

> 
> 
>  Kconfig             |   12 +
>  Makefile            |    7
>  pnxalloc.c          |   70 ++++++
>  pnxalloc.h          |    9
>  spi-pnx010x_atmel.c |   91 ++++++++
>  spipnx-resources.h  |  138 ++++++++++++
>  spipnx.c            |  581
> ++++++++++++++++++++++++++++++++++++++++++++++++++++
> 
>  spipnx.h            |  309
> +++++++++++++++++++++++++++
>  8 files changed, 1455 insertions(+)
> 
> Index: linux-2.6.10/drivers/spi/spipnx-resources.h
>
===================================================================
> --- /dev/null
> +++ linux-2.6.10/drivers/spi/spipnx-resources.h
> @@ -0,0 +1,138 @@
> +#ifdef CONFIG_MACH_PNX0106_GH450
> +struct resource spipnx_010x_resources_0[] = 
> +{
> +	{ 
> +	  .start = BLAS_SPI0_BASE, 
> +	  .end = BLAS_SPI0_BASE + SZ_4K, 
> +	  .flags = IORESOURCE_MEM,
> +	}, { 
> +	  .start = SPI0_FIFO_DMA_SLAVE_NR, 
> +	  .flags = IORESOURCE_DMA,
> +	},
> +	/*
> +	 * Note that the clocks are shutdown in this order
> and resumed
> +	 * in the opposite order.
> +	 */
> +       	{ 
> +	  .start = CGU_SWITCHBOX_BLAS_SPI0_PCLK_ID, 
> +	  .flags = IORESOURCE_CLOCK_ID,
> +	}, {
> +	  .start = CGU_SWITCHBOX_BLAS_SPI0_PCLK_GAT_ID,
> +	  .flags = IORESOURCE_CLOCK_ID,
> +	}, {
> +	  .start = CGU_SWITCHBOX_BLAS_SPI0_FIFO_PCLK_ID,
> +	  .flags = IORESOURCE_CLOCK_ID,
> +	}, { 
> +	   .start =
> CGU_SWITCHBOX_BLAS_SPI0_DUMMY_VPBCLK_ID, 
> +	  .flags = IORESOURCE_CLOCK_ID,
> +	}, {
> +	  .start = VH_INTC_INT_NUM_BLAS_SPI0_INT, 
> +	  .flags =  IORESOURCE_IRQ,
> +	}, {
> +	   .flags = 0,
> +	}
> +};
> +
> +struct resource spipnx_010x_resources_1[] = 
> +{
> +	{ 
> +	  .start = BLAS_SPI1_BASE, 
> +	  .end = BLAS_SPI1_BASE + SZ_4K, 
> +	  .flags = IORESOURCE_MEM,
> +	}, { 
> +	  .start = SPI1_FIFO_DMA_SLAVE_NR, 
> +	  .flags = IORESOURCE_DMA,
> +	}, 
> +	/*
> +	 * Note that the clocks are shutdown in this order
> and resumed
> +	 * in the opposite order.
> +	 */
> +	{ 
> +	  .start = CGU_SWITCHBOX_BLAS_SPI1_PCLK_ID, 
> +	  .flags = IORESOURCE_CLOCK_ID,
> +	}, { 
> +	   .start = CGU_SWITCHBOX_BLAS_SPI1_PCLK_GAT_ID,
> +	   .flags = IORESOURCE_CLOCK_ID,
> +	}, { 
> +	  .start = CGU_SWITCHBOX_BLAS_SPI1_FIFO_PCLK_ID,
> +	  .flags = IORESOURCE_CLOCK_ID,
> +	}, {
> +	   .start =
> CGU_SWITCHBOX_BLAS_SPI1_DUMMY_VPBCLK_ID, 
> +	  .flags = IORESOURCE_CLOCK_ID,
> +	}, {
> +	  .start = VH_INTC_INT_NUM_BLAS_SPI1_INT, 
> +	  .flags =  IORESOURCE_IRQ,
> +	}, {
> +	   .flags = 0,
> +	}
> +};
> +#endif
> +
> +#ifdef CONFIG_MACH_PNX0105_GH448
> +struct resource spipnx_010x_resources[] = 
> +{
> +	{ 
> +	  .start = BLAS_SPI_BASE, 
> +	  .end = BLAS_SPI_BASE + SZ_4K, 
> +	  .flags = IORESOURCE_MEM,
> +	}, { 
> +	  .start = BLAS_SPI_DMA_SLAVE_NR, 
> +	  .flags = IORESOURCE_DMA,
> +	}, 
> +	/*
> +	 * Note that the clocks are shutdown in this order
> and resumed
> +	 * in the opposite order.
> +	 */
> +	{
> +	   .start =  CGU_SWITCHBOX_BLAS_SPI_PCLK_ID,
> +	   .flags = IORESOURCE_CLOCK_ID,
> +	}, {
> +	   .start = CGU_SWITCHBOX_BLAS_SPI_PCLK_GAT_ID,
> +	   .flags = IORESOURCE_CLOCK_ID,
> +	}, {
> +	   .start = CGU_SWITCHBOX_BLAS_SPI_FIFO_PCLK_ID,
> +	   .flags = IORESOURCE_CLOCK_ID,
> +	}, { 
> +	  .start = VH_INTC_INT_NUM_BLAS_SPI_INT, 
> +	  .flags =  IORESOURCE_IRQ,
> +	}, {
> +	   .flags = 0,
> +	}
> +};
> +#endif
> +
> +#ifdef CONFIG_ARCH_PNX4008
> +struct resource spipnx_4008_resources_0[] = 
> +{
> +	{ 	      
> +	  .start = PNX4008_SPI1_BASE, 
> +	  .end = PNX4008_SPI1_BASE + SZ_4K, 
> +	  .flags = IORESOURCE_MEM,
> +	}, { 
> +	  .start = 11 /* SPI1_DMA_PERIPHERAL_ID */, 
> +	  .flags = IORESOURCE_DMA,
> +	}, { 
> +	  .start = SPI1_INT, 
> +	  .flags =  IORESOURCE_IRQ,
> +	}, {
> +	   .flags = 0,
> +	}
> +};
> +
> +struct resource spipnx_4008_resources_1[] = 
> +{
> +	{ 	      
> +	  .start = PNX4008_SPI2_BASE, 
> +	  .end = PNX4008_SPI2_BASE + SZ_4K, 
> +	  .flags = IORESOURCE_MEM,
> +	}, { 
> +	  .start = 12 /* SPI2_DMA_PERIPHERAL_ID */, 
> +	  .flags = IORESOURCE_DMA,
> +	}, { 
> +	  .start = SPI2_INT, 
> +	  .flags =  IORESOURCE_IRQ,
> +	}, {
> +	   .flags = 0,
> +	}
> +};
> +#endif
> Index: linux-2.6.10/drivers/spi/spipnx.c
> 
=== message truncated ===



	
	
		
___________________________________________________________ 
Yahoo! Messenger - NEW crystal clear PC to PC calling worldwide with voicemail http://uk.messenger.yahoo.com

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] spi
  2005-08-08  9:12 ` [PATCH] spi dmitry pervushin
                     ` (2 preceding siblings ...)
  2005-08-08 14:55   ` Greg KH
@ 2005-08-08 22:58   ` Andrew Morton
  2005-08-10 13:10   ` Pavel Machek
  4 siblings, 0 replies; 15+ messages in thread
From: Andrew Morton @ 2005-08-08 22:58 UTC (permalink / raw)
  To: dmitry pervushin; +Cc: Linux Kernel Mailing List

dmitry pervushin <dpervushin@gmail.com> wrote:
>

A few coding style nits.

> +#include "spi_locals.h"
> +
> +static LIST_HEAD( spi_busses );

Please don't put spaces after '(' and before ')'.

> +		if (0 == strncmp(*id, SPI_ID_ANY, strlen(SPI_ID_ANY))) {

And this trick isn't really needed.  If you do

	if (whatever = constant)

then the compiler will generate a warning.  Please do these comparisons in
the conventional way, with the constant on the right hand side.

> +	if( bus ) {
> +		init_MUTEX( &bus->lock );
> +
> +		bus->platform_device.name = NULL;
> +		bus->the_bus.name = NULL;
> +
> +		strncpy( busname, name ? name : "SPI", sizeof( busname ) );

Lots more extraneous spaces after '(' and before ')'.

> +		if( bus->the_bus.name ) {
> +			strcpy( bus->the_bus.name, fullname );
> +		}

No braces here.

> +		err = bus_register( &bus->the_bus );
> +		if( err ) {
> +			goto out;
> +		}

And here.

> +		list_add_tail( &bus->bus_list, &spi_busses );
> +		bus->platform_device.name = kmalloc( strlen( busname )+1, GFP_KERNEL );
> +		if( bus->platform_device.name ) {
> +			strcpy( bus->platform_device.name, busname );
> +		}

and here...

> +void spi_bus_unregister( struct spi_bus* bus )
> +{
> +	if( bus ) {

We do put a space after `if', so this line should be

	if (bus) {

> +struct spi_bus* spi_bus_find( char* id )

The asterisk goes with the variable, not with the type.  So the above should be

	struct spi_bus *spi_bus_find(char *id)

> +int spi_device_add( struct spi_bus* bus, struct spi_device *dev, char* name)

Here too.

> +int spi_do_probe( struct device* dev, void* device_driver )

You seem to have an awful lot of non-static functions.  Please check
whether they all really need to have global scope.

> +	if (NULL == dev) {

	if (dev == NULL) {

> +static int spidev_do_open(struct device *the_dev, void *context)
> +{
> +	struct spidev_openclose *o = (struct spidev_openclose *) context;

Don't typecast void* when assigning to and from pointers.  It adds clutter
and defeats typechecking.

> +	struct spi_device *dev = SPI_DEV(the_dev);
> +	struct spidev_driver_data *drvdata;
> +
> +	drvdata = (struct spidev_driver_data *) dev_get_drvdata(the_dev);

Ditto.

> +
> +      out_unreg:

Labels go in column zero.

> +	void *(*alloc) (size_t, int);
> +	void (*free) (const void *);
> +	unsigned long (*copy_from_user) (void *to, const void *from_user,
> +					 unsigned long len);
> +	unsigned long (*copy_to_user) (void *to_user, const void *from,
> +				       unsigned long len);

The above names are risky.  Some platform may implement copy_to_user() as a
macro.



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] spi
  2005-08-08 17:47       ` Marc Singer
@ 2005-08-09 17:54         ` Andy Isaacson
  2005-08-09 19:05           ` Marc Singer
  0 siblings, 1 reply; 15+ messages in thread
From: Andy Isaacson @ 2005-08-09 17:54 UTC (permalink / raw)
  To: Marc Singer; +Cc: Marcel Holtmann, Linux Kernel Mailing List

On Mon, Aug 08, 2005 at 10:47:21AM -0700, Marc Singer wrote:
> On Mon, Aug 08, 2005 at 07:35:36PM +0200, Marcel Holtmann wrote:
> > > > +	if (NULL == dev || NULL == driver) {
> > > 
> > > Put the variable on the left side, gcc will complain if you incorrectly
> > > put a "=" instead of a "==" here, which is all that you are defending
> > > against with this style.
> > 
> > I think in this case the preferred way is
> > 
> > 	if (!dev || !driver) {
> > 
> 
> That's not a guaranteed equivalence in the C standard.  Null pointers
> may not be zero.  I don't think we have any targets that work this
> way, however there is nothing wrong with explicitly testing for NULL.

False.  The expression  "!x" is precisely equivalent to "x==0", no
matter what the type of x is. [1]  And furthermore, NULL==0. [2]
Ergo, "NULL == dev" and "!dev" are defined to be equivalent.

What you're confused about is that the *representation* of a null
pointer constant does not necessarily have to be all-bits-zero.  That
is, the following code fragment might print something on a
standard-compliant C implementation:

	void *a = 0; unsigned char *p = (unsigned char *)&a;
	int i;
	for(i=0; i<sizeof(a); i++)
		if(p[i] != 0) printf("p[%d] = %02x!\n", i, p[i]);

That does not change the fact that the source-code fragment "NULL" is
defined to be equivalent to the source-code fragment "0".  Simply the
compiler must do whatever trickery necessary to ensure the correct
values get generated in the object code for my above hypothetical
architecture when I say "void *a = 0;".

This is very similar to how floating point is handled in the abstract
machine definition of the standard.  Consider a weird FP implementation
where 0.0 has a not-all-bits-zero representation, and change 'a' in my
example above to type 'double'.  Just because 0.0 is stored as the bit
pattern 0x8000000000000000 does not mean that I have to write something
other than "double a = 0;"!

And furthermore, all of this was well-understood in the C89 standard;
it's not new in the C99 standard, although there are some
clarifications.

[1] ISO/IEC 9899:1999 6.5.3.3 Unary arithmetic operators

  (5) The result of the logical negation operator ! is 0 if the value of
  its operand compares unequal to 0, 1 if the value of its operand
  compares equal to 0. The result has type int.  The expression !E is
  equivalent to (0==E).

[2] ISO/IEC 9899:1999 7.17

  The following types and macros are defined in the standard header
  <stddef.h>.  ...
         NULL
  which expands to an implementation-defined null pointer constant...

 and 6.3.2.3 Pointers
  (3) An integer constant expression with the value 0, or such an
  expression cast to type void *, is called a null pointer constant.

-andy

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] spi
  2005-08-09 17:54         ` Andy Isaacson
@ 2005-08-09 19:05           ` Marc Singer
  2005-08-09 19:29             ` Andy Isaacson
  0 siblings, 1 reply; 15+ messages in thread
From: Marc Singer @ 2005-08-09 19:05 UTC (permalink / raw)
  To: Andy Isaacson; +Cc: Marcel Holtmann, Linux Kernel Mailing List

On Tue, Aug 09, 2005 at 10:54:34AM -0700, Andy Isaacson wrote:
> On Mon, Aug 08, 2005 at 10:47:21AM -0700, Marc Singer wrote:
> > On Mon, Aug 08, 2005 at 07:35:36PM +0200, Marcel Holtmann wrote:
> > > > > +	if (NULL == dev || NULL == driver) {
> > > > 
> > > > Put the variable on the left side, gcc will complain if you incorrectly
> > > > put a "=" instead of a "==" here, which is all that you are defending
> > > > against with this style.
> > > 
> > > I think in this case the preferred way is
> > > 
> > > 	if (!dev || !driver) {
> > > 
> > 
> > That's not a guaranteed equivalence in the C standard.  Null pointers
> > may not be zero.  I don't think we have any targets that work this
> > way, however there is nothing wrong with explicitly testing for NULL.
> 
> False.  The expression  "!x" is precisely equivalent to "x==0", no
> matter what the type of x is. [1]  And furthermore, NULL==0. [2]
> Ergo, "NULL == dev" and "!dev" are defined to be equivalent.
> 
> What you're confused about is that the *representation* of a null
> pointer constant does not necessarily have to be all-bits-zero.  That
> is, the following code fragment might print something on a
> standard-compliant C implementation:

No, I'm not confused about the representation of a NULL.  Keep in mind
that telling someone what they do or don't
understand/believe/think/feel is the fast track to being flamed.

> 
> 	void *a = 0; unsigned char *p = (unsigned char *)&a;
> 	int i;
> 	for(i=0; i<sizeof(a); i++)
> 		if(p[i] != 0) printf("p[%d] = %02x!\n", i, p[i]);
> 
> That does not change the fact that the source-code fragment "NULL" is
> defined to be equivalent to the source-code fragment "0".  Simply the
> compiler must do whatever trickery necessary to ensure the correct
> values get generated in the object code for my above hypothetical
> architecture when I say "void *a = 0;".
> 
> This is very similar to how floating point is handled in the abstract
> machine definition of the standard.  Consider a weird FP implementation
> where 0.0 has a not-all-bits-zero representation, and change 'a' in my
> example above to type 'double'.  Just because 0.0 is stored as the bit
> pattern 0x8000000000000000 does not mean that I have to write something
> other than "double a = 0;"!
> 
> And furthermore, all of this was well-understood in the C89 standard;
> it's not new in the C99 standard, although there are some
> clarifications.
> 
> [1] ISO/IEC 9899:1999 6.5.3.3 Unary arithmetic operators
> 
>   (5) The result of the logical negation operator ! is 0 if the value of
>   its operand compares unequal to 0, 1 if the value of its operand
>   compares equal to 0. The result has type int.  The expression !E is
>   equivalent to (0==E).
> 
> [2] ISO/IEC 9899:1999 7.17
> 
>   The following types and macros are defined in the standard header
>   <stddef.h>.  ...
>          NULL
>   which expands to an implementation-defined null pointer constant...
> 
>  and 6.3.2.3 Pointers
>   (3) An integer constant expression with the value 0, or such an
>   expression cast to type void *, is called a null pointer constant.

It was explained to me that the !pointer test wasn't guaranteed to be
equivalent because of the way that the test is handled.  The spec
fragments above don't address how the boolean test is coerced.  Does
it cast pointer to an integer and perform the test, or does it cast
the 0 to a pointer and perform the test.  The C++ spec I have is vague
on this point.  The only reference it makes to pointers is that the
operand for ! may be a pointer.




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] spi
  2005-08-09 19:05           ` Marc Singer
@ 2005-08-09 19:29             ` Andy Isaacson
  2005-08-15  7:51               ` Denis Vlasenko
  0 siblings, 1 reply; 15+ messages in thread
From: Andy Isaacson @ 2005-08-09 19:29 UTC (permalink / raw)
  To: Marc Singer; +Cc: Marcel Holtmann, Linux Kernel Mailing List

The code in question is

On Tue, Aug 09, 2005 at 12:05:00PM -0700, Marc Singer wrote:
> > > On Mon, Aug 08, 2005 at 07:35:36PM +0200, Marcel Holtmann wrote:
> > > > > > +	if (NULL == dev || NULL == driver) {
> > > > 	if (!dev || !driver) {
> > > 

You said:

> > > That's not a guaranteed equivalence in the C standard.  Null pointers
> > > may not be zero.  I don't think we have any targets that work this
> > > way, however there is nothing wrong with explicitly testing for NULL.

I quoted chapter and verse why that statement is not true:

> > [1] ISO/IEC 9899:1999 6.5.3.3 Unary arithmetic operators
> > 
> >   (5) The result of the logical negation operator ! is 0 if the value of
> >   its operand compares unequal to 0, 1 if the value of its operand
> >   compares equal to 0. The result has type int.  The expression !E is
> >   equivalent to (0==E).
> > 
> > [2] ISO/IEC 9899:1999 7.17
> > 
> >   The following types and macros are defined in the standard header
> >   <stddef.h>.  ...
> >          NULL
> >   which expands to an implementation-defined null pointer constant...
> > 
> >  and 6.3.2.3 Pointers
> >   (3) An integer constant expression with the value 0, or such an
> >   expression cast to type void *, is called a null pointer constant.
> 
> It was explained to me that the !pointer test wasn't guaranteed to be
> equivalent because of the way that the test is handled.

Whoever explained that to you was wrong.  6.5.3.3 is the final word on
how "!x" is interpreted, and it *says* in the *text* that
"!x" === "x!=0".  I don't see how this could be any clearer.

> The spec fragments above don't address how the boolean test is
> coerced.  Does it cast pointer to an integer and perform the test, or
> does it cast the 0 to a pointer and perform the test.  The C++ spec I
> have is vague on this point.  The only reference it makes to pointers
> is that the operand for ! may be a pointer.

Because of the equivalence *given in the text of 6.5.3.3* we can simply
follow the money.  (I'm not concerned, here, about what ambiguities the
C++ folks may or may not have introduced into their monstrosity.  The
Linux kernel is written in C, and the C standard is unambiguous on this
point.  Though frankly I'd be suprised if C++ breaks something so
straightforward and useful.)

The section that defines != says

6.5.9 Equality operators
  Syntax
(1)      equality-expression:
                relational-expression
                equality-expression == relational-expression
                equality-expression != relational-expression
  Constraints

(2) One of the following shall hold:
  ...
  -- one operand is a pointer and the other is a null pointer constant.

(5) ... If one operand is a pointer and the other is a null pointer
  constant, the null pointer constant is converted to the type of the
  pointer. ...

So:
1. !x is defined equivalent to x!=0.
2. 0 is a "null pointer constant".
3. (assuming x is a pointer) 0 will be promoted to pointer type in the
   expression "x!=0".



With the facts taken care of, we can move on to

> No, I'm not confused about the representation of a NULL.  Keep in mind
> that telling someone what they do or don't
> understand/believe/think/feel is the fast track to being flamed.

On Linux-kernel, being wrong is the fast track to being flamed.  When
I'm wrong, I expect to be corrected.  (Frankly, I'm wrong and *not*
corrected much more frequently than I find comfortable.)  Adjust your
expectations accordingly and you may be more comfortable here.

Your original statement was wrong, so I corrected you (as much to keep
the disinformation level to a low roar, as anything).  The code
transformation quoted at the top of this message is both
(1) well-defined by the C standard and (2) in keeping with kernel coding
standards.

HTH, HAND.
-andy

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] spi
  2005-08-08  9:12 ` [PATCH] spi dmitry pervushin
                     ` (3 preceding siblings ...)
  2005-08-08 22:58   ` Andrew Morton
@ 2005-08-10 13:10   ` Pavel Machek
  4 siblings, 0 replies; 15+ messages in thread
From: Pavel Machek @ 2005-08-10 13:10 UTC (permalink / raw)
  To: dmitry pervushin; +Cc: Linux Kernel Mailing List

Hi!

> +menu "SPI support"
> +
> +config SPI
> +	default Y
> +	tristate "SPI support"
> +        default false
> +	help
> +	  Say Y if you need to enable SPI support on your kernel

I'd expect explanation what "SPI" means somewhere around here...
								Pavel

-- 
if you have sharp zaurus hardware you don't need... you know my address

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] spi
  2005-08-09 19:29             ` Andy Isaacson
@ 2005-08-15  7:51               ` Denis Vlasenko
  0 siblings, 0 replies; 15+ messages in thread
From: Denis Vlasenko @ 2005-08-15  7:51 UTC (permalink / raw)
  To: Andy Isaacson, Marc Singer; +Cc: Marcel Holtmann, Linux Kernel Mailing List

> > It was explained to me that the !pointer test wasn't guaranteed to be
> > equivalent because of the way that the test is handled.
> 
> Whoever explained that to you was wrong.  6.5.3.3 is the final word on
> how "!x" is interpreted, and it *says* in the *text* that
> "!x" === "x!=0".  I don't see how this could be any clearer.
> 
> > The spec fragments above don't address how the boolean test is
> > coerced.  Does it cast pointer to an integer and perform the test, or
> > does it cast the 0 to a pointer and perform the test.  The C++ spec I
> > have is vague on this point.  The only reference it makes to pointers
> > is that the operand for ! may be a pointer.
> 
> Because of the equivalence *given in the text of 6.5.3.3* we can simply
> follow the money.  (I'm not concerned, here, about what ambiguities the
> C++ folks may or may not have introduced into their monstrosity.  The
> Linux kernel is written in C, and the C standard is unambiguous on this
> point.  Though frankly I'd be suprised if C++ breaks something so
> straightforward and useful.)
> 
> The section that defines != says
> 
> 6.5.9 Equality operators
>   Syntax
> (1)      equality-expression:
>                 relational-expression
>                 equality-expression == relational-expression
>                 equality-expression != relational-expression
>   Constraints
> 
> (2) One of the following shall hold:
>   ...
>   -- one operand is a pointer and the other is a null pointer constant.
> 
> (5) ... If one operand is a pointer and the other is a null pointer
>   constant, the null pointer constant is converted to the type of the
>   pointer. ...
> 
> So:
> 1. !x is defined equivalent to x!=0.
> 2. 0 is a "null pointer constant".
> 3. (assuming x is a pointer) 0 will be promoted to pointer type in the
>    expression "x!=0".

You are right to 99.9% ;)

The last 0.1% of wrongness comes from linux/stddef.h:
...
#define NULL ((void *)0)

Thus, !ptr is equivalent to ptr==0 but not equivalent to ptr==NULL
in general case for the kernel code (it is equivalent if ptr is
a variable of a _pointer type_ because ptr then implicitly converted
to (void*)).

Our NULL isn't 0 by design. it's not a bug, regardless what Stroustrup says
about NULL define.
--
vda


^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2005-08-15  7:51 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-07-10 20:01 [PATCH 3/3] kconfig: linux.pot for all arch Egry Gábor
2005-08-08  9:12 ` [PATCH] spi dmitry pervushin
2005-08-08 10:41   ` Jiri Slaby
2005-08-08 13:16   ` Mark Underwood
2005-08-08 16:41     ` dmitry pervushin
2005-08-08 18:51       ` Mark Underwood
2005-08-08 14:55   ` Greg KH
2005-08-08 17:35     ` Marcel Holtmann
2005-08-08 17:47       ` Marc Singer
2005-08-09 17:54         ` Andy Isaacson
2005-08-09 19:05           ` Marc Singer
2005-08-09 19:29             ` Andy Isaacson
2005-08-15  7:51               ` Denis Vlasenko
2005-08-08 22:58   ` Andrew Morton
2005-08-10 13:10   ` Pavel Machek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®