Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 22 Apr 2008 23:47:54 +0000 (16:47 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 22 Apr 2008 23:47:54 +0000 (16:47 -0700)
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6:
  [IA64] run drivers/misc/sgi-xp through scripts/checkpatch.pl
  [IA64] run rest drivers/misc/sgi-xp through scripts/Lindent
  [IA64] run some drivers/misc/sgi-xp through scripts/Lindent
  [IA64] move XP and XPC to drivers/misc/sgi-xp
  [IA64] minor irq handler cleanups
  [IA64] simplify notify hooks in mca.c
  [IA64] do notify DIE_MCA_MONARCH_PROCESS for each monarchs
  [IA64] disable interrupts on exit of ia64_trace_syscall

99 files changed:
drivers/block/brd.c
drivers/hid/hid-core.c
drivers/hid/hid-debug.c
drivers/hid/hid-input-quirks.c
drivers/hid/usbhid/Kconfig
drivers/hid/usbhid/Makefile
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/hid-ff.c
drivers/hid/usbhid/hid-lg2ff.c [new file with mode: 0644]
drivers/hid/usbhid/hid-quirks.c
drivers/hid/usbhid/hiddev.c
drivers/hid/usbhid/usbhid.h
drivers/i2c/algos/Kconfig
drivers/i2c/algos/i2c-algo-pca.c
drivers/i2c/algos/i2c-algo-pca.h [deleted file]
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-at91.c
drivers/i2c/busses/i2c-au1550.c
drivers/i2c/busses/i2c-bfin-twi.c
drivers/i2c/busses/i2c-davinci.c
drivers/i2c/busses/i2c-gpio.c
drivers/i2c/busses/i2c-ibm_iic.c
drivers/i2c/busses/i2c-iop3xx.c
drivers/i2c/busses/i2c-ixp2000.c
drivers/i2c/busses/i2c-mpc.c
drivers/i2c/busses/i2c-ocores.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-pca-isa.c
drivers/i2c/busses/i2c-pca-platform.c [new file with mode: 0644]
drivers/i2c/busses/i2c-pmcmsp.c
drivers/i2c/busses/i2c-pnx.c
drivers/i2c/busses/i2c-powermac.c
drivers/i2c/busses/i2c-pxa.c
drivers/i2c/busses/i2c-s3c2410.c
drivers/i2c/busses/i2c-sh7760.c [new file with mode: 0644]
drivers/i2c/busses/i2c-sh_mobile.c [new file with mode: 0644]
drivers/i2c/busses/i2c-simtec.c
drivers/i2c/busses/i2c-versatile.c
drivers/i2c/busses/scx200_acb.c
drivers/i2c/chips/isp1301_omap.c
drivers/i2c/i2c-core.c
drivers/i2c/i2c-dev.c
fs/Kconfig
fs/dlm/Makefile
fs/dlm/config.c
fs/dlm/config.h
fs/dlm/dlm_internal.h
fs/dlm/lock.c
fs/dlm/lock.h
fs/dlm/main.c
fs/dlm/member.c
fs/dlm/plock.c [moved from fs/gfs2/locking/dlm/plock.c with 67% similarity]
fs/dlm/recoverd.c
fs/gfs2/locking/dlm/Makefile
fs/gfs2/locking/dlm/lock_dlm.h
fs/gfs2/locking/dlm/main.c
fs/gfs2/locking/dlm/mount.c
fs/read_write.c
fs/seq_file.c
fs/udf/Makefile
fs/udf/balloc.c
fs/udf/crc.c [deleted file]
fs/udf/dir.c
fs/udf/ecma_167.h
fs/udf/file.c
fs/udf/ialloc.c
fs/udf/inode.c
fs/udf/lowlevel.c
fs/udf/misc.c
fs/udf/namei.c
fs/udf/partition.c
fs/udf/super.c
fs/udf/symlink.c
fs/udf/truncate.c
fs/udf/udf_i.h
fs/udf/udf_sb.h
fs/udf/udfdecl.h
fs/udf/udfend.h
fs/udf/udftime.c
fs/udf/unicode.c
include/asm-sh/i2c-sh7760.h [new file with mode: 0644]
include/linux/Kbuild
include/linux/dlm.h
include/linux/dlm_device.h
include/linux/dlm_plock.h [new file with mode: 0644]
include/linux/dlmconstants.h
include/linux/hid.h
include/linux/hidraw.h
include/linux/i2c-algo-pca.h
include/linux/i2c-pca-platform.h [new file with mode: 0644]
include/linux/lock_dlm_plock.h [deleted file]
include/linux/udf_fs.h [deleted file]
include/linux/udf_fs_i.h
include/linux/udf_fs_sb.h [deleted file]
kernel/sched.c
security/selinux/avc.c
security/selinux/hooks.c
security/selinux/netif.c

index 8536480..7bd7663 100644 (file)
@@ -108,7 +108,7 @@ static struct page *brd_insert_page(struct brd_device *brd, sector_t sector)
 #ifndef CONFIG_BLK_DEV_XIP
        gfp_flags |= __GFP_HIGHMEM;
 #endif
-       page = alloc_page(GFP_NOIO | __GFP_HIGHMEM | __GFP_ZERO);
+       page = alloc_page(gfp_flags);
        if (!page)
                return NULL;
 
index f0b00ec..e03c67d 100644 (file)
@@ -44,8 +44,8 @@
 
 #ifdef CONFIG_HID_DEBUG
 int hid_debug = 0;
-module_param_named(debug, hid_debug, bool, 0600);
-MODULE_PARM_DESC(debug, "Turn HID debugging mode on and off");
+module_param_named(debug, hid_debug, int, 0600);
+MODULE_PARM_DESC(debug, "HID debugging (0=off, 1=probing info, 2=continuous data dumping)");
 EXPORT_SYMBOL_GPL(hid_debug);
 #endif
 
@@ -97,7 +97,7 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
        field->index = report->maxfield++;
        report->field[field->index] = field;
        field->usage = (struct hid_usage *)(field + 1);
-       field->value = (unsigned *)(field->usage + usages);
+       field->value = (s32 *)(field->usage + usages);
        field->report = report;
 
        return field;
@@ -830,7 +830,8 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field, s
  * reporting to the layer).
  */
 
-void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt)
+static void hid_input_field(struct hid_device *hid, struct hid_field *field,
+                           __u8 *data, int interrupt)
 {
        unsigned n;
        unsigned count = field->report_count;
@@ -876,7 +877,6 @@ void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data
 exit:
        kfree(value);
 }
-EXPORT_SYMBOL_GPL(hid_input_field);
 
 /*
  * Output the field into the report.
@@ -988,8 +988,13 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
 
        if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
                hid->hiddev_report_event(hid, report);
-       if (hid->claimed & HID_CLAIMED_HIDRAW)
-               hidraw_report_event(hid, data, size);
+       if (hid->claimed & HID_CLAIMED_HIDRAW) {
+               /* numbered reports need to be passed with the report num */
+               if (report_enum->numbered)
+                       hidraw_report_event(hid, data - 1, size + 1);
+               else
+                       hidraw_report_event(hid, data, size);
+       }
 
        for (n = 0; n < report->maxfield; n++)
                hid_input_field(hid, report->field[n], data, interrupt);
index 5c24fe4..f88714b 100644 (file)
@@ -498,7 +498,7 @@ void hid_dump_device(struct hid_device *device) {
 EXPORT_SYMBOL_GPL(hid_dump_device);
 
 void hid_dump_input(struct hid_usage *usage, __s32 value) {
-       if (!hid_debug)
+       if (hid_debug < 2)
                return;
 
        printk(KERN_DEBUG "hid-debug: input ");
index dceadd0..4c2052c 100644 (file)
@@ -276,6 +276,21 @@ static int quirk_btc_8193(struct hid_usage *usage, struct input_dev *input,
        return 1;
 }
 
+static int quirk_sunplus_wdesktop(struct hid_usage *usage, struct input_dev *input,
+                             unsigned long **bit, int *max)
+{
+       if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+               return 0;
+
+       switch (usage->hid & HID_USAGE) {
+               case 0x2003: map_key_clear(KEY_ZOOMIN);         break;
+               case 0x2103: map_key_clear(KEY_ZOOMOUT);        break;
+               default:
+                       return 0;
+       }
+       return 1;
+}
+
 #define VENDOR_ID_BELKIN                       0x1020
 #define DEVICE_ID_BELKIN_WIRELESS_KEYBOARD     0x0006
 
@@ -306,6 +321,9 @@ static int quirk_btc_8193(struct hid_usage *usage, struct input_dev *input,
 #define VENDOR_ID_PETALYNX                     0x18b1
 #define DEVICE_ID_PETALYNX_MAXTER_REMOTE       0x0037
 
+#define VENDOR_ID_SUNPLUS                      0x04fc
+#define DEVICE_ID_SUNPLUS_WDESKTOP             0x05d8
+
 static const struct hid_input_blacklist {
        __u16 idVendor;
        __u16 idProduct;
@@ -332,8 +350,10 @@ static const struct hid_input_blacklist {
        { VENDOR_ID_MONTEREY, DEVICE_ID_GENIUS_KB29E, quirk_cherry_genius_29e },
 
        { VENDOR_ID_PETALYNX, DEVICE_ID_PETALYNX_MAXTER_REMOTE, quirk_petalynx_remote },
-       
-       { 0, 0, 0 }
+
+       { VENDOR_ID_SUNPLUS, DEVICE_ID_SUNPLUS_WDESKTOP, quirk_sunplus_wdesktop },
+
+       { 0, 0, NULL }
 };
 
 int hidinput_mapping_quirks(struct hid_usage *usage, 
index 7160fa6..18f0910 100644 (file)
@@ -71,6 +71,14 @@ config LOGITECH_FF
          Note: if you say N here, this device will still be supported, but without
          force feedback.
 
+config LOGIRUMBLEPAD2_FF
+       bool "Logitech Rumblepad 2 support"
+       depends on HID_FF
+       select INPUT_FF_MEMLESS if USB_HID
+       help
+         Say Y here if you want to enable force feedback support for Logitech
+         Rumblepad 2 devices.
+
 config PANTHERLORD_FF
        bool "PantherLord/GreenAsia based device support"
        depends on HID_FF
@@ -80,8 +88,8 @@ config PANTHERLORD_FF
          or adapter and want to enable force feedback support for it.
 
 config THRUSTMASTER_FF
-       bool "ThrustMaster devices support (EXPERIMENTAL)"
-       depends on HID_FF && EXPERIMENTAL
+       bool "ThrustMaster devices support"
+       depends on HID_FF
        select INPUT_FF_MEMLESS if USB_HID
        help
          Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
index 8e6ab5b..00a7b70 100644 (file)
@@ -16,6 +16,9 @@ endif
 ifeq ($(CONFIG_LOGITECH_FF),y)
        usbhid-objs     += hid-lgff.o
 endif
+ifeq ($(CONFIG_LOGIRUMBLEPAD2_FF),y)
+       usbhid-objs     += hid-lg2ff.o
+endif
 ifeq ($(CONFIG_PANTHERLORD_FF),y)
        usbhid-objs     += hid-plff.o
 endif
index d95979f..e0d805f 100644 (file)
@@ -82,6 +82,7 @@ static int hid_start_in(struct hid_device *hid)
 
        spin_lock_irqsave(&usbhid->inlock, flags);
        if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) &&
+                       !test_bit(HID_DISCONNECTED, &usbhid->iofl) &&
                        !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
                rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
                if (rc != 0)
@@ -155,7 +156,7 @@ static void hid_io_error(struct hid_device *hid)
        spin_lock_irqsave(&usbhid->inlock, flags);
 
        /* Stop when disconnected */
-       if (usb_get_intfdata(usbhid->intf) == NULL)
+       if (test_bit(HID_DISCONNECTED, &usbhid->iofl))
                goto done;
 
        /* If it has been a while since the last error, we'll assume
@@ -341,7 +342,7 @@ static void hid_irq_out(struct urb *urb)
        if (usbhid->outhead != usbhid->outtail) {
                if (hid_submit_out(hid)) {
                        clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
-                       wake_up(&hid->wait);
+                       wake_up(&usbhid->wait);
                }
                spin_unlock_irqrestore(&usbhid->outlock, flags);
                return;
@@ -349,7 +350,7 @@ static void hid_irq_out(struct urb *urb)
 
        clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
        spin_unlock_irqrestore(&usbhid->outlock, flags);
-       wake_up(&hid->wait);
+       wake_up(&usbhid->wait);
 }
 
 /*
@@ -391,7 +392,7 @@ static void hid_ctrl(struct urb *urb)
        if (usbhid->ctrlhead != usbhid->ctrltail) {
                if (hid_submit_ctrl(hid)) {
                        clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
-                       wake_up(&hid->wait);
+                       wake_up(&usbhid->wait);
                }
                spin_unlock_irqrestore(&usbhid->ctrllock, flags);
                return;
@@ -399,7 +400,7 @@ static void hid_ctrl(struct urb *urb)
 
        clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
        spin_unlock_irqrestore(&usbhid->ctrllock, flags);
-       wake_up(&hid->wait);
+       wake_up(&usbhid->wait);
 }
 
 void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
@@ -478,8 +479,9 @@ int usbhid_wait_io(struct hid_device *hid)
 {
        struct usbhid_device *usbhid = hid->driver_data;
 
-       if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) &&
-                                       !test_bit(HID_OUT_RUNNING, &usbhid->iofl)),
+       if (!wait_event_timeout(usbhid->wait,
+                               (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) &&
+                               !test_bit(HID_OUT_RUNNING, &usbhid->iofl)),
                                        10*HZ)) {
                dbg_hid("timeout waiting for ctrl or out queue to clear\n");
                return -1;
@@ -610,10 +612,11 @@ static void usbhid_set_leds(struct hid_device *hid)
 /*
  * Traverse the supplied list of reports and find the longest
  */
-static void hid_find_max_report(struct hid_device *hid, unsigned int type, int *max)
+static void hid_find_max_report(struct hid_device *hid, unsigned int type,
+               unsigned int *max)
 {
        struct hid_report *report;
-       int size;
+       unsigned int size;
 
        list_for_each_entry(report, &hid->report_enum[type].report_list, list) {
                size = ((report->size - 1) >> 3) + 1;
@@ -705,9 +708,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
        struct hid_descriptor *hdesc;
        struct hid_device *hid;
        u32 quirks = 0;
-       unsigned rsize = 0;
+       unsigned int insize = 0, rsize = 0;
        char *rdesc;
-       int n, len, insize = 0;
+       int n, len;
        struct usbhid_device *usbhid;
 
        quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
@@ -800,6 +803,22 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
                goto fail;
        }
 
+       hid->name[0] = 0;
+
+       if (dev->manufacturer)
+               strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
+
+       if (dev->product) {
+               if (dev->manufacturer)
+                       strlcat(hid->name, " ", sizeof(hid->name));
+               strlcat(hid->name, dev->product, sizeof(hid->name));
+       }
+
+       if (!strlen(hid->name))
+               snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
+                        le16_to_cpu(dev->descriptor.idVendor),
+                        le16_to_cpu(dev->descriptor.idProduct));
+
        for (n = 0; n < interface->desc.bNumEndpoints; n++) {
 
                struct usb_endpoint_descriptor *endpoint;
@@ -812,6 +831,14 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 
                interval = endpoint->bInterval;
 
+               /* Some vendors give fullspeed interval on highspeed devides */
+               if (quirks & HID_QUIRK_FULLSPEED_INTERVAL  &&
+                   dev->speed == USB_SPEED_HIGH) {
+                       interval = fls(endpoint->bInterval*8);
+                       printk(KERN_INFO "%s: Fixing fullspeed to highspeed interval: %d -> %d\n",
+                              hid->name, endpoint->bInterval, interval);
+               }
+
                /* Change the polling interval of mice. */
                if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
                        interval = hid_mousepoll_interval;
@@ -844,8 +871,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
                goto fail;
        }
 
-       init_waitqueue_head(&hid->wait);
-
+       init_waitqueue_head(&usbhid->wait);
        INIT_WORK(&usbhid->reset_work, hid_reset);
        setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
 
@@ -859,22 +885,6 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
        usbhid->intf = intf;
        usbhid->ifnum = interface->desc.bInterfaceNumber;
 
-       hid->name[0] = 0;
-
-       if (dev->manufacturer)
-               strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
-
-       if (dev->product) {
-               if (dev->manufacturer)
-                       strlcat(hid->name, " ", sizeof(hid->name));
-               strlcat(hid->name, dev->product, sizeof(hid->name));
-       }
-
-       if (!strlen(hid->name))
-               snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
-                        le16_to_cpu(dev->descriptor.idVendor),
-                        le16_to_cpu(dev->descriptor.idProduct));
-
        hid->bus = BUS_USB;
        hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
        hid->product = le16_to_cpu(dev->descriptor.idProduct);
@@ -932,6 +942,7 @@ static void hid_disconnect(struct usb_interface *intf)
 
        spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
        usb_set_intfdata(intf, NULL);
+       set_bit(HID_DISCONNECTED, &usbhid->iofl);
        spin_unlock_irq(&usbhid->inlock);
        usb_kill_urb(usbhid->urbin);
        usb_kill_urb(usbhid->urbout);
index 4c210e1..1d0dac5 100644 (file)
@@ -59,6 +59,9 @@ static struct hid_ff_initializer inits[] = {
        { 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
        { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
 #endif
+#ifdef CONFIG_LOGIRUMBLEPAD2_FF
+       { 0x46d, 0xc218, hid_lg2ff_init }, /* Logitech Rumblepad 2 */
+#endif
 #ifdef CONFIG_PANTHERLORD_FF
        { 0x810, 0x0001, hid_plff_init }, /* "Twin USB Joystick" */
        { 0xe8f, 0x0003, hid_plff_init }, /* "GreenAsia Inc.    USB Joystick     " */
diff --git a/drivers/hid/usbhid/hid-lg2ff.c b/drivers/hid/usbhid/hid-lg2ff.c
new file mode 100644 (file)
index 0000000..d469bd0
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ *  Force feedback support for Logitech Rumblepad 2
+ *
+ *  Copyright (c) 2008 Anssi Hannula <anssi.hannula@gmail.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include "usbhid.h"
+
+struct lg2ff_device {
+       struct hid_report *report;
+};
+
+static int play_effect(struct input_dev *dev, void *data,
+                        struct ff_effect *effect)
+{
+       struct hid_device *hid = input_get_drvdata(dev);
+       struct lg2ff_device *lg2ff = data;
+       int weak, strong;
+
+       strong = effect->u.rumble.strong_magnitude;
+       weak = effect->u.rumble.weak_magnitude;
+
+       if (weak || strong) {
+               weak = weak * 0xff / 0xffff;
+               strong = strong * 0xff / 0xffff;
+
+               lg2ff->report->field[0]->value[0] = 0x51;
+               lg2ff->report->field[0]->value[2] = weak;
+               lg2ff->report->field[0]->value[4] = strong;
+       } else {
+               lg2ff->report->field[0]->value[0] = 0xf3;
+               lg2ff->report->field[0]->value[2] = 0x00;
+               lg2ff->report->field[0]->value[4] = 0x00;
+       }
+
+       usbhid_submit_report(hid, lg2ff->report, USB_DIR_OUT);
+       return 0;
+}
+
+int hid_lg2ff_init(struct hid_device *hid)
+{
+       struct lg2ff_device *lg2ff;
+       struct hid_report *report;
+       struct hid_input *hidinput = list_entry(hid->inputs.next,
+                                               struct hid_input, list);
+       struct list_head *report_list =
+                       &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+       struct input_dev *dev = hidinput->input;
+       int error;
+
+       if (list_empty(report_list)) {
+               printk(KERN_ERR "hid-lg2ff: no output report found\n");
+               return -ENODEV;
+       }
+
+       report = list_entry(report_list->next, struct hid_report, list);
+
+       if (report->maxfield < 1) {
+               printk(KERN_ERR "hid-lg2ff: output report is empty\n");
+               return -ENODEV;
+       }
+       if (report->field[0]->report_count < 7) {
+               printk(KERN_ERR "hid-lg2ff: not enough values in the field\n");
+               return -ENODEV;
+       }
+
+       lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL);
+       if (!lg2ff)
+               return -ENOMEM;
+
+       set_bit(FF_RUMBLE, dev->ffbit);
+
+       error = input_ff_create_memless(dev, lg2ff, play_effect);
+       if (error) {
+               kfree(lg2ff);
+               return error;
+       }
+
+       lg2ff->report = report;
+       report->field[0]->value[0] = 0xf3;
+       report->field[0]->value[1] = 0x00;
+       report->field[0]->value[2] = 0x00;
+       report->field[0]->value[3] = 0x00;
+       report->field[0]->value[4] = 0x00;
+       report->field[0]->value[5] = 0x00;
+       report->field[0]->value[6] = 0x00;
+
+       usbhid_submit_report(hid, report, USB_DIR_OUT);
+
+       printk(KERN_INFO "Force feedback for Logitech Rumblepad 2 by "
+              "Anssi Hannula <anssi.hannula@gmail.com>\n");
+
+       return 0;
+}
index e29a057..28ddc3f 100644 (file)
@@ -32,6 +32,9 @@
 #define USB_VENDOR_ID_ADS_TECH                 0x06e1
 #define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X    0xa155
 
+#define USB_VENDOR_ID_AFATECH          0x15a4
+#define USB_DEVICE_ID_AFATECH_AF9016   0x9016
+
 #define USB_VENDOR_ID_AIPTEK           0x08ca
 #define USB_DEVICE_ID_AIPTEK_01                0x0001
 #define USB_DEVICE_ID_AIPTEK_10                0x0010
 #define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
 #define USB_DEVICE_ID_DELORME_EM_LT20  0x0200
 
+#define USB_VENDOR_ID_DMI              0x0c0b
+#define USB_DEVICE_ID_DMI_ENC          0x5fab
+
 #define USB_VENDOR_ID_ELO              0x04E7
 #define USB_DEVICE_ID_ELO_TS2700       0x0020
 
 #define USB_DEVICE_ID_GTCO_502         0x0502
 #define USB_DEVICE_ID_GTCO_503         0x0503
 #define USB_DEVICE_ID_GTCO_504         0x0504
-#define USB_DEVICE_ID_GTCO_600         0x0600
-#define USB_DEVICE_ID_GTCO_601         0x0601
-#define USB_DEVICE_ID_GTCO_602         0x0602
-#define USB_DEVICE_ID_GTCO_603         0x0603
-#define USB_DEVICE_ID_GTCO_604         0x0604
-#define USB_DEVICE_ID_GTCO_605         0x0605
-#define USB_DEVICE_ID_GTCO_606         0x0606
-#define USB_DEVICE_ID_GTCO_607         0x0607
-#define USB_DEVICE_ID_GTCO_608         0x0608
-#define USB_DEVICE_ID_GTCO_609         0x0609
-#define USB_DEVICE_ID_GTCO_609         0x0609
 #define USB_DEVICE_ID_GTCO_1000                0x1000
 #define USB_DEVICE_ID_GTCO_1001                0x1001
 #define USB_DEVICE_ID_GTCO_1002                0x1002
 #define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500  0xc512
 #define USB_DEVICE_ID_MX3000_RECEIVER  0xc513
 #define USB_DEVICE_ID_DINOVO_EDGE      0xc714
+#define USB_DEVICE_ID_DINOVO_MINI      0xc71f
 
 #define USB_VENDOR_ID_MCC              0x09db
 #define USB_DEVICE_ID_MCC_PMD1024LS    0x0076
 #define USB_VENDOR_ID_MICROSOFT                0x045e
 #define USB_DEVICE_ID_SIDEWINDER_GV    0x003b
 #define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d
+#define USB_DEVICE_ID_DESKTOP_RECV_1028 0x00f9
 #define USB_DEVICE_ID_MS_NE4K          0x00db
 #define USB_DEVICE_ID_MS_LK6K          0x00f9
 
 #define USB_VENDOR_ID_SUN              0x0430
 #define USB_DEVICE_ID_RARITAN_KVM_DONGLE       0xcdab
 
+#define USB_VENDOR_ID_SUNPLUS          0x04fc
+#define USB_DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8
+
 #define USB_VENDOR_ID_TOPMAX           0x0663
 #define USB_DEVICE_ID_TOPMAX_COBRAPAD  0x0103
 
@@ -435,9 +435,13 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
        
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES },
+       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI, HID_QUIRK_DUPLICATE_USAGES },
+
+       { USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL },
 
        { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV },
        { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
+       { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
        { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT },
 
        { USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193, HID_QUIRK_HWHEEL_WHEEL_INVERT },
@@ -518,16 +522,6 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_600, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_601, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_602, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_603, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_604, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_605, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_606, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_607, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_608, HID_QUIRK_IGNORE },
-       { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_609, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002, HID_QUIRK_IGNORE },
@@ -601,6 +595,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET },
@@ -608,7 +603,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
-       { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
+       { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
        { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
 
        { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
@@ -719,6 +714,7 @@ static const struct hid_rdesc_blacklist {
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER, HID_QUIRK_RDESC_LOGITECH },
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_RDESC_LOGITECH },
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_RDESC_LOGITECH },
+       { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_DESKTOP_RECV_1028, HID_QUIRK_RDESC_MICROSOFT_RECV_1028 },
 
        { USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E, HID_QUIRK_RDESC_BUTTON_CONSUMER },
 
@@ -728,6 +724,8 @@ static const struct hid_rdesc_blacklist {
 
        { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_RDESC_SAMSUNG_REMOTE },
 
+       { USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP, HID_QUIRK_RDESC_SUNPLUS_WDESKTOP },
+
        { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
        { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
 
@@ -793,8 +791,8 @@ static struct hid_blacklist *usbhid_exists_dquirk(const u16 idVendor,
  *
  * Returns: 0 OK, -error on failure.
  */
-int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct,
-               const u32 quirks)
+static int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct,
+                               const u32 quirks)
 {
        struct quirks_list_struct *q_new, *q;
        int list_edited = 0;
@@ -1002,6 +1000,17 @@ static void usbhid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize)
        }
 }
 
+static void usbhid_fixup_sunplus_wdesktop(unsigned char *rdesc, int rsize)
+{
+       if (rsize >= 107 && rdesc[104] == 0x26
+                        && rdesc[105] == 0x80
+                        && rdesc[106] == 0x03) {
+               printk(KERN_INFO "Fixing up Sunplus Wireless Desktop report descriptor\n");
+               rdesc[105] = rdesc[110] = 0x03;
+               rdesc[106] = rdesc[111] = 0x21;
+       }
+}
+
 /*
  * Samsung IrDA remote controller (reports as Cypress USB Mouse).
  *
@@ -1089,6 +1098,28 @@ static void usbhid_fixup_button_consumer_descriptor(unsigned char *rdesc, int rs
        }
 }
 
+/*
+ * Microsoft Wireless Desktop Receiver (Model 1028) has several
+ * 'Usage Min/Max' where it ought to have 'Physical Min/Max'
+ */
+static void usbhid_fixup_microsoft_descriptor(unsigned char *rdesc, int rsize)
+{
+       if (rsize == 571 && rdesc[284] == 0x19
+                        && rdesc[286] == 0x2a
+                        && rdesc[304] == 0x19
+                        && rdesc[306] == 0x29
+                        && rdesc[352] == 0x1a
+                        && rdesc[355] == 0x2a
+                        && rdesc[557] == 0x19
+                        && rdesc[559] == 0x29) {
+               printk(KERN_INFO "Fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n");
+               rdesc[284] = rdesc[304] = rdesc[558] = 0x35;
+               rdesc[352] = 0x36;
+               rdesc[286] = rdesc[355] = 0x46;
+               rdesc[306] = rdesc[559] = 0x45;
+       }
+}
+
 static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize)
 {
        if ((quirks & HID_QUIRK_RDESC_CYMOTION))
@@ -1112,6 +1143,11 @@ static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned
        if (quirks & HID_QUIRK_RDESC_SAMSUNG_REMOTE)
                usbhid_fixup_samsung_irda_descriptor(rdesc, rsize);
 
+       if (quirks & HID_QUIRK_RDESC_MICROSOFT_RECV_1028)
+               usbhid_fixup_microsoft_descriptor(rdesc, rsize);
+
+       if (quirks & HID_QUIRK_RDESC_SUNPLUS_WDESKTOP)
+               usbhid_fixup_sunplus_wdesktop(rdesc, rsize);
 }
 
 /**
@@ -1150,5 +1186,4 @@ void usbhid_fixup_report_descriptor(const u16 idVendor, const u16 idProduct,
                else if (paramVendor == idVendor && paramProduct == idProduct)
                        __usbhid_fixup_report_descriptor(quirks, rdesc, rsize);
        }
-
 }
index 5fc4019..95cc192 100644 (file)
@@ -393,6 +393,153 @@ static unsigned int hiddev_poll(struct file *file, poll_table *wait)
 /*
  * "ioctl" file op
  */
+static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg)
+{
+       struct hid_device *hid = hiddev->hid;
+       struct hiddev_report_info rinfo;
+       struct hiddev_usage_ref_multi *uref_multi = NULL;
+       struct hiddev_usage_ref *uref;
+       struct hid_report *report;
+       struct hid_field *field;
+       int i;
+
+       uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
+       if (!uref_multi)
+               return -ENOMEM;
+       uref = &uref_multi->uref;
+       if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
+               if (copy_from_user(uref_multi, user_arg,
+                                  sizeof(*uref_multi)))
+                       goto fault;
+       } else {
+               if (copy_from_user(uref, user_arg, sizeof(*uref)))
+                       goto fault;
+       }
+
+       switch (cmd) {
+       case HIDIOCGUCODE:
+               rinfo.report_type = uref->report_type;
+               rinfo.report_id = uref->report_id;
+               if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+                       goto inval;
+
+               if (uref->field_index >= report->maxfield)
+                       goto inval;
+
+               field = report->field[uref->field_index];
+               if (uref->usage_index >= field->maxusage)
+                       goto inval;
+
+               uref->usage_code = field->usage[uref->usage_index].hid;
+
+               if (copy_to_user(user_arg, uref, sizeof(*uref)))
+                       goto fault;
+
+               kfree(uref_multi);
+               return 0;
+
+       default:
+               if (cmd != HIDIOCGUSAGE &&
+                   cmd != HIDIOCGUSAGES &&
+                   uref->report_type == HID_REPORT_TYPE_INPUT)
+                       goto inval;
+
+               if (uref->report_id == HID_REPORT_ID_UNKNOWN) {
+                       field = hiddev_lookup_usage(hid, uref);
+                       if (field == NULL)
+                               goto inval;
+               } else {
+                       rinfo.report_type = uref->report_type;
+                       rinfo.report_id = uref->report_id;
+                       if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+                               goto inval;
+
+                       if (uref->field_index >= report->maxfield)
+                               goto inval;
+
+                       field = report->field[uref->field_index];
+
+                       if (cmd == HIDIOCGCOLLECTIONINDEX) {
+                               if (uref->usage_index >= field->maxusage)
+                                       goto inval;
+                       } else if (uref->usage_index >= field->report_count)
+                               goto inval;
+
+                       else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) &&
+                                (uref_multi->num_values > HID_MAX_MULTI_USAGES ||
+                                 uref->usage_index + uref_multi->num_values > field->report_count))
+                               goto inval;
+                       }
+
+               switch (cmd) {
+               case HIDIOCGUSAGE:
+                       uref->value = field->value[uref->usage_index];
+                       if (copy_to_user(user_arg, uref, sizeof(*uref)))
+                               goto fault;
+                       goto goodreturn;
+
+               case HIDIOCSUSAGE:
+                       field->value[uref->usage_index] = uref->value;
+                       goto goodreturn;
+
+               case HIDIOCGCOLLECTIONINDEX:
+                       kfree(uref_multi);
+                       return field->usage[uref->usage_index].collection_index;
+               case HIDIOCGUSAGES:
+                       for (i = 0; i < uref_multi->num_values; i++)
+                               uref_multi->values[i] =
+                                   field->value[uref->usage_index + i];
+                       if (copy_to_user(user_arg, uref_multi,
+                                        sizeof(*uref_multi)))
+                               goto fault;
+                       goto goodreturn;
+               case HIDIOCSUSAGES:
+                       for (i = 0; i < uref_multi->num_values; i++)
+                               field->value[uref->usage_index + i] =
+                                   uref_multi->values[i];
+                       goto goodreturn;
+               }
+
+goodreturn:
+               kfree(uref_multi);
+               return 0;
+fault:
+               kfree(uref_multi);
+               return -EFAULT;
+inval:
+               kfree(uref_multi);
+               return -EINVAL;
+       }
+}
+
+static noinline int hiddev_ioctl_string(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg)
+{
+       struct hid_device *hid = hiddev->hid;
+       struct usb_device *dev = hid_to_usb_dev(hid);
+       int idx, len;
+       char *buf;
+
+       if (get_user(idx, (int __user *)user_arg))
+               return -EFAULT;
+
+       if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL)
+               return -ENOMEM;
+
+       if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) {
+               kfree(buf);
+               return -EINVAL;
+       }
+
+       if (copy_to_user(user_arg+sizeof(int), buf, len+1)) {
+               kfree(buf);
+               return -EFAULT;
+       }
+
+       kfree(buf);
+
+       return len;
+}
+
 static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
        struct hiddev_list *list = file->private_data;
@@ -402,8 +549,6 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
        struct hiddev_collection_info cinfo;
        struct hiddev_report_info rinfo;
        struct hiddev_field_info finfo;
-       struct hiddev_usage_ref_multi *uref_multi = NULL;
-       struct hiddev_usage_ref *uref;
        struct hiddev_devinfo dinfo;
        struct hid_report *report;
        struct hid_field *field;
@@ -470,30 +615,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                }
 
        case HIDIOCGSTRING:
-               {
-                       int idx, len;
-                       char *buf;
-
-                       if (get_user(idx, (int __user *)arg))
-                               return -EFAULT;
-
-                       if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL)
-                               return -ENOMEM;
-
-                       if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) {
-                               kfree(buf);
-                               return -EINVAL;
-                       }
-
-                       if (copy_to_user(user_arg+sizeof(int), buf, len+1)) {
-                               kfree(buf);
-                               return -EFAULT;
-                       }
-
-                       kfree(buf);
-
-                       return len;
-               }
+               return hiddev_ioctl_string(hiddev, cmd, user_arg);
 
        case HIDIOCINITREPORT:
                usbhid_init_reports(hid);
@@ -578,121 +700,13 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
                return 0;
 
        case HIDIOCGUCODE:
-               uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
-               if (!uref_multi)
-                       return -ENOMEM;
-               uref = &uref_multi->uref;
-               if (copy_from_user(uref, user_arg, sizeof(*uref)))
-                       goto fault;
-
-               rinfo.report_type = uref->report_type;
-               rinfo.report_id = uref->report_id;
-               if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-                       goto inval;
-
-               if (uref->field_index >= report->maxfield)
-                       goto inval;
-
-               field = report->field[uref->field_index];
-               if (uref->usage_index >= field->maxusage)
-                       goto inval;
-
-               uref->usage_code = field->usage[uref->usage_index].hid;
-
-               if (copy_to_user(user_arg, uref, sizeof(*uref)))
-                       goto fault;
-
-               kfree(uref_multi);
-               return 0;
-
+               /* fall through */
        case HIDIOCGUSAGE:
        case HIDIOCSUSAGE:
        case HIDIOCGUSAGES:
        case HIDIOCSUSAGES:
        case HIDIOCGCOLLECTIONINDEX:
-               uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
-               if (!uref_multi)
-                       return -ENOMEM;
-               uref = &uref_multi->uref;
-               if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
-                       if (copy_from_user(uref_multi, user_arg,
-                                          sizeof(*uref_multi)))
-                               goto fault;
-               } else {
-                       if (copy_from_user(uref, user_arg, sizeof(*uref)))
-                               goto fault;
-               }
-
-               if (cmd != HIDIOCGUSAGE &&
-                   cmd != HIDIOCGUSAGES &&
-                   uref->report_type == HID_REPORT_TYPE_INPUT)
-                       goto inval;
-
-               if (uref->report_id == HID_REPORT_ID_UNKNOWN) {
-                       field = hiddev_lookup_usage(hid, uref);
-                       if (field == NULL)
-                               goto inval;
-               } else {
-                       rinfo.report_type = uref->report_type;
-                       rinfo.report_id = uref->report_id;
-                       if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-                               goto inval;
-
-                       if (uref->field_index >= report->maxfield)
-                               goto inval;
-
-                       field = report->field[uref->field_index];
-
-                       if (cmd == HIDIOCGCOLLECTIONINDEX) {
-                               if (uref->usage_index >= field->maxusage)
-                                       goto inval;
-                       } else if (uref->usage_index >= field->report_count)
-                               goto inval;
-
-                       else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) &&
-                                (uref_multi->num_values > HID_MAX_MULTI_USAGES ||
-                                 uref->usage_index + uref_multi->num_values > field->report_count))
-                               goto inval;
-                       }
-
-               switch (cmd) {
-                       case HIDIOCGUSAGE:
-                               uref->value = field->value[uref->usage_index];
-                               if (copy_to_user(user_arg, uref, sizeof(*uref)))
-                                       goto fault;
-                               goto goodreturn;
-
-                       case HIDIOCSUSAGE:
-                               field->value[uref->usage_index] = uref->value;
-                               goto goodreturn;
-
-                       case HIDIOCGCOLLECTIONINDEX:
-                               kfree(uref_multi);
-                               return field->usage[uref->usage_index].collection_index;
-                       case HIDIOCGUSAGES:
-                               for (i = 0; i < uref_multi->num_values; i++)
-                                       uref_multi->values[i] =
-                                           field->value[uref->usage_index + i];
-                               if (copy_to_user(user_arg, uref_multi,
-                                                sizeof(*uref_multi)))
-                                       goto fault;
-                               goto goodreturn;
-                       case HIDIOCSUSAGES:
-                               for (i = 0; i < uref_multi->num_values; i++)
-                                       field->value[uref->usage_index + i] =
-                                           uref_multi->values[i];
-                               goto goodreturn;
-               }
-
-goodreturn:
-               kfree(uref_multi);
-               return 0;
-fault:
-               kfree(uref_multi);
-               return -EFAULT;
-inval:
-               kfree(uref_multi);
-               return -EINVAL;
+               return hiddev_ioctl_usage(hiddev, cmd, user_arg);
 
        case HIDIOCGCOLLECTIONINFO:
                if (copy_from_user(&cinfo, user_arg, sizeof(cinfo)))
index 0023f96..62d2d7c 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/list.h>
 #include <linux/timer.h>
+#include <linux/wait.h>
 #include <linux/workqueue.h>
 #include <linux/input.h>
 
@@ -77,7 +78,7 @@ struct usbhid_device {
        unsigned long stop_retry;                                       /* Time to give up, in jiffies */
        unsigned int retry_delay;                                       /* Delay length in ms */
        struct work_struct reset_work;                                  /* Task context for resets */
-
+       wait_queue_head_t wait;                                         /* For sleeping */
 };
 
 #define        hid_to_usb_dev(hid_dev) \
index 014dfa5..7137a17 100644 (file)
@@ -1,45 +1,16 @@
 #
-# Character device configuration
+# I2C algorithm drivers configuration
 #
 
-menu "I2C Algorithms"
-
 config I2C_ALGOBIT
-       tristate "I2C bit-banging interfaces"
-       help
-         This allows you to use a range of I2C adapters called bit-banging
-         adapters.  Say Y if you own an I2C adapter belonging to this class
-         and then say Y to the specific driver for you adapter below.
-
-         This support is also available as a module.  If so, the module 
-         will be called i2c-algo-bit.
+       tristate
 
 config I2C_ALGOPCF
-       tristate "I2C PCF 8584 interfaces"
-       help
-         This allows you to use a range of I2C adapters called PCF adapters.
-         Say Y if you own an I2C adapter belonging to this class and then say
-         Y to the specific driver for you adapter below.
-
-         This support is also available as a module.  If so, the module 
-         will be called i2c-algo-pcf.
+       tristate
 
 config I2C_ALGOPCA
-       tristate "I2C PCA 9564 interfaces"
-       help
-         This allows you to use a range of I2C adapters called PCA adapters.
-         Say Y if you own an I2C adapter belonging to this class and then say
-         Y to the specific driver for you adapter below.
-
-         This support is also available as a module.  If so, the module 
-         will be called i2c-algo-pca.
+       tristate
 
 config I2C_ALGO_SGI
-       tristate "I2C SGI interfaces"
+       tristate
        depends on SGI_IP22 || SGI_IP32 || X86_VISWS
-       help
-         Supports the SGI interfaces like the ones found on SGI Indy VINO
-         or SGI O2 MACE.
-
-endmenu
-
index 2a16211..e954a20 100644 (file)
@@ -1,6 +1,7 @@
 /*
- *  i2c-algo-pca.c i2c driver algorithms for PCA9564 adapters                
+ *  i2c-algo-pca.c i2c driver algorithms for PCA9564 adapters
  *    Copyright (C) 2004 Arcom Control Systems
+ *    Copyright (C) 2008 Pengutronix
  *
  *  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
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/delay.h>
-#include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-pca.h>
-#include "i2c-algo-pca.h"
-
-#define DRIVER "i2c-algo-pca"
 
 #define DEB1(fmt, args...) do { if (i2c_debug>=1) printk(fmt, ## args); } while(0)
 #define DEB2(fmt, args...) do { if (i2c_debug>=2) printk(fmt, ## args); } while(0)
 
 static int i2c_debug;
 
-#define pca_outw(adap, reg, val) adap->write_byte(adap, reg, val)
-#define pca_inw(adap, reg) adap->read_byte(adap, reg)
+#define pca_outw(adap, reg, val) adap->write_byte(adap->data, reg, val)
+#define pca_inw(adap, reg) adap->read_byte(adap->data, reg)
 
 #define pca_status(adap) pca_inw(adap, I2C_PCA_STA)
-#define pca_clock(adap) adap->get_clock(adap)
-#define pca_own(adap) adap->get_own(adap)
+#define pca_clock(adap) adap->i2c_clock
 #define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val)
 #define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON)
-#define pca_wait(adap) adap->wait_for_interrupt(adap)
+#define pca_wait(adap) adap->wait_for_completion(adap->data)
+#define pca_reset(adap) adap->reset_chip(adap->data)
 
 /*
  * Generate a start condition on the i2c bus.
@@ -99,7 +96,7 @@ static void pca_stop(struct i2c_algo_pca_data *adap)
  *
  * returns after the address has been sent
  */
-static void pca_address(struct i2c_algo_pca_data *adap, 
+static void pca_address(struct i2c_algo_pca_data *adap,
                        struct i2c_msg *msg)
 {
        int sta = pca_get_con(adap);
@@ -108,9 +105,9 @@ static void pca_address(struct i2c_algo_pca_data *adap,
        addr = ( (0x7f & msg->addr) << 1 );
        if (msg->flags & I2C_M_RD )
                addr |= 1;
-       DEB2("=== SLAVE ADDRESS %#04x+%c=%#04x\n", 
+       DEB2("=== SLAVE ADDRESS %#04x+%c=%#04x\n",
             msg->addr, msg->flags & I2C_M_RD ? 'R' : 'W', addr);
-       
+
        pca_outw(adap, I2C_PCA_DAT, addr);
 
        sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI);
@@ -124,7 +121,7 @@ static void pca_address(struct i2c_algo_pca_data *adap,
  *
  * Returns after the byte has been transmitted
  */
-static void pca_tx_byte(struct i2c_algo_pca_data *adap, 
+static void pca_tx_byte(struct i2c_algo_pca_data *adap,
                        __u8 b)
 {
        int sta = pca_get_con(adap);
@@ -142,19 +139,19 @@ static void pca_tx_byte(struct i2c_algo_pca_data *adap,
  *
  * returns immediately.
  */
-static void pca_rx_byte(struct i2c_algo_pca_data *adap, 
+static void pca_rx_byte(struct i2c_algo_pca_data *adap,
                        __u8 *b, int ack)
 {
        *b = pca_inw(adap, I2C_PCA_DAT);
        DEB2("=== READ %#04x %s\n", *b, ack ? "ACK" : "NACK");
 }
 
-/* 
+/*
  * Setup ACK or NACK for next received byte and wait for it to arrive.
  *
  * Returns after next byte has arrived.
  */
-static void pca_rx_ack(struct i2c_algo_pca_data *adap, 
+static void pca_rx_ack(struct i2c_algo_pca_data *adap,
                       int ack)
 {
        int sta = pca_get_con(adap);
@@ -168,15 +165,6 @@ static void pca_rx_ack(struct i2c_algo_pca_data *adap,
        pca_wait(adap);
 }
 
-/* 
- * Reset the i2c bus / SIO 
- */
-static void pca_reset(struct i2c_algo_pca_data *adap)
-{
-       /* apparently only an external reset will do it. not a lot can be done */
-       printk(KERN_ERR DRIVER ": Haven't figured out how to do a reset yet\n");
-}
-
 static int pca_xfer(struct i2c_adapter *i2c_adap,
                     struct i2c_msg *msgs,
                     int num)
@@ -187,7 +175,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap,
        int numbytes = 0;
        int state;
        int ret;
-       int timeout = 100;
+       int timeout = i2c_adap->timeout;
 
        while ((state = pca_status(adap)) != 0xf8 && timeout--) {
                msleep(10);
@@ -203,14 +191,14 @@ static int pca_xfer(struct i2c_adapter *i2c_adap,
                for (curmsg = 0; curmsg < num; curmsg++) {
                        int addr, i;
                        msg = &msgs[curmsg];
-                       
+
                        addr = (0x7f & msg->addr) ;
-               
+
                        if (msg->flags & I2C_M_RD )
-                               printk(KERN_INFO "    [%02d] RD %d bytes from %#02x [%#02x, ...]\n", 
+                               printk(KERN_INFO "    [%02d] RD %d bytes from %#02x [%#02x, ...]\n",
                                       curmsg, msg->len, addr, (addr<<1) | 1);
                        else {
-                               printk(KERN_INFO "    [%02d] WR %d bytes to %#02x [%#02x%s", 
+                               printk(KERN_INFO "    [%02d] WR %d bytes to %#02x [%#02x%s",
                                       curmsg, msg->len, addr, addr<<1,
                                       msg->len == 0 ? "" : ", ");
                                for(i=0; i < msg->len; i++)
@@ -237,7 +225,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap,
                case 0x10: /* A repeated start condition has been transmitted */
                        pca_address(adap, msg);
                        break;
-                       
+
                case 0x18: /* SLA+W has been transmitted; ACK has been received */
                case 0x28: /* Data byte in I2CDAT has been transmitted; ACK has been received */
                        if (numbytes < msg->len) {
@@ -287,7 +275,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap,
                case 0x38: /* Arbitration lost during SLA+W, SLA+R or data bytes */
                        DEB2("Arbitration lost\n");
                        goto out;
-                       
+
                case 0x58: /* Data byte has been received; NOT ACK has been returned */
                        if ( numbytes == msg->len - 1 ) {
                                pca_rx_byte(adap, &msg->buf[numbytes], 0);
@@ -317,16 +305,16 @@ static int pca_xfer(struct i2c_adapter *i2c_adap,
                        pca_reset(adap);
                        goto out;
                default:
-                       printk(KERN_ERR DRIVER ": unhandled SIO state 0x%02x\n", state);
+                       dev_err(&i2c_adap->dev, "unhandled SIO state 0x%02x\n", state);
                        break;
                }
-               
+
        }
 
        ret = curmsg;
  out:
        DEB1(KERN_CRIT "}}} transfered %d/%d messages. "
-            "status is %#04x. control is %#04x\n", 
+            "status is %#04x. control is %#04x\n",
             curmsg, num, pca_status(adap),
             pca_get_con(adap));
        return ret;
@@ -337,53 +325,65 @@ static u32 pca_func(struct i2c_adapter *adap)
         return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
 }
 
-static int pca_init(struct i2c_algo_pca_data *adap)
+static const struct i2c_algorithm pca_algo = {
+       .master_xfer    = pca_xfer,
+       .functionality  = pca_func,
+};
+
+static int pca_init(struct i2c_adapter *adap)
 {
        static int freqs[] = {330,288,217,146,88,59,44,36};
-       int own, clock;
+       int clock;
+       struct i2c_algo_pca_data *pca_data = adap->algo_data;
+
+       if (pca_data->i2c_clock > 7) {
+               printk(KERN_WARNING "%s: Invalid I2C clock speed selected. Trying default.\n",
+                       adap->name);
+               pca_data->i2c_clock = I2C_PCA_CON_59kHz;
+       }
+
+       adap->algo = &pca_algo;
 
-       own = pca_own(adap);
-       clock = pca_clock(adap);
-       DEB1(KERN_INFO DRIVER ": own address is %#04x\n", own);
-       DEB1(KERN_INFO DRIVER ": clock freqeuncy is %dkHz\n", freqs[clock]);
+       pca_reset(pca_data);
 
-       pca_outw(adap, I2C_PCA_ADR, own << 1);
+       clock = pca_clock(pca_data);
+       DEB1(KERN_INFO "%s: Clock frequency is %dkHz\n", adap->name, freqs[clock]);
 
-       pca_set_con(adap, I2C_PCA_CON_ENSIO | clock);
-       udelay(500); /* 500 Âµs for oscilator to stabilise */
+       pca_set_con(pca_data, I2C_PCA_CON_ENSIO | clock);
+       udelay(500); /* 500 us for oscilator to stabilise */
 
        return 0;
 }
 
-static const struct i2c_algorithm pca_algo = {
-       .master_xfer    = pca_xfer,
-       .functionality  = pca_func,
-};
-
-/* 
- * registering functions to load algorithms at runtime 
+/*
+ * registering functions to load algorithms at runtime
  */
 int i2c_pca_add_bus(struct i2c_adapter *adap)
 {
-       struct i2c_algo_pca_data *pca_adap = adap->algo_data;
        int rval;
 
-       /* register new adapter to i2c module... */
-       adap->algo = &pca_algo;
+       rval = pca_init(adap);
+       if (rval)
+               return rval;
 
-       adap->timeout = 100;            /* default values, should       */
-       adap->retries = 3;              /* be replaced by defines       */
+       return i2c_add_adapter(adap);
+}
+EXPORT_SYMBOL(i2c_pca_add_bus);
 
-       if ((rval = pca_init(pca_adap)))
-               return rval;
+int i2c_pca_add_numbered_bus(struct i2c_adapter *adap)
+{
+       int rval;
 
-       rval = i2c_add_adapter(adap);
+       rval = pca_init(adap);
+       if (rval)
+               return rval;
 
-       return rval;
+       return i2c_add_numbered_adapter(adap);
 }
-EXPORT_SYMBOL(i2c_pca_add_bus);
+EXPORT_SYMBOL(i2c_pca_add_numbered_bus);
 
-MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>");
+MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>, "
+       "Wolfram Sang <w.sang@pengutronix.de>");
 MODULE_DESCRIPTION("I2C-Bus PCA9564 algorithm");
 MODULE_LICENSE("GPL");
 
diff --git a/drivers/i2c/algos/i2c-algo-pca.h b/drivers/i2c/algos/i2c-algo-pca.h
deleted file mode 100644 (file)
index 2fee07e..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef I2C_PCA9564_H
-#define I2C_PCA9564_H 1
-
-#define I2C_PCA_STA            0x00 /* STATUS  Read Only  */
-#define I2C_PCA_TO             0x00 /* TIMEOUT Write Only */
-#define I2C_PCA_DAT            0x01 /* DATA    Read/Write */
-#define I2C_PCA_ADR            0x02 /* OWN ADR Read/Write */
-#define I2C_PCA_CON            0x03 /* CONTROL Read/Write */
-
-#define I2C_PCA_CON_AA         0x80 /* Assert Acknowledge */
-#define I2C_PCA_CON_ENSIO      0x40 /* Enable */
-#define I2C_PCA_CON_STA                0x20 /* Start */
-#define I2C_PCA_CON_STO                0x10 /* Stop */
-#define I2C_PCA_CON_SI         0x08 /* Serial Interrupt */
-#define I2C_PCA_CON_CR         0x07 /* Clock Rate (MASK) */
-
-#define I2C_PCA_CON_330kHz     0x00
-#define I2C_PCA_CON_288kHz     0x01
-#define I2C_PCA_CON_217kHz     0x02
-#define I2C_PCA_CON_146kHz     0x03
-#define I2C_PCA_CON_88kHz      0x04
-#define I2C_PCA_CON_59kHz      0x05
-#define I2C_PCA_CON_44kHz      0x06
-#define I2C_PCA_CON_36kHz      0x07
-
-#endif /* I2C_PCA9564_H */
index b04c995..48438cc 100644 (file)
@@ -100,9 +100,12 @@ config I2C_AU1550
 
 config I2C_BLACKFIN_TWI
        tristate "Blackfin TWI I2C support"
-       depends on BF534 || BF536 || BF537
+       depends on BLACKFIN
        help
-         This is the TWI I2C device driver for Blackfin 534/536/537/54x.
+         This is the TWI I2C device driver for Blackfin BF522, BF525,
+         BF527, BF534, BF536, BF537 and BF54x. For other Blackfin processors,
+         please don't use this driver.
+
          This driver can also be built as a module.  If so, the module
          will be called i2c-bfin-twi.
 
@@ -135,7 +138,7 @@ config I2C_ELEKTOR
          This supports the PCF8584 ISA bus I2C adapter.  Say Y if you own
          such an adapter.
 
-         This support is also available as a module.  If so, the module 
+         This support is also available as a module.  If so, the module
          will be called i2c-elektor.
 
 config I2C_GPIO
@@ -190,7 +193,7 @@ config I2C_I810
        select I2C_ALGOBIT
        help
          If you say yes to this option, support will be included for the Intel
-         810/815 family of mainboard I2C interfaces.  Specifically, the 
+         810/815 family of mainboard I2C interfaces.  Specifically, the
          following versions of the chipset are supported:
            i810AA
            i810AB
@@ -246,10 +249,10 @@ config I2C_PIIX4
 
 config I2C_IBM_IIC
        tristate "IBM PPC 4xx on-chip I2C interface"
-       depends on IBM_OCP
+       depends on 4xx
        help
-         Say Y here if you want to use IIC peripheral found on 
-         embedded IBM PPC 4xx based systems. 
+         Say Y here if you want to use IIC peripheral found on
+         embedded IBM PPC 4xx based systems.
 
          This driver can also be built as a module.  If so, the module
          will be called i2c-ibm_iic.
@@ -269,7 +272,7 @@ config I2C_IXP2000
        depends on ARCH_IXP2000
        select I2C_ALGOBIT
        help
-         Say Y here if you have an Intel IXP2000 (2400, 2800, 2850) based 
+         Say Y here if you have an Intel IXP2000 (2400, 2800, 2850) based
          system and are using GPIO lines for an I2C bus.
 
          This support is also available as a module. If so, the module
@@ -354,7 +357,7 @@ config I2C_PARPORT
          on the parport driver.  This is meant for embedded systems. Don't say
          Y here if you intend to say Y or M there.
 
-         This support is also available as a module.  If so, the module 
+         This support is also available as a module.  If so, the module
          will be called i2c-parport.
 
 config I2C_PARPORT_LIGHT
@@ -372,12 +375,12 @@ config I2C_PARPORT_LIGHT
          the clean but heavy parport handling is not an option.  The
          drawback is a reduced portability and the impossibility to
          daisy-chain other parallel port devices.
-         
+
          Don't say Y here if you said Y or M to i2c-parport.  Saying M to
          both is possible but both modules should not be loaded at the same
          time.
 
-         This support is also available as a module.  If so, the module 
+         This support is also available as a module.  If so, the module
          will be called i2c-parport-light.
 
 config I2C_PASEMI
@@ -401,7 +404,7 @@ config I2C_PROSAVAGE
 
          This driver is deprecated in favor of the savagefb driver.
 
-         This support is also available as a module.  If so, the module 
+         This support is also available as a module.  If so, the module
          will be called i2c-prosavage.
 
 config I2C_S3C2410
@@ -417,7 +420,7 @@ config I2C_SAVAGE4
        depends on PCI
        select I2C_ALGOBIT
        help
-         If you say yes to this option, support will be included for the 
+         If you say yes to this option, support will be included for the
          S3 Savage 4 I2C interface.
 
          This driver is deprecated in favor of the savagefb driver.
@@ -452,7 +455,7 @@ config SCx200_I2C
 
          If you don't know what to do here, say N.
 
-         This support is also available as a module.  If so, the module 
+         This support is also available as a module.  If so, the module
          will be called scx200_i2c.
 
          This driver is deprecated and will be dropped soon. Use i2c-gpio
@@ -483,14 +486,14 @@ config SCx200_ACB
 
          If you don't know what to do here, say N.
 
-         This support is also available as a module.  If so, the module 
+         This support is also available as a module.  If so, the module
          will be called scx200_acb.
 
 config I2C_SIS5595
        tristate "SiS 5595"
        depends on PCI
        help
-         If you say yes to this option, support will be included for the 
+         If you say yes to this option, support will be included for the
          SiS5595 SMBus (a subset of I2C) interface.
 
          This driver can also be built as a module.  If so, the module
@@ -500,7 +503,7 @@ config I2C_SIS630
        tristate "SiS 630/730"
        depends on PCI
        help
-         If you say yes to this option, support will be included for the 
+         If you say yes to this option, support will be included for the
          SiS630 and SiS730 SMBus (a subset of I2C) interface.
 
          This driver can also be built as a module.  If so, the module
@@ -632,9 +635,9 @@ config I2C_PCA_ISA
        select I2C_ALGOPCA
        default n
        help
-         This driver supports ISA boards using the Philips PCA 9564
-         Parallel bus to I2C bus controller
-         
+         This driver supports ISA boards using the Philips PCA9564
+         parallel bus to I2C bus controller.
+
          This driver can also be built as a module.  If so, the module
          will be called i2c-pca-isa.
 
@@ -643,6 +646,17 @@ config I2C_PCA_ISA
          delays when I2C/SMBus chip drivers are loaded (e.g. at boot
          time).  If unsure, say N.
 
+config I2C_PCA_PLATFORM
+       tristate "PCA9564 as platform device"
+       select I2C_ALGOPCA
+       default n
+       help
+         This driver supports a memory mapped Philips PCA9564
+         parallel bus to I2C bus controller.
+
+         This driver can also be built as a module.  If so, the module
+         will be called i2c-pca-platform.
+
 config I2C_MV64XXX
        tristate "Marvell mv64xxx I2C Controller"
        depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL
@@ -672,4 +686,23 @@ config I2C_PMCMSP
          This driver can also be built as module. If so, the module
          will be called i2c-pmcmsp.
 
+config I2C_SH7760
+       tristate "Renesas SH7760 I2C Controller"
+       depends on CPU_SUBTYPE_SH7760
+       help
+         This driver supports the 2 I2C interfaces on the Renesas SH7760.
+
+         This driver can also be built as a module.  If so, the module
+         will be called i2c-sh7760.
+
+config I2C_SH_MOBILE
+       tristate "SuperH Mobile I2C Controller"
+       depends on SUPERH
+       help
+         If you say yes to this option, support will be included for the
+         built-in I2C interface on the Renesas SH-Mobile processor.
+
+         This driver can also be built as a module.  If so, the module
+         will be called i2c-sh_mobile.
+
 endmenu
index ea7068f..e8c882a 100644 (file)
@@ -30,6 +30,7 @@ obj-$(CONFIG_I2C_PARPORT)     += i2c-parport.o
 obj-$(CONFIG_I2C_PARPORT_LIGHT)        += i2c-parport-light.o
 obj-$(CONFIG_I2C_PASEMI)       += i2c-pasemi.o
 obj-$(CONFIG_I2C_PCA_ISA)      += i2c-pca-isa.o
+obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o
 obj-$(CONFIG_I2C_PIIX4)                += i2c-piix4.o
 obj-$(CONFIG_I2C_PMCMSP)       += i2c-pmcmsp.o
 obj-$(CONFIG_I2C_PNX)          += i2c-pnx.o
@@ -37,6 +38,8 @@ obj-$(CONFIG_I2C_PROSAVAGE)   += i2c-prosavage.o
 obj-$(CONFIG_I2C_PXA)          += i2c-pxa.o
 obj-$(CONFIG_I2C_S3C2410)      += i2c-s3c2410.o
 obj-$(CONFIG_I2C_SAVAGE4)      += i2c-savage4.o
+obj-$(CONFIG_I2C_SH7760)       += i2c-sh7760.o
+obj-$(CONFIG_I2C_SH_MOBILE)    += i2c-sh_mobile.o
 obj-$(CONFIG_I2C_SIBYTE)       += i2c-sibyte.o
 obj-$(CONFIG_I2C_SIMTEC)       += i2c-simtec.o
 obj-$(CONFIG_I2C_SIS5595)      += i2c-sis5595.o
index c09b036..73d6194 100644 (file)
@@ -298,7 +298,7 @@ static int at91_i2c_resume(struct platform_device *pdev)
 #endif
 
 /* work with "modprobe at91_i2c" from hotplugging or coldplugging */
-MODULE_ALIAS("at91_i2c");
+MODULE_ALIAS("platform:at91_i2c");
 
 static struct platform_driver at91_i2c_driver = {
        .probe          = at91_i2c_probe,
index 1953b26..491718f 100644 (file)
@@ -472,6 +472,7 @@ i2c_au1550_exit(void)
 MODULE_AUTHOR("Dan Malek, Embedded Edge, LLC.");
 MODULE_DESCRIPTION("SMBus adapter Alchemy pb1550");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:au1xpsc_smbus");
 
 module_init (i2c_au1550_init);
 module_exit (i2c_au1550_exit);
index 7dbdaeb..48d084b 100644 (file)
@@ -1,25 +1,11 @@
 /*
- * drivers/i2c/busses/i2c-bfin-twi.c
+ * Blackfin On-Chip Two Wire Interface Driver
  *
- * Description: Driver for Blackfin Two Wire Interface
+ * Copyright 2005-2007 Analog Devices Inc.
  *
- * Author:      sonicz  <sonic.zhang@analog.com>
+ * Enter bugs at http://blackfin.uclinux.org/
  *
- * Copyright (c) 2005-2007 Analog Devices, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Licensed under the GPL-2 or later.
  */
 
 #include <linux/module.h>
 #include <linux/platform_device.h>
 
 #include <asm/blackfin.h>
+#include <asm/portmux.h>
 #include <asm/irq.h>
 
 #define POLL_TIMEOUT       (2 * HZ)
 
 /* SMBus mode*/
-#define TWI_I2C_MODE_STANDARD          0x01
-#define TWI_I2C_MODE_STANDARDSUB       0x02
-#define TWI_I2C_MODE_COMBINED          0x04
+#define TWI_I2C_MODE_STANDARD          1
+#define TWI_I2C_MODE_STANDARDSUB       2
+#define TWI_I2C_MODE_COMBINED          3
+#define TWI_I2C_MODE_REPEAT            4
 
 struct bfin_twi_iface {
        int                     irq;
@@ -58,39 +46,74 @@ struct bfin_twi_iface {
        struct timer_list       timeout_timer;
        struct i2c_adapter      adap;
        struct completion       complete;
+       struct i2c_msg          *pmsg;
+       int                     msg_num;
+       int                     cur_msg;
+       void __iomem            *regs_base;
 };
 
-static struct bfin_twi_iface twi_iface;
+
+#define DEFINE_TWI_REG(reg, off) \
+static inline u16 read_##reg(struct bfin_twi_iface *iface) \
+       { return bfin_read16(iface->regs_base + (off)); } \
+static inline void write_##reg(struct bfin_twi_iface *iface, u16 v) \
+       { bfin_write16(iface->regs_base + (off), v); }
+
+DEFINE_TWI_REG(CLKDIV, 0x00)
+DEFINE_TWI_REG(CONTROL, 0x04)
+DEFINE_TWI_REG(SLAVE_CTL, 0x08)
+DEFINE_TWI_REG(SLAVE_STAT, 0x0C)
+DEFINE_TWI_REG(SLAVE_ADDR, 0x10)
+DEFINE_TWI_REG(MASTER_CTL, 0x14)
+DEFINE_TWI_REG(MASTER_STAT, 0x18)
+DEFINE_TWI_REG(MASTER_ADDR, 0x1C)
+DEFINE_TWI_REG(INT_STAT, 0x20)
+DEFINE_TWI_REG(INT_MASK, 0x24)
+DEFINE_TWI_REG(FIFO_CTL, 0x28)
+DEFINE_TWI_REG(FIFO_STAT, 0x2C)
+DEFINE_TWI_REG(XMT_DATA8, 0x80)
+DEFINE_TWI_REG(XMT_DATA16, 0x84)
+DEFINE_TWI_REG(RCV_DATA8, 0x88)
+DEFINE_TWI_REG(RCV_DATA16, 0x8C)
+
+static const u16 pin_req[2][3] = {
+       {P_TWI0_SCL, P_TWI0_SDA, 0},
+       {P_TWI1_SCL, P_TWI1_SDA, 0},
+};
 
 static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
 {
-       unsigned short twi_int_status = bfin_read_TWI_INT_STAT();
-       unsigned short mast_stat = bfin_read_TWI_MASTER_STAT();
+       unsigned short twi_int_status = read_INT_STAT(iface);
+       unsigned short mast_stat = read_MASTER_STAT(iface);
 
        if (twi_int_status & XMTSERV) {
                /* Transmit next data */
                if (iface->writeNum > 0) {
-                       bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));
+                       write_XMT_DATA8(iface, *(iface->transPtr++));
                        iface->writeNum--;
                }
                /* start receive immediately after complete sending in
                 * combine mode.
                 */
-               else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
-                       bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
-                               | MDIR | RSTART);
-               } else if (iface->manual_stop)
-                       bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
-                               | STOP);
+               else if (iface->cur_mode == TWI_I2C_MODE_COMBINED)
+                       write_MASTER_CTL(iface,
+                               read_MASTER_CTL(iface) | MDIR | RSTART);
+               else if (iface->manual_stop)
+                       write_MASTER_CTL(iface,
+                               read_MASTER_CTL(iface) | STOP);
+               else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
+                               iface->cur_msg+1 < iface->msg_num)
+                       write_MASTER_CTL(iface,
+                               read_MASTER_CTL(iface) | RSTART);
                SSYNC();
                /* Clear status */
-               bfin_write_TWI_INT_STAT(XMTSERV);
+               write_INT_STAT(iface, XMTSERV);
                SSYNC();
        }
        if (twi_int_status & RCVSERV) {
                if (iface->readNum > 0) {
                        /* Receive next data */
-                       *(iface->transPtr) = bfin_read_TWI_RCV_DATA8();
+                       *(iface->transPtr) = read_RCV_DATA8(iface);
                        if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
                                /* Change combine mode into sub mode after
                                 * read first data.
@@ -105,28 +128,33 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
                        iface->transPtr++;
                        iface->readNum--;
                } else if (iface->manual_stop) {
-                       bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
-                               | STOP);
+                       write_MASTER_CTL(iface,
+                               read_MASTER_CTL(iface) | STOP);
+                       SSYNC();
+               } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
+                               iface->cur_msg+1 < iface->msg_num) {
+                       write_MASTER_CTL(iface,
+                               read_MASTER_CTL(iface) | RSTART);
                        SSYNC();
                }
                /* Clear interrupt source */
-               bfin_write_TWI_INT_STAT(RCVSERV);
+               write_INT_STAT(iface, RCVSERV);
                SSYNC();
        }
        if (twi_int_status & MERR) {
-               bfin_write_TWI_INT_STAT(MERR);
-               bfin_write_TWI_INT_MASK(0);
-               bfin_write_TWI_MASTER_STAT(0x3e);
-               bfin_write_TWI_MASTER_CTL(0);
+               write_INT_STAT(iface, MERR);
+               write_INT_MASK(iface, 0);
+               write_MASTER_STAT(iface, 0x3e);
+               write_MASTER_CTL(iface, 0);
                SSYNC();
-               iface->result = -1;
+               iface->result = -EIO;
                /* if both err and complete int stats are set, return proper
                 * results.
                 */
                if (twi_int_status & MCOMP) {
-                       bfin_write_TWI_INT_STAT(MCOMP);
-                       bfin_write_TWI_INT_MASK(0);
-                       bfin_write_TWI_MASTER_CTL(0);
+                       write_INT_STAT(iface, MCOMP);
+                       write_INT_MASK(iface, 0);
+                       write_MASTER_CTL(iface, 0);
                        SSYNC();
                        /* If it is a quick transfer, only address bug no data,
                         * not an err, return 1.
@@ -143,7 +171,7 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
                return;
        }
        if (twi_int_status & MCOMP) {
-               bfin_write_TWI_INT_STAT(MCOMP);
+               write_INT_STAT(iface, MCOMP);
                SSYNC();
                if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
                        if (iface->readNum == 0) {
@@ -152,28 +180,63 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
                                 */
                                iface->readNum = 1;
                                iface->manual_stop = 1;
-                               bfin_write_TWI_MASTER_CTL(
-                                       bfin_read_TWI_MASTER_CTL()
-                                       | (0xff << 6));
+                               write_MASTER_CTL(iface,
+                                       read_MASTER_CTL(iface) | (0xff << 6));
                        } else {
                                /* set the readd number in other
                                 * combine mode.
                                 */
-                               bfin_write_TWI_MASTER_CTL(
-                                       (bfin_read_TWI_MASTER_CTL() &
+                               write_MASTER_CTL(iface,
+                                       (read_MASTER_CTL(iface) &
                                        (~(0xff << 6))) |
-                                       ( iface->readNum << 6));
+                                       (iface->readNum << 6));
+                       }
+                       /* remove restart bit and enable master receive */
+                       write_MASTER_CTL(iface,
+                               read_MASTER_CTL(iface) & ~RSTART);
+                       write_MASTER_CTL(iface,
+                               read_MASTER_CTL(iface) | MEN | MDIR);
+                       SSYNC();
+               } else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
+                               iface->cur_msg+1 < iface->msg_num) {
+                       iface->cur_msg++;
+                       iface->transPtr = iface->pmsg[iface->cur_msg].buf;
+                       iface->writeNum = iface->readNum =
+                               iface->pmsg[iface->cur_msg].len;
+                       /* Set Transmit device address */
+                       write_MASTER_ADDR(iface,
+                               iface->pmsg[iface->cur_msg].addr);
+                       if (iface->pmsg[iface->cur_msg].flags & I2C_M_RD)
+                               iface->read_write = I2C_SMBUS_READ;
+                       else {
+                               iface->read_write = I2C_SMBUS_WRITE;
+                               /* Transmit first data */
+                               if (iface->writeNum > 0) {
+                                       write_XMT_DATA8(iface,
+                                               *(iface->transPtr++));
+                                       iface->writeNum--;
+                                       SSYNC();
+                               }
+                       }
+
+                       if (iface->pmsg[iface->cur_msg].len <= 255)
+                               write_MASTER_CTL(iface,
+                               iface->pmsg[iface->cur_msg].len << 6);
+                       else {
+                               write_MASTER_CTL(iface, 0xff << 6);
+                               iface->manual_stop = 1;
                        }
                        /* remove restart bit and enable master receive */
-                       bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() &
-                               ~RSTART);
-                       bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() |
-                               MEN | MDIR);
+                       write_MASTER_CTL(iface,
+                               read_MASTER_CTL(iface) & ~RSTART);
+                       write_MASTER_CTL(iface, read_MASTER_CTL(iface) |
+                               MEN | ((iface->read_write == I2C_SMBUS_READ) ?
+                               MDIR : 0));
                        SSYNC();
                } else {
                        iface->result = 1;
-                       bfin_write_TWI_INT_MASK(0);
-                       bfin_write_TWI_MASTER_CTL(0);
+                       write_INT_MASK(iface, 0);
+                       write_MASTER_CTL(iface, 0);
                        SSYNC();
                        complete(&iface->complete);
                }
@@ -221,91 +284,85 @@ static int bfin_twi_master_xfer(struct i2c_adapter *adap,
 {
        struct bfin_twi_iface *iface = adap->algo_data;
        struct i2c_msg *pmsg;
-       int i, ret;
        int rc = 0;
 
-       if (!(bfin_read_TWI_CONTROL() & TWI_ENA))
+       if (!(read_CONTROL(iface) & TWI_ENA))
                return -ENXIO;
 
-       while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) {
+       while (read_MASTER_STAT(iface) & BUSBUSY)
                yield();
+
+       iface->pmsg = msgs;
+       iface->msg_num = num;
+       iface->cur_msg = 0;
+
+       pmsg = &msgs[0];
+       if (pmsg->flags & I2C_M_TEN) {
+               dev_err(&adap->dev, "10 bits addr not supported!\n");
+               return -EINVAL;
        }
 
-       ret = 0;
-       for (i = 0; rc >= 0 && i < num; i++) {
-               pmsg = &msgs[i];
-               if (pmsg->flags & I2C_M_TEN) {
-                       dev_err(&(adap->dev), "i2c-bfin-twi: 10 bits addr "
-                               "not supported !\n");
-                       rc = -EINVAL;
-                       break;
-               }
+       iface->cur_mode = TWI_I2C_MODE_REPEAT;
+       iface->manual_stop = 0;
+       iface->transPtr = pmsg->buf;
+       iface->writeNum = iface->readNum = pmsg->len;
+       iface->result = 0;
+       iface->timeout_count = 10;
+       init_completion(&(iface->complete));
+       /* Set Transmit device address */
+       write_MASTER_ADDR(iface, pmsg->addr);
 
-               iface->cur_mode = TWI_I2C_MODE_STANDARD;
-               iface->manual_stop = 0;
-               iface->transPtr = pmsg->buf;
-               iface->writeNum = iface->readNum = pmsg->len;
-               iface->result = 0;
-               iface->timeout_count = 10;
-               /* Set Transmit device address */
-               bfin_write_TWI_MASTER_ADDR(pmsg->addr);
-
-               /* FIFO Initiation. Data in FIFO should be
-                *  discarded before start a new operation.
-                */
-               bfin_write_TWI_FIFO_CTL(0x3);
-               SSYNC();
-               bfin_write_TWI_FIFO_CTL(0);
-               SSYNC();
+       /* FIFO Initiation. Data in FIFO should be
+        *  discarded before start a new operation.
+        */
+       write_FIFO_CTL(iface, 0x3);
+       SSYNC();
+       write_FIFO_CTL(iface, 0);
+       SSYNC();
 
-               if (pmsg->flags & I2C_M_RD)
-                       iface->read_write = I2C_SMBUS_READ;
-               else {
-                       iface->read_write = I2C_SMBUS_WRITE;
-                       /* Transmit first data */
-                       if (iface->writeNum > 0) {
-                               bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));
-                               iface->writeNum--;
-                               SSYNC();
-                       }
+       if (pmsg->flags & I2C_M_RD)
+               iface->read_write = I2C_SMBUS_READ;
+       else {
+               iface->read_write = I2C_SMBUS_WRITE;
+               /* Transmit first data */
+               if (iface->writeNum > 0) {
+                       write_XMT_DATA8(iface, *(iface->transPtr++));
+                       iface->writeNum--;
+                       SSYNC();
                }
+       }
 
-               /* clear int stat */
-               bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV);
+       /* clear int stat */
+       write_INT_STAT(iface, MERR | MCOMP | XMTSERV | RCVSERV);
 
-               /* Interrupt mask . Enable XMT, RCV interrupt */
-               bfin_write_TWI_INT_MASK(MCOMP | MERR |
-                       ((iface->read_write == I2C_SMBUS_READ)?
-                       RCVSERV : XMTSERV));
-               SSYNC();
+       /* Interrupt mask . Enable XMT, RCV interrupt */
+       write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
+       SSYNC();
 
-               if (pmsg->len > 0 && pmsg->len <= 255)
-                       bfin_write_TWI_MASTER_CTL(pmsg->len << 6);
-               else if (pmsg->len > 255) {
-                       bfin_write_TWI_MASTER_CTL(0xff << 6);
-                       iface->manual_stop = 1;
-               } else
-                       break;
+       if (pmsg->len <= 255)
+               write_MASTER_CTL(iface, pmsg->len << 6);
+       else {
+               write_MASTER_CTL(iface, 0xff << 6);
+               iface->manual_stop = 1;
+       }
 
-               iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
-               add_timer(&iface->timeout_timer);
+       iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
+       add_timer(&iface->timeout_timer);
 
-               /* Master enable */
-               bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
-                       ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
-                       ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
-               SSYNC();
+       /* Master enable */
+       write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
+               ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
+               ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
+       SSYNC();
 
-               wait_for_completion(&iface->complete);
+       wait_for_completion(&iface->complete);
 
-               rc = iface->result;
-               if (rc == 1)
-                       ret++;
-               else if (rc == -1)
-                       break;
-       }
+       rc = iface->result;
 
-       return ret;
+       if (rc == 1)
+               return num;
+       else
+               return rc;
 }
 
 /*
@@ -319,12 +376,11 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
        struct bfin_twi_iface *iface = adap->algo_data;
        int rc = 0;
 
-       if (!(bfin_read_TWI_CONTROL() & TWI_ENA))
+       if (!(read_CONTROL(iface) & TWI_ENA))
                return -ENXIO;
 
-       while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) {
+       while (read_MASTER_STAT(iface) & BUSBUSY)
                yield();
-       }
 
        iface->writeNum = 0;
        iface->readNum = 0;
@@ -392,19 +448,20 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
        iface->read_write = read_write;
        iface->command = command;
        iface->timeout_count = 10;
+       init_completion(&(iface->complete));
 
        /* FIFO Initiation. Data in FIFO should be discarded before
         * start a new operation.
         */
-       bfin_write_TWI_FIFO_CTL(0x3);
+       write_FIFO_CTL(iface, 0x3);
        SSYNC();
-       bfin_write_TWI_FIFO_CTL(0);
+       write_FIFO_CTL(iface, 0);
 
        /* clear int stat */
-       bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV);
+       write_INT_STAT(iface, MERR | MCOMP | XMTSERV | RCVSERV);
 
        /* Set Transmit device address */
-       bfin_write_TWI_MASTER_ADDR(addr);
+       write_MASTER_ADDR(iface, addr);
        SSYNC();
 
        iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
@@ -412,60 +469,64 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
 
        switch (iface->cur_mode) {
        case TWI_I2C_MODE_STANDARDSUB:
-               bfin_write_TWI_XMT_DATA8(iface->command);
-               bfin_write_TWI_INT_MASK(MCOMP | MERR |
+               write_XMT_DATA8(iface, iface->command);
+               write_INT_MASK(iface, MCOMP | MERR |
                        ((iface->read_write == I2C_SMBUS_READ) ?
                        RCVSERV : XMTSERV));
                SSYNC();
 
                if (iface->writeNum + 1 <= 255)
-                       bfin_write_TWI_MASTER_CTL((iface->writeNum + 1) << 6);
+                       write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
                else {
-                       bfin_write_TWI_MASTER_CTL(0xff << 6);
+                       write_MASTER_CTL(iface, 0xff << 6);
                        iface->manual_stop = 1;
                }
                /* Master enable */
-               bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
+               write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
                        ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
                break;
        case TWI_I2C_MODE_COMBINED:
-               bfin_write_TWI_XMT_DATA8(iface->command);
-               bfin_write_TWI_INT_MASK(MCOMP | MERR | RCVSERV | XMTSERV);
+               write_XMT_DATA8(iface, iface->command);
+               write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
                SSYNC();
 
                if (iface->writeNum > 0)
-                       bfin_write_TWI_MASTER_CTL((iface->writeNum + 1) << 6);
+                       write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
                else
-                       bfin_write_TWI_MASTER_CTL(0x1 << 6);
+                       write_MASTER_CTL(iface, 0x1 << 6);
                /* Master enable */
-               bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
+               write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
                        ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
                break;
        default:
-               bfin_write_TWI_MASTER_CTL(0);
+               write_MASTER_CTL(iface, 0);
                if (size != I2C_SMBUS_QUICK) {
                        /* Don't access xmit data register when this is a
                         * read operation.
                         */
                        if (iface->read_write != I2C_SMBUS_READ) {
                                if (iface->writeNum > 0) {
-                                       bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));
+                                       write_XMT_DATA8(iface,
+                                               *(iface->transPtr++));
                                        if (iface->writeNum <= 255)
-                                               bfin_write_TWI_MASTER_CTL(iface->writeNum << 6);
+                                               write_MASTER_CTL(iface,
+                                                       iface->writeNum << 6);
                                        else {
-                                               bfin_write_TWI_MASTER_CTL(0xff << 6);
+                                               write_MASTER_CTL(iface,
+                                                       0xff << 6);
                                                iface->manual_stop = 1;
                                        }
                                        iface->writeNum--;
                                } else {
-                                       bfin_write_TWI_XMT_DATA8(iface->command);
-                                       bfin_write_TWI_MASTER_CTL(1 << 6);
+                                       write_XMT_DATA8(iface, iface->command);
+                                       write_MASTER_CTL(iface, 1 << 6);
                                }
                        } else {
                                if (iface->readNum > 0 && iface->readNum <= 255)
-                                       bfin_write_TWI_MASTER_CTL(iface->readNum << 6);
+                                       write_MASTER_CTL(iface,
+                                               iface->readNum << 6);
                                else if (iface->readNum > 255) {
-                                       bfin_write_TWI_MASTER_CTL(0xff << 6);
+                                       write_MASTER_CTL(iface, 0xff << 6);
                                        iface->manual_stop = 1;
                                } else {
                                        del_timer(&iface->timeout_timer);
@@ -473,13 +534,13 @@ int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
                                }
                        }
                }
-               bfin_write_TWI_INT_MASK(MCOMP | MERR |
+               write_INT_MASK(iface, MCOMP | MERR |
                        ((iface->read_write == I2C_SMBUS_READ) ?
                        RCVSERV : XMTSERV));
                SSYNC();
 
                /* Master enable */
-               bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
+               write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
                        ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
                        ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
                break;
@@ -514,10 +575,10 @@ static struct i2c_algorithm bfin_twi_algorithm = {
 
 static int i2c_bfin_twi_suspend(struct platform_device *dev, pm_message_t state)
 {
-/*     struct bfin_twi_iface *iface = platform_get_drvdata(dev);*/
+       struct bfin_twi_iface *iface = platform_get_drvdata(dev);
 
        /* Disable TWI */
-       bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() & ~TWI_ENA);
+       write_CONTROL(iface, read_CONTROL(iface) & ~TWI_ENA);
        SSYNC();
 
        return 0;
@@ -525,24 +586,52 @@ static int i2c_bfin_twi_suspend(struct platform_device *dev, pm_message_t state)
 
 static int i2c_bfin_twi_resume(struct platform_device *dev)
 {
-/*     struct bfin_twi_iface *iface = platform_get_drvdata(dev);*/
+       struct bfin_twi_iface *iface = platform_get_drvdata(dev);
 
        /* Enable TWI */
-       bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA);
+       write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA);
        SSYNC();
 
        return 0;
 }
 
-static int i2c_bfin_twi_probe(struct platform_device *dev)
+static int i2c_bfin_twi_probe(struct platform_device *pdev)
 {
-       struct bfin_twi_iface *iface = &twi_iface;
+       struct bfin_twi_iface *iface;
        struct i2c_adapter *p_adap;
+       struct resource *res;
        int rc;
 
+       iface = kzalloc(sizeof(struct bfin_twi_iface), GFP_KERNEL);
+       if (!iface) {
+               dev_err(&pdev->dev, "Cannot allocate memory\n");
+               rc = -ENOMEM;
+               goto out_error_nomem;
+       }
+
        spin_lock_init(&(iface->lock));
-       init_completion(&(iface->complete));
-       iface->irq = IRQ_TWI;
+
+       /* Find and map our resources */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
+               rc = -ENOENT;
+               goto out_error_get_res;
+       }
+
+       iface->regs_base = ioremap(res->start, res->end - res->start + 1);
+       if (iface->regs_base == NULL) {
+               dev_err(&pdev->dev, "Cannot map IO\n");
+               rc = -ENXIO;
+               goto out_error_ioremap;
+       }
+
+       iface->irq = platform_get_irq(pdev, 0);
+       if (iface->irq < 0) {
+               dev_err(&pdev->dev, "No IRQ specified\n");
+               rc = -ENOENT;
+               goto out_error_no_irq;
+       }
 
        init_timer(&(iface->timeout_timer));
        iface->timeout_timer.function = bfin_twi_timeout;
@@ -550,39 +639,63 @@ static int i2c_bfin_twi_probe(struct platform_device *dev)
 
        p_adap = &iface->adap;
        p_adap->id = I2C_HW_BLACKFIN;
-       p_adap->nr = dev->id;
-       strlcpy(p_adap->name, dev->name, sizeof(p_adap->name));
+       p_adap->nr = pdev->id;
+       strlcpy(p_adap->name, pdev->name, sizeof(p_adap->name));
        p_adap->algo = &bfin_twi_algorithm;
        p_adap->algo_data = iface;
        p_adap->class = I2C_CLASS_ALL;
-       p_adap->dev.parent = &dev->dev;
+       p_adap->dev.parent = &pdev->dev;
+
+       rc = peripheral_request_list(pin_req[pdev->id], "i2c-bfin-twi");
+       if (rc) {
+               dev_err(&pdev->dev, "Can't setup pin mux!\n");
+               goto out_error_pin_mux;
+       }
 
        rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
-               IRQF_DISABLED, dev->name, iface);
+               IRQF_DISABLED, pdev->name, iface);
        if (rc) {
-               dev_err(&(p_adap->dev), "i2c-bfin-twi: can't get IRQ %d !\n",
-                       iface->irq);
-               return -ENODEV;
+               dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
+               rc = -ENODEV;
+               goto out_error_req_irq;
        }
 
        /* Set TWI internal clock as 10MHz */
-       bfin_write_TWI_CONTROL(((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F);
+       write_CONTROL(iface, ((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F);
 
        /* Set Twi interface clock as specified */
-       bfin_write_TWI_CLKDIV((( 5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ )
-                       << 8) | (( 5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ )
+       write_CLKDIV(iface, ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ)
+                       << 8) | ((5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ)
                        & 0xFF));
 
        /* Enable TWI */
-       bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA);
+       write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA);
        SSYNC();
 
        rc = i2c_add_numbered_adapter(p_adap);
-       if (rc < 0)
-               free_irq(iface->irq, iface);
-       else
-               platform_set_drvdata(dev, iface);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "Can't add i2c adapter!\n");
+               goto out_error_add_adapter;
+       }
+
+       platform_set_drvdata(pdev, iface);
 
+       dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Contoller, "
+               "regs_base@%p\n", iface->regs_base);
+
+       return 0;
+
+out_error_add_adapter:
+       free_irq(iface->irq, iface);
+out_error_req_irq:
+out_error_no_irq:
+       peripheral_free_list(pin_req[pdev->id]);
+out_error_pin_mux:
+       iounmap(iface->regs_base);
+out_error_ioremap:
+out_error_get_res:
+       kfree(iface);
+out_error_nomem:
        return rc;
 }
 
@@ -594,6 +707,9 @@ static int i2c_bfin_twi_remove(struct platform_device *pdev)
 
        i2c_del_adapter(&(iface->adap));
        free_irq(iface->irq, iface);
+       peripheral_free_list(pin_req[pdev->id]);
+       iounmap(iface->regs_base);
+       kfree(iface);
 
        return 0;
 }
@@ -611,8 +727,6 @@ static struct platform_driver i2c_bfin_twi_driver = {
 
 static int __init i2c_bfin_twi_init(void)
 {
-       pr_info("I2C: Blackfin I2C TWI driver\n");
-
        return platform_driver_register(&i2c_bfin_twi_driver);
 }
 
@@ -621,9 +735,10 @@ static void __exit i2c_bfin_twi_exit(void)
        platform_driver_unregister(&i2c_bfin_twi_driver);
 }
 
-MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
-MODULE_DESCRIPTION("I2C-Bus adapter routines for Blackfin TWI");
-MODULE_LICENSE("GPL");
-
 module_init(i2c_bfin_twi_init);
 module_exit(i2c_bfin_twi_exit);
+
+MODULE_AUTHOR("Bryan Wu, Sonic Zhang");
+MODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Contoller Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:i2c-bfin-twi");
index fde2634..7ecbfc4 100644 (file)
@@ -328,7 +328,7 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
        int i;
        int ret;
 
-       dev_dbg(dev->dev, "%s: msgs: %d\n", __FUNCTION__, num);
+       dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);
 
        ret = i2c_davinci_wait_bus_not_busy(dev, 1);
        if (ret < 0) {
@@ -342,7 +342,7 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
                        return ret;
        }
 
-       dev_dbg(dev->dev, "%s:%d ret: %d\n", __FUNCTION__, __LINE__, ret);
+       dev_dbg(dev->dev, "%s:%d ret: %d\n", __func__, __LINE__, ret);
 
        return num;
 }
@@ -364,7 +364,7 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
        u16 w;
 
        while ((stat = davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG))) {
-               dev_dbg(dev->dev, "%s: stat=0x%x\n", __FUNCTION__, stat);
+               dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat);
                if (count++ == 100) {
                        dev_warn(dev->dev, "Too much work in one IRQ\n");
                        break;
@@ -553,6 +553,9 @@ static int davinci_i2c_remove(struct platform_device *pdev)
        return 0;
 }
 
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:i2c_davinci");
+
 static struct platform_driver davinci_i2c_driver = {
        .probe          = davinci_i2c_probe,
        .remove         = davinci_i2c_remove,
index 3ca19fc..7c1b762 100644 (file)
@@ -220,3 +220,4 @@ module_exit(i2c_gpio_exit);
 MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
 MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:i2c-gpio");
index 22bb247..85dbf34 100644 (file)
@@ -6,6 +6,9 @@
  * Copyright (c) 2003, 2004 Zultys Technologies.
  * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
  *
+ * Copyright (c) 2008 PIKA Technologies
+ * Sean MacLennan <smaclennan@pikatech.com>
+ *
  * Based on original work by
  *     Ian DaSilva  <idasilva@mvista.com>
  *      Armin Kuster <akuster@mvista.com>
 #include <asm/io.h>
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
+
+#ifdef CONFIG_IBM_OCP
 #include <asm/ocp.h>
 #include <asm/ibm4xx.h>
+#else
+#include <linux/of_platform.h>
+#endif
 
 #include "i2c-ibm_iic.h"
 
-#define DRIVER_VERSION "2.1"
+#define DRIVER_VERSION "2.2"
 
 MODULE_DESCRIPTION("IBM IIC driver v" DRIVER_VERSION);
 MODULE_LICENSE("GPL");
@@ -650,13 +658,14 @@ static inline u8 iic_clckdiv(unsigned int opb)
        opb /= 1000000;
 
        if (opb < 20 || opb > 150){
-               printk(KERN_CRIT "ibm-iic: invalid OPB clock frequency %u MHz\n",
+               printk(KERN_WARNING "ibm-iic: invalid OPB clock frequency %u MHz\n",
                        opb);
                opb = opb < 20 ? 20 : 150;
        }
        return (u8)((opb + 9) / 10 - 1);
 }
 
+#ifdef CONFIG_IBM_OCP
 /*
  * Register single IIC interface
  */
@@ -672,7 +681,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
                        ocp->def->index);
 
        if (!(dev = kzalloc(sizeof(*dev), GFP_KERNEL))) {
-               printk(KERN_CRIT "ibm-iic%d: failed to allocate device data\n",
+               printk(KERN_ERR "ibm-iic%d: failed to allocate device data\n",
                        ocp->def->index);
                return -ENOMEM;
        }
@@ -687,7 +696,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
        }
 
        if (!(dev->vaddr = ioremap(ocp->def->paddr, sizeof(struct iic_regs)))){
-               printk(KERN_CRIT "ibm-iic%d: failed to ioremap device registers\n",
+               printk(KERN_ERR "ibm-iic%d: failed to ioremap device registers\n",
                        dev->idx);
                ret = -ENXIO;
                goto fail2;
@@ -745,7 +754,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
        adap->nr = dev->idx >= 0 ? dev->idx : 0;
 
        if ((ret = i2c_add_numbered_adapter(adap)) < 0) {
-               printk(KERN_CRIT "ibm-iic%d: failed to register i2c adapter\n",
+               printk(KERN_ERR "ibm-iic%d: failed to register i2c adapter\n",
                        dev->idx);
                goto fail;
        }
@@ -778,7 +787,7 @@ static void __devexit iic_remove(struct ocp_device *ocp)
        struct ibm_iic_private* dev = (struct ibm_iic_private*)ocp_get_drvdata(ocp);
        BUG_ON(dev == NULL);
        if (i2c_del_adapter(&dev->adap)){
-               printk(KERN_CRIT "ibm-iic%d: failed to delete i2c adapter :(\n",
+               printk(KERN_ERR "ibm-iic%d: failed to delete i2c adapter :(\n",
                        dev->idx);
                /* That's *very* bad, just shutdown IRQ ... */
                if (dev->irq >= 0){
@@ -828,5 +837,181 @@ static void __exit iic_exit(void)
        ocp_unregister_driver(&ibm_iic_driver);
 }
 
+#else  /* !CONFIG_IBM_OCP */
+
+static int __devinit iic_request_irq(struct of_device *ofdev,
+                                    struct ibm_iic_private *dev)
+{
+       struct device_node *np = ofdev->node;
+       int irq;
+
+       if (iic_force_poll)
+               return NO_IRQ;
+
+       irq = irq_of_parse_and_map(np, 0);
+       if (irq == NO_IRQ) {
+               dev_err(&ofdev->dev, "irq_of_parse_and_map failed\n");
+               return NO_IRQ;
+       }
+
+       /* Disable interrupts until we finish initialization, assumes
+        *  level-sensitive IRQ setup...
+        */
+       iic_interrupt_mode(dev, 0);
+       if (request_irq(irq, iic_handler, 0, "IBM IIC", dev)) {
+               dev_err(&ofdev->dev, "request_irq %d failed\n", irq);
+               /* Fallback to the polling mode */
+               return NO_IRQ;
+       }
+
+       return irq;
+}
+
+/*
+ * Register single IIC interface
+ */
+static int __devinit iic_probe(struct of_device *ofdev,
+                              const struct of_device_id *match)
+{
+       struct device_node *np = ofdev->node;
+       struct ibm_iic_private *dev;
+       struct i2c_adapter *adap;
+       const u32 *indexp, *freq;
+       int ret;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               dev_err(&ofdev->dev, "failed to allocate device data\n");
+               return -ENOMEM;
+       }
+
+       dev_set_drvdata(&ofdev->dev, dev);
+
+       indexp = of_get_property(np, "index", NULL);
+       if (!indexp) {
+               dev_err(&ofdev->dev, "no index specified\n");
+               ret = -EINVAL;
+               goto error_cleanup;
+       }
+       dev->idx = *indexp;
+
+       dev->vaddr = of_iomap(np, 0);
+       if (dev->vaddr == NULL) {
+               dev_err(&ofdev->dev, "failed to iomap device\n");
+               ret = -ENXIO;
+               goto error_cleanup;
+       }
+
+       init_waitqueue_head(&dev->wq);
+
+       dev->irq = iic_request_irq(ofdev, dev);
+       if (dev->irq == NO_IRQ)
+               dev_warn(&ofdev->dev, "using polling mode\n");
+
+       /* Board specific settings */
+       if (iic_force_fast || of_get_property(np, "fast-mode", NULL))
+               dev->fast_mode = 1;
+
+       freq = of_get_property(np, "clock-frequency", NULL);
+       if (freq == NULL) {
+               freq = of_get_property(np->parent, "clock-frequency", NULL);
+               if (freq == NULL) {
+                       dev_err(&ofdev->dev, "Unable to get bus frequency\n");
+                       ret = -EINVAL;
+                       goto error_cleanup;
+               }
+       }
+
+       dev->clckdiv = iic_clckdiv(*freq);
+       dev_dbg(&ofdev->dev, "clckdiv = %d\n", dev->clckdiv);
+
+       /* Initialize IIC interface */
+       iic_dev_init(dev);
+
+       /* Register it with i2c layer */
+       adap = &dev->adap;
+       adap->dev.parent = &ofdev->dev;
+       strlcpy(adap->name, "IBM IIC", sizeof(adap->name));
+       i2c_set_adapdata(adap, dev);
+       adap->id = I2C_HW_OCP;
+       adap->class = I2C_CLASS_HWMON;
+       adap->algo = &iic_algo;
+       adap->timeout = 1;
+       adap->nr = dev->idx;
+
+       ret = i2c_add_numbered_adapter(adap);
+       if (ret  < 0) {
+               dev_err(&ofdev->dev, "failed to register i2c adapter\n");
+               goto error_cleanup;
+       }
+
+       dev_info(&ofdev->dev, "using %s mode\n",
+                dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)");
+
+       return 0;
+
+error_cleanup:
+       if (dev->irq != NO_IRQ) {
+               iic_interrupt_mode(dev, 0);
+               free_irq(dev->irq, dev);
+       }
+
+       if (dev->vaddr)
+               iounmap(dev->vaddr);
+
+       dev_set_drvdata(&ofdev->dev, NULL);
+       kfree(dev);
+       return ret;
+}
+
+/*
+ * Cleanup initialized IIC interface
+ */
+static int __devexit iic_remove(struct of_device *ofdev)
+{
+       struct ibm_iic_private *dev = dev_get_drvdata(&ofdev->dev);
+
+       dev_set_drvdata(&ofdev->dev, NULL);
+
+       i2c_del_adapter(&dev->adap);
+
+       if (dev->irq != NO_IRQ) {
+               iic_interrupt_mode(dev, 0);
+               free_irq(dev->irq, dev);
+       }
+
+       iounmap(dev->vaddr);
+       kfree(dev);
+
+       return 0;
+}
+
+static const struct of_device_id ibm_iic_match[] = {
+       { .compatible = "ibm,iic-405ex", },
+       { .compatible = "ibm,iic-405gp", },
+       { .compatible = "ibm,iic-440gp", },
+       { .compatible = "ibm,iic-440gpx", },
+       { .compatible = "ibm,iic-440grx", },
+       {}
+};
+
+static struct of_platform_driver ibm_iic_driver = {
+       .name   = "ibm-iic",
+       .match_table = ibm_iic_match,
+       .probe  = iic_probe,
+       .remove = __devexit_p(iic_remove),
+};
+
+static int __init iic_init(void)
+{
+       return of_register_platform_driver(&ibm_iic_driver);
+}
+
+static void __exit iic_exit(void)
+{
+       of_unregister_platform_driver(&ibm_iic_driver);
+}
+#endif /* CONFIG_IBM_OCP */
+
 module_init(iic_init);
 module_exit(iic_exit);
index ab41400..39884e7 100644 (file)
@@ -550,3 +550,4 @@ module_exit (i2c_iop3xx_exit);
 MODULE_AUTHOR("D-TACQ Solutions Ltd <www.d-tacq.com>");
 MODULE_DESCRIPTION("IOP3xx iic algorithm and driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:IOP3xx-I2C");
index 6352121..5af9e65 100644 (file)
@@ -164,4 +164,5 @@ module_exit(ixp2000_i2c_exit);
 MODULE_AUTHOR ("Deepak Saxena <dsaxena@plexity.net>");
 MODULE_DESCRIPTION("IXP2000 GPIO-based I2C bus driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:IXP2000-I2C");
 
index bbe787b..18beb0a 100644 (file)
@@ -392,6 +392,9 @@ static int fsl_i2c_remove(struct platform_device *pdev)
        return 0;
 };
 
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:fsl-i2c");
+
 /* Structure for a device driver */
 static struct platform_driver fsl_i2c_driver = {
        .probe = fsl_i2c_probe,
index e417c2c..f145692 100644 (file)
@@ -312,6 +312,9 @@ static int __devexit ocores_i2c_remove(struct platform_device* pdev)
        return 0;
 }
 
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:ocores-i2c");
+
 static struct platform_driver ocores_i2c_driver = {
        .probe  = ocores_i2c_probe,
        .remove = __devexit_p(ocores_i2c_remove),
index 7ba3177..e7eb7bf 100644 (file)
@@ -693,3 +693,4 @@ module_exit(omap_i2c_exit_driver);
 MODULE_AUTHOR("MontaVista Software, Inc. (and others)");
 MODULE_DESCRIPTION("TI OMAP I2C bus adapter");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:i2c_omap");
index 496ee87..a119784 100644 (file)
@@ -1,6 +1,7 @@
 /*
  *  i2c-pca-isa.c driver for PCA9564 on ISA boards
  *    Copyright (C) 2004 Arcom Control Systems
+ *    Copyright (C) 2008 Pengutronix
  *
  *  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
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/delay.h>
-#include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/wait.h>
-
 #include <linux/isa.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-pca.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#include "../algos/i2c-algo-pca.h"
-
+#define DRIVER "i2c-pca-isa"
 #define IO_SIZE 4
 
-#undef DEBUG_IO
-//#define DEBUG_IO
-
 static unsigned long base   = 0x330;
 static int irq           = 10;
 
@@ -48,22 +43,9 @@ static int irq         = 10;
  * in the actual clock rate */
 static int clock  = I2C_PCA_CON_59kHz;
 
-static int own    = 0x55;
-
 static wait_queue_head_t pca_wait;
 
-static int pca_isa_getown(struct i2c_algo_pca_data *adap)
-{
-       return (own);
-}
-
-static int pca_isa_getclock(struct i2c_algo_pca_data *adap)
-{
-       return (clock);
-}
-
-static void
-pca_isa_writebyte(struct i2c_algo_pca_data *adap, int reg, int val)
+static void pca_isa_writebyte(void *pd, int reg, int val)
 {
 #ifdef DEBUG_IO
        static char *names[] = { "T/O", "DAT", "ADR", "CON" };
@@ -72,44 +54,49 @@ pca_isa_writebyte(struct i2c_algo_pca_data *adap, int reg, int val)
        outb(val, base+reg);
 }
 
-static int
-pca_isa_readbyte(struct i2c_algo_pca_data *adap, int reg)
+static int pca_isa_readbyte(void *pd, int reg)
 {
        int res = inb(base+reg);
 #ifdef DEBUG_IO
        {
-               static char *names[] = { "STA", "DAT", "ADR", "CON" };  
+               static char *names[] = { "STA", "DAT", "ADR", "CON" };
                printk("*** read  %s => %#04x\n", names[reg], res);
        }
 #endif
        return res;
 }
 
-static int pca_isa_waitforinterrupt(struct i2c_algo_pca_data *adap)
+static int pca_isa_waitforcompletion(void *pd)
 {
        int ret = 0;
 
        if (irq > -1) {
                ret = wait_event_interruptible(pca_wait,
-                                              pca_isa_readbyte(adap, I2C_PCA_CON) & I2C_PCA_CON_SI);
+                                              pca_isa_readbyte(pd, I2C_PCA_CON) & I2C_PCA_CON_SI);
        } else {
-               while ((pca_isa_readbyte(adap, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0) 
+               while ((pca_isa_readbyte(pd, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0)
                        udelay(100);
        }
        return ret;
 }
 
+static void pca_isa_resetchip(void *pd)
+{
+       /* apparently only an external reset will do it. not a lot can be done */
+       printk(KERN_WARNING DRIVER ": Haven't figured out how to do a reset yet\n");
+}
+
 static irqreturn_t pca_handler(int this_irq, void *dev_id) {
        wake_up_interruptible(&pca_wait);
        return IRQ_HANDLED;
 }
 
 static struct i2c_algo_pca_data pca_isa_data = {
-       .get_own                = pca_isa_getown,
-       .get_clock              = pca_isa_getclock,
+       /* .data intentionally left NULL, not needed with ISA */
        .write_byte             = pca_isa_writebyte,
        .read_byte              = pca_isa_readbyte,
-       .wait_for_interrupt     = pca_isa_waitforinterrupt,
+       .wait_for_completion    = pca_isa_waitforcompletion,
+       .reset_chip             = pca_isa_resetchip,
 };
 
 static struct i2c_adapter pca_isa_ops = {
@@ -117,6 +104,7 @@ static struct i2c_adapter pca_isa_ops = {
        .id             = I2C_HW_A_ISA,
        .algo_data      = &pca_isa_data,
        .name           = "PCA9564 ISA Adapter",
+       .timeout        = 100,
 };
 
 static int __devinit pca_isa_probe(struct device *dev, unsigned int id)
@@ -144,6 +132,7 @@ static int __devinit pca_isa_probe(struct device *dev, unsigned int id)
                }
        }
 
+       pca_isa_data.i2c_clock = clock;
        if (i2c_pca_add_bus(&pca_isa_ops) < 0) {
                dev_err(dev, "Failed to add i2c bus\n");
                goto out_irq;
@@ -178,7 +167,7 @@ static struct isa_driver pca_isa_driver = {
        .remove         = __devexit_p(pca_isa_remove),
        .driver = {
                .owner  = THIS_MODULE,
-               .name   = "i2c-pca-isa",
+               .name   = DRIVER,
        }
 };
 
@@ -204,7 +193,5 @@ MODULE_PARM_DESC(irq, "IRQ");
 module_param(clock, int, 0);
 MODULE_PARM_DESC(clock, "Clock rate as described in table 1 of PCA9564 datasheet");
 
-module_param(own, int, 0); /* the driver can't do slave mode, so there's no real point in this */
-
 module_init(pca_isa_init);
 module_exit(pca_isa_exit);
diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c
new file mode 100644 (file)
index 0000000..9d75f51
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ *  i2c_pca_platform.c
+ *
+ *  Platform driver for the PCA9564 I2C controller.
+ *
+ *  Copyright (C) 2008 Pengutronix
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c-algo-pca.h>
+#include <linux/i2c-pca-platform.h>
+#include <linux/gpio.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#define res_len(r)             ((r)->end - (r)->start + 1)
+
+struct i2c_pca_pf_data {
+       void __iomem                    *reg_base;
+       int                             irq;    /* if 0, use polling */
+       int                             gpio;
+       wait_queue_head_t               wait;
+       struct i2c_adapter              adap;
+       struct i2c_algo_pca_data        algo_data;
+       unsigned long                   io_base;
+       unsigned long                   io_size;
+};
+
+/* Read/Write functions for different register alignments */
+
+static int i2c_pca_pf_readbyte8(void *pd, int reg)
+{
+       struct i2c_pca_pf_data *i2c = pd;
+       return ioread8(i2c->reg_base + reg);
+}
+
+static int i2c_pca_pf_readbyte16(void *pd, int reg)
+{
+       struct i2c_pca_pf_data *i2c = pd;
+       return ioread8(i2c->reg_base + reg * 2);
+}
+
+static int i2c_pca_pf_readbyte32(void *pd, int reg)
+{
+       struct i2c_pca_pf_data *i2c = pd;
+       return ioread8(i2c->reg_base + reg * 4);
+}
+
+static void i2c_pca_pf_writebyte8(void *pd, int reg, int val)
+{
+       struct i2c_pca_pf_data *i2c = pd;
+       iowrite8(val, i2c->reg_base + reg);
+}
+
+static void i2c_pca_pf_writebyte16(void *pd, int reg, int val)
+{
+       struct i2c_pca_pf_data *i2c = pd;
+       iowrite8(val, i2c->reg_base + reg * 2);
+}
+
+static void i2c_pca_pf_writebyte32(void *pd, int reg, int val)
+{
+       struct i2c_pca_pf_data *i2c = pd;
+       iowrite8(val, i2c->reg_base + reg * 4);
+}
+
+
+static int i2c_pca_pf_waitforcompletion(void *pd)
+{
+       struct i2c_pca_pf_data *i2c = pd;
+       int ret = 0;
+
+       if (i2c->irq) {
+               ret = wait_event_interruptible(i2c->wait,
+                       i2c->algo_data.read_byte(i2c, I2C_PCA_CON)
+                       & I2C_PCA_CON_SI);
+       } else {
+               /*
+                * Do polling...
+                * XXX: Could get stuck in extreme cases!
+                *      Maybe add timeout, but using irqs is preferred anyhow.
+                */
+               while ((i2c->algo_data.read_byte(i2c, I2C_PCA_CON)
+                               & I2C_PCA_CON_SI) == 0)
+                       udelay(100);
+       }
+
+       return ret;
+}
+
+static void i2c_pca_pf_dummyreset(void *pd)
+{
+       struct i2c_pca_pf_data *i2c = pd;
+       printk(KERN_WARNING "%s: No reset-pin found. Chip may get stuck!\n",
+               i2c->adap.name);
+}
+
+static void i2c_pca_pf_resetchip(void *pd)
+{
+       struct i2c_pca_pf_data *i2c = pd;
+
+       gpio_set_value(i2c->gpio, 0);
+       ndelay(100);
+       gpio_set_value(i2c->gpio, 1);
+}
+
+static irqreturn_t i2c_pca_pf_handler(int this_irq, void *dev_id)
+{
+       struct i2c_pca_pf_data *i2c = dev_id;
+
+       if ((i2c->algo_data.read_byte(i2c, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0)
+               return IRQ_NONE;
+
+       wake_up_interruptible(&i2c->wait);
+
+       return IRQ_HANDLED;
+}
+
+
+static int __devinit i2c_pca_pf_probe(struct platform_device *pdev)
+{
+       struct i2c_pca_pf_data *i2c;
+       struct resource *res;
+       struct i2c_pca9564_pf_platform_data *platform_data =
+                               pdev->dev.platform_data;
+       int ret = 0;
+       int irq;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       irq = platform_get_irq(pdev, 0);
+       /* If irq is 0, we do polling. */
+
+       if (res == NULL) {
+               ret = -ENODEV;
+               goto e_print;
+       }
+
+       if (!request_mem_region(res->start, res_len(res), res->name)) {
+               ret = -ENOMEM;
+               goto e_print;
+       }
+
+       i2c = kzalloc(sizeof(struct i2c_pca_pf_data), GFP_KERNEL);
+       if (!i2c) {
+               ret = -ENOMEM;
+               goto e_alloc;
+       }
+
+       init_waitqueue_head(&i2c->wait);
+
+       i2c->reg_base = ioremap(res->start, res_len(res));
+       if (!i2c->reg_base) {
+               ret = -EIO;
+               goto e_remap;
+       }
+       i2c->io_base = res->start;
+       i2c->io_size = res_len(res);
+       i2c->irq = irq;
+
+       i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0;
+       i2c->adap.owner = THIS_MODULE;
+       snprintf(i2c->adap.name, sizeof(i2c->adap.name), "PCA9564 at 0x%08lx",
+               (unsigned long) res->start);
+       i2c->adap.algo_data = &i2c->algo_data;
+       i2c->adap.dev.parent = &pdev->dev;
+       i2c->adap.timeout = platform_data->timeout;
+
+       i2c->algo_data.i2c_clock = platform_data->i2c_clock_speed;
+       i2c->algo_data.data = i2c;
+
+       switch (res->flags & IORESOURCE_MEM_TYPE_MASK) {
+       case IORESOURCE_MEM_32BIT:
+               i2c->algo_data.write_byte = i2c_pca_pf_writebyte32;
+               i2c->algo_data.read_byte = i2c_pca_pf_readbyte32;
+               break;
+       case IORESOURCE_MEM_16BIT:
+               i2c->algo_data.write_byte = i2c_pca_pf_writebyte16;
+               i2c->algo_data.read_byte = i2c_pca_pf_readbyte16;
+               break;
+       case IORESOURCE_MEM_8BIT:
+       default:
+               i2c->algo_data.write_byte = i2c_pca_pf_writebyte8;
+               i2c->algo_data.read_byte = i2c_pca_pf_readbyte8;
+               break;
+       }
+
+       i2c->algo_data.wait_for_completion = i2c_pca_pf_waitforcompletion;
+
+       i2c->gpio = platform_data->gpio;
+       i2c->algo_data.reset_chip = i2c_pca_pf_dummyreset;
+
+       /* Use gpio_is_valid() when in mainline */
+       if (i2c->gpio > -1) {
+               ret = gpio_request(i2c->gpio, i2c->adap.name);
+               if (ret == 0) {
+                       gpio_direction_output(i2c->gpio, 1);
+                       i2c->algo_data.reset_chip = i2c_pca_pf_resetchip;
+               } else {
+                       printk(KERN_WARNING "%s: Registering gpio failed!\n",
+                               i2c->adap.name);
+                       i2c->gpio = ret;
+               }
+       }
+
+       if (irq) {
+               ret = request_irq(irq, i2c_pca_pf_handler,
+                       IRQF_TRIGGER_FALLING, i2c->adap.name, i2c);
+               if (ret)
+                       goto e_reqirq;
+       }
+
+       if (i2c_pca_add_numbered_bus(&i2c->adap) < 0) {
+               ret = -ENODEV;
+               goto e_adapt;
+       }
+
+       platform_set_drvdata(pdev, i2c);
+
+       printk(KERN_INFO "%s registered.\n", i2c->adap.name);
+
+       return 0;
+
+e_adapt:
+       if (irq)
+               free_irq(irq, i2c);
+e_reqirq:
+       if (i2c->gpio > -1)
+               gpio_free(i2c->gpio);
+
+       iounmap(i2c->reg_base);
+e_remap:
+       kfree(i2c);
+e_alloc:
+       release_mem_region(res->start, res_len(res));
+e_print:
+       printk(KERN_ERR "Registering PCA9564 FAILED! (%d)\n", ret);
+       return ret;
+}
+
+static int __devexit i2c_pca_pf_remove(struct platform_device *pdev)
+{
+       struct i2c_pca_pf_data *i2c = platform_get_drvdata(pdev);
+       platform_set_drvdata(pdev, NULL);
+
+       i2c_del_adapter(&i2c->adap);
+
+       if (i2c->irq)
+               free_irq(i2c->irq, i2c);
+
+       if (i2c->gpio > -1)
+               gpio_free(i2c->gpio);
+
+       iounmap(i2c->reg_base);
+       release_mem_region(i2c->io_base, i2c->io_size);
+       kfree(i2c);
+
+       return 0;
+}
+
+static struct platform_driver i2c_pca_pf_driver = {
+       .probe = i2c_pca_pf_probe,
+       .remove = __devexit_p(i2c_pca_pf_remove),
+       .driver = {
+               .name = "i2c-pca-platform",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init i2c_pca_pf_init(void)
+{
+       return platform_driver_register(&i2c_pca_pf_driver);
+}
+
+static void __exit i2c_pca_pf_exit(void)
+{
+       platform_driver_unregister(&i2c_pca_pf_driver);
+}
+
+MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_DESCRIPTION("I2C-PCA9564 platform driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_pca_pf_init);
+module_exit(i2c_pca_pf_exit);
+
index b03af56..63b3e2c 100644 (file)
@@ -467,7 +467,7 @@ static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd(
            (cmd->read_len == 0 || cmd->write_len == 0))) {
                dev_err(&pmcmsptwi_adapter.dev,
                        "%s: Cannot transfer less than 1 byte\n",
-                       __FUNCTION__);
+                       __func__);
                return -EINVAL;
        }
 
@@ -475,7 +475,7 @@ static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd(
            cmd->write_len > MSP_MAX_BYTES_PER_RW) {
                dev_err(&pmcmsptwi_adapter.dev,
                        "%s: Cannot transfer more than %d bytes\n",
-                       __FUNCTION__, MSP_MAX_BYTES_PER_RW);
+                       __func__, MSP_MAX_BYTES_PER_RW);
                return -EINVAL;
        }
 
@@ -627,6 +627,9 @@ static struct i2c_adapter pmcmsptwi_adapter = {
        .name           = DRV_NAME,
 };
 
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:" DRV_NAME);
+
 static struct platform_driver pmcmsptwi_driver = {
        .probe  = pmcmsptwi_probe,
        .remove = __devexit_p(pmcmsptwi_remove),
index f8d0dff..1ca2108 100644 (file)
@@ -76,7 +76,7 @@ static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap)
 {
        struct i2c_pnx_algo_data *alg_data = adap->algo_data;
 
-       dev_dbg(&adap->dev, "%s(): addr 0x%x mode %d\n", __FUNCTION__,
+       dev_dbg(&adap->dev, "%s(): addr 0x%x mode %d\n", __func__,
                slave_addr, alg_data->mif.mode);
 
        /* Check for 7 bit slave addresses only */
@@ -110,14 +110,14 @@ static int i2c_pnx_start(unsigned char slave_addr, struct i2c_adapter *adap)
        iowrite32(ioread32(I2C_REG_STS(alg_data)) | mstatus_tdi | mstatus_afi,
                  I2C_REG_STS(alg_data));
 
-       dev_dbg(&adap->dev, "%s(): sending %#x\n", __FUNCTION__,
+       dev_dbg(&adap->dev, "%s(): sending %#x\n", __func__,
                (slave_addr << 1) | start_bit | alg_data->mif.mode);
 
        /* Write the slave address, START bit and R/W bit */
        iowrite32((slave_addr << 1) | start_bit | alg_data->mif.mode,
                  I2C_REG_TX(alg_data));
 
-       dev_dbg(&adap->dev, "%s(): exit\n", __FUNCTION__);
+       dev_dbg(&adap->dev, "%s(): exit\n", __func__);
 
        return 0;
 }
@@ -135,7 +135,7 @@ static void i2c_pnx_stop(struct i2c_adapter *adap)
        long timeout = 1000;
 
        dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
-               __FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
+               __func__, ioread32(I2C_REG_STS(alg_data)));
 
        /* Write a STOP bit to TX FIFO */
        iowrite32(0xff | stop_bit, I2C_REG_TX(alg_data));
@@ -149,7 +149,7 @@ static void i2c_pnx_stop(struct i2c_adapter *adap)
        }
 
        dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
-               __FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
+               __func__, ioread32(I2C_REG_STS(alg_data)));
 }
 
 /**
@@ -164,7 +164,7 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
        u32 val;
 
        dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
-               __FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
+               __func__, ioread32(I2C_REG_STS(alg_data)));
 
        if (alg_data->mif.len > 0) {
                /* We still have something to talk about... */
@@ -179,7 +179,7 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
                alg_data->mif.len--;
                iowrite32(val, I2C_REG_TX(alg_data));
 
-               dev_dbg(&adap->dev, "%s(): xmit %#x [%d]\n", __FUNCTION__,
+               dev_dbg(&adap->dev, "%s(): xmit %#x [%d]\n", __func__,
                        val, alg_data->mif.len + 1);
 
                if (alg_data->mif.len == 0) {
@@ -197,7 +197,7 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
                        del_timer_sync(&alg_data->mif.timer);
 
                        dev_dbg(&adap->dev, "%s(): Waking up xfer routine.\n",
-                               __FUNCTION__);
+                               __func__);
 
                        complete(&alg_data->mif.complete);
                }
@@ -213,13 +213,13 @@ static int i2c_pnx_master_xmit(struct i2c_adapter *adap)
                /* Stop timer. */
                del_timer_sync(&alg_data->mif.timer);
                dev_dbg(&adap->dev, "%s(): Waking up xfer routine after "
-                       "zero-xfer.\n", __FUNCTION__);
+                       "zero-xfer.\n", __func__);
 
                complete(&alg_data->mif.complete);
        }
 
        dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
-               __FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
+               __func__, ioread32(I2C_REG_STS(alg_data)));
 
        return 0;
 }
@@ -237,14 +237,14 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
        u32 ctl = 0;
 
        dev_dbg(&adap->dev, "%s(): entering: stat = %04x.\n",
-               __FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
+               __func__, ioread32(I2C_REG_STS(alg_data)));
 
        /* Check, whether there is already data,
         * or we didn't 'ask' for it yet.
         */
        if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) {
                dev_dbg(&adap->dev, "%s(): Write dummy data to fill "
-                       "Rx-fifo...\n", __FUNCTION__);
+                       "Rx-fifo...\n", __func__);
 
                if (alg_data->mif.len == 1) {
                        /* Last byte, do not acknowledge next rcv. */
@@ -276,7 +276,7 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
        if (alg_data->mif.len > 0) {
                val = ioread32(I2C_REG_RX(alg_data));
                *alg_data->mif.buf++ = (u8) (val & 0xff);
-               dev_dbg(&adap->dev, "%s(): rcv 0x%x [%d]\n", __FUNCTION__, val,
+               dev_dbg(&adap->dev, "%s(): rcv 0x%x [%d]\n", __func__, val,
                        alg_data->mif.len);
 
                alg_data->mif.len--;
@@ -300,7 +300,7 @@ static int i2c_pnx_master_rcv(struct i2c_adapter *adap)
        }
 
        dev_dbg(&adap->dev, "%s(): exiting: stat = %04x.\n",
-               __FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
+               __func__, ioread32(I2C_REG_STS(alg_data)));
 
        return 0;
 }
@@ -312,7 +312,7 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
        struct i2c_pnx_algo_data *alg_data = adap->algo_data;
 
        dev_dbg(&adap->dev, "%s(): mstat = %x mctrl = %x, mode = %d\n",
-               __FUNCTION__,
+               __func__,
                ioread32(I2C_REG_STS(alg_data)),
                ioread32(I2C_REG_CTL(alg_data)),
                alg_data->mif.mode);
@@ -336,7 +336,7 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
                /* Slave did not acknowledge, generate a STOP */
                dev_dbg(&adap->dev, "%s(): "
                        "Slave did not acknowledge, generating a STOP.\n",
-                       __FUNCTION__);
+                       __func__);
                i2c_pnx_stop(adap);
 
                /* Disable master interrupts. */
@@ -375,7 +375,7 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
        iowrite32(stat | mstatus_tdi | mstatus_afi, I2C_REG_STS(alg_data));
 
        dev_dbg(&adap->dev, "%s(): exiting, stat = %x ctrl = %x.\n",
-                __FUNCTION__, ioread32(I2C_REG_STS(alg_data)),
+                __func__, ioread32(I2C_REG_STS(alg_data)),
                 ioread32(I2C_REG_CTL(alg_data)));
 
        return IRQ_HANDLED;
@@ -447,7 +447,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
        u32 stat = ioread32(I2C_REG_STS(alg_data));
 
        dev_dbg(&adap->dev, "%s(): entering: %d messages, stat = %04x.\n",
-               __FUNCTION__, num, ioread32(I2C_REG_STS(alg_data)));
+               __func__, num, ioread32(I2C_REG_STS(alg_data)));
 
        bus_reset_if_active(adap);
 
@@ -473,7 +473,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                alg_data->mif.ret = 0;
                alg_data->last = (i == num - 1);
 
-               dev_dbg(&adap->dev, "%s(): mode %d, %d bytes\n", __FUNCTION__,
+               dev_dbg(&adap->dev, "%s(): mode %d, %d bytes\n", __func__,
                        alg_data->mif.mode,
                        alg_data->mif.len);
 
@@ -498,7 +498,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                if (!(rc = alg_data->mif.ret))
                        completed++;
                dev_dbg(&adap->dev, "%s(): Complete, return code = %d.\n",
-                       __FUNCTION__, rc);
+                       __func__, rc);
 
                /* Clear TDI and AFI bits in case they are set. */
                if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_tdi) {
@@ -522,7 +522,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
        alg_data->mif.len = 0;
 
        dev_dbg(&adap->dev, "%s(): exiting, stat = %x\n",
-               __FUNCTION__, ioread32(I2C_REG_STS(alg_data)));
+               __func__, ioread32(I2C_REG_STS(alg_data)));
 
        if (completed != num)
                return ((rc < 0) ? rc : -EREMOTEIO);
@@ -563,7 +563,7 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
 
        if (!i2c_pnx || !i2c_pnx->adapter) {
                dev_err(&pdev->dev, "%s: no platform data supplied\n",
-                      __FUNCTION__);
+                      __func__);
                ret = -EINVAL;
                goto out;
        }
@@ -697,6 +697,7 @@ static void __exit i2c_adap_pnx_exit(void)
 MODULE_AUTHOR("Vitaly Wool, Dennis Kovalev <source@mvista.com>");
 MODULE_DESCRIPTION("I2C driver for Philips IP3204-based I2C busses");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pnx-i2c");
 
 /* We need to make sure I2C is initialized before USB */
 subsys_initcall(i2c_adap_pnx_init);
index 7813127..22f6d5c 100644 (file)
@@ -263,6 +263,9 @@ static int __devexit i2c_powermac_probe(struct platform_device *dev)
 }
 
 
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:i2c-powermac");
+
 static struct platform_driver i2c_powermac_driver = {
        .probe = i2c_powermac_probe,
        .remove = __devexit_p(i2c_powermac_remove),
index 6fd2d6a..eb69fba 100644 (file)
@@ -155,7 +155,7 @@ static void i2c_pxa_show_state(struct pxa_i2c *i2c, int lno, const char *fname)
                readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c)));
 }
 
-#define show_state(i2c) i2c_pxa_show_state(i2c, __LINE__, __FUNCTION__)
+#define show_state(i2c) i2c_pxa_show_state(i2c, __LINE__, __func__)
 #else
 #define i2c_debug      0
 
@@ -1132,6 +1132,7 @@ static void __exit i2c_adap_pxa_exit(void)
 }
 
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-i2c");
 
 module_init(i2c_adap_pxa_init);
 module_exit(i2c_adap_pxa_exit);
index c44ada5..1305ef1 100644 (file)
@@ -276,12 +276,12 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
        switch (i2c->state) {
 
        case STATE_IDLE:
-               dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __FUNCTION__);
+               dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __func__);
                goto out;
                break;
 
        case STATE_STOP:
-               dev_err(i2c->dev, "%s: called in STATE_STOP\n", __FUNCTION__);
+               dev_err(i2c->dev, "%s: called in STATE_STOP\n", __func__);
                s3c24xx_i2c_disable_irq(i2c);           
                goto out_ack;
 
@@ -948,3 +948,4 @@ module_exit(i2c_adap_s3c_exit);
 MODULE_DESCRIPTION("S3C24XX I2C Bus driver");
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c2410-i2c");
diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c
new file mode 100644 (file)
index 0000000..5e0e254
--- /dev/null
@@ -0,0 +1,577 @@
+/*
+ * I2C bus driver for the SH7760 I2C Interfaces.
+ *
+ * (c) 2005-2008 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com>
+ *
+ * licensed under the terms outlined in the file COPYING.
+ *
+ */
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <asm/clock.h>
+#include <asm/i2c-sh7760.h>
+#include <asm/io.h>
+
+/* register offsets */
+#define I2CSCR         0x0             /* slave ctrl           */
+#define I2CMCR         0x4             /* master ctrl          */
+#define I2CSSR         0x8             /* slave status         */
+#define I2CMSR         0xC             /* master status        */
+#define I2CSIER                0x10            /* slave irq enable     */
+#define I2CMIER                0x14            /* master irq enable    */
+#define I2CCCR         0x18            /* clock dividers       */
+#define I2CSAR         0x1c            /* slave address        */
+#define I2CMAR         0x20            /* master address       */
+#define I2CRXTX                0x24            /* data port            */
+#define I2CFCR         0x28            /* fifo control         */
+#define I2CFSR         0x2C            /* fifo status          */
+#define I2CFIER                0x30            /* fifo irq enable      */
+#define I2CRFDR                0x34            /* rx fifo count        */
+#define I2CTFDR                0x38            /* tx fifo count        */
+
+#define REGSIZE                0x3C
+
+#define MCR_MDBS       0x80            /* non-fifo mode switch */
+#define MCR_FSCL       0x40            /* override SCL pin     */
+#define MCR_FSDA       0x20            /* override SDA pin     */
+#define MCR_OBPC       0x10            /* override pins        */
+#define MCR_MIE                0x08            /* master if enable     */
+#define MCR_TSBE       0x04
+#define MCR_FSB                0x02            /* force stop bit       */
+#define MCR_ESG                0x01            /* en startbit gen.     */
+
+#define MSR_MNR                0x40            /* nack received        */
+#define MSR_MAL                0x20            /* arbitration lost     */
+#define MSR_MST                0x10            /* sent a stop          */
+#define MSR_MDE                0x08
+#define MSR_MDT                0x04
+#define MSR_MDR                0x02
+#define MSR_MAT                0x01            /* slave addr xfer done */
+
+#define MIE_MNRE       0x40            /* nack irq en          */
+#define MIE_MALE       0x20            /* arblos irq en        */
+#define MIE_MSTE       0x10            /* stop irq en          */
+#define MIE_MDEE       0x08
+#define MIE_MDTE       0x04
+#define MIE_MDRE       0x02
+#define MIE_MATE       0x01            /* address sent irq en  */
+
+#define FCR_RFRST      0x02            /* reset rx fifo        */
+#define FCR_TFRST      0x01            /* reset tx fifo        */
+
+#define FSR_TEND       0x04            /* last byte sent       */
+#define FSR_RDF                0x02            /* rx fifo trigger      */
+#define FSR_TDFE       0x01            /* tx fifo empty        */
+
+#define FIER_TEIE      0x04            /* tx fifo empty irq en */
+#define FIER_RXIE      0x02            /* rx fifo trig irq en  */
+#define FIER_TXIE      0x01            /* tx fifo trig irq en  */
+
+#define FIFO_SIZE      16
+
+struct cami2c {
+       void __iomem *iobase;
+       struct i2c_adapter adap;
+
+       /* message processing */
+       struct i2c_msg  *msg;
+#define IDF_SEND       1
+#define IDF_RECV       2
+#define IDF_STOP       4
+       int             flags;
+
+#define IDS_DONE       1
+#define IDS_ARBLOST    2
+#define IDS_NACK       4
+       int             status;
+       struct completion xfer_done;
+
+       int irq;
+       struct resource *ioarea;
+};
+
+static inline void OUT32(struct cami2c *cam, int reg, unsigned long val)
+{
+       ctrl_outl(val, (unsigned long)cam->iobase + reg);
+}
+
+static inline unsigned long IN32(struct cami2c *cam, int reg)
+{
+       return ctrl_inl((unsigned long)cam->iobase + reg);
+}
+
+static irqreturn_t sh7760_i2c_irq(int irq, void *ptr)
+{
+       struct cami2c *id = ptr;
+       struct i2c_msg *msg = id->msg;
+       char *data = msg->buf;
+       unsigned long msr, fsr, fier, len;
+
+       msr = IN32(id, I2CMSR);
+       fsr = IN32(id, I2CFSR);
+
+       /* arbitration lost */
+       if (msr & MSR_MAL) {
+               OUT32(id, I2CMCR, 0);
+               OUT32(id, I2CSCR, 0);
+               OUT32(id, I2CSAR, 0);
+               id->status |= IDS_DONE | IDS_ARBLOST;
+               goto out;
+       }
+
+       if (msr & MSR_MNR) {
+               /* NACK handling is very screwed up.  After receiving a
+                * NAK IRQ one has to wait a bit  before writing to any
+                * registers, or the ctl will lock up. After that delay
+                * do a normal i2c stop. Then wait at least 1 ms before
+                * attempting another transfer or ctl will stop working
+                */
+               udelay(100);    /* wait or risk ctl hang */
+               OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
+               OUT32(id, I2CMCR, MCR_MIE | MCR_FSB);
+               OUT32(id, I2CFIER, 0);
+               OUT32(id, I2CMIER, MIE_MSTE);
+               OUT32(id, I2CSCR, 0);
+               OUT32(id, I2CSAR, 0);
+               id->status |= IDS_NACK;
+               msr &= ~MSR_MAT;
+               fsr = 0;
+               /* In some cases the MST bit is also set. */
+       }
+
+       /* i2c-stop was sent */
+       if (msr & MSR_MST) {
+               id->status |= IDS_DONE;
+               goto out;
+       }
+
+       /* i2c slave addr was sent; set to "normal" operation */
+       if (msr & MSR_MAT)
+               OUT32(id, I2CMCR, MCR_MIE);
+
+       fier = IN32(id, I2CFIER);
+
+       if (fsr & FSR_RDF) {
+               len = IN32(id, I2CRFDR);
+               if (msg->len <= len) {
+                       if (id->flags & IDF_STOP) {
+                               OUT32(id, I2CMCR, MCR_MIE | MCR_FSB);
+                               OUT32(id, I2CFIER, 0);
+                               /* manual says: wait >= 0.5 SCL times */
+                               udelay(5);
+                               /* next int should be MST */
+                       } else {
+                               id->status |= IDS_DONE;
+                               /* keep the RDF bit: ctrl holds SCL low
+                                * until the setup for the next i2c_msg
+                                * clears this bit.
+                                */
+                               fsr &= ~FSR_RDF;
+                       }
+               }
+               while (msg->len && len) {
+                       *data++ = IN32(id, I2CRXTX);
+                       msg->len--;
+                       len--;
+               }
+
+               if (msg->len) {
+                       len = (msg->len >= FIFO_SIZE) ? FIFO_SIZE - 1
+                                                     : msg->len - 1;
+
+                       OUT32(id, I2CFCR, FCR_TFRST | ((len & 0xf) << 4));
+               }
+
+       } else if (id->flags & IDF_SEND) {
+               if ((fsr & FSR_TEND) && (msg->len < 1)) {
+                       if (id->flags & IDF_STOP) {
+                               OUT32(id, I2CMCR, MCR_MIE | MCR_FSB);
+                       } else {
+                               id->status |= IDS_DONE;
+                               /* keep the TEND bit: ctl holds SCL low
+                                * until the setup for the next i2c_msg
+                                * clears this bit.
+                                */
+                               fsr &= ~FSR_TEND;
+                       }
+               }
+               if (fsr & FSR_TDFE) {
+                       while (msg->len && (IN32(id, I2CTFDR) < FIFO_SIZE)) {
+                               OUT32(id, I2CRXTX, *data++);
+                               msg->len--;
+                       }
+
+                       if (msg->len < 1) {
+                               fier &= ~FIER_TXIE;
+                               OUT32(id, I2CFIER, fier);
+                       } else {
+                               len = (msg->len >= FIFO_SIZE) ? 2 : 0;
+                               OUT32(id, I2CFCR,
+                                         FCR_RFRST | ((len & 3) << 2));
+                       }
+               }
+       }
+out:
+       if (id->status & IDS_DONE) {
+               OUT32(id, I2CMIER, 0);
+               OUT32(id, I2CFIER, 0);
+               id->msg = NULL;
+               complete(&id->xfer_done);
+       }
+       /* clear status flags and ctrl resumes work */
+       OUT32(id, I2CMSR, ~msr);
+       OUT32(id, I2CFSR, ~fsr);
+       OUT32(id, I2CSSR, 0);
+
+       return IRQ_HANDLED;
+}
+
+
+/* prepare and start a master receive operation */
+static void sh7760_i2c_mrecv(struct cami2c *id)
+{
+       int len;
+
+       id->flags |= IDF_RECV;
+
+       /* set the slave addr reg; otherwise rcv wont work! */
+       OUT32(id, I2CSAR, 0xfe);
+       OUT32(id, I2CMAR, (id->msg->addr << 1) | 1);
+
+       /* adjust rx fifo trigger */
+       if (id->msg->len >= FIFO_SIZE)
+               len = FIFO_SIZE - 1;    /* trigger at fifo full */
+       else
+               len = id->msg->len - 1; /* trigger before all received */
+
+       OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
+       OUT32(id, I2CFCR, FCR_TFRST | ((len & 0xF) << 4));
+
+       OUT32(id, I2CMSR, 0);
+       OUT32(id, I2CMCR, MCR_MIE | MCR_ESG);
+       OUT32(id, I2CMIER, MIE_MNRE | MIE_MALE | MIE_MSTE | MIE_MATE);
+       OUT32(id, I2CFIER, FIER_RXIE);
+}
+
+/* prepare and start a master send operation */
+static void sh7760_i2c_msend(struct cami2c *id)
+{
+       int len;
+
+       id->flags |= IDF_SEND;
+
+       /* set the slave addr reg; otherwise xmit wont work! */
+       OUT32(id, I2CSAR, 0xfe);
+       OUT32(id, I2CMAR, (id->msg->addr << 1) | 0);
+
+       /* adjust tx fifo trigger */
+       if (id->msg->len >= FIFO_SIZE)
+               len = 2;        /* trig: 2 bytes left in TX fifo */
+       else
+               len = 0;        /* trig: 8 bytes left in TX fifo */
+
+       OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
+       OUT32(id, I2CFCR, FCR_RFRST | ((len & 3) << 2));
+
+       while (id->msg->len && IN32(id, I2CTFDR) < FIFO_SIZE) {
+               OUT32(id, I2CRXTX, *(id->msg->buf));
+               (id->msg->len)--;
+               (id->msg->buf)++;
+       }
+
+       OUT32(id, I2CMSR, 0);
+       OUT32(id, I2CMCR, MCR_MIE | MCR_ESG);
+       OUT32(id, I2CFSR, 0);
+       OUT32(id, I2CMIER, MIE_MNRE | MIE_MALE | MIE_MSTE | MIE_MATE);
+       OUT32(id, I2CFIER, FIER_TEIE | (id->msg->len ? FIER_TXIE : 0));
+}
+
+static inline int sh7760_i2c_busy_check(struct cami2c *id)
+{
+       return (IN32(id, I2CMCR) & MCR_FSDA);
+}
+
+static int sh7760_i2c_master_xfer(struct i2c_adapter *adap,
+                                 struct i2c_msg *msgs,
+                                 int num)
+{
+       struct cami2c *id = adap->algo_data;
+       int i, retr;
+
+       if (sh7760_i2c_busy_check(id)) {
+               dev_err(&adap->dev, "sh7760-i2c%d: bus busy!\n", adap->nr);
+               return -EBUSY;
+       }
+
+       i = 0;
+       while (i < num) {
+               retr = adap->retries;
+retry:
+               id->flags = ((i == (num-1)) ? IDF_STOP : 0);
+               id->status = 0;
+               id->msg = msgs;
+               init_completion(&id->xfer_done);
+
+               if (msgs->flags & I2C_M_RD)
+                       sh7760_i2c_mrecv(id);
+               else
+                       sh7760_i2c_msend(id);
+
+               wait_for_completion(&id->xfer_done);
+
+               if (id->status == 0) {
+                       num = -EIO;
+                       break;
+               }
+
+               if (id->status & IDS_NACK) {
+                       /* wait a bit or i2c module stops working */
+                       mdelay(1);
+                       num = -EREMOTEIO;
+                       break;
+               }
+
+               if (id->status & IDS_ARBLOST) {
+                       if (retr--) {
+                               mdelay(2);
+                               goto retry;
+                       }
+                       num = -EREMOTEIO;
+                       break;
+               }
+
+               msgs++;
+               i++;
+       }
+
+       id->msg = NULL;
+       id->flags = 0;
+       id->status = 0;
+
+       OUT32(id, I2CMCR, 0);
+       OUT32(id, I2CMSR, 0);
+       OUT32(id, I2CMIER, 0);
+       OUT32(id, I2CFIER, 0);
+
+       /* reset slave module registers too: master mode enables slave
+        * module for receive ops (ack, data). Without this reset,
+        * eternal bus activity might be reported after NACK / ARBLOST.
+        */
+       OUT32(id, I2CSCR, 0);
+       OUT32(id, I2CSAR, 0);
+       OUT32(id, I2CSSR, 0);
+
+       return num;
+}
+
+static u32 sh7760_i2c_func(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static const struct i2c_algorithm sh7760_i2c_algo = {
+       .master_xfer    = sh7760_i2c_master_xfer,
+       .functionality  = sh7760_i2c_func,
+};
+
+/* calculate CCR register setting for a desired scl clock.  SCL clock is
+ * derived from I2C module clock  (iclk)  which in turn is derived from
+ * peripheral module clock (mclk, usually around 33MHz):
+ * iclk = mclk/(CDF + 1).  iclk must be < 20MHz.
+ * scl = iclk/(SCGD*8 + 20).
+ */
+static int __devinit calc_CCR(unsigned long scl_hz)
+{
+       struct clk *mclk;
+       unsigned long mck, m1, dff, odff, iclk;
+       signed char cdf, cdfm;
+       int scgd, scgdm, scgds;
+
+       mclk = clk_get(NULL, "module_clk");
+       if (IS_ERR(mclk)) {
+               return PTR_ERR(mclk);
+       } else {
+               mck = mclk->rate;
+               clk_put(mclk);
+       }
+
+       odff = scl_hz;
+       scgdm = cdfm = m1 = 0;
+       for (cdf = 3; cdf >= 0; cdf--) {
+               iclk = mck / (1 + cdf);
+               if (iclk >= 20000000)
+                       continue;
+               scgds = ((iclk / scl_hz) - 20) >> 3;
+               for (scgd = scgds; (scgd < 63) && scgd <= scgds + 1; scgd++) {
+                       m1 = iclk / (20 + (scgd << 3));
+                       dff = abs(scl_hz - m1);
+                       if (dff < odff) {
+                               odff = dff;
+                               cdfm = cdf;
+                               scgdm = scgd;
+                       }
+               }
+       }
+       /* fail if more than 25% off of requested SCL */
+       if (odff > (scl_hz >> 2))
+               return -EINVAL;
+
+       /* create a CCR register value */
+       return ((scgdm << 2) | cdfm);
+}
+
+static int __devinit sh7760_i2c_probe(struct platform_device *pdev)
+{
+       struct sh7760_i2c_platdata *pd;
+       struct resource *res;
+       struct cami2c *id;
+       int ret;
+
+       pd = pdev->dev.platform_data;
+       if (!pd) {
+               dev_err(&pdev->dev, "no platform_data!\n");
+               ret = -ENODEV;
+               goto out0;
+       }
+
+       id = kzalloc(sizeof(struct cami2c), GFP_KERNEL);
+       if (!id) {
+               dev_err(&pdev->dev, "no mem for private data\n");
+               ret = -ENOMEM;
+               goto out0;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "no mmio resources\n");
+               ret = -ENODEV;
+               goto out1;
+       }
+
+       id->ioarea = request_mem_region(res->start, REGSIZE, pdev->name);
+       if (!id->ioarea) {
+               dev_err(&pdev->dev, "mmio already reserved\n");
+               ret = -EBUSY;
+               goto out1;
+       }
+
+       id->iobase = ioremap(res->start, REGSIZE);
+       if (!id->iobase) {
+               dev_err(&pdev->dev, "cannot ioremap\n");
+               ret = -ENODEV;
+               goto out2;
+       }
+
+       id->irq = platform_get_irq(pdev, 0);
+
+       id->adap.nr = pdev->id;
+       id->adap.algo = &sh7760_i2c_algo;
+       id->adap.class = I2C_CLASS_ALL;
+       id->adap.retries = 3;
+       id->adap.algo_data = id;
+       id->adap.dev.parent = &pdev->dev;
+       snprintf(id->adap.name, sizeof(id->adap.name),
+               "SH7760 I2C at %08lx", (unsigned long)res->start);
+
+       OUT32(id, I2CMCR, 0);
+       OUT32(id, I2CMSR, 0);
+       OUT32(id, I2CMIER, 0);
+       OUT32(id, I2CMAR, 0);
+       OUT32(id, I2CSIER, 0);
+       OUT32(id, I2CSAR, 0);
+       OUT32(id, I2CSCR, 0);
+       OUT32(id, I2CSSR, 0);
+       OUT32(id, I2CFIER, 0);
+       OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
+       OUT32(id, I2CFSR, 0);
+
+       ret = calc_CCR(pd->speed_khz * 1000);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "invalid SCL clock: %dkHz\n",
+                       pd->speed_khz);
+               goto out3;
+       }
+       OUT32(id, I2CCCR, ret);
+
+       if (request_irq(id->irq, sh7760_i2c_irq, IRQF_DISABLED,
+                       SH7760_I2C_DEVNAME, id)) {
+               dev_err(&pdev->dev, "cannot get irq %d\n", id->irq);
+               ret = -EBUSY;
+               goto out3;
+       }
+
+       ret = i2c_add_numbered_adapter(&id->adap);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "reg adap failed: %d\n", ret);
+               goto out4;
+       }
+
+       platform_set_drvdata(pdev, id);
+
+       dev_info(&pdev->dev, "%d kHz mmio %08x irq %d\n",
+                pd->speed_khz, res->start, id->irq);
+
+       return 0;
+
+out4:
+       free_irq(id->irq, id);
+out3:
+       iounmap(id->iobase);
+out2:
+       release_resource(id->ioarea);
+       kfree(id->ioarea);
+out1:
+       kfree(id);
+out0:
+       return ret;
+}
+
+static int __devexit sh7760_i2c_remove(struct platform_device *pdev)
+{
+       struct cami2c *id = platform_get_drvdata(pdev);
+
+       i2c_del_adapter(&id->adap);
+       free_irq(id->irq, id);
+       iounmap(id->iobase);
+       release_resource(id->ioarea);
+       kfree(id->ioarea);
+       kfree(id);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver sh7760_i2c_drv = {
+       .driver = {
+               .name   = SH7760_I2C_DEVNAME,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = sh7760_i2c_probe,
+       .remove         = __devexit_p(sh7760_i2c_remove),
+};
+
+static int __init sh7760_i2c_init(void)
+{
+       return platform_driver_register(&sh7760_i2c_drv);
+}
+
+static void __exit sh7760_i2c_exit(void)
+{
+       platform_driver_unregister(&sh7760_i2c_drv);
+}
+
+module_init(sh7760_i2c_init);
+module_exit(sh7760_i2c_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SH7760 I2C bus driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
new file mode 100644 (file)
index 0000000..840e634
--- /dev/null
@@ -0,0 +1,500 @@
+/*
+ * SuperH Mobile I2C Controller
+ *
+ * Copyright (C) 2008 Magnus Damm
+ *
+ * Portions of the code based on out-of-tree driver i2c-sh7343.c
+ * Copyright (c) 2006 Carlos Munoz <carlos@kenati.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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+enum sh_mobile_i2c_op {
+       OP_START = 0,
+       OP_TX_ONLY,
+       OP_TX_STOP,
+       OP_TX_TO_RX,
+       OP_RX_ONLY,
+       OP_RX_STOP,
+};
+
+struct sh_mobile_i2c_data {
+       struct device *dev;
+       void __iomem *reg;
+       struct i2c_adapter adap;
+
+       struct clk *clk;
+       u_int8_t iccl;
+       u_int8_t icch;
+
+       spinlock_t lock;
+       wait_queue_head_t wait;
+       struct i2c_msg *msg;
+       int pos;
+       int sr;
+};
+
+#define NORMAL_SPEED           100000 /* FAST_SPEED 400000 */
+
+/* Register offsets */
+#define ICDR(pd)               (pd->reg + 0x00)
+#define ICCR(pd)               (pd->reg + 0x04)
+#define ICSR(pd)               (pd->reg + 0x08)
+#define ICIC(pd)               (pd->reg + 0x0c)
+#define ICCL(pd)               (pd->reg + 0x10)
+#define ICCH(pd)               (pd->reg + 0x14)
+
+/* Register bits */
+#define ICCR_ICE               0x80
+#define ICCR_RACK              0x40
+#define ICCR_TRS               0x10
+#define ICCR_BBSY              0x04
+#define ICCR_SCP               0x01
+
+#define ICSR_SCLM              0x80
+#define ICSR_SDAM              0x40
+#define SW_DONE                        0x20
+#define ICSR_BUSY              0x10
+#define ICSR_AL                        0x08
+#define ICSR_TACK              0x04
+#define ICSR_WAIT              0x02
+#define ICSR_DTE               0x01
+
+#define ICIC_ALE               0x08
+#define ICIC_TACKE             0x04
+#define ICIC_WAITE             0x02
+#define ICIC_DTEE              0x01
+
+static void activate_ch(struct sh_mobile_i2c_data *pd)
+{
+       /* Make sure the clock is enabled */
+       clk_enable(pd->clk);
+
+       /* Enable channel and configure rx ack */
+       iowrite8(ioread8(ICCR(pd)) | ICCR_ICE, ICCR(pd));
+
+       /* Mask all interrupts */
+       iowrite8(0, ICIC(pd));
+
+       /* Set the clock */
+       iowrite8(pd->iccl, ICCL(pd));
+       iowrite8(pd->icch, ICCH(pd));
+}
+
+static void deactivate_ch(struct sh_mobile_i2c_data *pd)
+{
+       /* Clear/disable interrupts */
+       iowrite8(0, ICSR(pd));
+       iowrite8(0, ICIC(pd));
+
+       /* Disable channel */
+       iowrite8(ioread8(ICCR(pd)) & ~ICCR_ICE, ICCR(pd));
+
+       /* Disable clock */
+       clk_disable(pd->clk);
+}
+
+static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
+                           enum sh_mobile_i2c_op op, unsigned char data)
+{
+       unsigned char ret = 0;
+       unsigned long flags;
+
+       dev_dbg(pd->dev, "op %d, data in 0x%02x\n", op, data);
+
+       spin_lock_irqsave(&pd->lock, flags);
+
+       switch (op) {
+       case OP_START:
+               iowrite8(0x94, ICCR(pd));
+               break;
+       case OP_TX_ONLY:
+               iowrite8(data, ICDR(pd));
+               break;
+       case OP_TX_STOP:
+               iowrite8(data, ICDR(pd));
+               iowrite8(0x90, ICCR(pd));
+               iowrite8(ICIC_ALE | ICIC_TACKE, ICIC(pd));
+               break;
+       case OP_TX_TO_RX:
+               iowrite8(data, ICDR(pd));
+               iowrite8(0x81, ICCR(pd));
+               break;
+       case OP_RX_ONLY:
+               ret = ioread8(ICDR(pd));
+               break;
+       case OP_RX_STOP:
+               ret = ioread8(ICDR(pd));
+               iowrite8(0xc0, ICCR(pd));
+               break;
+       }
+
+       spin_unlock_irqrestore(&pd->lock, flags);
+
+       dev_dbg(pd->dev, "op %d, data out 0x%02x\n", op, ret);
+       return ret;
+}
+
+static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
+{
+       struct platform_device *dev = dev_id;
+       struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev);
+       struct i2c_msg *msg = pd->msg;
+       unsigned char data, sr;
+       int wakeup = 0;
+
+       sr = ioread8(ICSR(pd));
+       pd->sr |= sr;
+
+       dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr,
+              (msg->flags & I2C_M_RD) ? "read" : "write",
+              pd->pos, msg->len);
+
+       if (sr & (ICSR_AL | ICSR_TACK)) {
+               iowrite8(0, ICIC(pd)); /* disable interrupts */
+               wakeup = 1;
+               goto do_wakeup;
+       }
+
+       if (pd->pos == msg->len) {
+               i2c_op(pd, OP_RX_ONLY, 0);
+               wakeup = 1;
+               goto do_wakeup;
+       }
+
+       if (pd->pos == -1) {
+               data = (msg->addr & 0x7f) << 1;
+               data |= (msg->flags & I2C_M_RD) ? 1 : 0;
+       } else
+               data = msg->buf[pd->pos];
+
+       if ((pd->pos == -1) || !(msg->flags & I2C_M_RD)) {
+               if (msg->flags & I2C_M_RD)
+                       i2c_op(pd, OP_TX_TO_RX, data);
+               else if (pd->pos == (msg->len - 1)) {
+                       i2c_op(pd, OP_TX_STOP, data);
+                       wakeup = 1;
+               } else
+                       i2c_op(pd, OP_TX_ONLY, data);
+       } else {
+               if (pd->pos == (msg->len - 1))
+                       data = i2c_op(pd, OP_RX_STOP, 0);
+               else
+                       data = i2c_op(pd, OP_RX_ONLY, 0);
+
+               msg->buf[pd->pos] = data;
+       }
+       pd->pos++;
+
+ do_wakeup:
+       if (wakeup) {
+               pd->sr |= SW_DONE;
+               wake_up(&pd->wait);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg)
+{
+       /* Initialize channel registers */
+       iowrite8(ioread8(ICCR(pd)) & ~ICCR_ICE, ICCR(pd));
+
+       /* Enable channel and configure rx ack */
+       iowrite8(ioread8(ICCR(pd)) | ICCR_ICE, ICCR(pd));
+
+       /* Set the clock */
+       iowrite8(pd->iccl, ICCL(pd));
+       iowrite8(pd->icch, ICCH(pd));
+
+       pd->msg = usr_msg;
+       pd->pos = -1;
+       pd->sr = 0;
+
+       /* Enable all interrupts except wait */
+       iowrite8(ioread8(ICIC(pd)) | ICIC_ALE | ICIC_TACKE | ICIC_DTEE,
+                ICIC(pd));
+       return 0;
+}
+
+static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
+                             struct i2c_msg *msgs,
+                             int num)
+{
+       struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
+       struct i2c_msg  *msg;
+       int err = 0;
+       u_int8_t val;
+       int i, k, retry_count;
+
+       activate_ch(pd);
+
+       /* Process all messages */
+       for (i = 0; i < num; i++) {
+               msg = &msgs[i];
+
+               err = start_ch(pd, msg);
+               if (err)
+                       break;
+
+               i2c_op(pd, OP_START, 0);
+
+               /* The interrupt handler takes care of the rest... */
+               k = wait_event_timeout(pd->wait,
+                                      pd->sr & (ICSR_TACK | SW_DONE),
+                                      5 * HZ);
+               if (!k)
+                       dev_err(pd->dev, "Transfer request timed out\n");
+
+               retry_count = 10;
+again:
+               val = ioread8(ICSR(pd));
+
+               dev_dbg(pd->dev, "val 0x%02x pd->sr 0x%02x\n", val, pd->sr);
+
+               if ((val | pd->sr) & (ICSR_TACK | ICSR_AL)) {
+                       err = -EIO;
+                       break;
+               }
+
+               /* the interrupt handler may wake us up before the
+                * transfer is finished, so poll the hardware
+                * until we're done.
+                */
+
+               if (!(!(val & ICSR_BUSY) && (val & ICSR_SCLM) &&
+                     (val & ICSR_SDAM))) {
+                       msleep(1);
+                       if (retry_count--)
+                               goto again;
+
+                       err = -EIO;
+                       dev_err(pd->dev, "Polling timed out\n");
+                       break;
+               }
+       }
+
+       deactivate_ch(pd);
+
+       if (!err)
+               err = num;
+       return err;
+}
+
+static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm sh_mobile_i2c_algorithm = {
+       .functionality  = sh_mobile_i2c_func,
+       .master_xfer    = sh_mobile_i2c_xfer,
+};
+
+static void sh_mobile_i2c_setup_channel(struct platform_device *dev)
+{
+       struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev);
+       unsigned long peripheral_clk = clk_get_rate(pd->clk);
+       u_int32_t num;
+       u_int32_t denom;
+       u_int32_t tmp;
+
+       spin_lock_init(&pd->lock);
+       init_waitqueue_head(&pd->wait);
+
+       /* Calculate the value for iccl. From the data sheet:
+        * iccl = (p clock / transfer rate) * (L / (L + H))
+        * where L and H are the SCL low/high ratio (5/4 in this case).
+        * We also round off the result.
+        */
+       num = peripheral_clk * 5;
+       denom = NORMAL_SPEED * 9;
+       tmp = num * 10 / denom;
+       if (tmp % 10 >= 5)
+               pd->iccl = (u_int8_t)((num/denom) + 1);
+       else
+               pd->iccl = (u_int8_t)(num/denom);
+
+       /* Calculate the value for icch. From the data sheet:
+          icch = (p clock / transfer rate) * (H / (L + H)) */
+       num = peripheral_clk * 4;
+       tmp = num * 10 / denom;
+       if (tmp % 10 >= 5)
+               pd->icch = (u_int8_t)((num/denom) + 1);
+       else
+               pd->icch = (u_int8_t)(num/denom);
+}
+
+static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook)
+{
+       struct resource *res;
+       int ret = -ENXIO;
+       int q, m;
+       int k = 0;
+       int n = 0;
+
+       while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) {
+               for (n = res->start; hook && n <= res->end; n++) {
+                       if (request_irq(n, sh_mobile_i2c_isr, IRQF_DISABLED,
+                                       dev->dev.bus_id, dev))
+                               goto rollback;
+               }
+               k++;
+       }
+
+       if (hook)
+               return k > 0 ? 0 : -ENOENT;
+
+       k--;
+       ret = 0;
+
+ rollback:
+       for (q = k; k >= 0; k--) {
+               for (m = n; m >= res->start; m--)
+                       free_irq(m, dev);
+
+               res = platform_get_resource(dev, IORESOURCE_IRQ, k - 1);
+               m = res->end;
+       }
+
+       return ret;
+}
+
+static int sh_mobile_i2c_probe(struct platform_device *dev)
+{
+       struct sh_mobile_i2c_data *pd;
+       struct i2c_adapter *adap;
+       struct resource *res;
+       int size;
+       int ret;
+
+       pd = kzalloc(sizeof(struct sh_mobile_i2c_data), GFP_KERNEL);
+       if (pd == NULL) {
+               dev_err(&dev->dev, "cannot allocate private data\n");
+               return -ENOMEM;
+       }
+
+       pd->clk = clk_get(&dev->dev, "peripheral_clk");
+       if (IS_ERR(pd->clk)) {
+               dev_err(&dev->dev, "cannot get peripheral clock\n");
+               ret = PTR_ERR(pd->clk);
+               goto err;
+       }
+
+       ret = sh_mobile_i2c_hook_irqs(dev, 1);
+       if (ret) {
+               dev_err(&dev->dev, "cannot request IRQ\n");
+               goto err_clk;
+       }
+
+       pd->dev = &dev->dev;
+       platform_set_drvdata(dev, pd);
+
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&dev->dev, "cannot find IO resource\n");
+               ret = -ENOENT;
+               goto err_irq;
+       }
+
+       size = (res->end - res->start) + 1;
+
+       pd->reg = ioremap(res->start, size);
+       if (pd->reg == NULL) {
+               dev_err(&dev->dev, "cannot map IO\n");
+               ret = -ENXIO;
+               goto err_irq;
+       }
+
+       /* setup the private data */
+       adap = &pd->adap;
+       i2c_set_adapdata(adap, pd);
+
+       adap->owner = THIS_MODULE;
+       adap->algo = &sh_mobile_i2c_algorithm;
+       adap->dev.parent = &dev->dev;
+       adap->retries = 5;
+       adap->nr = dev->id;
+
+       strlcpy(adap->name, dev->name, sizeof(adap->name));
+
+       sh_mobile_i2c_setup_channel(dev);
+
+       ret = i2c_add_numbered_adapter(adap);
+       if (ret < 0) {
+               dev_err(&dev->dev, "cannot add numbered adapter\n");
+               goto err_all;
+       }
+
+       return 0;
+
+ err_all:
+       iounmap(pd->reg);
+ err_irq:
+       sh_mobile_i2c_hook_irqs(dev, 0);
+ err_clk:
+       clk_put(pd->clk);
+ err:
+       kfree(pd);
+       return ret;
+}
+
+static int sh_mobile_i2c_remove(struct platform_device *dev)
+{
+       struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev);
+
+       i2c_del_adapter(&pd->adap);
+       iounmap(pd->reg);
+       sh_mobile_i2c_hook_irqs(dev, 0);
+       clk_put(pd->clk);
+       kfree(pd);
+       return 0;
+}
+
+static struct platform_driver sh_mobile_i2c_driver = {
+       .driver         = {
+               .name           = "i2c-sh_mobile",
+               .owner          = THIS_MODULE,
+       },
+       .probe          = sh_mobile_i2c_probe,
+       .remove         = sh_mobile_i2c_remove,
+};
+
+static int __init sh_mobile_i2c_adap_init(void)
+{
+       return platform_driver_register(&sh_mobile_i2c_driver);
+}
+
+static void __exit sh_mobile_i2c_adap_exit(void)
+{
+       platform_driver_unregister(&sh_mobile_i2c_driver);
+}
+
+module_init(sh_mobile_i2c_adap_init);
+module_exit(sh_mobile_i2c_adap_exit);
+
+MODULE_DESCRIPTION("SuperH Mobile I2C Bus Controller driver");
+MODULE_AUTHOR("Magnus Damm");
+MODULE_LICENSE("GPL v2");
index 10af8d3..042fda2 100644 (file)
@@ -159,6 +159,9 @@ static int simtec_i2c_remove(struct platform_device *dev)
 
 /* device driver */
 
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:simtec-i2c");
+
 static struct platform_driver simtec_i2c_driver = {
        .driver         = {
                .name           = "simtec-i2c",
index 081d957..4678bab 100644 (file)
@@ -151,3 +151,4 @@ module_exit(i2c_versatile_exit);
 
 MODULE_DESCRIPTION("ARM Versatile I2C bus driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:versatile-i2c");
index f5e7a70..61abe0f 100644 (file)
@@ -527,7 +527,7 @@ static int __init scx200_create_isa(const char *text, unsigned long base,
        if (iface == NULL)
                return -ENOMEM;
 
-       if (request_region(base, 8, iface->adapter.name) == 0) {
+       if (!request_region(base, 8, iface->adapter.name)) {
                printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n",
                       base, base + 8 - 1);
                rc = -EBUSY;
index 2a31601..b1b45dd 100644 (file)
@@ -658,7 +658,7 @@ pulldown:
                OTG_CTRL_REG |= OTG_PULLUP;
        }
 
-       check_state(isp, __FUNCTION__);
+       check_state(isp, __func__);
        dump_regs(isp, "otg->isp1301");
 }
 
@@ -782,7 +782,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
                if (otg_ctrl & OTG_DRIVER_SEL) {
                        switch (isp->otg.state) {
                        case OTG_STATE_A_IDLE:
-                               b_idle(isp, __FUNCTION__);
+                               b_idle(isp, __func__);
                                break;
                        default:
                                break;
@@ -826,7 +826,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
                                                isp->otg.host->otg_port);
        }
 
-       check_state(isp, __FUNCTION__);
+       check_state(isp, __func__);
        return ret;
 }
 
@@ -837,7 +837,7 @@ static int otg_init(struct isp1301 *isp)
        if (!otg_dev)
                return -ENODEV;
 
-       dump_regs(isp, __FUNCTION__);
+       dump_regs(isp, __func__);
        /* some of these values are board-specific... */
        OTG_SYSCON_2_REG |= OTG_EN
                /* for B-device: */
@@ -853,9 +853,9 @@ static int otg_init(struct isp1301 *isp)
        update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE));
        update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS));
 
-       check_state(isp, __FUNCTION__);
+       check_state(isp, __func__);
        pr_debug("otg: %s, %s %06x\n",
-                       state_name(isp), __FUNCTION__, OTG_CTRL_REG);
+                       state_name(isp), __func__, OTG_CTRL_REG);
 
        OTG_IRQ_EN_REG = DRIVER_SWITCH | OPRT_CHG
                        | B_SRP_TMROUT | B_HNP_FAIL
@@ -1041,11 +1041,11 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
                                                OTG1_DP_PULLDOWN);
                        isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1,
                                                OTG1_DP_PULLUP);
-                       dump_regs(isp, __FUNCTION__);
+                       dump_regs(isp, __func__);
 #endif
                        /* FALLTHROUGH */
                case OTG_STATE_B_SRP_INIT:
-                       b_idle(isp, __FUNCTION__);
+                       b_idle(isp, __func__);
                        OTG_CTRL_REG &= OTG_CTRL_REG & OTG_XCEIV_OUTPUTS;
                        /* FALLTHROUGH */
                case OTG_STATE_B_IDLE:
@@ -1077,7 +1077,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
         */
        update_otg1(isp, isp_stat);
        update_otg2(isp, isp_bstat);
-       check_state(isp, __FUNCTION__);
+       check_state(isp, __func__);
 #endif
 
        dump_regs(isp, "isp1301->otg");
@@ -1310,7 +1310,7 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
         */
        isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_VBUS_DRV);
 
-       dump_regs(isp, __FUNCTION__);
+       dump_regs(isp, __func__);
 
        return 0;
 
@@ -1365,7 +1365,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
        isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
                INTR_VBUS_VLD);
        dev_info(&isp->client.dev, "B-Peripheral sessions ok\n");
-       dump_regs(isp, __FUNCTION__);
+       dump_regs(isp, __func__);
 
        /* If this has a Mini-AB connector, this mode is highly
         * nonstandard ... but can be handy for testing, so long
@@ -1416,7 +1416,7 @@ isp1301_start_srp(struct otg_transceiver *dev)
 
        pr_debug("otg: SRP, %s ... %06x\n", state_name(isp), OTG_CTRL_REG);
 #ifdef CONFIG_USB_OTG
-       check_state(isp, __FUNCTION__);
+       check_state(isp, __func__);
 #endif
        return 0;
 }
@@ -1463,7 +1463,7 @@ isp1301_start_hnp(struct otg_transceiver *dev)
        }
        pr_debug("otg: HNP %s, %06x ...\n",
                state_name(isp), OTG_CTRL_REG);
-       check_state(isp, __FUNCTION__);
+       check_state(isp, __func__);
        return 0;
 #else
        /* srp-only */
@@ -1601,7 +1601,7 @@ fail2:
        update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS));
 #endif
 
-       dump_regs(isp, __FUNCTION__);
+       dump_regs(isp, __func__);
 
 #ifdef VERBOSE
        mod_timer(&isp->timer, jiffies + TIMER_JIFFIES);
index e186df6..6c7fa8d 100644 (file)
@@ -1506,7 +1506,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
                read_write = I2C_SMBUS_READ;
                if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
                        dev_err(&adapter->dev, "%s called with invalid "
-                               "block proc call size (%d)\n", __FUNCTION__,
+                               "block proc call size (%d)\n", __func__,
                                data->block[0]);
                        return -1;
                }
index 393e679..d34c14c 100644 (file)
@@ -200,16 +200,176 @@ static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
        return device_for_each_child(&adapter->dev, &addr, i2cdev_check);
 }
 
-static int i2cdev_ioctl(struct inode *inode, struct file *file,
-               unsigned int cmd, unsigned long arg)
+static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
+               unsigned long arg)
 {
-       struct i2c_client *client = (struct i2c_client *)file->private_data;
        struct i2c_rdwr_ioctl_data rdwr_arg;
-       struct i2c_smbus_ioctl_data data_arg;
-       union i2c_smbus_data temp;
        struct i2c_msg *rdwr_pa;
        u8 __user **data_ptrs;
-       int i,datasize,res;
+       int i, res;
+
+       if (copy_from_user(&rdwr_arg,
+                          (struct i2c_rdwr_ioctl_data __user *)arg,
+                          sizeof(rdwr_arg)))
+               return -EFAULT;
+
+       /* Put an arbitrary limit on the number of messages that can
+        * be sent at once */
+       if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
+               return -EINVAL;
+
+       rdwr_pa = (struct i2c_msg *)
+               kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg),
+               GFP_KERNEL);
+       if (!rdwr_pa)
+               return -ENOMEM;
+
+       if (copy_from_user(rdwr_pa, rdwr_arg.msgs,
+                          rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
+               kfree(rdwr_pa);
+               return -EFAULT;
+       }
+
+       data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
+       if (data_ptrs == NULL) {
+               kfree(rdwr_pa);
+               return -ENOMEM;
+       }
+
+       res = 0;
+       for (i = 0; i < rdwr_arg.nmsgs; i++) {
+               /* Limit the size of the message to a sane amount;
+                * and don't let length change either. */
+               if ((rdwr_pa[i].len > 8192) ||
+                   (rdwr_pa[i].flags & I2C_M_RECV_LEN)) {
+                       res = -EINVAL;
+                       break;
+               }
+               data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
+               rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
+               if (rdwr_pa[i].buf == NULL) {
+                       res = -ENOMEM;
+                       break;
+               }
+               if (copy_from_user(rdwr_pa[i].buf, data_ptrs[i],
+                                  rdwr_pa[i].len)) {
+                               ++i; /* Needs to be kfreed too */
+                               res = -EFAULT;
+                       break;
+               }
+       }
+       if (res < 0) {
+               int j;
+               for (j = 0; j < i; ++j)
+                       kfree(rdwr_pa[j].buf);
+               kfree(data_ptrs);
+               kfree(rdwr_pa);
+               return res;
+       }
+
+       res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs);
+       while (i-- > 0) {
+               if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) {
+                       if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf,
+                                        rdwr_pa[i].len))
+                               res = -EFAULT;
+               }
+               kfree(rdwr_pa[i].buf);
+       }
+       kfree(data_ptrs);
+       kfree(rdwr_pa);
+       return res;
+}
+
+static noinline int i2cdev_ioctl_smbus(struct i2c_client *client,
+               unsigned long arg)
+{
+       struct i2c_smbus_ioctl_data data_arg;
+       union i2c_smbus_data temp;
+       int datasize, res;
+
+       if (copy_from_user(&data_arg,
+                          (struct i2c_smbus_ioctl_data __user *) arg,
+                          sizeof(struct i2c_smbus_ioctl_data)))
+               return -EFAULT;
+       if ((data_arg.size != I2C_SMBUS_BYTE) &&
+           (data_arg.size != I2C_SMBUS_QUICK) &&
+           (data_arg.size != I2C_SMBUS_BYTE_DATA) &&
+           (data_arg.size != I2C_SMBUS_WORD_DATA) &&
+           (data_arg.size != I2C_SMBUS_PROC_CALL) &&
+           (data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
+           (data_arg.size != I2C_SMBUS_I2C_BLOCK_BROKEN) &&
+           (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) &&
+           (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) {
+               dev_dbg(&client->adapter->dev,
+                       "size out of range (%x) in ioctl I2C_SMBUS.\n",
+                       data_arg.size);
+               return -EINVAL;
+       }
+       /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1,
+          so the check is valid if size==I2C_SMBUS_QUICK too. */
+       if ((data_arg.read_write != I2C_SMBUS_READ) &&
+           (data_arg.read_write != I2C_SMBUS_WRITE)) {
+               dev_dbg(&client->adapter->dev,
+                       "read_write out of range (%x) in ioctl I2C_SMBUS.\n",
+                       data_arg.read_write);
+               return -EINVAL;
+       }
+
+       /* Note that command values are always valid! */
+
+       if ((data_arg.size == I2C_SMBUS_QUICK) ||
+           ((data_arg.size == I2C_SMBUS_BYTE) &&
+           (data_arg.read_write == I2C_SMBUS_WRITE)))
+               /* These are special: we do not use data */
+               return i2c_smbus_xfer(client->adapter, client->addr,
+                                     client->flags, data_arg.read_write,
+                                     data_arg.command, data_arg.size, NULL);
+
+       if (data_arg.data == NULL) {
+               dev_dbg(&client->adapter->dev,
+                       "data is NULL pointer in ioctl I2C_SMBUS.\n");
+               return -EINVAL;
+       }
+
+       if ((data_arg.size == I2C_SMBUS_BYTE_DATA) ||
+           (data_arg.size == I2C_SMBUS_BYTE))
+               datasize = sizeof(data_arg.data->byte);
+       else if ((data_arg.size == I2C_SMBUS_WORD_DATA) ||
+                (data_arg.size == I2C_SMBUS_PROC_CALL))
+               datasize = sizeof(data_arg.data->word);
+       else /* size == smbus block, i2c block, or block proc. call */
+               datasize = sizeof(data_arg.data->block);
+
+       if ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
+           (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
+           (data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) ||
+           (data_arg.read_write == I2C_SMBUS_WRITE)) {
+               if (copy_from_user(&temp, data_arg.data, datasize))
+                       return -EFAULT;
+       }
+       if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) {
+               /* Convert old I2C block commands to the new
+                  convention. This preserves binary compatibility. */
+               data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA;
+               if (data_arg.read_write == I2C_SMBUS_READ)
+                       temp.block[0] = I2C_SMBUS_BLOCK_MAX;
+       }
+       res = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+             data_arg.read_write, data_arg.command, data_arg.size, &temp);
+       if (!res && ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
+                    (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
+                    (data_arg.read_write == I2C_SMBUS_READ))) {
+               if (copy_to_user(data_arg.data, &temp, datasize))
+                       return -EFAULT;
+       }
+       return res;
+}
+
+static int i2cdev_ioctl(struct inode *inode, struct file *file,
+               unsigned int cmd, unsigned long arg)
+{
+       struct i2c_client *client = (struct i2c_client *)file->private_data;
        unsigned long funcs;
 
        dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",
@@ -253,164 +413,11 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
                return put_user(funcs, (unsigned long __user *)arg);
 
        case I2C_RDWR:
-               if (copy_from_user(&rdwr_arg,
-                                  (struct i2c_rdwr_ioctl_data __user *)arg,
-                                  sizeof(rdwr_arg)))
-                       return -EFAULT;
-
-               /* Put an arbitrary limit on the number of messages that can
-                * be sent at once */
-               if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
-                       return -EINVAL;
-
-               rdwr_pa = (struct i2c_msg *)
-                       kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg),
-                       GFP_KERNEL);
-
-               if (rdwr_pa == NULL) return -ENOMEM;
-
-               if (copy_from_user(rdwr_pa, rdwr_arg.msgs,
-                                  rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
-                       kfree(rdwr_pa);
-                       return -EFAULT;
-               }
-
-               data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
-               if (data_ptrs == NULL) {
-                       kfree(rdwr_pa);
-                       return -ENOMEM;
-               }
-
-               res = 0;
-               for( i=0; i<rdwr_arg.nmsgs; i++ ) {
-                       /* Limit the size of the message to a sane amount;
-                        * and don't let length change either. */
-                       if ((rdwr_pa[i].len > 8192) ||
-                           (rdwr_pa[i].flags & I2C_M_RECV_LEN)) {
-                               res = -EINVAL;
-                               break;
-                       }
-                       data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
-                       rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
-                       if(rdwr_pa[i].buf == NULL) {
-                               res = -ENOMEM;
-                               break;
-                       }
-                       if(copy_from_user(rdwr_pa[i].buf,
-                               data_ptrs[i],
-                               rdwr_pa[i].len)) {
-                                       ++i; /* Needs to be kfreed too */
-                                       res = -EFAULT;
-                               break;
-                       }
-               }
-               if (res < 0) {
-                       int j;
-                       for (j = 0; j < i; ++j)
-                               kfree(rdwr_pa[j].buf);
-                       kfree(data_ptrs);
-                       kfree(rdwr_pa);
-                       return res;
-               }
-
-               res = i2c_transfer(client->adapter,
-                       rdwr_pa,
-                       rdwr_arg.nmsgs);
-               while(i-- > 0) {
-                       if( res>=0 && (rdwr_pa[i].flags & I2C_M_RD)) {
-                               if(copy_to_user(
-                                       data_ptrs[i],
-                                       rdwr_pa[i].buf,
-                                       rdwr_pa[i].len)) {
-                                       res = -EFAULT;
-                               }
-                       }
-                       kfree(rdwr_pa[i].buf);
-               }
-               kfree(data_ptrs);
-               kfree(rdwr_pa);
-               return res;
+               return i2cdev_ioctl_rdrw(client, arg);
 
        case I2C_SMBUS:
-               if (copy_from_user(&data_arg,
-                                  (struct i2c_smbus_ioctl_data __user *) arg,
-                                  sizeof(struct i2c_smbus_ioctl_data)))
-                       return -EFAULT;
-               if ((data_arg.size != I2C_SMBUS_BYTE) &&
-                   (data_arg.size != I2C_SMBUS_QUICK) &&
-                   (data_arg.size != I2C_SMBUS_BYTE_DATA) &&
-                   (data_arg.size != I2C_SMBUS_WORD_DATA) &&
-                   (data_arg.size != I2C_SMBUS_PROC_CALL) &&
-                   (data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
-                   (data_arg.size != I2C_SMBUS_I2C_BLOCK_BROKEN) &&
-                   (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) &&
-                   (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) {
-                       dev_dbg(&client->adapter->dev,
-                               "size out of range (%x) in ioctl I2C_SMBUS.\n",
-                               data_arg.size);
-                       return -EINVAL;
-               }
-               /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1,
-                  so the check is valid if size==I2C_SMBUS_QUICK too. */
-               if ((data_arg.read_write != I2C_SMBUS_READ) &&
-                   (data_arg.read_write != I2C_SMBUS_WRITE)) {
-                       dev_dbg(&client->adapter->dev,
-                               "read_write out of range (%x) in ioctl I2C_SMBUS.\n",
-                               data_arg.read_write);
-                       return -EINVAL;
-               }
-
-               /* Note that command values are always valid! */
-
-               if ((data_arg.size == I2C_SMBUS_QUICK) ||
-                   ((data_arg.size == I2C_SMBUS_BYTE) &&
-                   (data_arg.read_write == I2C_SMBUS_WRITE)))
-                       /* These are special: we do not use data */
-                       return i2c_smbus_xfer(client->adapter, client->addr,
-                                             client->flags,
-                                             data_arg.read_write,
-                                             data_arg.command,
-                                             data_arg.size, NULL);
-
-               if (data_arg.data == NULL) {
-                       dev_dbg(&client->adapter->dev,
-                               "data is NULL pointer in ioctl I2C_SMBUS.\n");
-                       return -EINVAL;
-               }
+               return i2cdev_ioctl_smbus(client, arg);
 
-               if ((data_arg.size == I2C_SMBUS_BYTE_DATA) ||
-                   (data_arg.size == I2C_SMBUS_BYTE))
-                       datasize = sizeof(data_arg.data->byte);
-               else if ((data_arg.size == I2C_SMBUS_WORD_DATA) ||
-                        (data_arg.size == I2C_SMBUS_PROC_CALL))
-                       datasize = sizeof(data_arg.data->word);
-               else /* size == smbus block, i2c block, or block proc. call */
-                       datasize = sizeof(data_arg.data->block);
-
-               if ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
-                   (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
-                   (data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) ||
-                   (data_arg.read_write == I2C_SMBUS_WRITE)) {
-                       if (copy_from_user(&temp, data_arg.data, datasize))
-                               return -EFAULT;
-               }
-               if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) {
-                       /* Convert old I2C block commands to the new
-                          convention. This preserves binary compatibility. */
-                       data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA;
-                       if (data_arg.read_write == I2C_SMBUS_READ)
-                               temp.block[0] = I2C_SMBUS_BLOCK_MAX;
-               }
-               res = i2c_smbus_xfer(client->adapter,client->addr,client->flags,
-                     data_arg.read_write,
-                     data_arg.command,data_arg.size,&temp);
-               if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
-                             (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
-                             (data_arg.read_write == I2C_SMBUS_READ))) {
-                       if (copy_to_user(data_arg.data, &temp, datasize))
-                               return -EFAULT;
-               }
-               return res;
        case I2C_RETRIES:
                client->adapter->retries = arg;
                break;
index 028ae38..8b18a87 100644 (file)
@@ -689,6 +689,7 @@ config ZISOFS
 
 config UDF_FS
        tristate "UDF file system support"
+       select CRC_ITU_T
        help
          This is the new file system used on some CD-ROMs and DVDs. Say Y if
          you intend to mount DVD discs or CDRW's written in packet mode, or
index d248e60..ca1c912 100644 (file)
@@ -10,6 +10,7 @@ dlm-y :=                      ast.o \
                                midcomms.o \
                                netlink.o \
                                lowcomms.o \
+                               plock.o \
                                rcom.o \
                                recover.o \
                                recoverd.o \
index c3ad1df..eac23bd 100644 (file)
@@ -114,7 +114,7 @@ struct cluster_attribute {
 };
 
 static ssize_t cluster_set(struct cluster *cl, unsigned int *cl_field,
-                          unsigned int *info_field, int check_zero,
+                          int *info_field, int check_zero,
                           const char *buf, size_t len)
 {
        unsigned int x;
@@ -284,6 +284,7 @@ struct node {
        struct list_head list; /* space->members */
        int nodeid;
        int weight;
+       int new;
 };
 
 static struct configfs_group_operations clusters_ops = {
@@ -565,6 +566,7 @@ static struct config_item *make_node(struct config_group *g, const char *name)
        config_item_init_type_name(&nd->item, name, &node_type);
        nd->nodeid = -1;
        nd->weight = 1;  /* default weight of 1 if none is set */
+       nd->new = 1;     /* set to 0 once it's been read by dlm_nodeid_list() */
 
        mutex_lock(&sp->members_lock);
        list_add(&nd->list, &sp->members);
@@ -805,12 +807,13 @@ static void put_comm(struct comm *cm)
 }
 
 /* caller must free mem */
-int dlm_nodeid_list(char *lsname, int **ids_out)
+int dlm_nodeid_list(char *lsname, int **ids_out, int *ids_count_out,
+                   int **new_out, int *new_count_out)
 {
        struct space *sp;
        struct node *nd;
-       int i = 0, rv = 0;
-       int *ids;
+       int i = 0, rv = 0, ids_count = 0, new_count = 0;
+       int *ids, *new;
 
        sp = get_space(lsname);
        if (!sp)
@@ -818,23 +821,50 @@ int dlm_nodeid_list(char *lsname, int **ids_out)
 
        mutex_lock(&sp->members_lock);
        if (!sp->members_count) {
-               rv = 0;
+               rv = -EINVAL;
+               printk(KERN_ERR "dlm: zero members_count\n");
                goto out;
        }
 
-       ids = kcalloc(sp->members_count, sizeof(int), GFP_KERNEL);
+       ids_count = sp->members_count;
+
+       ids = kcalloc(ids_count, sizeof(int), GFP_KERNEL);
        if (!ids) {
                rv = -ENOMEM;
                goto out;
        }
 
-       rv = sp->members_count;
-       list_for_each_entry(nd, &sp->members, list)
+       list_for_each_entry(nd, &sp->members, list) {
                ids[i++] = nd->nodeid;
+               if (nd->new)
+                       new_count++;
+       }
+
+       if (ids_count != i)
+               printk(KERN_ERR "dlm: bad nodeid count %d %d\n", ids_count, i);
+
+       if (!new_count)
+               goto out_ids;
+
+       new = kcalloc(new_count, sizeof(int), GFP_KERNEL);
+       if (!new) {
+               kfree(ids);
+               rv = -ENOMEM;
+               goto out;
+       }
 
-       if (rv != i)
-               printk("bad nodeid count %d %d\n", rv, i);
+       i = 0;
+       list_for_each_entry(nd, &sp->members, list) {
+               if (nd->new) {
+                       new[i++] = nd->nodeid;
+                       nd->new = 0;
+               }
+       }
+       *new_count_out = new_count;
+       *new_out = new;
 
+ out_ids:
+       *ids_count_out = ids_count;
        *ids_out = ids;
  out:
        mutex_unlock(&sp->members_lock);
index a3170fe..4f1d6fc 100644 (file)
@@ -35,7 +35,8 @@ extern struct dlm_config_info dlm_config;
 int dlm_config_init(void);
 void dlm_config_exit(void);
 int dlm_node_weight(char *lsname, int nodeid);
-int dlm_nodeid_list(char *lsname, int **ids_out);
+int dlm_nodeid_list(char *lsname, int **ids_out, int *ids_count_out,
+                   int **new_out, int *new_count_out);
 int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr);
 int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid);
 int dlm_our_nodeid(void);
index 7a8824f..5a7ac33 100644 (file)
@@ -42,8 +42,6 @@
 #include <linux/dlm.h>
 #include "config.h"
 
-#define DLM_LOCKSPACE_LEN      64
-
 /* Size of the temp buffer midcomms allocates on the stack.
    We try to make this large enough so most messages fit.
    FIXME: should sctp make this unnecessary? */
@@ -132,8 +130,10 @@ struct dlm_member {
 
 struct dlm_recover {
        struct list_head        list;
-       int                     *nodeids;
+       int                     *nodeids;   /* nodeids of all members */
        int                     node_count;
+       int                     *new;       /* nodeids of new members */
+       int                     new_count;
        uint64_t                seq;
 };
 
@@ -579,6 +579,8 @@ static inline int dlm_no_directory(struct dlm_ls *ls)
 int dlm_netlink_init(void);
 void dlm_netlink_exit(void);
 void dlm_timeout_warn(struct dlm_lkb *lkb);
+int dlm_plock_init(void);
+void dlm_plock_exit(void);
 
 #ifdef CONFIG_DLM_DEBUG
 int dlm_register_debugfs(void);
index 8f250ac..2d3d102 100644 (file)
@@ -165,7 +165,7 @@ void dlm_print_lkb(struct dlm_lkb *lkb)
               lkb->lkb_grmode, lkb->lkb_wait_type, lkb->lkb_ast_type);
 }
 
-void dlm_print_rsb(struct dlm_rsb *r)
+static void dlm_print_rsb(struct dlm_rsb *r)
 {
        printk(KERN_ERR "rsb: nodeid %d flags %lx first %x rlc %d name %s\n",
               r->res_nodeid, r->res_flags, r->res_first_lkid,
@@ -1956,8 +1956,7 @@ static void confirm_master(struct dlm_rsb *r, int error)
                        list_del_init(&lkb->lkb_rsb_lookup);
                        r->res_first_lkid = lkb->lkb_id;
                        _request_lock(r, lkb);
-               } else
-                       r->res_nodeid = -1;
+               }
                break;
 
        default:
index 05d9c82..88e93c8 100644 (file)
@@ -13,7 +13,6 @@
 #ifndef __LOCK_DOT_H__
 #define __LOCK_DOT_H__
 
-void dlm_print_rsb(struct dlm_rsb *r);
 void dlm_dump_rsb(struct dlm_rsb *r);
 void dlm_print_lkb(struct dlm_lkb *lkb);
 void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms);
index 58487fb..b80e0aa 100644 (file)
@@ -46,10 +46,16 @@ static int __init init_dlm(void)
        if (error)
                goto out_user;
 
+       error = dlm_plock_init();
+       if (error)
+               goto out_netlink;
+
        printk("DLM (built %s %s) installed\n", __DATE__, __TIME__);
 
        return 0;
 
+ out_netlink:
+       dlm_netlink_exit();
  out_user:
        dlm_user_exit();
  out_debug:
@@ -66,6 +72,7 @@ static int __init init_dlm(void)
 
 static void __exit exit_dlm(void)
 {
+       dlm_plock_exit();
        dlm_netlink_exit();
        dlm_user_exit();
        dlm_config_exit();
index fa17f5a..26133f0 100644 (file)
@@ -210,6 +210,23 @@ int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out)
                }
        }
 
+       /* Add an entry to ls_nodes_gone for members that were removed and
+          then added again, so that previous state for these nodes will be
+          cleared during recovery. */
+
+       for (i = 0; i < rv->new_count; i++) {
+               if (!dlm_is_member(ls, rv->new[i]))
+                       continue;
+               log_debug(ls, "new nodeid %d is a re-added member", rv->new[i]);
+
+               memb = kzalloc(sizeof(struct dlm_member), GFP_KERNEL);
+               if (!memb)
+                       return -ENOMEM;
+               memb->nodeid = rv->new[i];
+               list_add_tail(&memb->list, &ls->ls_nodes_gone);
+               neg++;
+       }
+
        /* add new members to ls_nodes */
 
        for (i = 0; i < rv->node_count; i++) {
@@ -314,15 +331,16 @@ int dlm_ls_stop(struct dlm_ls *ls)
 int dlm_ls_start(struct dlm_ls *ls)
 {
        struct dlm_recover *rv = NULL, *rv_old;
-       int *ids = NULL;
-       int error, count;
+       int *ids = NULL, *new = NULL;
+       int error, ids_count = 0, new_count = 0;
 
        rv = kzalloc(sizeof(struct dlm_recover), GFP_KERNEL);
        if (!rv)
                return -ENOMEM;
 
-       error = count = dlm_nodeid_list(ls->ls_name, &ids);
-       if (error <= 0)
+       error = dlm_nodeid_list(ls->ls_name, &ids, &ids_count,
+                               &new, &new_count);
+       if (error < 0)
                goto fail;
 
        spin_lock(&ls->ls_recover_lock);
@@ -337,14 +355,19 @@ int dlm_ls_start(struct dlm_ls *ls)
        }
 
        rv->nodeids = ids;
-       rv->node_count = count;
+       rv->node_count = ids_count;
+       rv->new = new;
+       rv->new_count = new_count;
        rv->seq = ++ls->ls_recover_seq;
        rv_old = ls->ls_recover_args;
        ls->ls_recover_args = rv;
        spin_unlock(&ls->ls_recover_lock);
 
        if (rv_old) {
+               log_error(ls, "unused recovery %llx %d",
+                         (unsigned long long)rv_old->seq, rv_old->node_count);
                kfree(rv_old->nodeids);
+               kfree(rv_old->new);
                kfree(rv_old);
        }
 
@@ -354,6 +377,7 @@ int dlm_ls_start(struct dlm_ls *ls)
  fail:
        kfree(rv);
        kfree(ids);
+       kfree(new);
        return error;
 }
 
similarity index 67%
rename from fs/gfs2/locking/dlm/plock.c
rename to fs/dlm/plock.c
index 2ebd374..d6d6e37 100644 (file)
@@ -1,17 +1,19 @@
 /*
- * Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+ * Copyright (C) 2005-2008 Red Hat, Inc.  All rights reserved.
  *
  * This copyrighted material is made available to anyone wishing to use,
  * modify, copy, or redistribute it subject to the terms and conditions
  * of the GNU General Public License version 2.
  */
 
+#include <linux/fs.h>
 #include <linux/miscdevice.h>
-#include <linux/lock_dlm_plock.h>
 #include <linux/poll.h>
+#include <linux/dlm.h>
+#include <linux/dlm_plock.h>
 
-#include "lock_dlm.h"
-
+#include "dlm_internal.h"
+#include "lockspace.h"
 
 static spinlock_t ops_lock;
 static struct list_head send_list;
@@ -22,7 +24,7 @@ static wait_queue_head_t recv_wq;
 struct plock_op {
        struct list_head list;
        int done;
-       struct gdlm_plock_info info;
+       struct dlm_plock_info info;
 };
 
 struct plock_xop {
@@ -34,22 +36,22 @@ struct plock_xop {
 };
 
 
-static inline void set_version(struct gdlm_plock_info *info)
+static inline void set_version(struct dlm_plock_info *info)
 {
-       info->version[0] = GDLM_PLOCK_VERSION_MAJOR;
-       info->version[1] = GDLM_PLOCK_VERSION_MINOR;
-       info->version[2] = GDLM_PLOCK_VERSION_PATCH;
+       info->version[0] = DLM_PLOCK_VERSION_MAJOR;
+       info->version[1] = DLM_PLOCK_VERSION_MINOR;
+       info->version[2] = DLM_PLOCK_VERSION_PATCH;
 }
 
-static int check_version(struct gdlm_plock_info *info)
+static int check_version(struct dlm_plock_info *info)
 {
-       if ((GDLM_PLOCK_VERSION_MAJOR != info->version[0]) ||
-           (GDLM_PLOCK_VERSION_MINOR < info->version[1])) {
-               log_error("plock device version mismatch: "
+       if ((DLM_PLOCK_VERSION_MAJOR != info->version[0]) ||
+           (DLM_PLOCK_VERSION_MINOR < info->version[1])) {
+               log_print("plock device version mismatch: "
                          "kernel (%u.%u.%u), user (%u.%u.%u)",
-                         GDLM_PLOCK_VERSION_MAJOR,
-                         GDLM_PLOCK_VERSION_MINOR,
-                         GDLM_PLOCK_VERSION_PATCH,
+                         DLM_PLOCK_VERSION_MAJOR,
+                         DLM_PLOCK_VERSION_MINOR,
+                         DLM_PLOCK_VERSION_PATCH,
                          info->version[0],
                          info->version[1],
                          info->version[2]);
@@ -68,25 +70,31 @@ static void send_op(struct plock_op *op)
        wake_up(&send_wq);
 }
 
-int gdlm_plock(void *lockspace, struct lm_lockname *name,
-              struct file *file, int cmd, struct file_lock *fl)
+int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+                  int cmd, struct file_lock *fl)
 {
-       struct gdlm_ls *ls = lockspace;
+       struct dlm_ls *ls;
        struct plock_op *op;
        struct plock_xop *xop;
        int rv;
 
+       ls = dlm_find_lockspace_local(lockspace);
+       if (!ls)
+               return -EINVAL;
+
        xop = kzalloc(sizeof(*xop), GFP_KERNEL);
-       if (!xop)
-               return -ENOMEM;
+       if (!xop) {
+               rv = -ENOMEM;
+               goto out;
+       }
 
        op = &xop->xop;
-       op->info.optype         = GDLM_PLOCK_OP_LOCK;
+       op->info.optype         = DLM_PLOCK_OP_LOCK;
        op->info.pid            = fl->fl_pid;
        op->info.ex             = (fl->fl_type == F_WRLCK);
        op->info.wait           = IS_SETLKW(cmd);
-       op->info.fsid           = ls->id;
-       op->info.number         = name->ln_number;
+       op->info.fsid           = ls->ls_global_id;
+       op->info.number         = number;
        op->info.start          = fl->fl_start;
        op->info.end            = fl->fl_end;
        if (fl->fl_lmops && fl->fl_lmops->fl_grant) {
@@ -107,12 +115,15 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
 
        if (xop->callback == NULL)
                wait_event(recv_wq, (op->done != 0));
-       else
-               return -EINPROGRESS;
+       else {
+               rv = -EINPROGRESS;
+               goto out;
+       }
 
        spin_lock(&ops_lock);
        if (!list_empty(&op->list)) {
-               printk(KERN_INFO "plock op on list\n");
+               log_error(ls, "dlm_posix_lock: op on list %llx",
+                         (unsigned long long)number);
                list_del(&op->list);
        }
        spin_unlock(&ops_lock);
@@ -121,17 +132,19 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
 
        if (!rv) {
                if (posix_lock_file_wait(file, fl) < 0)
-                       log_error("gdlm_plock: vfs lock error %x,%llx",
-                                 name->ln_type,
-                                 (unsigned long long)name->ln_number);
+                       log_error(ls, "dlm_posix_lock: vfs lock error %llx",
+                                 (unsigned long long)number);
        }
 
        kfree(xop);
+out:
+       dlm_put_lockspace(ls);
        return rv;
 }
+EXPORT_SYMBOL_GPL(dlm_posix_lock);
 
 /* Returns failure iff a succesful lock operation should be canceled */
-static int gdlm_plock_callback(struct plock_op *op)
+static int dlm_plock_callback(struct plock_op *op)
 {
        struct file *file;
        struct file_lock *fl;
@@ -142,7 +155,8 @@ static int gdlm_plock_callback(struct plock_op *op)
 
        spin_lock(&ops_lock);
        if (!list_empty(&op->list)) {
-               printk(KERN_INFO "plock op on list\n");
+               log_print("dlm_plock_callback: op on list %llx",
+                         (unsigned long long)op->info.number);
                list_del(&op->list);
        }
        spin_unlock(&ops_lock);
@@ -165,19 +179,19 @@ static int gdlm_plock_callback(struct plock_op *op)
                 * This can only happen in the case of kmalloc() failure.
                 * The filesystem's own lock is the authoritative lock,
                 * so a failure to get the lock locally is not a disaster.
-                * As long as GFS cannot reliably cancel locks (especially
+                * As long as the fs cannot reliably cancel locks (especially
                 * in a low-memory situation), we're better off ignoring
                 * this failure than trying to recover.
                 */
-               log_error("gdlm_plock: vfs lock error file %p fl %p",
-                               file, fl);
+               log_print("dlm_plock_callback: vfs lock error %llx file %p fl %p",
+                         (unsigned long long)op->info.number, file, fl);
        }
 
        rv = notify(flc, NULL, 0);
        if (rv) {
                /* XXX: We need to cancel the fs lock here: */
-               printk("gfs2 lock granted after lock request failed;"
-                                               " dangling lock!\n");
+               log_print("dlm_plock_callback: lock granted after lock request "
+                         "failed; dangling lock!\n");
                goto out;
        }
 
@@ -186,25 +200,31 @@ out:
        return rv;
 }
 
-int gdlm_punlock(void *lockspace, struct lm_lockname *name,
-                struct file *file, struct file_lock *fl)
+int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+                    struct file_lock *fl)
 {
-       struct gdlm_ls *ls = lockspace;
+       struct dlm_ls *ls;
        struct plock_op *op;
        int rv;
 
+       ls = dlm_find_lockspace_local(lockspace);
+       if (!ls)
+               return -EINVAL;
+
        op = kzalloc(sizeof(*op), GFP_KERNEL);
-       if (!op)
-               return -ENOMEM;
+       if (!op) {
+               rv = -ENOMEM;
+               goto out;
+       }
 
        if (posix_lock_file_wait(file, fl) < 0)
-               log_error("gdlm_punlock: vfs unlock error %x,%llx",
-                         name->ln_type, (unsigned long long)name->ln_number);
+               log_error(ls, "dlm_posix_unlock: vfs unlock error %llx",
+                         (unsigned long long)number);
 
-       op->info.optype         = GDLM_PLOCK_OP_UNLOCK;
+       op->info.optype         = DLM_PLOCK_OP_UNLOCK;
        op->info.pid            = fl->fl_pid;
-       op->info.fsid           = ls->id;
-       op->info.number         = name->ln_number;
+       op->info.fsid           = ls->ls_global_id;
+       op->info.number         = number;
        op->info.start          = fl->fl_start;
        op->info.end            = fl->fl_end;
        if (fl->fl_lmops && fl->fl_lmops->fl_grant)
@@ -217,7 +237,8 @@ int gdlm_punlock(void *lockspace, struct lm_lockname *name,
 
        spin_lock(&ops_lock);
        if (!list_empty(&op->list)) {
-               printk(KERN_INFO "punlock op on list\n");
+               log_error(ls, "dlm_posix_unlock: op on list %llx",
+                         (unsigned long long)number);
                list_del(&op->list);
        }
        spin_unlock(&ops_lock);
@@ -228,25 +249,34 @@ int gdlm_punlock(void *lockspace, struct lm_lockname *name,
                rv = 0;
 
        kfree(op);
+out:
+       dlm_put_lockspace(ls);
        return rv;
 }
+EXPORT_SYMBOL_GPL(dlm_posix_unlock);
 
-int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
-                  struct file *file, struct file_lock *fl)
+int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+                 struct file_lock *fl)
 {
-       struct gdlm_ls *ls = lockspace;
+       struct dlm_ls *ls;
        struct plock_op *op;
        int rv;
 
+       ls = dlm_find_lockspace_local(lockspace);
+       if (!ls)
+               return -EINVAL;
+
        op = kzalloc(sizeof(*op), GFP_KERNEL);
-       if (!op)
-               return -ENOMEM;
+       if (!op) {
+               rv = -ENOMEM;
+               goto out;
+       }
 
-       op->info.optype         = GDLM_PLOCK_OP_GET;
+       op->info.optype         = DLM_PLOCK_OP_GET;
        op->info.pid            = fl->fl_pid;
        op->info.ex             = (fl->fl_type == F_WRLCK);
-       op->info.fsid           = ls->id;
-       op->info.number         = name->ln_number;
+       op->info.fsid           = ls->ls_global_id;
+       op->info.number         = number;
        op->info.start          = fl->fl_start;
        op->info.end            = fl->fl_end;
        if (fl->fl_lmops && fl->fl_lmops->fl_grant)
@@ -259,7 +289,8 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
 
        spin_lock(&ops_lock);
        if (!list_empty(&op->list)) {
-               printk(KERN_INFO "plock_get op on list\n");
+               log_error(ls, "dlm_posix_get: op on list %llx",
+                         (unsigned long long)number);
                list_del(&op->list);
        }
        spin_unlock(&ops_lock);
@@ -281,14 +312,17 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
        }
 
        kfree(op);
+out:
+       dlm_put_lockspace(ls);
        return rv;
 }
+EXPORT_SYMBOL_GPL(dlm_posix_get);
 
 /* a read copies out one plock request from the send list */
 static ssize_t dev_read(struct file *file, char __user *u, size_t count,
                        loff_t *ppos)
 {
-       struct gdlm_plock_info info;
+       struct dlm_plock_info info;
        struct plock_op *op = NULL;
 
        if (count < sizeof(info))
@@ -315,7 +349,7 @@ static ssize_t dev_read(struct file *file, char __user *u, size_t count,
 static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
                         loff_t *ppos)
 {
-       struct gdlm_plock_info info;
+       struct dlm_plock_info info;
        struct plock_op *op;
        int found = 0;
 
@@ -345,12 +379,12 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
                struct plock_xop *xop;
                xop = (struct plock_xop *)op;
                if (xop->callback)
-                       count = gdlm_plock_callback(op);
+                       count = dlm_plock_callback(op);
                else
                        wake_up(&recv_wq);
        } else
-               printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid,
-                       (unsigned long long)info.number);
+               log_print("dev_write no op %x %llx", info.fsid,
+                         (unsigned long long)info.number);
        return count;
 }
 
@@ -377,11 +411,11 @@ static const struct file_operations dev_fops = {
 
 static struct miscdevice plock_dev_misc = {
        .minor = MISC_DYNAMIC_MINOR,
-       .name = GDLM_PLOCK_MISC_NAME,
+       .name = DLM_PLOCK_MISC_NAME,
        .fops = &dev_fops
 };
 
-int gdlm_plock_init(void)
+int dlm_plock_init(void)
 {
        int rv;
 
@@ -393,14 +427,13 @@ int gdlm_plock_init(void)
 
        rv = misc_register(&plock_dev_misc);
        if (rv)
-               printk(KERN_INFO "gdlm_plock_init: misc_register failed %d",
-                      rv);
+               log_print("dlm_plock_init: misc_register failed %d", rv);
        return rv;
 }
 
-void gdlm_plock_exit(void)
+void dlm_plock_exit(void)
 {
        if (misc_deregister(&plock_dev_misc) < 0)
-               printk(KERN_INFO "gdlm_plock_exit: misc_deregister failed");
+               log_print("dlm_plock_exit: misc_deregister failed");
 }
 
index 997f953..fd677c8 100644 (file)
@@ -257,6 +257,7 @@ static void do_ls_recovery(struct dlm_ls *ls)
        if (rv) {
                ls_recover(ls, rv);
                kfree(rv->nodeids);
+               kfree(rv->new);
                kfree(rv);
        }
 }
index 89b93b6..2609bb6 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_GFS2_FS_LOCKING_DLM) += lock_dlm.o
-lock_dlm-y := lock.o main.o mount.o sysfs.o thread.o plock.o
+lock_dlm-y := lock.o main.o mount.o sysfs.o thread.o
 
index 58fcf8c..a243cf6 100644 (file)
@@ -25,6 +25,7 @@
 #include <net/sock.h>
 
 #include <linux/dlm.h>
+#include <linux/dlm_plock.h>
 #include <linux/lm_interface.h>
 
 /*
@@ -173,17 +174,6 @@ void gdlm_cancel(void *);
 int gdlm_hold_lvb(void *, char **);
 void gdlm_unhold_lvb(void *, char *);
 
-/* plock.c */
-
-int gdlm_plock_init(void);
-void gdlm_plock_exit(void);
-int gdlm_plock(void *, struct lm_lockname *, struct file *, int,
-               struct file_lock *);
-int gdlm_plock_get(void *, struct lm_lockname *, struct file *,
-               struct file_lock *);
-int gdlm_punlock(void *, struct lm_lockname *, struct file *,
-               struct file_lock *);
-
 /* mount.c */
 
 extern const struct lm_lockops gdlm_ops;
index 36a2258..b9a03a7 100644 (file)
@@ -28,13 +28,6 @@ static int __init init_lock_dlm(void)
                return error;
        }
 
-       error = gdlm_plock_init();
-       if (error) {
-               gdlm_sysfs_exit();
-               gfs2_unregister_lockproto(&gdlm_ops);
-               return error;
-       }
-
        printk(KERN_INFO
               "Lock_DLM (built %s %s) installed\n", __DATE__, __TIME__);
        return 0;
@@ -42,7 +35,6 @@ static int __init init_lock_dlm(void)
 
 static void __exit exit_lock_dlm(void)
 {
-       gdlm_plock_exit();
        gdlm_sysfs_exit();
        gfs2_unregister_lockproto(&gdlm_ops);
 }
index f2efff4..470bdf6 100644 (file)
@@ -236,6 +236,27 @@ static void gdlm_withdraw(void *lockspace)
        gdlm_kobject_release(ls);
 }
 
+static int gdlm_plock(void *lockspace, struct lm_lockname *name,
+              struct file *file, int cmd, struct file_lock *fl)
+{
+       struct gdlm_ls *ls = lockspace;
+       return dlm_posix_lock(ls->dlm_lockspace, name->ln_number, file, cmd, fl);
+}
+
+static int gdlm_punlock(void *lockspace, struct lm_lockname *name,
+                struct file *file, struct file_lock *fl)
+{
+       struct gdlm_ls *ls = lockspace;
+       return dlm_posix_unlock(ls->dlm_lockspace, name->ln_number, file, fl);
+}
+
+static int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
+                  struct file *file, struct file_lock *fl)
+{
+       struct gdlm_ls *ls = lockspace;
+       return dlm_posix_get(ls->dlm_lockspace, name->ln_number, file, fl);
+}
+
 const struct lm_lockops gdlm_ops = {
        .lm_proto_name = "lock_dlm",
        .lm_mount = gdlm_mount,
index 49a9871..f0d1240 100644 (file)
@@ -33,7 +33,7 @@ EXPORT_SYMBOL(generic_ro_fops);
 
 loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
 {
-       long long retval;
+       loff_t retval;
        struct inode *inode = file->f_mapping->host;
 
        mutex_lock(&inode->i_mutex);
@@ -60,7 +60,7 @@ EXPORT_SYMBOL(generic_file_llseek);
 
 loff_t remote_llseek(struct file *file, loff_t offset, int origin)
 {
-       long long retval;
+       loff_t retval;
 
        lock_kernel();
        switch (origin) {
@@ -91,7 +91,7 @@ EXPORT_SYMBOL(no_llseek);
 
 loff_t default_llseek(struct file *file, loff_t offset, int origin)
 {
-       long long retval;
+       loff_t retval;
 
        lock_kernel();
        switch (origin) {
index 8537702..9943408 100644 (file)
@@ -239,7 +239,7 @@ Eoverflow:
 loff_t seq_lseek(struct file *file, loff_t offset, int origin)
 {
        struct seq_file *m = (struct seq_file *)file->private_data;
-       long long retval = -EINVAL;
+       loff_t retval = -EINVAL;
 
        mutex_lock(&m->lock);
        m->version = file->f_version;
index be845e7..0d4503f 100644 (file)
@@ -6,4 +6,4 @@ obj-$(CONFIG_UDF_FS) += udf.o
 
 udf-objs     := balloc.o dir.o file.o ialloc.o inode.o lowlevel.o namei.o \
                partition.o super.o truncate.o symlink.o fsync.o \
-               crc.o directory.o misc.o udftime.o unicode.o
+               directory.o misc.o udftime.o unicode.o
index f855dcb..1b809bd 100644 (file)
@@ -149,8 +149,7 @@ static bool udf_add_free_space(struct udf_sb_info *sbi,
                return false;
 
        lvid = (struct logicalVolIntegrityDesc *)sbi->s_lvid_bh->b_data;
-       lvid->freeSpaceTable[partition] = cpu_to_le32(le32_to_cpu(
-                                       lvid->freeSpaceTable[partition]) + cnt);
+       le32_add_cpu(&lvid->freeSpaceTable[partition], cnt);
        return true;
 }
 
@@ -589,10 +588,8 @@ static void udf_table_free_blocks(struct super_block *sb,
                                        sptr = oepos.bh->b_data + epos.offset;
                                        aed = (struct allocExtDesc *)
                                                oepos.bh->b_data;
-                                       aed->lengthAllocDescs =
-                                               cpu_to_le32(le32_to_cpu(
-                                                       aed->lengthAllocDescs) +
-                                                               adsize);
+                                       le32_add_cpu(&aed->lengthAllocDescs,
+                                                       adsize);
                                } else {
                                        sptr = iinfo->i_ext.i_data +
                                                                epos.offset;
@@ -645,9 +642,7 @@ static void udf_table_free_blocks(struct super_block *sb,
                                mark_inode_dirty(table);
                        } else {
                                aed = (struct allocExtDesc *)epos.bh->b_data;
-                               aed->lengthAllocDescs =
-                                       cpu_to_le32(le32_to_cpu(
-                                           aed->lengthAllocDescs) + adsize);
+                               le32_add_cpu(&aed->lengthAllocDescs, adsize);
                                udf_update_tag(epos.bh->b_data, epos.offset);
                                mark_buffer_dirty(epos.bh);
                        }
diff --git a/fs/udf/crc.c b/fs/udf/crc.c
deleted file mode 100644 (file)
index b166129..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * crc.c
- *
- * PURPOSE
- *     Routines to generate, calculate, and test a 16-bit CRC.
- *
- * DESCRIPTION
- *     The CRC code was devised by Don P. Mitchell of AT&T Bell Laboratories
- *     and Ned W. Rhodes of Software Systems Group. It has been published in
- *     "Design and Validation of Computer Protocols", Prentice Hall,
- *     Englewood Cliffs, NJ, 1991, Chapter 3, ISBN 0-13-539925-4.
- *
- *     Copyright is held by AT&T.
- *
- *     AT&T gives permission for the free use of the CRC source code.
- *
- * COPYRIGHT
- *     This file is distributed under the terms of the GNU General Public
- *     License (GPL). Copies of the GPL can be obtained from:
- *             ftp://prep.ai.mit.edu/pub/gnu/GPL
- *     Each contributing author retains all rights to their own work.
- */
-
-#include "udfdecl.h"
-
-static uint16_t crc_table[256] = {
-       0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50a5U, 0x60c6U, 0x70e7U,
-       0x8108U, 0x9129U, 0xa14aU, 0xb16bU, 0xc18cU, 0xd1adU, 0xe1ceU, 0xf1efU,
-       0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52b5U, 0x4294U, 0x72f7U, 0x62d6U,
-       0x9339U, 0x8318U, 0xb37bU, 0xa35aU, 0xd3bdU, 0xc39cU, 0xf3ffU, 0xe3deU,
-       0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64e6U, 0x74c7U, 0x44a4U, 0x5485U,
-       0xa56aU, 0xb54bU, 0x8528U, 0x9509U, 0xe5eeU, 0xf5cfU, 0xc5acU, 0xd58dU,
-       0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76d7U, 0x66f6U, 0x5695U, 0x46b4U,
-       0xb75bU, 0xa77aU, 0x9719U, 0x8738U, 0xf7dfU, 0xe7feU, 0xd79dU, 0xc7bcU,
-       0x48c4U, 0x58e5U, 0x6886U, 0x78a7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U,
-       0xc9ccU, 0xd9edU, 0xe98eU, 0xf9afU, 0x8948U, 0x9969U, 0xa90aU, 0xb92bU,
-       0x5af5U, 0x4ad4U, 0x7ab7U, 0x6a96U, 0x1a71U, 0x0a50U, 0x3a33U, 0x2a12U,
-       0xdbfdU, 0xcbdcU, 0xfbbfU, 0xeb9eU, 0x9b79U, 0x8b58U, 0xbb3bU, 0xab1aU,
-       0x6ca6U, 0x7c87U, 0x4ce4U, 0x5cc5U, 0x2c22U, 0x3c03U, 0x0c60U, 0x1c41U,
-       0xedaeU, 0xfd8fU, 0xcdecU, 0xddcdU, 0xad2aU, 0xbd0bU, 0x8d68U, 0x9d49U,
-       0x7e97U, 0x6eb6U, 0x5ed5U, 0x4ef4U, 0x3e13U, 0x2e32U, 0x1e51U, 0x0e70U,
-       0xff9fU, 0xefbeU, 0xdfddU, 0xcffcU, 0xbf1bU, 0xaf3aU, 0x9f59U, 0x8f78U,
-       0x9188U, 0x81a9U, 0xb1caU, 0xa1ebU, 0xd10cU, 0xc12dU, 0xf14eU, 0xe16fU,
-       0x1080U, 0x00a1U, 0x30c2U, 0x20e3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U,
-       0x83b9U, 0x9398U, 0xa3fbU, 0xb3daU, 0xc33dU, 0xd31cU, 0xe37fU, 0xf35eU,
-       0x02b1U, 0x1290U, 0x22f3U, 0x32d2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U,
-       0xb5eaU, 0xa5cbU, 0x95a8U, 0x8589U, 0xf56eU, 0xe54fU, 0xd52cU, 0xc50dU,
-       0x34e2U, 0x24c3U, 0x14a0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U,
-       0xa7dbU, 0xb7faU, 0x8799U, 0x97b8U, 0xe75fU, 0xf77eU, 0xc71dU, 0xd73cU,
-       0x26d3U, 0x36f2U, 0x0691U, 0x16b0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U,
-       0xd94cU, 0xc96dU, 0xf90eU, 0xe92fU, 0x99c8U, 0x89e9U, 0xb98aU, 0xa9abU,
-       0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18c0U, 0x08e1U, 0x3882U, 0x28a3U,
-       0xcb7dU, 0xdb5cU, 0xeb3fU, 0xfb1eU, 0x8bf9U, 0x9bd8U, 0xabbbU, 0xbb9aU,
-       0x4a75U, 0x5a54U, 0x6a37U, 0x7a16U, 0x0af1U, 0x1ad0U, 0x2ab3U, 0x3a92U,
-       0xfd2eU, 0xed0fU, 0xdd6cU, 0xcd4dU, 0xbdaaU, 0xad8bU, 0x9de8U, 0x8dc9U,
-       0x7c26U, 0x6c07U, 0x5c64U, 0x4c45U, 0x3ca2U, 0x2c83U, 0x1ce0U, 0x0cc1U,
-       0xef1fU, 0xff3eU, 0xcf5dU, 0xdf7cU, 0xaf9bU, 0xbfbaU, 0x8fd9U, 0x9ff8U,
-       0x6e17U, 0x7e36U, 0x4e55U, 0x5e74U, 0x2e93U, 0x3eb2U, 0x0ed1U, 0x1ef0U
-};
-
-/*
- * udf_crc
- *
- * PURPOSE
- *     Calculate a 16-bit CRC checksum using ITU-T V.41 polynomial.
- *
- * DESCRIPTION
- *     The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory.
- *     The polynomial used is: x^16 + x^12 + x^15 + 1
- *
- * PRE-CONDITIONS
- *     data            Pointer to the data block.
- *     size            Size of the data block.
- *
- * POST-CONDITIONS
- *     <return>        CRC of the data block.
- *
- * HISTORY
- *     July 21, 1997 - Andrew E. Mileski
- *     Adapted from OSTA-UDF(tm) 1.50 standard.
- */
-uint16_t udf_crc(uint8_t *data, uint32_t size, uint16_t crc)
-{
-       while (size--)
-               crc = crc_table[(crc >> 8 ^ *(data++)) & 0xffU] ^ (crc << 8);
-
-       return crc;
-}
-
-/****************************************************************************/
-#if defined(TEST)
-
-/*
- * PURPOSE
- *     Test udf_crc()
- *
- * HISTORY
- *     July 21, 1997 - Andrew E. Mileski
- *     Adapted from OSTA-UDF(tm) 1.50 standard.
- */
-
-unsigned char bytes[] = { 0x70U, 0x6AU, 0x77U };
-
-int main(void)
-{
-       unsigned short x;
-
-       x = udf_crc(bytes, sizeof bytes);
-       printf("udf_crc: calculated = %4.4x, correct = %4.4x\n", x, 0x3299U);
-
-       return 0;
-}
-
-#endif /* defined(TEST) */
-
-/****************************************************************************/
-#if defined(GENERATE)
-
-/*
- * PURPOSE
- *     Generate a table for fast 16-bit CRC calculations (any polynomial).
- *
- * DESCRIPTION
- *     The ITU-T V.41 polynomial is 010041.
- *
- * HISTORY
- *     July 21, 1997 - Andrew E. Mileski
- *     Adapted from OSTA-UDF(tm) 1.50 standard.
- */
-
-#include <stdio.h>
-
-int main(int argc, char **argv)
-{
-       unsigned long crc, poly;
-       int n, i;
-
-       /* Get the polynomial */
-       sscanf(argv[1], "%lo", &poly);
-       if (poly & 0xffff0000U) {
-               fprintf(stderr, "polynomial is too large\en");
-               exit(1);
-       }
-
-       printf("/* CRC 0%o */\n", poly);
-
-       /* Create a table */
-       printf("static unsigned short crc_table[256] = {\n");
-       for (n = 0; n < 256; n++) {
-               if (n % 8 == 0)
-                       printf("\t");
-               crc = n << 8;
-               for (i = 0; i < 8; i++) {
-                       if (crc & 0x8000U)
-                               crc = (crc << 1) ^ poly;
-                       else
-                               crc <<= 1;
-                       crc &= 0xFFFFU;
-               }
-               if (n == 255)
-                       printf("0x%04xU ", crc);
-               else
-                       printf("0x%04xU, ", crc);
-               if (n % 8 == 7)
-                       printf("\n");
-       }
-       printf("};\n");
-
-       return 0;
-}
-
-#endif /* defined(GENERATE) */
index 8d8643a..62dc270 100644 (file)
 static int do_udf_readdir(struct inode *dir, struct file *filp,
                          filldir_t filldir, void *dirent)
 {
-       struct udf_fileident_bh fibh;
+       struct udf_fileident_bh fibh = { .sbh = NULL, .ebh = NULL};
        struct fileIdentDesc *fi = NULL;
        struct fileIdentDesc cfi;
        int block, iblock;
        loff_t nf_pos = (filp->f_pos - 1) << 2;
        int flen;
-       char fname[UDF_NAME_LEN];
+       char *fname = NULL;
        char *nameptr;
        uint16_t liu;
        uint8_t lfi;
@@ -54,23 +54,32 @@ static int do_udf_readdir(struct inode *dir, struct file *filp,
        kernel_lb_addr eloc;
        uint32_t elen;
        sector_t offset;
-       int i, num;
+       int i, num, ret = 0;
        unsigned int dt_type;
        struct extent_position epos = { NULL, 0, {0, 0} };
        struct udf_inode_info *iinfo;
 
        if (nf_pos >= size)
-               return 0;
+               goto out;
+
+       fname = kmalloc(UDF_NAME_LEN, GFP_NOFS);
+       if (!fname) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
        if (nf_pos == 0)
                nf_pos = udf_ext0_offset(dir);
 
        fibh.soffset = fibh.eoffset = nf_pos & (dir->i_sb->s_blocksize - 1);
        iinfo = UDF_I(dir);
-       if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
-               fibh.sbh = fibh.ebh = NULL;
-       } else if (inode_bmap(dir, nf_pos >> dir->i_sb->s_blocksize_bits,
-                             &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) {
+       if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+               if (inode_bmap(dir, nf_pos >> dir->i_sb->s_blocksize_bits,
+                   &epos, &eloc, &elen, &offset)
+                   != (EXT_RECORDED_ALLOCATED >> 30)) {
+                       ret = -ENOENT;
+                       goto out;
+               }
                block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
                if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
                        if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
@@ -83,8 +92,8 @@ static int do_udf_readdir(struct inode *dir, struct file *filp,
                }
 
                if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) {
-                       brelse(epos.bh);
-                       return -EIO;
+                       ret = -EIO;
+                       goto out;
                }
 
                if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9)) - 1))) {
@@ -105,9 +114,6 @@ static int do_udf_readdir(struct inode *dir, struct file *filp,
                                        brelse(bha[i]);
                        }
                }
-       } else {
-               brelse(epos.bh);
-               return -ENOENT;
        }
 
        while (nf_pos < size) {
@@ -115,13 +121,8 @@ static int do_udf_readdir(struct inode *dir, struct file *filp,
 
                fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc,
                                        &elen, &offset);
-               if (!fi) {
-                       if (fibh.sbh != fibh.ebh)
-                               brelse(fibh.ebh);
-                       brelse(fibh.sbh);
-                       brelse(epos.bh);
-                       return 0;
-               }
+               if (!fi)
+                       goto out;
 
                liu = le16_to_cpu(cfi.lengthOfImpUse);
                lfi = cfi.lengthFileIdent;
@@ -167,53 +168,23 @@ static int do_udf_readdir(struct inode *dir, struct file *filp,
                        dt_type = DT_UNKNOWN;
                }
 
-               if (flen) {
-                       if (filldir(dirent, fname, flen, filp->f_pos, iblock, dt_type) < 0) {
-                               if (fibh.sbh != fibh.ebh)
-                                       brelse(fibh.ebh);
-                               brelse(fibh.sbh);
-                               brelse(epos.bh);
-                               return 0;
-                       }
-               }
+               if (flen && filldir(dirent, fname, flen, filp->f_pos,
+                                   iblock, dt_type) < 0)
+                       goto out;
        } /* end while */
 
        filp->f_pos = (nf_pos >> 2) + 1;
 
+out:
        if (fibh.sbh != fibh.ebh)
                brelse(fibh.ebh);
        brelse(fibh.sbh);
        brelse(epos.bh);
+       kfree(fname);
 
-       return 0;
+       return ret;
 }
 
-/*
- * udf_readdir
- *
- * PURPOSE
- *     Read a directory entry.
- *
- * DESCRIPTION
- *     Optional - sys_getdents() will return -ENOTDIR if this routine is not
- *     available.
- *
- *     Refer to sys_getdents() in fs/readdir.c
- *     sys_getdents() -> .
- *
- * PRE-CONDITIONS
- *     filp                    Pointer to directory file.
- *     buf                     Pointer to directory entry buffer.
- *     filldir                 Pointer to filldir function.
- *
- * POST-CONDITIONS
- *     <return>                >=0 on success.
- *
- * HISTORY
- *     July 1, 1997 - Andrew E. Mileski
- *     Written, tested, and released.
- */
-
 static int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
        struct inode *dir = filp->f_path.dentry->d_inode;
index 5638771..a0974df 100644 (file)
@@ -70,19 +70,6 @@ typedef struct {
        uint8_t         microseconds;
 } __attribute__ ((packed)) timestamp;
 
-typedef struct {
-       uint16_t        typeAndTimezone;
-       int16_t         year;
-       uint8_t         month;
-       uint8_t         day;
-       uint8_t         hour;
-       uint8_t         minute;
-       uint8_t         second;
-       uint8_t         centiseconds;
-       uint8_t         hundredsOfMicroseconds;
-       uint8_t         microseconds;
-} __attribute__ ((packed)) kernel_timestamp;
-
 /* Type and Time Zone (ECMA 167r3 1/7.3.1) */
 #define TIMESTAMP_TYPE_MASK            0xF000
 #define TIMESTAMP_TYPE_CUT             0x0000
index 97c71ae..0ed6e14 100644 (file)
@@ -27,7 +27,6 @@
 
 #include "udfdecl.h"
 #include <linux/fs.h>
-#include <linux/udf_fs.h>
 #include <asm/uaccess.h>
 #include <linux/kernel.h>
 #include <linux/string.h> /* memset */
@@ -144,40 +143,6 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
        return retval;
 }
 
-/*
- * udf_ioctl
- *
- * PURPOSE
- *     Issue an ioctl.
- *
- * DESCRIPTION
- *     Optional - sys_ioctl() will return -ENOTTY if this routine is not
- *     available, and the ioctl cannot be handled without filesystem help.
- *
- *     sys_ioctl() handles these ioctls that apply only to regular files:
- *             FIBMAP [requires udf_block_map()], FIGETBSZ, FIONREAD
- *     These ioctls are also handled by sys_ioctl():
- *             FIOCLEX, FIONCLEX, FIONBIO, FIOASYNC
- *     All other ioctls are passed to the filesystem.
- *
- *     Refer to sys_ioctl() in fs/ioctl.c
- *     sys_ioctl() -> .
- *
- * PRE-CONDITIONS
- *     inode                   Pointer to inode that ioctl was issued on.
- *     filp                    Pointer to file that ioctl was issued on.
- *     cmd                     The ioctl command.
- *     arg                     The ioctl argument [can be interpreted as a
- *                             user-space pointer if desired].
- *
- * POST-CONDITIONS
- *     <return>                Success (>=0) or an error code (<=0) that
- *                             sys_ioctl() will return.
- *
- * HISTORY
- *     July 1, 1997 - Andrew E. Mileski
- *     Written, tested, and released.
- */
 int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
              unsigned long arg)
 {
@@ -225,18 +190,6 @@ int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
        return result;
 }
 
-/*
- * udf_release_file
- *
- * PURPOSE
- *  Called when all references to the file are closed
- *
- * DESCRIPTION
- *  Discard prealloced blocks
- *
- * HISTORY
- *
- */
 static int udf_release_file(struct inode *inode, struct file *filp)
 {
        if (filp->f_mode & FMODE_WRITE) {
index 8436031..eb9cfa2 100644 (file)
@@ -21,7 +21,6 @@
 #include "udfdecl.h"
 #include <linux/fs.h>
 #include <linux/quotaops.h>
-#include <linux/udf_fs.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 
@@ -47,11 +46,9 @@ void udf_free_inode(struct inode *inode)
                struct logicalVolIntegrityDescImpUse *lvidiu =
                                                        udf_sb_lvidiu(sbi);
                if (S_ISDIR(inode->i_mode))
-                       lvidiu->numDirs =
-                               cpu_to_le32(le32_to_cpu(lvidiu->numDirs) - 1);
+                       le32_add_cpu(&lvidiu->numDirs, -1);
                else
-                       lvidiu->numFiles =
-                               cpu_to_le32(le32_to_cpu(lvidiu->numFiles) - 1);
+                       le32_add_cpu(&lvidiu->numFiles, -1);
 
                mark_buffer_dirty(sbi->s_lvid_bh);
        }
@@ -105,11 +102,9 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err)
                lvhd = (struct logicalVolHeaderDesc *)
                                (lvid->logicalVolContentsUse);
                if (S_ISDIR(mode))
-                       lvidiu->numDirs =
-                               cpu_to_le32(le32_to_cpu(lvidiu->numDirs) + 1);
+                       le32_add_cpu(&lvidiu->numDirs, 1);
                else
-                       lvidiu->numFiles =
-                               cpu_to_le32(le32_to_cpu(lvidiu->numFiles) + 1);
+                       le32_add_cpu(&lvidiu->numFiles, 1);
                iinfo->i_unique = uniqueID = le64_to_cpu(lvhd->uniqueID);
                if (!(++uniqueID & 0x00000000FFFFFFFFUL))
                        uniqueID += 16;
index 24cfa55..6e74b11 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/buffer_head.h>
 #include <linux/writeback.h>
 #include <linux/slab.h>
+#include <linux/crc-itu-t.h>
 
 #include "udf_i.h"
 #include "udf_sb.h"
@@ -66,22 +67,7 @@ static void udf_update_extents(struct inode *,
                               struct extent_position *);
 static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int);
 
-/*
- * udf_delete_inode
- *
- * PURPOSE
- *     Clean-up before the specified inode is destroyed.
- *
- * DESCRIPTION
- *     This routine is called when the kernel destroys an inode structure
- *     ie. when iput() finds i_count == 0.
- *
- * HISTORY
- *     July 1, 1997 - Andrew E. Mileski
- *     Written, tested, and released.
- *
- *  Called at the last iput() if i_nlink is zero.
- */
+
 void udf_delete_inode(struct inode *inode)
 {
        truncate_inode_pages(&inode->i_data, 0);
@@ -323,9 +309,6 @@ static int udf_get_block(struct inode *inode, sector_t block,
 
        lock_kernel();
 
-       if (block < 0)
-               goto abort_negative;
-
        iinfo = UDF_I(inode);
        if (block == iinfo->i_next_alloc_block + 1) {
                iinfo->i_next_alloc_block++;
@@ -347,10 +330,6 @@ static int udf_get_block(struct inode *inode, sector_t block,
 abort:
        unlock_kernel();
        return err;
-
-abort_negative:
-       udf_warning(inode->i_sb, "udf_get_block", "block < 0");
-       goto abort;
 }
 
 static struct buffer_head *udf_getblk(struct inode *inode, long block,
@@ -1116,42 +1095,36 @@ static void __udf_read_inode(struct inode *inode)
        fe = (struct fileEntry *)bh->b_data;
 
        if (fe->icbTag.strategyType == cpu_to_le16(4096)) {
-               struct buffer_head *ibh = NULL, *nbh = NULL;
-               struct indirectEntry *ie;
+               struct buffer_head *ibh;
 
                ibh = udf_read_ptagged(inode->i_sb, iinfo->i_location, 1,
                                        &ident);
-               if (ident == TAG_IDENT_IE) {
-                       if (ibh) {
-                               kernel_lb_addr loc;
-                               ie = (struct indirectEntry *)ibh->b_data;
-
-                               loc = lelb_to_cpu(ie->indirectICB.extLocation);
-
-                               if (ie->indirectICB.extLength &&
-                                   (nbh = udf_read_ptagged(inode->i_sb, loc, 0,
-                                                           &ident))) {
-                                       if (ident == TAG_IDENT_FE ||
-                                           ident == TAG_IDENT_EFE) {
-                                               memcpy(&iinfo->i_location,
-                                                      &loc,
-                                                      sizeof(kernel_lb_addr));
-                                               brelse(bh);
-                                               brelse(ibh);
-                                               brelse(nbh);
-                                               __udf_read_inode(inode);
-                                               return;
-                                       } else {
-                                               brelse(nbh);
-                                               brelse(ibh);
-                                       }
-                               } else {
+               if (ident == TAG_IDENT_IE && ibh) {
+                       struct buffer_head *nbh = NULL;
+                       kernel_lb_addr loc;
+                       struct indirectEntry *ie;
+
+                       ie = (struct indirectEntry *)ibh->b_data;
+                       loc = lelb_to_cpu(ie->indirectICB.extLocation);
+
+                       if (ie->indirectICB.extLength &&
+                               (nbh = udf_read_ptagged(inode->i_sb, loc, 0,
+                                                       &ident))) {
+                               if (ident == TAG_IDENT_FE ||
+                                       ident == TAG_IDENT_EFE) {
+                                       memcpy(&iinfo->i_location,
+                                               &loc,
+                                               sizeof(kernel_lb_addr));
+                                       brelse(bh);
                                        brelse(ibh);
+                                       brelse(nbh);
+                                       __udf_read_inode(inode);
+                                       return;
                                }
+                               brelse(nbh);
                        }
-               } else {
-                       brelse(ibh);
                }
+               brelse(ibh);
        } else if (fe->icbTag.strategyType != cpu_to_le16(4)) {
                printk(KERN_ERR "udf: unsupported strategy type: %d\n",
                       le16_to_cpu(fe->icbTag.strategyType));
@@ -1168,8 +1141,6 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
 {
        struct fileEntry *fe;
        struct extendedFileEntry *efe;
-       time_t convtime;
-       long convtime_usec;
        int offset;
        struct udf_sb_info *sbi = UDF_SB(inode->i_sb);
        struct udf_inode_info *iinfo = UDF_I(inode);
@@ -1257,29 +1228,15 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
                inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) <<
                        (inode->i_sb->s_blocksize_bits - 9);
 
-               if (udf_stamp_to_time(&convtime, &convtime_usec,
-                                     lets_to_cpu(fe->accessTime))) {
-                       inode->i_atime.tv_sec = convtime;
-                       inode->i_atime.tv_nsec = convtime_usec * 1000;
-               } else {
+               if (!udf_disk_stamp_to_time(&inode->i_atime, fe->accessTime))
                        inode->i_atime = sbi->s_record_time;
-               }
 
-               if (udf_stamp_to_time(&convtime, &convtime_usec,
-                                     lets_to_cpu(fe->modificationTime))) {
-                       inode->i_mtime.tv_sec = convtime;
-                       inode->i_mtime.tv_nsec = convtime_usec * 1000;
-               } else {
+               if (!udf_disk_stamp_to_time(&inode->i_mtime,
+                                           fe->modificationTime))
                        inode->i_mtime = sbi->s_record_time;
-               }
 
-               if (udf_stamp_to_time(&convtime, &convtime_usec,
-                                     lets_to_cpu(fe->attrTime))) {
-                       inode->i_ctime.tv_sec = convtime;
-                       inode->i_ctime.tv_nsec = convtime_usec * 1000;
-               } else {
+               if (!udf_disk_stamp_to_time(&inode->i_ctime, fe->attrTime))
                        inode->i_ctime = sbi->s_record_time;
-               }
 
                iinfo->i_unique = le64_to_cpu(fe->uniqueID);
                iinfo->i_lenEAttr = le32_to_cpu(fe->lengthExtendedAttr);
@@ -1289,37 +1246,18 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
                inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) <<
                    (inode->i_sb->s_blocksize_bits - 9);
 
-               if (udf_stamp_to_time(&convtime, &convtime_usec,
-                                     lets_to_cpu(efe->accessTime))) {
-                       inode->i_atime.tv_sec = convtime;
-                       inode->i_atime.tv_nsec = convtime_usec * 1000;
-               } else {
+               if (!udf_disk_stamp_to_time(&inode->i_atime, efe->accessTime))
                        inode->i_atime = sbi->s_record_time;
-               }
 
-               if (udf_stamp_to_time(&convtime, &convtime_usec,
-                                     lets_to_cpu(efe->modificationTime))) {
-                       inode->i_mtime.tv_sec = convtime;
-                       inode->i_mtime.tv_nsec = convtime_usec * 1000;
-               } else {
+               if (!udf_disk_stamp_to_time(&inode->i_mtime,
+                                           efe->modificationTime))
                        inode->i_mtime = sbi->s_record_time;
-               }
 
-               if (udf_stamp_to_time(&convtime, &convtime_usec,
-                                     lets_to_cpu(efe->createTime))) {
-                       iinfo->i_crtime.tv_sec = convtime;
-                       iinfo->i_crtime.tv_nsec = convtime_usec * 1000;
-               } else {
+               if (!udf_disk_stamp_to_time(&iinfo->i_crtime, efe->createTime))
                        iinfo->i_crtime = sbi->s_record_time;
-               }
 
-               if (udf_stamp_to_time(&convtime, &convtime_usec,
-                                     lets_to_cpu(efe->attrTime))) {
-                       inode->i_ctime.tv_sec = convtime;
-                       inode->i_ctime.tv_nsec = convtime_usec * 1000;
-               } else {
+               if (!udf_disk_stamp_to_time(&inode->i_ctime, efe->attrTime))
                        inode->i_ctime = sbi->s_record_time;
-               }
 
                iinfo->i_unique = le64_to_cpu(efe->uniqueID);
                iinfo->i_lenEAttr = le32_to_cpu(efe->lengthExtendedAttr);
@@ -1338,6 +1276,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
        case ICBTAG_FILE_TYPE_REALTIME:
        case ICBTAG_FILE_TYPE_REGULAR:
        case ICBTAG_FILE_TYPE_UNDEF:
+       case ICBTAG_FILE_TYPE_VAT20:
                if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
                        inode->i_data.a_ops = &udf_adinicb_aops;
                else
@@ -1363,6 +1302,15 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
                inode->i_op = &page_symlink_inode_operations;
                inode->i_mode = S_IFLNK | S_IRWXUGO;
                break;
+       case ICBTAG_FILE_TYPE_MAIN:
+               udf_debug("METADATA FILE-----\n");
+               break;
+       case ICBTAG_FILE_TYPE_MIRROR:
+               udf_debug("METADATA MIRROR FILE-----\n");
+               break;
+       case ICBTAG_FILE_TYPE_BITMAP:
+               udf_debug("METADATA BITMAP FILE-----\n");
+               break;
        default:
                printk(KERN_ERR "udf: udf_fill_inode(ino %ld) failed unknown "
                                "file type=%d\n", inode->i_ino,
@@ -1416,21 +1364,6 @@ static mode_t udf_convert_permissions(struct fileEntry *fe)
        return mode;
 }
 
-/*
- * udf_write_inode
- *
- * PURPOSE
- *     Write out the specified inode.
- *
- * DESCRIPTION
- *     This routine is called whenever an inode is synced.
- *     Currently this routine is just a placeholder.
- *
- * HISTORY
- *     July 1, 1997 - Andrew E. Mileski
- *     Written, tested, and released.
- */
-
 int udf_write_inode(struct inode *inode, int sync)
 {
        int ret;
@@ -1455,7 +1388,6 @@ static int udf_update_inode(struct inode *inode, int do_sync)
        uint32_t udfperms;
        uint16_t icbflags;
        uint16_t crclen;
-       kernel_timestamp cpu_time;
        int err = 0;
        struct udf_sb_info *sbi = UDF_SB(inode->i_sb);
        unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits;
@@ -1488,9 +1420,9 @@ static int udf_update_inode(struct inode *inode, int do_sync)
                                                iinfo->i_location.
                                                        logicalBlockNum);
                use->descTag.descCRCLength = cpu_to_le16(crclen);
-               use->descTag.descCRC = cpu_to_le16(udf_crc((char *)use +
-                                                          sizeof(tag), crclen,
-                                                          0));
+               use->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)use +
+                                                          sizeof(tag),
+                                                          crclen));
                use->descTag.tagChecksum = udf_tag_checksum(&use->descTag);
 
                mark_buffer_dirty(bh);
@@ -1558,12 +1490,9 @@ static int udf_update_inode(struct inode *inode, int do_sync)
                        (inode->i_blocks + (1 << (blocksize_bits - 9)) - 1) >>
                        (blocksize_bits - 9));
 
-               if (udf_time_to_stamp(&cpu_time, inode->i_atime))
-                       fe->accessTime = cpu_to_lets(cpu_time);
-               if (udf_time_to_stamp(&cpu_time, inode->i_mtime))
-                       fe->modificationTime = cpu_to_lets(cpu_time);
-               if (udf_time_to_stamp(&cpu_time, inode->i_ctime))
-                       fe->attrTime = cpu_to_lets(cpu_time);
+               udf_time_to_disk_stamp(&fe->accessTime, inode->i_atime);
+               udf_time_to_disk_stamp(&fe->modificationTime, inode->i_mtime);
+               udf_time_to_disk_stamp(&fe->attrTime, inode->i_ctime);
                memset(&(fe->impIdent), 0, sizeof(regid));
                strcpy(fe->impIdent.ident, UDF_ID_DEVELOPER);
                fe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
@@ -1598,14 +1527,10 @@ static int udf_update_inode(struct inode *inode, int do_sync)
                     iinfo->i_crtime.tv_nsec > inode->i_ctime.tv_nsec))
                        iinfo->i_crtime = inode->i_ctime;
 
-               if (udf_time_to_stamp(&cpu_time, inode->i_atime))
-                       efe->accessTime = cpu_to_lets(cpu_time);
-               if (udf_time_to_stamp(&cpu_time, inode->i_mtime))
-                       efe->modificationTime = cpu_to_lets(cpu_time);
-               if (udf_time_to_stamp(&cpu_time, iinfo->i_crtime))
-                       efe->createTime = cpu_to_lets(cpu_time);
-               if (udf_time_to_stamp(&cpu_time, inode->i_ctime))
-                       efe->attrTime = cpu_to_lets(cpu_time);
+               udf_time_to_disk_stamp(&efe->accessTime, inode->i_atime);
+               udf_time_to_disk_stamp(&efe->modificationTime, inode->i_mtime);
+               udf_time_to_disk_stamp(&efe->createTime, iinfo->i_crtime);
+               udf_time_to_disk_stamp(&efe->attrTime, inode->i_ctime);
 
                memset(&(efe->impIdent), 0, sizeof(regid));
                strcpy(efe->impIdent.ident, UDF_ID_DEVELOPER);
@@ -1660,8 +1585,8 @@ static int udf_update_inode(struct inode *inode, int do_sync)
        crclen += iinfo->i_lenEAttr + iinfo->i_lenAlloc -
                                                                sizeof(tag);
        fe->descTag.descCRCLength = cpu_to_le16(crclen);
-       fe->descTag.descCRC = cpu_to_le16(udf_crc((char *)fe + sizeof(tag),
-                                                 crclen, 0));
+       fe->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)fe + sizeof(tag),
+                                                 crclen));
        fe->descTag.tagChecksum = udf_tag_checksum(&fe->descTag);
 
        /* write the data blocks */
@@ -1778,9 +1703,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
 
                        if (epos->bh) {
                                aed = (struct allocExtDesc *)epos->bh->b_data;
-                               aed->lengthAllocDescs =
-                                       cpu_to_le32(le32_to_cpu(
-                                       aed->lengthAllocDescs) + adsize);
+                               le32_add_cpu(&aed->lengthAllocDescs, adsize);
                        } else {
                                iinfo->i_lenAlloc += adsize;
                                mark_inode_dirty(inode);
@@ -1830,9 +1753,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
                mark_inode_dirty(inode);
        } else {
                aed = (struct allocExtDesc *)epos->bh->b_data;
-               aed->lengthAllocDescs =
-                       cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) +
-                                   adsize);
+               le32_add_cpu(&aed->lengthAllocDescs, adsize);
                if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
                                UDF_SB(inode->i_sb)->s_udfrev >= 0x0201)
                        udf_update_tag(epos->bh->b_data,
@@ -2046,9 +1967,7 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
                        mark_inode_dirty(inode);
                } else {
                        aed = (struct allocExtDesc *)oepos.bh->b_data;
-                       aed->lengthAllocDescs =
-                               cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) -
-                                           (2 * adsize));
+                       le32_add_cpu(&aed->lengthAllocDescs, -(2 * adsize));
                        if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
                            UDF_SB(inode->i_sb)->s_udfrev >= 0x0201)
                                udf_update_tag(oepos.bh->b_data,
@@ -2065,9 +1984,7 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
                        mark_inode_dirty(inode);
                } else {
                        aed = (struct allocExtDesc *)oepos.bh->b_data;
-                       aed->lengthAllocDescs =
-                               cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) -
-                                           adsize);
+                       le32_add_cpu(&aed->lengthAllocDescs, -adsize);
                        if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
                            UDF_SB(inode->i_sb)->s_udfrev >= 0x0201)
                                udf_update_tag(oepos.bh->b_data,
@@ -2095,11 +2012,6 @@ int8_t inode_bmap(struct inode *inode, sector_t block,
        int8_t etype;
        struct udf_inode_info *iinfo;
 
-       if (block < 0) {
-               printk(KERN_ERR "udf: inode_bmap: block < 0\n");
-               return -1;
-       }
-
        iinfo = UDF_I(inode);
        pos->offset = 0;
        pos->block = iinfo->i_location;
index 579bae7..703843f 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/cdrom.h>
 #include <asm/uaccess.h>
 
-#include <linux/udf_fs.h>
 #include "udf_sb.h"
 
 unsigned int udf_get_last_session(struct super_block *sb)
index a1d6da0..84bf0fd 100644 (file)
@@ -23,8 +23,8 @@
 
 #include <linux/fs.h>
 #include <linux/string.h>
-#include <linux/udf_fs.h>
 #include <linux/buffer_head.h>
+#include <linux/crc-itu-t.h>
 
 #include "udf_i.h"
 #include "udf_sb.h"
@@ -136,8 +136,8 @@ struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size,
                /* rewrite CRC + checksum of eahd */
                crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(tag);
                eahd->descTag.descCRCLength = cpu_to_le16(crclen);
-               eahd->descTag.descCRC = cpu_to_le16(udf_crc((char *)eahd +
-                                               sizeof(tag), crclen, 0));
+               eahd->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)eahd +
+                                               sizeof(tag), crclen));
                eahd->descTag.tagChecksum = udf_tag_checksum(&eahd->descTag);
                iinfo->i_lenEAttr += size;
                return (struct genericFormat *)&ea[offset];
@@ -204,16 +204,15 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block,
 {
        tag *tag_p;
        struct buffer_head *bh = NULL;
-       struct udf_sb_info *sbi = UDF_SB(sb);
 
        /* Read the block */
        if (block == 0xFFFFFFFF)
                return NULL;
 
-       bh = udf_tread(sb, block + sbi->s_session);
+       bh = udf_tread(sb, block);
        if (!bh) {
                udf_debug("block=%d, location=%d: read failed\n",
-                         block + sbi->s_session, location);
+                         block, location);
                return NULL;
        }
 
@@ -223,8 +222,7 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block,
 
        if (location != le32_to_cpu(tag_p->tagLocation)) {
                udf_debug("location mismatch block %u, tag %u != %u\n",
-                         block + sbi->s_session,
-                         le32_to_cpu(tag_p->tagLocation), location);
+                         block, le32_to_cpu(tag_p->tagLocation), location);
                goto error_out;
        }
 
@@ -244,13 +242,13 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block,
 
        /* Verify the descriptor CRC */
        if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize ||
-           le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag),
-                                       le16_to_cpu(tag_p->descCRCLength), 0))
+           le16_to_cpu(tag_p->descCRC) == crc_itu_t(0,
+                                       bh->b_data + sizeof(tag),
+                                       le16_to_cpu(tag_p->descCRCLength)))
                return bh;
 
-       udf_debug("Crc failure block %d: crc = %d, crclen = %d\n",
-                 block + sbi->s_session, le16_to_cpu(tag_p->descCRC),
-                 le16_to_cpu(tag_p->descCRCLength));
+       udf_debug("Crc failure block %d: crc = %d, crclen = %d\n", block,
+           le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength));
 
 error_out:
        brelse(bh);
@@ -270,7 +268,7 @@ void udf_update_tag(char *data, int length)
        length -= sizeof(tag);
 
        tptr->descCRCLength = cpu_to_le16(length);
-       tptr->descCRC = cpu_to_le16(udf_crc(data + sizeof(tag), length, 0));
+       tptr->descCRC = cpu_to_le16(crc_itu_t(0, data + sizeof(tag), length));
        tptr->tagChecksum = udf_tag_checksum(tptr);
 }
 
index 112a5fb..ba5537d 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
 #include <linux/sched.h>
+#include <linux/crc-itu-t.h>
 
 static inline int udf_match(int len1, const char *name1, int len2,
                            const char *name2)
@@ -97,25 +98,23 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
                memset(fibh->ebh->b_data, 0x00, padlen + offset);
        }
 
-       crc = udf_crc((uint8_t *)cfi + sizeof(tag),
-                     sizeof(struct fileIdentDesc) - sizeof(tag), 0);
+       crc = crc_itu_t(0, (uint8_t *)cfi + sizeof(tag),
+                     sizeof(struct fileIdentDesc) - sizeof(tag));
 
        if (fibh->sbh == fibh->ebh) {
-               crc = udf_crc((uint8_t *)sfi->impUse,
+               crc = crc_itu_t(crc, (uint8_t *)sfi->impUse,
                              crclen + sizeof(tag) -
-                             sizeof(struct fileIdentDesc), crc);
+                             sizeof(struct fileIdentDesc));
        } else if (sizeof(struct fileIdentDesc) >= -fibh->soffset) {
-               crc = udf_crc(fibh->ebh->b_data +
+               crc = crc_itu_t(crc, fibh->ebh->b_data +
                                        sizeof(struct fileIdentDesc) +
                                        fibh->soffset,
                              crclen + sizeof(tag) -
-                                       sizeof(struct fileIdentDesc),
-                             crc);
+                                       sizeof(struct fileIdentDesc));
        } else {
-               crc = udf_crc((uint8_t *)sfi->impUse,
-                             -fibh->soffset - sizeof(struct fileIdentDesc),
-                             crc);
-               crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc);
+               crc = crc_itu_t(crc, (uint8_t *)sfi->impUse,
+                             -fibh->soffset - sizeof(struct fileIdentDesc));
+               crc = crc_itu_t(crc, fibh->ebh->b_data, fibh->eoffset);
        }
 
        cfi->descTag.descCRC = cpu_to_le16(crc);
@@ -149,7 +148,7 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
        struct fileIdentDesc *fi = NULL;
        loff_t f_pos;
        int block, flen;
-       char fname[UDF_NAME_LEN];
+       char *fname = NULL;
        char *nameptr;
        uint8_t lfi;
        uint16_t liu;
@@ -163,12 +162,12 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
        size = udf_ext0_offset(dir) + dir->i_size;
        f_pos = udf_ext0_offset(dir);
 
+       fibh->sbh = fibh->ebh = NULL;
        fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1);
-       if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
-               fibh->sbh = fibh->ebh = NULL;
-       else if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits,
-                             &epos, &eloc, &elen, &offset) ==
-                                       (EXT_RECORDED_ALLOCATED >> 30)) {
+       if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+               if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos,
+                   &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30))
+                       goto out_err;
                block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
                if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
                        if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
@@ -179,25 +178,19 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
                        offset = 0;
 
                fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
-               if (!fibh->sbh) {
-                       brelse(epos.bh);
-                       return NULL;
-               }
-       } else {
-               brelse(epos.bh);
-               return NULL;
+               if (!fibh->sbh)
+                       goto out_err;
        }
 
+       fname = kmalloc(UDF_NAME_LEN, GFP_NOFS);
+       if (!fname)
+               goto out_err;
+
        while (f_pos < size) {
                fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc,
                                        &elen, &offset);
-               if (!fi) {
-                       if (fibh->sbh != fibh->ebh)
-                               brelse(fibh->ebh);
-                       brelse(fibh->sbh);
-                       brelse(epos.bh);
-                       return NULL;
-               }
+               if (!fi)
+                       goto out_err;
 
                liu = le16_to_cpu(cfi->lengthOfImpUse);
                lfi = cfi->lengthFileIdent;
@@ -237,53 +230,22 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
 
                flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
                if (flen && udf_match(flen, fname, dentry->d_name.len,
-                                     dentry->d_name.name)) {
-                       brelse(epos.bh);
-                       return fi;
-               }
+                                     dentry->d_name.name))
+                       goto out_ok;
        }
 
+out_err:
+       fi = NULL;
        if (fibh->sbh != fibh->ebh)
                brelse(fibh->ebh);
        brelse(fibh->sbh);
+out_ok:
        brelse(epos.bh);
+       kfree(fname);
 
-       return NULL;
+       return fi;
 }
 
-/*
- * udf_lookup
- *
- * PURPOSE
- *     Look-up the inode for a given name.
- *
- * DESCRIPTION
- *     Required - lookup_dentry() will return -ENOTDIR if this routine is not
- *     available for a directory. The filesystem is useless if this routine is
- *     not available for at least the filesystem's root directory.
- *
- *     This routine is passed an incomplete dentry - it must be completed by
- *     calling d_add(dentry, inode). If the name does not exist, then the
- *     specified inode must be set to null. An error should only be returned
- *     when the lookup fails for a reason other than the name not existing.
- *     Note that the directory inode semaphore is held during the call.
- *
- *     Refer to lookup_dentry() in fs/namei.c
- *     lookup_dentry() -> lookup() -> real_lookup() -> .
- *
- * PRE-CONDITIONS
- *     dir                     Pointer to inode of parent directory.
- *     dentry                  Pointer to dentry to complete.
- *     nd                      Pointer to lookup nameidata
- *
- * POST-CONDITIONS
- *     <return>                Zero on success.
- *
- * HISTORY
- *     July 1, 1997 - Andrew E. Mileski
- *     Written, tested, and released.
- */
-
 static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
                                 struct nameidata *nd)
 {
@@ -336,11 +298,9 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
 {
        struct super_block *sb = dir->i_sb;
        struct fileIdentDesc *fi = NULL;
-       char name[UDF_NAME_LEN], fname[UDF_NAME_LEN];
+       char *name = NULL;
        int namelen;
        loff_t f_pos;
-       int flen;
-       char *nameptr;
        loff_t size = udf_ext0_offset(dir) + dir->i_size;
        int nfidlen;
        uint8_t lfi;
@@ -352,16 +312,23 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
        struct extent_position epos = {};
        struct udf_inode_info *dinfo;
 
+       fibh->sbh = fibh->ebh = NULL;
+       name = kmalloc(UDF_NAME_LEN, GFP_NOFS);
+       if (!name) {
+               *err = -ENOMEM;
+               goto out_err;
+       }
+
        if (dentry) {
                if (!dentry->d_name.len) {
                        *err = -EINVAL;
-                       return NULL;
+                       goto out_err;
                }
                namelen = udf_put_filename(sb, dentry->d_name.name, name,
                                                 dentry->d_name.len);
                if (!namelen) {
                        *err = -ENAMETOOLONG;
-                       return NULL;
+                       goto out_err;
                }
        } else {
                namelen = 0;
@@ -373,11 +340,14 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
 
        fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1);
        dinfo = UDF_I(dir);
-       if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
-               fibh->sbh = fibh->ebh = NULL;
-       else if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits,
-                             &epos, &eloc, &elen, &offset) ==
-                                       (EXT_RECORDED_ALLOCATED >> 30)) {
+       if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+               if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos,
+                   &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) {
+                       block = udf_get_lb_pblock(dir->i_sb,
+                                       dinfo->i_location, 0);
+                       fibh->soffset = fibh->eoffset = sb->s_blocksize;
+                       goto add;
+               }
                block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
                if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
                        if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
@@ -389,17 +359,11 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
 
                fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
                if (!fibh->sbh) {
-                       brelse(epos.bh);
                        *err = -EIO;
-                       return NULL;
+                       goto out_err;
                }
 
                block = dinfo->i_location.logicalBlockNum;
-       } else {
-               block = udf_get_lb_pblock(dir->i_sb, dinfo->i_location, 0);
-               fibh->sbh = fibh->ebh = NULL;
-               fibh->soffset = fibh->eoffset = sb->s_blocksize;
-               goto add;
        }
 
        while (f_pos < size) {
@@ -407,41 +371,16 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
                                        &elen, &offset);
 
                if (!fi) {
-                       if (fibh->sbh != fibh->ebh)
-                               brelse(fibh->ebh);
-                       brelse(fibh->sbh);
-                       brelse(epos.bh);
                        *err = -EIO;
-                       return NULL;
+                       goto out_err;
                }
 
                liu = le16_to_cpu(cfi->lengthOfImpUse);
                lfi = cfi->lengthFileIdent;
 
-               if (fibh->sbh == fibh->ebh)
-                       nameptr = fi->fileIdent + liu;
-               else {
-                       int poffset;    /* Unpaded ending offset */
-
-                       poffset = fibh->soffset + sizeof(struct fileIdentDesc) +
-                                       liu + lfi;
-
-                       if (poffset >= lfi)
-                               nameptr = (char *)(fibh->ebh->b_data +
-                                                  poffset - lfi);
-                       else {
-                               nameptr = fname;
-                               memcpy(nameptr, fi->fileIdent + liu,
-                                       lfi - poffset);
-                               memcpy(nameptr + lfi - poffset,
-                                       fibh->ebh->b_data, poffset);
-                       }
-               }
-
                if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
                        if (((sizeof(struct fileIdentDesc) +
                                        liu + lfi + 3) & ~3) == nfidlen) {
-                               brelse(epos.bh);
                                cfi->descTag.tagSerialNum = cpu_to_le16(1);
                                cfi->fileVersionNum = cpu_to_le16(1);
                                cfi->fileCharacteristics = 0;
@@ -449,27 +388,13 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
                                cfi->lengthOfImpUse = cpu_to_le16(0);
                                if (!udf_write_fi(dir, cfi, fi, fibh, NULL,
                                                  name))
-                                       return fi;
+                                       goto out_ok;
                                else {
                                        *err = -EIO;
-                                       return NULL;
+                                       goto out_err;
                                }
                        }
                }
-
-               if (!lfi || !dentry)
-                       continue;
-
-               flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
-               if (flen && udf_match(flen, fname, dentry->d_name.len,
-                                     dentry->d_name.name)) {
-                       if (fibh->sbh != fibh->ebh)
-                               brelse(fibh->ebh);
-                       brelse(fibh->sbh);
-                       brelse(epos.bh);
-                       *err = -EEXIST;
-                       return NULL;
-               }
        }
 
 add:
@@ -496,7 +421,7 @@ add:
                fibh->sbh = fibh->ebh =
                                udf_expand_dir_adinicb(dir, &block, err);
                if (!fibh->sbh)
-                       return NULL;
+                       goto out_err;
                epos.block = dinfo->i_location;
                epos.offset = udf_file_entry_alloc_offset(dir);
                /* Load extent udf_expand_dir_adinicb() has created */
@@ -537,11 +462,8 @@ add:
                                                dir->i_sb->s_blocksize_bits);
                fibh->ebh = udf_bread(dir,
                                f_pos >> dir->i_sb->s_blocksize_bits, 1, err);
-               if (!fibh->ebh) {
-                       brelse(epos.bh);
-                       brelse(fibh->sbh);
-                       return NULL;
-               }
+               if (!fibh->ebh)
+                       goto out_err;
 
                if (!fibh->soffset) {
                        if (udf_next_aext(dir, &epos, &eloc, &elen, 1) ==
@@ -572,20 +494,25 @@ add:
        cfi->lengthFileIdent = namelen;
        cfi->lengthOfImpUse = cpu_to_le16(0);
        if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) {
-               brelse(epos.bh);
                dir->i_size += nfidlen;
                if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
                        dinfo->i_lenAlloc += nfidlen;
                mark_inode_dirty(dir);
-               return fi;
+               goto out_ok;
        } else {
-               brelse(epos.bh);
-               if (fibh->sbh != fibh->ebh)
-                       brelse(fibh->ebh);
-               brelse(fibh->sbh);
                *err = -EIO;
-               return NULL;
+               goto out_err;
        }
+
+out_err:
+       fi = NULL;
+       if (fibh->sbh != fibh->ebh)
+               brelse(fibh->ebh);
+       brelse(fibh->sbh);
+out_ok:
+       brelse(epos.bh);
+       kfree(name);
+       return fi;
 }
 
 static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi,
@@ -940,7 +867,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
        char *ea;
        int err;
        int block;
-       char name[UDF_NAME_LEN];
+       char *name = NULL;
        int namelen;
        struct buffer_head *bh;
        struct udf_inode_info *iinfo;
@@ -950,6 +877,12 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
        if (!inode)
                goto out;
 
+       name = kmalloc(UDF_NAME_LEN, GFP_NOFS);
+       if (!name) {
+               err = -ENOMEM;
+               goto out_no_entry;
+       }
+
        iinfo = UDF_I(inode);
        inode->i_mode = S_IFLNK | S_IRWXUGO;
        inode->i_data.a_ops = &udf_symlink_aops;
@@ -1089,6 +1022,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
        err = 0;
 
 out:
+       kfree(name);
        unlock_kernel();
        return err;
 
index fc53334..63610f0 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <linux/fs.h>
 #include <linux/string.h>
-#include <linux/udf_fs.h>
 #include <linux/slab.h>
 #include <linux/buffer_head.h>
 
@@ -55,11 +54,10 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
        struct udf_sb_info *sbi = UDF_SB(sb);
        struct udf_part_map *map;
        struct udf_virtual_data *vdata;
-       struct udf_inode_info *iinfo;
+       struct udf_inode_info *iinfo = UDF_I(sbi->s_vat_inode);
 
        map = &sbi->s_partmaps[partition];
        vdata = &map->s_type_specific.s_virtual;
-       index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t);
 
        if (block > vdata->s_num_entries) {
                udf_debug("Trying to access block beyond end of VAT "
@@ -67,6 +65,12 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
                return 0xFFFFFFFF;
        }
 
+       if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+               loc = le32_to_cpu(((__le32 *)(iinfo->i_ext.i_data +
+                       vdata->s_start_offset))[block]);
+               goto translate;
+       }
+       index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t);
        if (block >= index) {
                block -= index;
                newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t)));
@@ -89,7 +93,7 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
 
        brelse(bh);
 
-       iinfo = UDF_I(sbi->s_vat_inode);
+translate:
        if (iinfo->i_location.partitionReferenceNum == partition) {
                udf_debug("recursive call to udf_get_pblock!\n");
                return 0xFFFFFFFF;
@@ -263,3 +267,58 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
 
        return 0;
 }
+
+static uint32_t udf_try_read_meta(struct inode *inode, uint32_t block,
+                                       uint16_t partition, uint32_t offset)
+{
+       struct super_block *sb = inode->i_sb;
+       struct udf_part_map *map;
+       kernel_lb_addr eloc;
+       uint32_t elen;
+       sector_t ext_offset;
+       struct extent_position epos = {};
+       uint32_t phyblock;
+
+       if (inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset) !=
+                                               (EXT_RECORDED_ALLOCATED >> 30))
+               phyblock = 0xFFFFFFFF;
+       else {
+               map = &UDF_SB(sb)->s_partmaps[partition];
+               /* map to sparable/physical partition desc */
+               phyblock = udf_get_pblock(sb, eloc.logicalBlockNum,
+                       map->s_partition_num, ext_offset + offset);
+       }
+
+       brelse(epos.bh);
+       return phyblock;
+}
+
+uint32_t udf_get_pblock_meta25(struct super_block *sb, uint32_t block,
+                               uint16_t partition, uint32_t offset)
+{
+       struct udf_sb_info *sbi = UDF_SB(sb);
+       struct udf_part_map *map;
+       struct udf_meta_data *mdata;
+       uint32_t retblk;
+       struct inode *inode;
+
+       udf_debug("READING from METADATA\n");
+
+       map = &sbi->s_partmaps[partition];
+       mdata = &map->s_type_specific.s_metadata;
+       inode = mdata->s_metadata_fe ? : mdata->s_mirror_fe;
+
+       /* We shouldn't mount such media... */
+       BUG_ON(!inode);
+       retblk = udf_try_read_meta(inode, block, partition, offset);
+       if (retblk == 0xFFFFFFFF) {
+               udf_warning(sb, __func__, "error reading from METADATA, "
+                       "trying to read from MIRROR");
+               inode = mdata->s_mirror_fe;
+               if (!inode)
+                       return 0xFFFFFFFF;
+               retblk = udf_try_read_meta(inode, block, partition, offset);
+       }
+
+       return retblk;
+}
index f3ac4ab..b564fc1 100644 (file)
 #include <linux/errno.h>
 #include <linux/mount.h>
 #include <linux/seq_file.h>
+#include <linux/bitmap.h>
+#include <linux/crc-itu-t.h>
 #include <asm/byteorder.h>
 
-#include <linux/udf_fs.h>
 #include "udf_sb.h"
 #include "udf_i.h"
 
@@ -84,22 +85,19 @@ static void udf_write_super(struct super_block *);
 static int udf_remount_fs(struct super_block *, int *, char *);
 static int udf_check_valid(struct super_block *, int, int);
 static int udf_vrs(struct super_block *sb, int silent);
-static int udf_load_partition(struct super_block *, kernel_lb_addr *);
-static int udf_load_logicalvol(struct super_block *, struct buffer_head *,
-                              kernel_lb_addr *);
 static void udf_load_logicalvolint(struct super_block *, kernel_extent_ad);
 static void udf_find_anchor(struct super_block *);
 static int udf_find_fileset(struct super_block *, kernel_lb_addr *,
                            kernel_lb_addr *);
-static void udf_load_pvoldesc(struct super_block *, struct buffer_head *);
 static void udf_load_fileset(struct super_block *, struct buffer_head *,
                             kernel_lb_addr *);
-static int udf_load_partdesc(struct super_block *, struct buffer_head *);
 static void udf_open_lvid(struct super_block *);
 static void udf_close_lvid(struct super_block *);
 static unsigned int udf_count_free(struct super_block *);
 static int udf_statfs(struct dentry *, struct kstatfs *);
 static int udf_show_options(struct seq_file *, struct vfsmount *);
+static void udf_error(struct super_block *sb, const char *function,
+                     const char *fmt, ...);
 
 struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct udf_sb_info *sbi)
 {
@@ -587,48 +585,10 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
        return 0;
 }
 
-/*
- * udf_set_blocksize
- *
- * PURPOSE
- *     Set the block size to be used in all transfers.
- *
- * DESCRIPTION
- *     To allow room for a DMA transfer, it is best to guess big when unsure.
- *     This routine picks 2048 bytes as the blocksize when guessing. This
- *     should be adequate until devices with larger block sizes become common.
- *
- *     Note that the Linux kernel can currently only deal with blocksizes of
- *     512, 1024, 2048, 4096, and 8192 bytes.
- *
- * PRE-CONDITIONS
- *     sb                      Pointer to _locked_ superblock.
- *
- * POST-CONDITIONS
- *     sb->s_blocksize         Blocksize.
- *     sb->s_blocksize_bits    log2 of blocksize.
- *     <return>        0       Blocksize is valid.
- *     <return>        1       Blocksize is invalid.
- *
- * HISTORY
- *     July 1, 1997 - Andrew E. Mileski
- *     Written, tested, and released.
- */
-static int udf_set_blocksize(struct super_block *sb, int bsize)
-{
-       if (!sb_min_blocksize(sb, bsize)) {
-               udf_debug("Bad block size (%d)\n", bsize);
-               printk(KERN_ERR "udf: bad block size (%d)\n", bsize);
-               return 0;
-       }
-
-       return sb->s_blocksize;
-}
-
 static int udf_vrs(struct super_block *sb, int silent)
 {
        struct volStructDesc *vsd = NULL;
-       int sector = 32768;
+       loff_t sector = 32768;
        int sectorsize;
        struct buffer_head *bh = NULL;
        int iso9660 = 0;
@@ -649,7 +609,8 @@ static int udf_vrs(struct super_block *sb, int silent)
        sector += (sbi->s_session << sb->s_blocksize_bits);
 
        udf_debug("Starting at sector %u (%ld byte sectors)\n",
-                 (sector >> sb->s_blocksize_bits), sb->s_blocksize);
+                 (unsigned int)(sector >> sb->s_blocksize_bits),
+                 sb->s_blocksize);
        /* Process the sequence (if applicable) */
        for (; !nsr02 && !nsr03; sector += sectorsize) {
                /* Read a block */
@@ -719,162 +680,140 @@ static int udf_vrs(struct super_block *sb, int silent)
 }
 
 /*
- * udf_find_anchor
- *
- * PURPOSE
- *     Find an anchor volume descriptor.
- *
- * PRE-CONDITIONS
- *     sb                      Pointer to _locked_ superblock.
- *     lastblock               Last block on media.
- *
- * POST-CONDITIONS
- *     <return>                1 if not found, 0 if ok
- *
- * HISTORY
- *     July 1, 1997 - Andrew E. Mileski
- *     Written, tested, and released.
+ * Check whether there is an anchor block in the given block
  */
-static void udf_find_anchor(struct super_block *sb)
+static int udf_check_anchor_block(struct super_block *sb, sector_t block,
+                                       bool varconv)
 {
-       int lastblock;
        struct buffer_head *bh = NULL;
+       tag *t;
        uint16_t ident;
        uint32_t location;
-       int i;
-       struct udf_sb_info *sbi;
 
-       sbi = UDF_SB(sb);
-       lastblock = sbi->s_last_block;
+       if (varconv) {
+               if (udf_fixed_to_variable(block) >=
+                   sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits)
+                       return 0;
+               bh = sb_bread(sb, udf_fixed_to_variable(block));
+       }
+       else
+               bh = sb_bread(sb, block);
 
-       if (lastblock) {
-               int varlastblock = udf_variable_to_fixed(lastblock);
-               int last[] =  { lastblock, lastblock - 2,
-                               lastblock - 150, lastblock - 152,
-                               varlastblock, varlastblock - 2,
-                               varlastblock - 150, varlastblock - 152 };
-
-               lastblock = 0;
-
-               /* Search for an anchor volume descriptor pointer */
-
-               /*  according to spec, anchor is in either:
-                *     block 256
-                *     lastblock-256
-                *     lastblock
-                *  however, if the disc isn't closed, it could be 512 */
-
-               for (i = 0; !lastblock && i < ARRAY_SIZE(last); i++) {
-                       ident = location = 0;
-                       if (last[i] >= 0) {
-                               bh = sb_bread(sb, last[i]);
-                               if (bh) {
-                                       tag *t = (tag *)bh->b_data;
-                                       ident = le16_to_cpu(t->tagIdent);
-                                       location = le32_to_cpu(t->tagLocation);
-                                       brelse(bh);
-                               }
-                       }
+       if (!bh)
+               return 0;
 
-                       if (ident == TAG_IDENT_AVDP) {
-                               if (location == last[i] - sbi->s_session) {
-                                       lastblock = last[i] - sbi->s_session;
-                                       sbi->s_anchor[0] = lastblock;
-                                       sbi->s_anchor[1] = lastblock - 256;
-                               } else if (location ==
-                                               udf_variable_to_fixed(last[i]) -
-                                                       sbi->s_session) {
-                                       UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
-                                       lastblock =
-                                               udf_variable_to_fixed(last[i]) -
-                                                       sbi->s_session;
-                                       sbi->s_anchor[0] = lastblock;
-                                       sbi->s_anchor[1] = lastblock - 256 -
-                                                               sbi->s_session;
-                               } else {
-                                       udf_debug("Anchor found at block %d, "
-                                                 "location mismatch %d.\n",
-                                                 last[i], location);
-                               }
-                       } else if (ident == TAG_IDENT_FE ||
-                                       ident == TAG_IDENT_EFE) {
-                               lastblock = last[i];
-                               sbi->s_anchor[3] = 512;
-                       } else {
-                               ident = location = 0;
-                               if (last[i] >= 256) {
-                                       bh = sb_bread(sb, last[i] - 256);
-                                       if (bh) {
-                                               tag *t = (tag *)bh->b_data;
-                                               ident = le16_to_cpu(
-                                                               t->tagIdent);
-                                               location = le32_to_cpu(
-                                                               t->tagLocation);
-                                               brelse(bh);
-                                       }
-                               }
+       t = (tag *)bh->b_data;
+       ident = le16_to_cpu(t->tagIdent);
+       location = le32_to_cpu(t->tagLocation);
+       brelse(bh);
+       if (ident != TAG_IDENT_AVDP)
+               return 0;
+       return location == block;
+}
 
-                               if (ident == TAG_IDENT_AVDP &&
-                                   location == last[i] - 256 -
-                                               sbi->s_session) {
-                                       lastblock = last[i];
-                                       sbi->s_anchor[1] = last[i] - 256;
-                               } else {
-                                       ident = location = 0;
-                                       if (last[i] >= 312 + sbi->s_session) {
-                                               bh = sb_bread(sb,
-                                                               last[i] - 312 -
-                                                               sbi->s_session);
-                                               if (bh) {
-                                                       tag *t = (tag *)
-                                                                bh->b_data;
-                                                       ident = le16_to_cpu(
-                                                               t->tagIdent);
-                                                       location = le32_to_cpu(
-                                                               t->tagLocation);
-                                                       brelse(bh);
-                                               }
-                                       }
+/* Search for an anchor volume descriptor pointer */
+static sector_t udf_scan_anchors(struct super_block *sb, bool varconv,
+                                       sector_t lastblock)
+{
+       sector_t last[6];
+       int i;
+       struct udf_sb_info *sbi = UDF_SB(sb);
 
-                                       if (ident == TAG_IDENT_AVDP &&
-                                           location == udf_variable_to_fixed(last[i]) - 256) {
-                                               UDF_SET_FLAG(sb,
-                                                            UDF_FLAG_VARCONV);
-                                               lastblock = udf_variable_to_fixed(last[i]);
-                                               sbi->s_anchor[1] = lastblock - 256;
-                                       }
-                               }
-                       }
+       last[0] = lastblock;
+       last[1] = last[0] - 1;
+       last[2] = last[0] + 1;
+       last[3] = last[0] - 2;
+       last[4] = last[0] - 150;
+       last[5] = last[0] - 152;
+
+       /*  according to spec, anchor is in either:
+        *     block 256
+        *     lastblock-256
+        *     lastblock
+        *  however, if the disc isn't closed, it could be 512 */
+
+       for (i = 0; i < ARRAY_SIZE(last); i++) {
+               if (last[i] < 0)
+                       continue;
+               if (last[i] >= sb->s_bdev->bd_inode->i_size >>
+                               sb->s_blocksize_bits)
+                       continue;
+
+               if (udf_check_anchor_block(sb, last[i], varconv)) {
+                       sbi->s_anchor[0] = last[i];
+                       sbi->s_anchor[1] = last[i] - 256;
+                       return last[i];
                }
-       }
 
-       if (!lastblock) {
-               /* We haven't found the lastblock. check 312 */
-               bh = sb_bread(sb, 312 + sbi->s_session);
-               if (bh) {
-                       tag *t = (tag *)bh->b_data;
-                       ident = le16_to_cpu(t->tagIdent);
-                       location = le32_to_cpu(t->tagLocation);
-                       brelse(bh);
+               if (last[i] < 256)
+                       continue;
 
-                       if (ident == TAG_IDENT_AVDP && location == 256)
-                               UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
+               if (udf_check_anchor_block(sb, last[i] - 256, varconv)) {
+                       sbi->s_anchor[1] = last[i] - 256;
+                       return last[i];
                }
        }
 
+       if (udf_check_anchor_block(sb, sbi->s_session + 256, varconv)) {
+               sbi->s_anchor[0] = sbi->s_session + 256;
+               return last[0];
+       }
+       if (udf_check_anchor_block(sb, sbi->s_session + 512, varconv)) {
+               sbi->s_anchor[0] = sbi->s_session + 512;
+               return last[0];
+       }
+       return 0;
+}
+
+/*
+ * Find an anchor volume descriptor. The function expects sbi->s_lastblock to
+ * be the last block on the media.
+ *
+ * Return 1 if not found, 0 if ok
+ *
+ */
+static void udf_find_anchor(struct super_block *sb)
+{
+       sector_t lastblock;
+       struct buffer_head *bh = NULL;
+       uint16_t ident;
+       int i;
+       struct udf_sb_info *sbi = UDF_SB(sb);
+
+       lastblock = udf_scan_anchors(sb, 0, sbi->s_last_block);
+       if (lastblock)
+               goto check_anchor;
+
+       /* No anchor found? Try VARCONV conversion of block numbers */
+       /* Firstly, we try to not convert number of the last block */
+       lastblock = udf_scan_anchors(sb, 1,
+                               udf_variable_to_fixed(sbi->s_last_block));
+       if (lastblock) {
+               UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
+               goto check_anchor;
+       }
+
+       /* Secondly, we try with converted number of the last block */
+       lastblock = udf_scan_anchors(sb, 1, sbi->s_last_block);
+       if (lastblock)
+               UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
+
+check_anchor:
+       /*
+        * Check located anchors and the anchor block supplied via
+        * mount options
+        */
        for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) {
-               if (sbi->s_anchor[i]) {
-                       bh = udf_read_tagged(sb, sbi->s_anchor[i],
-                                            sbi->s_anchor[i], &ident);
-                       if (!bh)
+               if (!sbi->s_anchor[i])
+                       continue;
+               bh = udf_read_tagged(sb, sbi->s_anchor[i],
+                                       sbi->s_anchor[i], &ident);
+               if (!bh)
+                       sbi->s_anchor[i] = 0;
+               else {
+                       brelse(bh);
+                       if (ident != TAG_IDENT_AVDP)
                                sbi->s_anchor[i] = 0;
-                       else {
-                               brelse(bh);
-                               if ((ident != TAG_IDENT_AVDP) &&
-                                   (i || (ident != TAG_IDENT_FE &&
-                                          ident != TAG_IDENT_EFE)))
-                                       sbi->s_anchor[i] = 0;
-                       }
                }
        }
 
@@ -971,27 +910,30 @@ static int udf_find_fileset(struct super_block *sb,
        return 1;
 }
 
-static void udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh)
+static int udf_load_pvoldesc(struct super_block *sb, sector_t block)
 {
        struct primaryVolDesc *pvoldesc;
-       time_t recording;
-       long recording_usec;
        struct ustr instr;
        struct ustr outstr;
+       struct buffer_head *bh;
+       uint16_t ident;
+
+       bh = udf_read_tagged(sb, block, block, &ident);
+       if (!bh)
+               return 1;
+       BUG_ON(ident != TAG_IDENT_PVD);
 
        pvoldesc = (struct primaryVolDesc *)bh->b_data;
 
-       if (udf_stamp_to_time(&recording, &recording_usec,
-                             lets_to_cpu(pvoldesc->recordingDateAndTime))) {
-               kernel_timestamp ts;
-               ts = lets_to_cpu(pvoldesc->recordingDateAndTime);
-               udf_debug("recording time %ld/%ld, %04u/%02u/%02u"
+       if (udf_disk_stamp_to_time(&UDF_SB(sb)->s_record_time,
+                             pvoldesc->recordingDateAndTime)) {
+#ifdef UDFFS_DEBUG
+               timestamp *ts = &pvoldesc->recordingDateAndTime;
+               udf_debug("recording time %04u/%02u/%02u"
                          " %02u:%02u (%x)\n",
-                         recording, recording_usec,
-                         ts.year, ts.month, ts.day, ts.hour,
-                         ts.minute, ts.typeAndTimezone);
-               UDF_SB(sb)->s_record_time.tv_sec = recording;
-               UDF_SB(sb)->s_record_time.tv_nsec = recording_usec * 1000;
+                         le16_to_cpu(ts->year), ts->month, ts->day, ts->hour,
+                         ts->minute, le16_to_cpu(ts->typeAndTimezone));
+#endif
        }
 
        if (!udf_build_ustr(&instr, pvoldesc->volIdent, 32))
@@ -1005,6 +947,104 @@ static void udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh)
        if (!udf_build_ustr(&instr, pvoldesc->volSetIdent, 128))
                if (udf_CS0toUTF8(&outstr, &instr))
                        udf_debug("volSetIdent[] = '%s'\n", outstr.u_name);
+
+       brelse(bh);
+       return 0;
+}
+
+static int udf_load_metadata_files(struct super_block *sb, int partition)
+{
+       struct udf_sb_info *sbi = UDF_SB(sb);
+       struct udf_part_map *map;
+       struct udf_meta_data *mdata;
+       kernel_lb_addr addr;
+       int fe_error = 0;
+
+       map = &sbi->s_partmaps[partition];
+       mdata = &map->s_type_specific.s_metadata;
+
+       /* metadata address */
+       addr.logicalBlockNum =  mdata->s_meta_file_loc;
+       addr.partitionReferenceNum = map->s_partition_num;
+
+       udf_debug("Metadata file location: block = %d part = %d\n",
+                         addr.logicalBlockNum, addr.partitionReferenceNum);
+
+       mdata->s_metadata_fe = udf_iget(sb, addr);
+
+       if (mdata->s_metadata_fe == NULL) {
+               udf_warning(sb, __func__, "metadata inode efe not found, "
+                               "will try mirror inode.");
+               fe_error = 1;
+       } else if (UDF_I(mdata->s_metadata_fe)->i_alloc_type !=
+                ICBTAG_FLAG_AD_SHORT) {
+               udf_warning(sb, __func__, "metadata inode efe does not have "
+                       "short allocation descriptors!");
+               fe_error = 1;
+               iput(mdata->s_metadata_fe);
+               mdata->s_metadata_fe = NULL;
+       }
+
+       /* mirror file entry */
+       addr.logicalBlockNum = mdata->s_mirror_file_loc;
+       addr.partitionReferenceNum = map->s_partition_num;
+
+       udf_debug("Mirror metadata file location: block = %d part = %d\n",
+                         addr.logicalBlockNum, addr.partitionReferenceNum);
+
+       mdata->s_mirror_fe = udf_iget(sb, addr);
+
+       if (mdata->s_mirror_fe == NULL) {
+               if (fe_error) {
+                       udf_error(sb, __func__, "mirror inode efe not found "
+                       "and metadata inode is missing too, exiting...");
+                       goto error_exit;
+               } else
+                       udf_warning(sb, __func__, "mirror inode efe not found,"
+                                       " but metadata inode is OK");
+       } else if (UDF_I(mdata->s_mirror_fe)->i_alloc_type !=
+                ICBTAG_FLAG_AD_SHORT) {
+               udf_warning(sb, __func__, "mirror inode efe does not have "
+                       "short allocation descriptors!");
+               iput(mdata->s_mirror_fe);
+               mdata->s_mirror_fe = NULL;
+               if (fe_error)
+                       goto error_exit;
+       }
+
+       /*
+        * bitmap file entry
+        * Note:
+        * Load only if bitmap file location differs from 0xFFFFFFFF (DCN-5102)
+       */
+       if (mdata->s_bitmap_file_loc != 0xFFFFFFFF) {
+               addr.logicalBlockNum = mdata->s_bitmap_file_loc;
+               addr.partitionReferenceNum = map->s_partition_num;
+
+               udf_debug("Bitmap file location: block = %d part = %d\n",
+                       addr.logicalBlockNum, addr.partitionReferenceNum);
+
+               mdata->s_bitmap_fe = udf_iget(sb, addr);
+
+               if (mdata->s_bitmap_fe == NULL) {
+                       if (sb->s_flags & MS_RDONLY)
+                               udf_warning(sb, __func__, "bitmap inode efe "
+                                       "not found but it's ok since the disc"
+                                       " is mounted read-only");
+                       else {
+                               udf_error(sb, __func__, "bitmap inode efe not "
+                                       "found and attempted read-write mount");
+                               goto error_exit;
+                       }
+               }
+       }
+
+       udf_debug("udf_load_metadata_files Ok\n");
+
+       return 0;
+
+error_exit:
+       return 1;
 }
 
 static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh,
@@ -1025,10 +1065,9 @@ static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh,
 int udf_compute_nr_groups(struct super_block *sb, u32 partition)
 {
        struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
-       return (map->s_partition_len +
-               (sizeof(struct spaceBitmapDesc) << 3) +
-               (sb->s_blocksize * 8) - 1) /
-               (sb->s_blocksize * 8);
+       return DIV_ROUND_UP(map->s_partition_len +
+                           (sizeof(struct spaceBitmapDesc) << 3),
+                           sb->s_blocksize * 8);
 }
 
 static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index)
@@ -1059,134 +1098,241 @@ static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index)
        return bitmap;
 }
 
-static int udf_load_partdesc(struct super_block *sb, struct buffer_head *bh)
+static int udf_fill_partdesc_info(struct super_block *sb,
+               struct partitionDesc *p, int p_index)
+{
+       struct udf_part_map *map;
+       struct udf_sb_info *sbi = UDF_SB(sb);
+       struct partitionHeaderDesc *phd;
+
+       map = &sbi->s_partmaps[p_index];
+
+       map->s_partition_len = le32_to_cpu(p->partitionLength); /* blocks */
+       map->s_partition_root = le32_to_cpu(p->partitionStartingLocation);
+
+       if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY))
+               map->s_partition_flags |= UDF_PART_FLAG_READ_ONLY;
+       if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_WRITE_ONCE))
+               map->s_partition_flags |= UDF_PART_FLAG_WRITE_ONCE;
+       if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_REWRITABLE))
+               map->s_partition_flags |= UDF_PART_FLAG_REWRITABLE;
+       if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_OVERWRITABLE))
+               map->s_partition_flags |= UDF_PART_FLAG_OVERWRITABLE;
+
+       udf_debug("Partition (%d type %x) starts at physical %d, "
+                 "block length %d\n", p_index,
+                 map->s_partition_type, map->s_partition_root,
+                 map->s_partition_len);
+
+       if (strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR02) &&
+           strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR03))
+               return 0;
+
+       phd = (struct partitionHeaderDesc *)p->partitionContentsUse;
+       if (phd->unallocSpaceTable.extLength) {
+               kernel_lb_addr loc = {
+                       .logicalBlockNum = le32_to_cpu(
+                               phd->unallocSpaceTable.extPosition),
+                       .partitionReferenceNum = p_index,
+               };
+
+               map->s_uspace.s_table = udf_iget(sb, loc);
+               if (!map->s_uspace.s_table) {
+                       udf_debug("cannot load unallocSpaceTable (part %d)\n",
+                                       p_index);
+                       return 1;
+               }
+               map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_TABLE;
+               udf_debug("unallocSpaceTable (part %d) @ %ld\n",
+                               p_index, map->s_uspace.s_table->i_ino);
+       }
+
+       if (phd->unallocSpaceBitmap.extLength) {
+               struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index);
+               if (!bitmap)
+                       return 1;
+               map->s_uspace.s_bitmap = bitmap;
+               bitmap->s_extLength = le32_to_cpu(
+                               phd->unallocSpaceBitmap.extLength);
+               bitmap->s_extPosition = le32_to_cpu(
+                               phd->unallocSpaceBitmap.extPosition);
+               map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP;
+               udf_debug("unallocSpaceBitmap (part %d) @ %d\n", p_index,
+                                               bitmap->s_extPosition);
+       }
+
+       if (phd->partitionIntegrityTable.extLength)
+               udf_debug("partitionIntegrityTable (part %d)\n", p_index);
+
+       if (phd->freedSpaceTable.extLength) {
+               kernel_lb_addr loc = {
+                       .logicalBlockNum = le32_to_cpu(
+                               phd->freedSpaceTable.extPosition),
+                       .partitionReferenceNum = p_index,
+               };
+
+               map->s_fspace.s_table = udf_iget(sb, loc);
+               if (!map->s_fspace.s_table) {
+                       udf_debug("cannot load freedSpaceTable (part %d)\n",
+                               p_index);
+                       return 1;
+               }
+
+               map->s_partition_flags |= UDF_PART_FLAG_FREED_TABLE;
+               udf_debug("freedSpaceTable (part %d) @ %ld\n",
+                               p_index, map->s_fspace.s_table->i_ino);
+       }
+
+       if (phd->freedSpaceBitmap.extLength) {
+               struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index);
+               if (!bitmap)
+                       return 1;
+               map->s_fspace.s_bitmap = bitmap;
+               bitmap->s_extLength = le32_to_cpu(
+                               phd->freedSpaceBitmap.extLength);
+               bitmap->s_extPosition = le32_to_cpu(
+                               phd->freedSpaceBitmap.extPosition);
+               map->s_partition_flags |= UDF_PART_FLAG_FREED_BITMAP;
+               udf_debug("freedSpaceBitmap (part %d) @ %d\n", p_index,
+                                       bitmap->s_extPosition);
+       }
+       return 0;
+}
+
+static int udf_load_vat(struct super_block *sb, int p_index, int type1_index)
+{
+       struct udf_sb_info *sbi = UDF_SB(sb);
+       struct udf_part_map *map = &sbi->s_partmaps[p_index];
+       kernel_lb_addr ino;
+       struct buffer_head *bh = NULL;
+       struct udf_inode_info *vati;
+       uint32_t pos;
+       struct virtualAllocationTable20 *vat20;
+
+       /* VAT file entry is in the last recorded block */
+       ino.partitionReferenceNum = type1_index;
+       ino.logicalBlockNum = sbi->s_last_block - map->s_partition_root;
+       sbi->s_vat_inode = udf_iget(sb, ino);
+       if (!sbi->s_vat_inode)
+               return 1;
+
+       if (map->s_partition_type == UDF_VIRTUAL_MAP15) {
+               map->s_type_specific.s_virtual.s_start_offset = 0;
+               map->s_type_specific.s_virtual.s_num_entries =
+                       (sbi->s_vat_inode->i_size - 36) >> 2;
+       } else if (map->s_partition_type == UDF_VIRTUAL_MAP20) {
+               vati = UDF_I(sbi->s_vat_inode);
+               if (vati->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+                       pos = udf_block_map(sbi->s_vat_inode, 0);
+                       bh = sb_bread(sb, pos);
+                       if (!bh)
+                               return 1;
+                       vat20 = (struct virtualAllocationTable20 *)bh->b_data;
+               } else {
+                       vat20 = (struct virtualAllocationTable20 *)
+                                                       vati->i_ext.i_data;
+               }
+
+               map->s_type_specific.s_virtual.s_start_offset =
+                       le16_to_cpu(vat20->lengthHeader);
+               map->s_type_specific.s_virtual.s_num_entries =
+                       (sbi->s_vat_inode->i_size -
+                               map->s_type_specific.s_virtual.
+                                       s_start_offset) >> 2;
+               brelse(bh);
+       }
+       return 0;
+}
+
+static int udf_load_partdesc(struct super_block *sb, sector_t block)
 {
+       struct buffer_head *bh;
        struct partitionDesc *p;
-       int i;
        struct udf_part_map *map;
-       struct udf_sb_info *sbi;
+       struct udf_sb_info *sbi = UDF_SB(sb);
+       int i, type1_idx;
+       uint16_t partitionNumber;
+       uint16_t ident;
+       int ret = 0;
+
+       bh = udf_read_tagged(sb, block, block, &ident);
+       if (!bh)
+               return 1;
+       if (ident != TAG_IDENT_PD)
+               goto out_bh;
 
        p = (struct partitionDesc *)bh->b_data;
-       sbi = UDF_SB(sb);
+       partitionNumber = le16_to_cpu(p->partitionNumber);
 
+       /* First scan for TYPE1, SPARABLE and METADATA partitions */
        for (i = 0; i < sbi->s_partitions; i++) {
                map = &sbi->s_partmaps[i];
                udf_debug("Searching map: (%d == %d)\n",
-                         map->s_partition_num,
-                         le16_to_cpu(p->partitionNumber));
-               if (map->s_partition_num ==
-                               le16_to_cpu(p->partitionNumber)) {
-                       map->s_partition_len =
-                               le32_to_cpu(p->partitionLength); /* blocks */
-                       map->s_partition_root =
-                               le32_to_cpu(p->partitionStartingLocation);
-                       if (p->accessType ==
-                                       cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY))
-                               map->s_partition_flags |=
-                                               UDF_PART_FLAG_READ_ONLY;
-                       if (p->accessType ==
-                                       cpu_to_le32(PD_ACCESS_TYPE_WRITE_ONCE))
-                               map->s_partition_flags |=
-                                               UDF_PART_FLAG_WRITE_ONCE;
-                       if (p->accessType ==
-                                       cpu_to_le32(PD_ACCESS_TYPE_REWRITABLE))
-                               map->s_partition_flags |=
-                                               UDF_PART_FLAG_REWRITABLE;
-                       if (p->accessType ==
-                                   cpu_to_le32(PD_ACCESS_TYPE_OVERWRITABLE))
-                               map->s_partition_flags |=
-                                               UDF_PART_FLAG_OVERWRITABLE;
-
-                       if (!strcmp(p->partitionContents.ident,
-                                   PD_PARTITION_CONTENTS_NSR02) ||
-                           !strcmp(p->partitionContents.ident,
-                                   PD_PARTITION_CONTENTS_NSR03)) {
-                               struct partitionHeaderDesc *phd;
-
-                               phd = (struct partitionHeaderDesc *)
-                                               (p->partitionContentsUse);
-                               if (phd->unallocSpaceTable.extLength) {
-                                       kernel_lb_addr loc = {
-                                               .logicalBlockNum = le32_to_cpu(phd->unallocSpaceTable.extPosition),
-                                               .partitionReferenceNum = i,
-                                       };
-
-                                       map->s_uspace.s_table =
-                                               udf_iget(sb, loc);
-                                       if (!map->s_uspace.s_table) {
-                                               udf_debug("cannot load unallocSpaceTable (part %d)\n", i);
-                                               return 1;
-                                       }
-                                       map->s_partition_flags |=
-                                               UDF_PART_FLAG_UNALLOC_TABLE;
-                                       udf_debug("unallocSpaceTable (part %d) @ %ld\n",
-                                                 i, map->s_uspace.s_table->i_ino);
-                               }
-                               if (phd->unallocSpaceBitmap.extLength) {
-                                       struct udf_bitmap *bitmap =
-                                               udf_sb_alloc_bitmap(sb, i);
-                                       map->s_uspace.s_bitmap = bitmap;
-                                       if (bitmap != NULL) {
-                                               bitmap->s_extLength =
-                                                       le32_to_cpu(phd->unallocSpaceBitmap.extLength);
-                                               bitmap->s_extPosition =
-                                                       le32_to_cpu(phd->unallocSpaceBitmap.extPosition);
-                                               map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP;
-                                               udf_debug("unallocSpaceBitmap (part %d) @ %d\n",
-                                                         i, bitmap->s_extPosition);
-                                       }
-                               }
-                               if (phd->partitionIntegrityTable.extLength)
-                                       udf_debug("partitionIntegrityTable (part %d)\n", i);
-                               if (phd->freedSpaceTable.extLength) {
-                                       kernel_lb_addr loc = {
-                                               .logicalBlockNum = le32_to_cpu(phd->freedSpaceTable.extPosition),
-                                               .partitionReferenceNum = i,
-                                       };
-
-                                       map->s_fspace.s_table =
-                                               udf_iget(sb, loc);
-                                       if (!map->s_fspace.s_table) {
-                                               udf_debug("cannot load freedSpaceTable (part %d)\n", i);
-                                               return 1;
-                                       }
-                                       map->s_partition_flags |=
-                                               UDF_PART_FLAG_FREED_TABLE;
-                                       udf_debug("freedSpaceTable (part %d) @ %ld\n",
-                                                 i, map->s_fspace.s_table->i_ino);
-                               }
-                               if (phd->freedSpaceBitmap.extLength) {
-                                       struct udf_bitmap *bitmap =
-                                               udf_sb_alloc_bitmap(sb, i);
-                                       map->s_fspace.s_bitmap = bitmap;
-                                       if (bitmap != NULL) {
-                                               bitmap->s_extLength =
-                                                       le32_to_cpu(phd->freedSpaceBitmap.extLength);
-                                               bitmap->s_extPosition =
-                                                       le32_to_cpu(phd->freedSpaceBitmap.extPosition);
-                                               map->s_partition_flags |= UDF_PART_FLAG_FREED_BITMAP;
-                                               udf_debug("freedSpaceBitmap (part %d) @ %d\n",
-                                                         i, bitmap->s_extPosition);
-                                       }
-                               }
-                       }
+                         map->s_partition_num, partitionNumber);
+               if (map->s_partition_num == partitionNumber &&
+                   (map->s_partition_type == UDF_TYPE1_MAP15 ||
+                    map->s_partition_type == UDF_SPARABLE_MAP15))
                        break;
-               }
        }
-       if (i == sbi->s_partitions)
+
+       if (i >= sbi->s_partitions) {
                udf_debug("Partition (%d) not found in partition map\n",
-                         le16_to_cpu(p->partitionNumber));
-       else
-               udf_debug("Partition (%d:%d type %x) starts at physical %d, "
-                         "block length %d\n",
-                         le16_to_cpu(p->partitionNumber), i,
-                         map->s_partition_type,
-                         map->s_partition_root,
-                         map->s_partition_len);
-       return 0;
+                         partitionNumber);
+               goto out_bh;
+       }
+
+       ret = udf_fill_partdesc_info(sb, p, i);
+
+       /*
+        * Now rescan for VIRTUAL or METADATA partitions when SPARABLE and
+        * PHYSICAL partitions are already set up
+        */
+       type1_idx = i;
+       for (i = 0; i < sbi->s_partitions; i++) {
+               map = &sbi->s_partmaps[i];
+
+               if (map->s_partition_num == partitionNumber &&
+                   (map->s_partition_type == UDF_VIRTUAL_MAP15 ||
+                    map->s_partition_type == UDF_VIRTUAL_MAP20 ||
+                    map->s_partition_type == UDF_METADATA_MAP25))
+                       break;
+       }
+
+       if (i >= sbi->s_partitions)
+               goto out_bh;
+
+       ret = udf_fill_partdesc_info(sb, p, i);
+       if (ret)
+               goto out_bh;
+
+       if (map->s_partition_type == UDF_METADATA_MAP25) {
+               ret = udf_load_metadata_files(sb, i);
+               if (ret) {
+                       printk(KERN_ERR "UDF-fs: error loading MetaData "
+                       "partition map %d\n", i);
+                       goto out_bh;
+               }
+       } else {
+               ret = udf_load_vat(sb, i, type1_idx);
+               if (ret)
+                       goto out_bh;
+               /*
+                * Mark filesystem read-only if we have a partition with
+                * virtual map since we don't handle writing to it (we
+                * overwrite blocks instead of relocating them).
+                */
+               sb->s_flags |= MS_RDONLY;
+               printk(KERN_NOTICE "UDF-fs: Filesystem marked read-only "
+                       "because writing to pseudooverwrite partition is "
+                       "not implemented.\n");
+       }
+out_bh:
+       /* In case loading failed, we handle cleanup in udf_fill_super */
+       brelse(bh);
+       return ret;
 }
 
-static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh,
+static int udf_load_logicalvol(struct super_block *sb, sector_t block,
                               kernel_lb_addr *fileset)
 {
        struct logicalVolDesc *lvd;
@@ -1194,12 +1340,21 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh,
        uint8_t type;
        struct udf_sb_info *sbi = UDF_SB(sb);
        struct genericPartitionMap *gpm;
+       uint16_t ident;
+       struct buffer_head *bh;
+       int ret = 0;
 
+       bh = udf_read_tagged(sb, block, block, &ident);
+       if (!bh)
+               return 1;
+       BUG_ON(ident != TAG_IDENT_LVD);
        lvd = (struct logicalVolDesc *)bh->b_data;
 
        i = udf_sb_alloc_partition_maps(sb, le32_to_cpu(lvd->numPartitionMaps));
-       if (i != 0)
-               return i;
+       if (i != 0) {
+               ret = i;
+               goto out_bh;
+       }
 
        for (i = 0, offset = 0;
             i < sbi->s_partitions && offset < le32_to_cpu(lvd->mapTableLength);
@@ -1223,12 +1378,12 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh,
                                u16 suf =
                                        le16_to_cpu(((__le16 *)upm2->partIdent.
                                                        identSuffix)[0]);
-                               if (suf == 0x0150) {
+                               if (suf < 0x0200) {
                                        map->s_partition_type =
                                                        UDF_VIRTUAL_MAP15;
                                        map->s_partition_func =
                                                        udf_get_pblock_virt15;
-                               } else if (suf == 0x0200) {
+                               } else {
                                        map->s_partition_type =
                                                        UDF_VIRTUAL_MAP20;
                                        map->s_partition_func =
@@ -1238,7 +1393,6 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh,
                                                UDF_ID_SPARABLE,
                                                strlen(UDF_ID_SPARABLE))) {
                                uint32_t loc;
-                               uint16_t ident;
                                struct sparingTable *st;
                                struct sparablePartitionMap *spm =
                                        (struct sparablePartitionMap *)gpm;
@@ -1256,22 +1410,64 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh,
                                        map->s_type_specific.s_sparing.
                                                        s_spar_map[j] = bh2;
 
-                                       if (bh2 != NULL) {
-                                               st = (struct sparingTable *)
-                                                               bh2->b_data;
-                                               if (ident != 0 || strncmp(
-                                                       st->sparingIdent.ident,
-                                                       UDF_ID_SPARING,
-                                                       strlen(UDF_ID_SPARING))) {
-                                                       brelse(bh2);
-                                                       map->s_type_specific.
-                                                               s_sparing.
-                                                               s_spar_map[j] =
-                                                                       NULL;
-                                               }
+                                       if (bh2 == NULL)
+                                               continue;
+
+                                       st = (struct sparingTable *)bh2->b_data;
+                                       if (ident != 0 || strncmp(
+                                               st->sparingIdent.ident,
+                                               UDF_ID_SPARING,
+                                               strlen(UDF_ID_SPARING))) {
+                                               brelse(bh2);
+                                               map->s_type_specific.s_sparing.
+                                                       s_spar_map[j] = NULL;
                                        }
                                }
                                map->s_partition_func = udf_get_pblock_spar15;
+                       } else if (!strncmp(upm2->partIdent.ident,
+                                               UDF_ID_METADATA,
+                                               strlen(UDF_ID_METADATA))) {
+                               struct udf_meta_data *mdata =
+                                       &map->s_type_specific.s_metadata;
+                               struct metadataPartitionMap *mdm =
+                                               (struct metadataPartitionMap *)
+                                               &(lvd->partitionMaps[offset]);
+                               udf_debug("Parsing Logical vol part %d "
+                                       "type %d  id=%s\n", i, type,
+                                       UDF_ID_METADATA);
+
+                               map->s_partition_type = UDF_METADATA_MAP25;
+                               map->s_partition_func = udf_get_pblock_meta25;
+
+                               mdata->s_meta_file_loc   =
+                                       le32_to_cpu(mdm->metadataFileLoc);
+                               mdata->s_mirror_file_loc =
+                                       le32_to_cpu(mdm->metadataMirrorFileLoc);
+                               mdata->s_bitmap_file_loc =
+                                       le32_to_cpu(mdm->metadataBitmapFileLoc);
+                               mdata->s_alloc_unit_size =
+                                       le32_to_cpu(mdm->allocUnitSize);
+                               mdata->s_align_unit_size =
+                                       le16_to_cpu(mdm->alignUnitSize);
+                               mdata->s_dup_md_flag     =
+                                       mdm->flags & 0x01;
+
+                               udf_debug("Metadata Ident suffix=0x%x\n",
+                                       (le16_to_cpu(
+                                        ((__le16 *)
+                                             mdm->partIdent.identSuffix)[0])));
+                               udf_debug("Metadata part num=%d\n",
+                                       le16_to_cpu(mdm->partitionNum));
+                               udf_debug("Metadata part alloc unit size=%d\n",
+                                       le32_to_cpu(mdm->allocUnitSize));
+                               udf_debug("Metadata file loc=%d\n",
+                                       le32_to_cpu(mdm->metadataFileLoc));
+                               udf_debug("Mirror file loc=%d\n",
+                                      le32_to_cpu(mdm->metadataMirrorFileLoc));
+                               udf_debug("Bitmap file loc=%d\n",
+                                      le32_to_cpu(mdm->metadataBitmapFileLoc));
+                               udf_debug("Duplicate Flag: %d %d\n",
+                                       mdata->s_dup_md_flag, mdm->flags);
                        } else {
                                udf_debug("Unknown ident: %s\n",
                                          upm2->partIdent.ident);
@@ -1296,7 +1492,9 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh,
        if (lvd->integritySeqExt.extLength)
                udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt));
 
-       return 0;
+out_bh:
+       brelse(bh);
+       return ret;
 }
 
 /*
@@ -1345,7 +1543,7 @@ static void udf_load_logicalvolint(struct super_block *sb, kernel_extent_ad loc)
  *     July 1, 1997 - Andrew E. Mileski
  *     Written, tested, and released.
  */
-static int udf_process_sequence(struct super_block *sb, long block,
+static noinline int udf_process_sequence(struct super_block *sb, long block,
                                long lastblock, kernel_lb_addr *fileset)
 {
        struct buffer_head *bh = NULL;
@@ -1354,19 +1552,25 @@ static int udf_process_sequence(struct super_block *sb, long block,
        struct generic_desc *gd;
        struct volDescPtr *vdp;
        int done = 0;
-       int i, j;
        uint32_t vdsn;
        uint16_t ident;
        long next_s = 0, next_e = 0;
 
        memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH);
 
-       /* Read the main descriptor sequence */
+       /*
+        * Read the main descriptor sequence and find which descriptors
+        * are in it.
+        */
        for (; (!done && block <= lastblock); block++) {
 
                bh = udf_read_tagged(sb, block, block, &ident);
-               if (!bh)
-                       break;
+               if (!bh) {
+                       printk(KERN_ERR "udf: Block %Lu of volume descriptor "
+                              "sequence is corrupted or we could not read "
+                              "it.\n", (unsigned long long)block);
+                       return 1;
+               }
 
                /* Process each descriptor (ISO 13346 3/8.3-8.4) */
                gd = (struct generic_desc *)bh->b_data;
@@ -1432,41 +1636,31 @@ static int udf_process_sequence(struct super_block *sb, long block,
                }
                brelse(bh);
        }
-       for (i = 0; i < VDS_POS_LENGTH; i++) {
-               if (vds[i].block) {
-                       bh = udf_read_tagged(sb, vds[i].block, vds[i].block,
-                                            &ident);
-
-                       if (i == VDS_POS_PRIMARY_VOL_DESC) {
-                               udf_load_pvoldesc(sb, bh);
-                       } else if (i == VDS_POS_LOGICAL_VOL_DESC) {
-                               if (udf_load_logicalvol(sb, bh, fileset)) {
-                                       brelse(bh);
-                                       return 1;
-                               }
-                       } else if (i == VDS_POS_PARTITION_DESC) {
-                               struct buffer_head *bh2 = NULL;
-                               if (udf_load_partdesc(sb, bh)) {
-                                       brelse(bh);
-                                       return 1;
-                               }
-                               for (j = vds[i].block + 1;
-                                    j <  vds[VDS_POS_TERMINATING_DESC].block;
-                                    j++) {
-                                       bh2 = udf_read_tagged(sb, j, j, &ident);
-                                       gd = (struct generic_desc *)bh2->b_data;
-                                       if (ident == TAG_IDENT_PD)
-                                               if (udf_load_partdesc(sb,
-                                                                     bh2)) {
-                                                       brelse(bh);
-                                                       brelse(bh2);
-                                                       return 1;
-                                               }
-                                       brelse(bh2);
-                               }
-                       }
-                       brelse(bh);
-               }
+       /*
+        * Now read interesting descriptors again and process them
+        * in a suitable order
+        */
+       if (!vds[VDS_POS_PRIMARY_VOL_DESC].block) {
+               printk(KERN_ERR "udf: Primary Volume Descriptor not found!\n");
+               return 1;
+       }
+       if (udf_load_pvoldesc(sb, vds[VDS_POS_PRIMARY_VOL_DESC].block))
+               return 1;
+
+       if (vds[VDS_POS_LOGICAL_VOL_DESC].block && udf_load_logicalvol(sb,
+           vds[VDS_POS_LOGICAL_VOL_DESC].block, fileset))
+               return 1;
+
+       if (vds[VDS_POS_PARTITION_DESC].block) {
+               /*
+                * We rescan the whole descriptor sequence to find
+                * partition descriptor blocks and process them.
+                */
+               for (block = vds[VDS_POS_PARTITION_DESC].block;
+                    block < vds[VDS_POS_TERMINATING_DESC].block;
+                    block++)
+                       if (udf_load_partdesc(sb, block))
+                               return 1;
        }
 
        return 0;
@@ -1478,6 +1672,7 @@ static int udf_process_sequence(struct super_block *sb, long block,
 static int udf_check_valid(struct super_block *sb, int novrs, int silent)
 {
        long block;
+       struct udf_sb_info *sbi = UDF_SB(sb);
 
        if (novrs) {
                udf_debug("Validity check skipped because of novrs option\n");
@@ -1485,27 +1680,22 @@ static int udf_check_valid(struct super_block *sb, int novrs, int silent)
        }
        /* Check that it is NSR02 compliant */
        /* Process any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */
-       else {
-               block = udf_vrs(sb, silent);
-               if (block == -1) {
-                       struct udf_sb_info *sbi = UDF_SB(sb);
-                       udf_debug("Failed to read byte 32768. Assuming open "
-                                 "disc. Skipping validity check\n");
-                       if (!sbi->s_last_block)
-                               sbi->s_last_block = udf_get_last_block(sb);
-                       return 0;
-               } else
-                       return !block;
-       }
+       block = udf_vrs(sb, silent);
+       if (block == -1)
+               udf_debug("Failed to read byte 32768. Assuming open "
+                         "disc. Skipping validity check\n");
+       if (block && !sbi->s_last_block)
+               sbi->s_last_block = udf_get_last_block(sb);
+       return !block;
 }
 
-static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
+static int udf_load_sequence(struct super_block *sb, kernel_lb_addr *fileset)
 {
        struct anchorVolDescPtr *anchor;
        uint16_t ident;
        struct buffer_head *bh;
        long main_s, main_e, reserve_s, reserve_e;
-       int i, j;
+       int i;
        struct udf_sb_info *sbi;
 
        if (!sb)
@@ -1515,6 +1705,7 @@ static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
        for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) {
                if (!sbi->s_anchor[i])
                        continue;
+
                bh = udf_read_tagged(sb, sbi->s_anchor[i], sbi->s_anchor[i],
                                     &ident);
                if (!bh)
@@ -1553,76 +1744,6 @@ static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
        }
        udf_debug("Using anchor in block %d\n", sbi->s_anchor[i]);
 
-       for (i = 0; i < sbi->s_partitions; i++) {
-               kernel_lb_addr uninitialized_var(ino);
-               struct udf_part_map *map = &sbi->s_partmaps[i];
-               switch (map->s_partition_type) {
-               case UDF_VIRTUAL_MAP15:
-               case UDF_VIRTUAL_MAP20:
-                       if (!sbi->s_last_block) {
-                               sbi->s_last_block = udf_get_last_block(sb);
-                               udf_find_anchor(sb);
-                       }
-
-                       if (!sbi->s_last_block) {
-                               udf_debug("Unable to determine Lastblock (For "
-                                         "Virtual Partition)\n");
-                               return 1;
-                       }
-
-                       for (j = 0; j < sbi->s_partitions; j++) {
-                               struct udf_part_map *map2 = &sbi->s_partmaps[j];
-                               if (j != i &&
-                                   map->s_volumeseqnum ==
-                                               map2->s_volumeseqnum &&
-                                   map->s_partition_num ==
-                                               map2->s_partition_num) {
-                                       ino.partitionReferenceNum = j;
-                                       ino.logicalBlockNum =
-                                               sbi->s_last_block -
-                                                       map2->s_partition_root;
-                                       break;
-                               }
-                       }
-
-                       if (j == sbi->s_partitions)
-                               return 1;
-
-                       sbi->s_vat_inode = udf_iget(sb, ino);
-                       if (!sbi->s_vat_inode)
-                               return 1;
-
-                       if (map->s_partition_type == UDF_VIRTUAL_MAP15) {
-                               map->s_type_specific.s_virtual.s_start_offset =
-                                       udf_ext0_offset(sbi->s_vat_inode);
-                               map->s_type_specific.s_virtual.s_num_entries =
-                                       (sbi->s_vat_inode->i_size - 36) >> 2;
-                       } else if (map->s_partition_type == UDF_VIRTUAL_MAP20) {
-                               uint32_t pos;
-                               struct virtualAllocationTable20 *vat20;
-
-                               pos = udf_block_map(sbi->s_vat_inode, 0);
-                               bh = sb_bread(sb, pos);
-                               if (!bh)
-                                       return 1;
-                               vat20 = (struct virtualAllocationTable20 *)
-                                       bh->b_data +
-                                       udf_ext0_offset(sbi->s_vat_inode);
-                               map->s_type_specific.s_virtual.s_start_offset =
-                                       le16_to_cpu(vat20->lengthHeader) +
-                                       udf_ext0_offset(sbi->s_vat_inode);
-                               map->s_type_specific.s_virtual.s_num_entries =
-                                       (sbi->s_vat_inode->i_size -
-                                        map->s_type_specific.s_virtual.
-                                                       s_start_offset) >> 2;
-                               brelse(bh);
-                       }
-                       map->s_partition_root = udf_get_pblock(sb, 0, i, 0);
-                       map->s_partition_len =
-                               sbi->s_partmaps[ino.partitionReferenceNum].
-                                                               s_partition_len;
-               }
-       }
        return 0;
 }
 
@@ -1630,65 +1751,61 @@ static void udf_open_lvid(struct super_block *sb)
 {
        struct udf_sb_info *sbi = UDF_SB(sb);
        struct buffer_head *bh = sbi->s_lvid_bh;
-       if (bh) {
-               kernel_timestamp cpu_time;
-               struct logicalVolIntegrityDesc *lvid =
-                               (struct logicalVolIntegrityDesc *)bh->b_data;
-               struct logicalVolIntegrityDescImpUse *lvidiu =
-                                                       udf_sb_lvidiu(sbi);
+       struct logicalVolIntegrityDesc *lvid;
+       struct logicalVolIntegrityDescImpUse *lvidiu;
+       if (!bh)
+               return;
 
-               lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
-               lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
-               if (udf_time_to_stamp(&cpu_time, CURRENT_TIME))
-                       lvid->recordingDateAndTime = cpu_to_lets(cpu_time);
-               lvid->integrityType = LVID_INTEGRITY_TYPE_OPEN;
+       lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
+       lvidiu = udf_sb_lvidiu(sbi);
 
-               lvid->descTag.descCRC = cpu_to_le16(
-                       udf_crc((char *)lvid + sizeof(tag),
-                               le16_to_cpu(lvid->descTag.descCRCLength),
-                               0));
+       lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
+       lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
+       udf_time_to_disk_stamp(&lvid->recordingDateAndTime,
+                               CURRENT_TIME);
+       lvid->integrityType = LVID_INTEGRITY_TYPE_OPEN;
 
-               lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag);
-               mark_buffer_dirty(bh);
-       }
+       lvid->descTag.descCRC = cpu_to_le16(
+               crc_itu_t(0, (char *)lvid + sizeof(tag),
+                       le16_to_cpu(lvid->descTag.descCRCLength)));
+
+       lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag);
+       mark_buffer_dirty(bh);
 }
 
 static void udf_close_lvid(struct super_block *sb)
 {
-       kernel_timestamp cpu_time;
        struct udf_sb_info *sbi = UDF_SB(sb);
        struct buffer_head *bh = sbi->s_lvid_bh;
        struct logicalVolIntegrityDesc *lvid;
+       struct logicalVolIntegrityDescImpUse *lvidiu;
 
        if (!bh)
                return;
 
        lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
 
-       if (lvid->integrityType == LVID_INTEGRITY_TYPE_OPEN) {
-               struct logicalVolIntegrityDescImpUse *lvidiu =
-                                                       udf_sb_lvidiu(sbi);
-               lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
-               lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
-               if (udf_time_to_stamp(&cpu_time, CURRENT_TIME))
-                       lvid->recordingDateAndTime = cpu_to_lets(cpu_time);
-               if (UDF_MAX_WRITE_VERSION > le16_to_cpu(lvidiu->maxUDFWriteRev))
-                       lvidiu->maxUDFWriteRev =
-                                       cpu_to_le16(UDF_MAX_WRITE_VERSION);
-               if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFReadRev))
-                       lvidiu->minUDFReadRev = cpu_to_le16(sbi->s_udfrev);
-               if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFWriteRev))
-                       lvidiu->minUDFWriteRev = cpu_to_le16(sbi->s_udfrev);
-               lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE);
-
-               lvid->descTag.descCRC = cpu_to_le16(
-                       udf_crc((char *)lvid + sizeof(tag),
-                               le16_to_cpu(lvid->descTag.descCRCLength),
-                               0));
-
-               lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag);
-               mark_buffer_dirty(bh);
-       }
+       if (lvid->integrityType != LVID_INTEGRITY_TYPE_OPEN)
+               return;
+
+       lvidiu = udf_sb_lvidiu(sbi);
+       lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
+       lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
+       udf_time_to_disk_stamp(&lvid->recordingDateAndTime, CURRENT_TIME);
+       if (UDF_MAX_WRITE_VERSION > le16_to_cpu(lvidiu->maxUDFWriteRev))
+               lvidiu->maxUDFWriteRev = cpu_to_le16(UDF_MAX_WRITE_VERSION);
+       if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFReadRev))
+               lvidiu->minUDFReadRev = cpu_to_le16(sbi->s_udfrev);
+       if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFWriteRev))
+               lvidiu->minUDFWriteRev = cpu_to_le16(sbi->s_udfrev);
+       lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE);
+
+       lvid->descTag.descCRC = cpu_to_le16(
+                       crc_itu_t(0, (char *)lvid + sizeof(tag),
+                               le16_to_cpu(lvid->descTag.descCRCLength)));
+
+       lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag);
+       mark_buffer_dirty(bh);
 }
 
 static void udf_sb_free_bitmap(struct udf_bitmap *bitmap)
@@ -1708,22 +1825,35 @@ static void udf_sb_free_bitmap(struct udf_bitmap *bitmap)
                vfree(bitmap);
 }
 
-/*
- * udf_read_super
- *
- * PURPOSE
- *     Complete the specified super block.
- *
- * PRE-CONDITIONS
- *     sb                      Pointer to superblock to complete - never NULL.
- *     sb->s_dev               Device to read suberblock from.
- *     options                 Pointer to mount options.
- *     silent                  Silent flag.
- *
- * HISTORY
- *     July 1, 1997 - Andrew E. Mileski
- *     Written, tested, and released.
- */
+static void udf_free_partition(struct udf_part_map *map)
+{
+       int i;
+       struct udf_meta_data *mdata;
+
+       if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE)
+               iput(map->s_uspace.s_table);
+       if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE)
+               iput(map->s_fspace.s_table);
+       if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP)
+               udf_sb_free_bitmap(map->s_uspace.s_bitmap);
+       if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP)
+               udf_sb_free_bitmap(map->s_fspace.s_bitmap);
+       if (map->s_partition_type == UDF_SPARABLE_MAP15)
+               for (i = 0; i < 4; i++)
+                       brelse(map->s_type_specific.s_sparing.s_spar_map[i]);
+       else if (map->s_partition_type == UDF_METADATA_MAP25) {
+               mdata = &map->s_type_specific.s_metadata;
+               iput(mdata->s_metadata_fe);
+               mdata->s_metadata_fe = NULL;
+
+               iput(mdata->s_mirror_fe);
+               mdata->s_mirror_fe = NULL;
+
+               iput(mdata->s_bitmap_fe);
+               mdata->s_bitmap_fe = NULL;
+       }
+}
+
 static int udf_fill_super(struct super_block *sb, void *options, int silent)
 {
        int i;
@@ -1776,8 +1906,11 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        sbi->s_nls_map = uopt.nls_map;
 
        /* Set the block size for all transfers */
-       if (!udf_set_blocksize(sb, uopt.blocksize))
+       if (!sb_min_blocksize(sb, uopt.blocksize)) {
+               udf_debug("Bad block size (%d)\n", uopt.blocksize);
+               printk(KERN_ERR "udf: bad block size (%d)\n", uopt.blocksize);
                goto error_out;
+       }
 
        if (uopt.session == 0xFFFFFFFF)
                sbi->s_session = udf_get_last_session(sb);
@@ -1789,7 +1922,6 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        sbi->s_last_block = uopt.lastblock;
        sbi->s_anchor[0] = sbi->s_anchor[1] = 0;
        sbi->s_anchor[2] = uopt.anchor;
-       sbi->s_anchor[3] = 256;
 
        if (udf_check_valid(sb, uopt.novrs, silent)) {
                /* read volume recognition sequences */
@@ -1806,7 +1938,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        sb->s_magic = UDF_SUPER_MAGIC;
        sb->s_time_gran = 1000;
 
-       if (udf_load_partition(sb, &fileset)) {
+       if (udf_load_sequence(sb, &fileset)) {
                printk(KERN_WARNING "UDF-fs: No partition found (1)\n");
                goto error_out;
        }
@@ -1856,12 +1988,12 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
        }
 
        if (!silent) {
-               kernel_timestamp ts;
-               udf_time_to_stamp(&ts, sbi->s_record_time);
+               timestamp ts;
+               udf_time_to_disk_stamp(&ts, sbi->s_record_time);
                udf_info("UDF: Mounting volume '%s', "
                         "timestamp %04u/%02u/%02u %02u:%02u (%x)\n",
-                        sbi->s_volume_ident, ts.year, ts.month, ts.day,
-                        ts.hour, ts.minute, ts.typeAndTimezone);
+                        sbi->s_volume_ident, le16_to_cpu(ts.year), ts.month, ts.day,
+                        ts.hour, ts.minute, le16_to_cpu(ts.typeAndTimezone));
        }
        if (!(sb->s_flags & MS_RDONLY))
                udf_open_lvid(sb);
@@ -1890,21 +2022,9 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
 error_out:
        if (sbi->s_vat_inode)
                iput(sbi->s_vat_inode);
-       if (sbi->s_partitions) {
-               struct udf_part_map *map = &sbi->s_partmaps[sbi->s_partition];
-               if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE)
-                       iput(map->s_uspace.s_table);
-               if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE)
-                       iput(map->s_fspace.s_table);
-               if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP)
-                       udf_sb_free_bitmap(map->s_uspace.s_bitmap);
-               if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP)
-                       udf_sb_free_bitmap(map->s_fspace.s_bitmap);
-               if (map->s_partition_type == UDF_SPARABLE_MAP15)
-                       for (i = 0; i < 4; i++)
-                               brelse(map->s_type_specific.s_sparing.
-                                               s_spar_map[i]);
-       }
+       if (sbi->s_partitions)
+               for (i = 0; i < sbi->s_partitions; i++)
+                       udf_free_partition(&sbi->s_partmaps[i]);
 #ifdef CONFIG_UDF_NLS
        if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
                unload_nls(sbi->s_nls_map);
@@ -1920,8 +2040,8 @@ error_out:
        return -EINVAL;
 }
 
-void udf_error(struct super_block *sb, const char *function,
-              const char *fmt, ...)
+static void udf_error(struct super_block *sb, const char *function,
+                     const char *fmt, ...)
 {
        va_list args;
 
@@ -1948,19 +2068,6 @@ void udf_warning(struct super_block *sb, const char *function,
               sb->s_id, function, error_buf);
 }
 
-/*
- * udf_put_super
- *
- * PURPOSE
- *     Prepare for destruction of the superblock.
- *
- * DESCRIPTION
- *     Called before the filesystem is unmounted.
- *
- * HISTORY
- *     July 1, 1997 - Andrew E. Mileski
- *     Written, tested, and released.
- */
 static void udf_put_super(struct super_block *sb)
 {
        int i;
@@ -1969,21 +2076,9 @@ static void udf_put_super(struct super_block *sb)
        sbi = UDF_SB(sb);
        if (sbi->s_vat_inode)
                iput(sbi->s_vat_inode);
-       if (sbi->s_partitions) {
-               struct udf_part_map *map = &sbi->s_partmaps[sbi->s_partition];
-               if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE)
-                       iput(map->s_uspace.s_table);
-               if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE)
-                       iput(map->s_fspace.s_table);
-               if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP)
-                       udf_sb_free_bitmap(map->s_uspace.s_bitmap);
-               if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP)
-                       udf_sb_free_bitmap(map->s_fspace.s_bitmap);
-               if (map->s_partition_type == UDF_SPARABLE_MAP15)
-                       for (i = 0; i < 4; i++)
-                               brelse(map->s_type_specific.s_sparing.
-                                               s_spar_map[i]);
-       }
+       if (sbi->s_partitions)
+               for (i = 0; i < sbi->s_partitions; i++)
+                       udf_free_partition(&sbi->s_partmaps[i]);
 #ifdef CONFIG_UDF_NLS
        if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
                unload_nls(sbi->s_nls_map);
@@ -1996,19 +2091,6 @@ static void udf_put_super(struct super_block *sb)
        sb->s_fs_info = NULL;
 }
 
-/*
- * udf_stat_fs
- *
- * PURPOSE
- *     Return info about the filesystem.
- *
- * DESCRIPTION
- *     Called by sys_statfs()
- *
- * HISTORY
- *     July 1, 1997 - Andrew E. Mileski
- *     Written, tested, and released.
- */
 static int udf_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
@@ -2035,10 +2117,6 @@ static int udf_statfs(struct dentry *dentry, struct kstatfs *buf)
        return 0;
 }
 
-static unsigned char udf_bitmap_lookup[16] = {
-       0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
-};
-
 static unsigned int udf_count_free_bitmap(struct super_block *sb,
                                          struct udf_bitmap *bitmap)
 {
@@ -2048,7 +2126,6 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb,
        int block = 0, newblock;
        kernel_lb_addr loc;
        uint32_t bytes;
-       uint8_t value;
        uint8_t *ptr;
        uint16_t ident;
        struct spaceBitmapDesc *bm;
@@ -2074,13 +2151,10 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb,
        ptr = (uint8_t *)bh->b_data;
 
        while (bytes > 0) {
-               while ((bytes > 0) && (index < sb->s_blocksize)) {
-                       value = ptr[index];
-                       accum += udf_bitmap_lookup[value & 0x0f];
-                       accum += udf_bitmap_lookup[value >> 4];
-                       index++;
-                       bytes--;
-               }
+               u32 cur_bytes = min_t(u32, bytes, sb->s_blocksize - index);
+               accum += bitmap_weight((const unsigned long *)(ptr + index),
+                                       cur_bytes * 8);
+               bytes -= cur_bytes;
                if (bytes) {
                        brelse(bh);
                        newblock = udf_get_lb_pblock(sb, loc, ++block);
index 6ec9922..c3265e1 100644 (file)
@@ -23,7 +23,6 @@
 #include <asm/uaccess.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
-#include <linux/udf_fs.h>
 #include <linux/time.h>
 #include <linux/mm.h>
 #include <linux/stat.h>
index fe61be1..65e19b4 100644 (file)
@@ -22,7 +22,6 @@
 #include "udfdecl.h"
 #include <linux/fs.h>
 #include <linux/mm.h>
-#include <linux/udf_fs.h>
 #include <linux/buffer_head.h>
 
 #include "udf_i.h"
@@ -180,6 +179,24 @@ void udf_discard_prealloc(struct inode *inode)
        brelse(epos.bh);
 }
 
+static void udf_update_alloc_ext_desc(struct inode *inode,
+                                     struct extent_position *epos,
+                                     u32 lenalloc)
+{
+       struct super_block *sb = inode->i_sb;
+       struct udf_sb_info *sbi = UDF_SB(sb);
+
+       struct allocExtDesc *aed = (struct allocExtDesc *) (epos->bh->b_data);
+       int len = sizeof(struct allocExtDesc);
+
+       aed->lengthAllocDescs = cpu_to_le32(lenalloc);
+       if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || sbi->s_udfrev >= 0x0201)
+               len += lenalloc;
+
+       udf_update_tag(epos->bh->b_data, len);
+       mark_buffer_dirty_inode(epos->bh, inode);
+}
+
 void udf_truncate_extents(struct inode *inode)
 {
        struct extent_position epos;
@@ -187,7 +204,6 @@ void udf_truncate_extents(struct inode *inode)
        uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc;
        int8_t etype;
        struct super_block *sb = inode->i_sb;
-       struct udf_sb_info *sbi = UDF_SB(sb);
        sector_t first_block = inode->i_size >> sb->s_blocksize_bits, offset;
        loff_t byte_offset;
        int adsize;
@@ -224,35 +240,15 @@ void udf_truncate_extents(struct inode *inode)
                                if (indirect_ext_len) {
                                        /* We managed to free all extents in the
                                         * indirect extent - free it too */
-                                       if (!epos.bh)
-                                               BUG();
+                                       BUG_ON(!epos.bh);
                                        udf_free_blocks(sb, inode, epos.block,
                                                        0, indirect_ext_len);
-                               } else {
-                                       if (!epos.bh) {
-                                               iinfo->i_lenAlloc =
-                                                               lenalloc;
-                                               mark_inode_dirty(inode);
-                                       } else {
-                                               struct allocExtDesc *aed =
-                                                       (struct allocExtDesc *)
-                                                       (epos.bh->b_data);
-                                               int len =
-                                                   sizeof(struct allocExtDesc);
-
-                                               aed->lengthAllocDescs =
-                                                   cpu_to_le32(lenalloc);
-                                               if (!UDF_QUERY_FLAG(sb,
-                                                       UDF_FLAG_STRICT) ||
-                                                   sbi->s_udfrev >= 0x0201)
-                                                       len += lenalloc;
-
-                                               udf_update_tag(epos.bh->b_data,
-                                                               len);
-                                               mark_buffer_dirty_inode(
-                                                               epos.bh, inode);
-                                       }
-                               }
+                               } else if (!epos.bh) {
+                                       iinfo->i_lenAlloc = lenalloc;
+                                       mark_inode_dirty(inode);
+                               } else
+                                       udf_update_alloc_ext_desc(inode,
+                                                       &epos, lenalloc);
                                brelse(epos.bh);
                                epos.offset = sizeof(struct allocExtDesc);
                                epos.block = eloc;
@@ -272,29 +268,14 @@ void udf_truncate_extents(struct inode *inode)
                }
 
                if (indirect_ext_len) {
-                       if (!epos.bh)
-                               BUG();
+                       BUG_ON(!epos.bh);
                        udf_free_blocks(sb, inode, epos.block, 0,
                                        indirect_ext_len);
-               } else {
-                       if (!epos.bh) {
-                               iinfo->i_lenAlloc = lenalloc;
-                               mark_inode_dirty(inode);
-                       } else {
-                               struct allocExtDesc *aed =
-                                   (struct allocExtDesc *)(epos.bh->b_data);
-                               aed->lengthAllocDescs = cpu_to_le32(lenalloc);
-                               if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) ||
-                                   sbi->s_udfrev >= 0x0201)
-                                       udf_update_tag(epos.bh->b_data,
-                                               lenalloc +
-                                               sizeof(struct allocExtDesc));
-                               else
-                                       udf_update_tag(epos.bh->b_data,
-                                               sizeof(struct allocExtDesc));
-                               mark_buffer_dirty_inode(epos.bh, inode);
-                       }
-               }
+               } else if (!epos.bh) {
+                       iinfo->i_lenAlloc = lenalloc;
+                       mark_inode_dirty(inode);
+               } else
+                       udf_update_alloc_ext_desc(inode, &epos, lenalloc);
        } else if (inode->i_size) {
                if (byte_offset) {
                        kernel_long_ad extent;
index ccc52f1..4f86b1d 100644 (file)
@@ -1,10 +1,32 @@
-#ifndef __LINUX_UDF_I_H
-#define __LINUX_UDF_I_H
+#ifndef _UDF_I_H
+#define _UDF_I_H
+
+struct udf_inode_info {
+       struct timespec         i_crtime;
+       /* Physical address of inode */
+       kernel_lb_addr          i_location;
+       __u64                   i_unique;
+       __u32                   i_lenEAttr;
+       __u32                   i_lenAlloc;
+       __u64                   i_lenExtents;
+       __u32                   i_next_alloc_block;
+       __u32                   i_next_alloc_goal;
+       unsigned                i_alloc_type : 3;
+       unsigned                i_efe : 1;      /* extendedFileEntry */
+       unsigned                i_use : 1;      /* unallocSpaceEntry */
+       unsigned                i_strat4096 : 1;
+       unsigned                reserved : 26;
+       union {
+               short_ad        *i_sad;
+               long_ad         *i_lad;
+               __u8            *i_data;
+       } i_ext;
+       struct inode vfs_inode;
+};
 
-#include <linux/udf_fs_i.h>
 static inline struct udf_inode_info *UDF_I(struct inode *inode)
 {
        return list_entry(inode, struct udf_inode_info, vfs_inode);
 }
 
-#endif /* !defined(_LINUX_UDF_I_H) */
+#endif /* _UDF_I_H) */
index 737d1c6..1c1c514 100644 (file)
@@ -1,10 +1,12 @@
 #ifndef __LINUX_UDF_SB_H
 #define __LINUX_UDF_SB_H
 
+#include <linux/mutex.h>
+
 /* Since UDF 2.01 is ISO 13346 based... */
 #define UDF_SUPER_MAGIC                        0x15013346
 
-#define UDF_MAX_READ_VERSION           0x0201
+#define UDF_MAX_READ_VERSION           0x0250
 #define UDF_MAX_WRITE_VERSION          0x0201
 
 #define UDF_FLAG_USE_EXTENDED_FE       0
 #define UDF_PART_FLAG_REWRITABLE       0x0040
 #define UDF_PART_FLAG_OVERWRITABLE     0x0080
 
+#define UDF_MAX_BLOCK_LOADED   8
+
+#define UDF_TYPE1_MAP15                        0x1511U
+#define UDF_VIRTUAL_MAP15              0x1512U
+#define UDF_VIRTUAL_MAP20              0x2012U
+#define UDF_SPARABLE_MAP15             0x1522U
+#define UDF_METADATA_MAP25             0x2511U
+
+#pragma pack(1) /* XXX(hch): Why?  This file just defines in-core structures */
+
+struct udf_meta_data {
+       __u32   s_meta_file_loc;
+       __u32   s_mirror_file_loc;
+       __u32   s_bitmap_file_loc;
+       __u32   s_alloc_unit_size;
+       __u16   s_align_unit_size;
+       __u8    s_dup_md_flag;
+       struct inode *s_metadata_fe;
+       struct inode *s_mirror_fe;
+       struct inode *s_bitmap_fe;
+};
+
+struct udf_sparing_data {
+       __u16   s_packet_len;
+       struct buffer_head *s_spar_map[4];
+};
+
+struct udf_virtual_data {
+       __u32   s_num_entries;
+       __u16   s_start_offset;
+};
+
+struct udf_bitmap {
+       __u32                   s_extLength;
+       __u32                   s_extPosition;
+       __u16                   s_nr_groups;
+       struct buffer_head      **s_block_bitmap;
+};
+
+struct udf_part_map {
+       union {
+               struct udf_bitmap       *s_bitmap;
+               struct inode            *s_table;
+       } s_uspace;
+       union {
+               struct udf_bitmap       *s_bitmap;
+               struct inode            *s_table;
+       } s_fspace;
+       __u32   s_partition_root;
+       __u32   s_partition_len;
+       __u16   s_partition_type;
+       __u16   s_partition_num;
+       union {
+               struct udf_sparing_data s_sparing;
+               struct udf_virtual_data s_virtual;
+               struct udf_meta_data s_metadata;
+       } s_type_specific;
+       __u32   (*s_partition_func)(struct super_block *, __u32, __u16, __u32);
+       __u16   s_volumeseqnum;
+       __u16   s_partition_flags;
+};
+
+#pragma pack()
+
+struct udf_sb_info {
+       struct udf_part_map     *s_partmaps;
+       __u8                    s_volume_ident[32];
+
+       /* Overall info */
+       __u16                   s_partitions;
+       __u16                   s_partition;
+
+       /* Sector headers */
+       __s32                   s_session;
+       __u32                   s_anchor[3];
+       __u32                   s_last_block;
+
+       struct buffer_head      *s_lvid_bh;
+
+       /* Default permissions */
+       mode_t                  s_umask;
+       gid_t                   s_gid;
+       uid_t                   s_uid;
+
+       /* Root Info */
+       struct timespec         s_record_time;
+
+       /* Fileset Info */
+       __u16                   s_serial_number;
+
+       /* highest UDF revision we have recorded to this media */
+       __u16                   s_udfrev;
+
+       /* Miscellaneous flags */
+       __u32                   s_flags;
+
+       /* Encoding info */
+       struct nls_table        *s_nls_map;
+
+       /* VAT inode */
+       struct inode            *s_vat_inode;
+
+       struct mutex            s_alloc_mutex;
+};
+
 static inline struct udf_sb_info *UDF_SB(struct super_block *sb)
 {
        return sb->s_fs_info;
index 681dc2b..f3f45d0 100644 (file)
@@ -1,17 +1,37 @@
 #ifndef __UDF_DECL_H
 #define __UDF_DECL_H
 
-#include <linux/udf_fs.h>
 #include "ecma_167.h"
 #include "osta_udf.h"
 
 #include <linux/fs.h>
 #include <linux/types.h>
-#include <linux/udf_fs_i.h>
-#include <linux/udf_fs_sb.h>
 #include <linux/buffer_head.h>
+#include <linux/udf_fs_i.h>
 
+#include "udf_sb.h"
 #include "udfend.h"
+#include "udf_i.h"
+
+#define UDF_PREALLOCATE
+#define UDF_DEFAULT_PREALLOC_BLOCKS    8
+
+#define UDFFS_DEBUG
+
+#ifdef UDFFS_DEBUG
+#define udf_debug(f, a...) \
+do { \
+       printk(KERN_DEBUG "UDF-fs DEBUG %s:%d:%s: ", \
+               __FILE__, __LINE__, __func__); \
+       printk(f, ##a); \
+} while (0)
+#else
+#define udf_debug(f, a...) /**/
+#endif
+
+#define udf_info(f, a...) \
+       printk(KERN_INFO "UDF-fs INFO " f, ##a);
+
 
 #define udf_fixed_to_variable(x) ( ( ( (x) >> 5 ) * 39 ) + ( (x) & 0x0000001F ) )
 #define udf_variable_to_fixed(x) ( ( ( (x) / 39 ) << 5 ) + ( (x) % 39 ) )
 #define UDF_NAME_LEN           256
 #define UDF_PATH_LEN           1023
 
-#define udf_file_entry_alloc_offset(inode)\
-       (UDF_I(inode)->i_use ?\
-               sizeof(struct unallocSpaceEntry) :\
-               ((UDF_I(inode)->i_efe ?\
-                       sizeof(struct extendedFileEntry) :\
-                       sizeof(struct fileEntry)) + UDF_I(inode)->i_lenEAttr))
-
-#define udf_ext0_offset(inode)\
-       (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB ?\
-               udf_file_entry_alloc_offset(inode) : 0)
+static inline size_t udf_file_entry_alloc_offset(struct inode *inode)
+{
+       struct udf_inode_info *iinfo = UDF_I(inode);
+       if (iinfo->i_use)
+               return sizeof(struct unallocSpaceEntry);
+       else if (iinfo->i_efe)
+               return sizeof(struct extendedFileEntry) + iinfo->i_lenEAttr;
+       else
+               return sizeof(struct fileEntry) + iinfo->i_lenEAttr;
+}
+
+static inline size_t udf_ext0_offset(struct inode *inode)
+{
+       if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
+               return udf_file_entry_alloc_offset(inode);
+       else
+               return 0;
+}
 
 #define udf_get_lb_pblock(sb,loc,offset) udf_get_pblock((sb), (loc).logicalBlockNum, (loc).partitionReferenceNum, (offset))
 
@@ -83,7 +111,6 @@ struct extent_position {
 };
 
 /* super.c */
-extern void udf_error(struct super_block *, const char *, const char *, ...);
 extern void udf_warning(struct super_block *, const char *, const char *, ...);
 
 /* namei.c */
@@ -150,6 +177,8 @@ extern uint32_t udf_get_pblock_virt20(struct super_block *, uint32_t, uint16_t,
                                      uint32_t);
 extern uint32_t udf_get_pblock_spar15(struct super_block *, uint32_t, uint16_t,
                                      uint32_t);
+extern uint32_t udf_get_pblock_meta25(struct super_block *, uint32_t, uint16_t,
+                                         uint32_t);
 extern int udf_relocate_blocks(struct super_block *, long, long *);
 
 /* unicode.c */
@@ -157,7 +186,7 @@ extern int udf_get_filename(struct super_block *, uint8_t *, uint8_t *, int);
 extern int udf_put_filename(struct super_block *, const uint8_t *, uint8_t *,
                            int);
 extern int udf_build_ustr(struct ustr *, dstring *, int);
-extern int udf_CS0toUTF8(struct ustr *, struct ustr *);
+extern int udf_CS0toUTF8(struct ustr *, const struct ustr *);
 
 /* ialloc.c */
 extern void udf_free_inode(struct inode *);
@@ -191,11 +220,9 @@ extern struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize,
 extern long_ad *udf_get_filelongad(uint8_t *, int, uint32_t *, int);
 extern short_ad *udf_get_fileshortad(uint8_t *, int, uint32_t *, int);
 
-/* crc.c */
-extern uint16_t udf_crc(uint8_t *, uint32_t, uint16_t);
-
 /* udftime.c */
-extern time_t *udf_stamp_to_time(time_t *, long *, kernel_timestamp);
-extern kernel_timestamp *udf_time_to_stamp(kernel_timestamp *, struct timespec);
+extern struct timespec *udf_disk_stamp_to_time(struct timespec *dest,
+                                               timestamp src);
+extern timestamp *udf_time_to_disk_stamp(timestamp *dest, struct timespec src);
 
 #endif                         /* __UDF_DECL_H */
index c4bd120..489f52f 100644 (file)
@@ -24,17 +24,6 @@ static inline lb_addr cpu_to_lelb(kernel_lb_addr in)
        return out;
 }
 
-static inline kernel_timestamp lets_to_cpu(timestamp in)
-{
-       kernel_timestamp out;
-
-       memcpy(&out, &in, sizeof(timestamp));
-       out.typeAndTimezone = le16_to_cpu(in.typeAndTimezone);
-       out.year = le16_to_cpu(in.year);
-
-       return out;
-}
-
 static inline short_ad lesa_to_cpu(short_ad in)
 {
        short_ad out;
@@ -85,15 +74,4 @@ static inline kernel_extent_ad leea_to_cpu(extent_ad in)
        return out;
 }
 
-static inline timestamp cpu_to_lets(kernel_timestamp in)
-{
-       timestamp out;
-
-       memcpy(&out, &in, sizeof(timestamp));
-       out.typeAndTimezone = cpu_to_le16(in.typeAndTimezone);
-       out.year = cpu_to_le16(in.year);
-
-       return out;
-}
-
 #endif /* __UDF_ENDIAN_H */
index ce59573..5f81165 100644 (file)
@@ -85,39 +85,38 @@ extern struct timezone sys_tz;
 #define SECS_PER_HOUR  (60 * 60)
 #define SECS_PER_DAY   (SECS_PER_HOUR * 24)
 
-time_t *udf_stamp_to_time(time_t *dest, long *dest_usec, kernel_timestamp src)
+struct timespec *udf_disk_stamp_to_time(struct timespec *dest, timestamp src)
 {
        int yday;
-       uint8_t type = src.typeAndTimezone >> 12;
+       u16 typeAndTimezone = le16_to_cpu(src.typeAndTimezone);
+       u16 year = le16_to_cpu(src.year);
+       uint8_t type = typeAndTimezone >> 12;
        int16_t offset;
 
        if (type == 1) {
-               offset = src.typeAndTimezone << 4;
+               offset = typeAndTimezone << 4;
                /* sign extent offset */
                offset = (offset >> 4);
                if (offset == -2047) /* unspecified offset */
                        offset = 0;
-       } else {
+       } else
                offset = 0;
-       }
 
-       if ((src.year < EPOCH_YEAR) ||
-           (src.year >= EPOCH_YEAR + MAX_YEAR_SECONDS)) {
-               *dest = -1;
-               *dest_usec = -1;
+       if ((year < EPOCH_YEAR) ||
+           (year >= EPOCH_YEAR + MAX_YEAR_SECONDS)) {
                return NULL;
        }
-       *dest = year_seconds[src.year - EPOCH_YEAR];
-       *dest -= offset * 60;
+       dest->tv_sec = year_seconds[year - EPOCH_YEAR];
+       dest->tv_sec -= offset * 60;
 
-       yday = ((__mon_yday[__isleap(src.year)][src.month - 1]) + src.day - 1);
-       *dest += (((yday * 24) + src.hour) * 60 + src.minute) * 60 + src.second;
-       *dest_usec = src.centiseconds * 10000 +
-                       src.hundredsOfMicroseconds * 100 + src.microseconds;
+       yday = ((__mon_yday[__isleap(year)][src.month - 1]) + src.day - 1);
+       dest->tv_sec += (((yday * 24) + src.hour) * 60 + src.minute) * 60 + src.second;
+       dest->tv_nsec = 1000 * (src.centiseconds * 10000 +
+                       src.hundredsOfMicroseconds * 100 + src.microseconds);
        return dest;
 }
 
-kernel_timestamp *udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts)
+timestamp *udf_time_to_disk_stamp(timestamp *dest, struct timespec ts)
 {
        long int days, rem, y;
        const unsigned short int *ip;
@@ -128,7 +127,7 @@ kernel_timestamp *udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts)
        if (!dest)
                return NULL;
 
-       dest->typeAndTimezone = 0x1000 | (offset & 0x0FFF);
+       dest->typeAndTimezone = cpu_to_le16(0x1000 | (offset & 0x0FFF));
 
        ts.tv_sec += offset * 60;
        days = ts.tv_sec / SECS_PER_DAY;
@@ -151,7 +150,7 @@ kernel_timestamp *udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts)
                         - LEAPS_THRU_END_OF(y - 1));
                y = yg;
        }
-       dest->year = y;
+       dest->year = cpu_to_le16(y);
        ip = __mon_yday[__isleap(y)];
        for (y = 11; days < (long int)ip[y]; --y)
                continue;
index e533b11..9fdf8c9 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>      /* for memset */
 #include <linux/nls.h>
-#include <linux/udf_fs.h>
+#include <linux/crc-itu-t.h>
 
 #include "udf_sb.h"
 
@@ -49,14 +49,16 @@ int udf_build_ustr(struct ustr *dest, dstring *ptr, int size)
 {
        int usesize;
 
-       if ((!dest) || (!ptr) || (!size))
+       if (!dest || !ptr || !size)
                return -1;
+       BUG_ON(size < 2);
 
-       memset(dest, 0, sizeof(struct ustr));
-       usesize = (size > UDF_NAME_LEN) ? UDF_NAME_LEN : size;
+       usesize = min_t(size_t, ptr[size - 1], sizeof(dest->u_name));
+       usesize = min(usesize, size - 2);
        dest->u_cmpID = ptr[0];
-       dest->u_len = ptr[size - 1];
-       memcpy(dest->u_name, ptr + 1, usesize - 1);
+       dest->u_len = usesize;
+       memcpy(dest->u_name, ptr + 1, usesize);
+       memset(dest->u_name + usesize, 0, sizeof(dest->u_name) - usesize);
 
        return 0;
 }
@@ -83,9 +85,6 @@ static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize)
  * PURPOSE
  *     Convert OSTA Compressed Unicode to the UTF-8 equivalent.
  *
- * DESCRIPTION
- *     This routine is only called by udf_filldir().
- *
  * PRE-CONDITIONS
  *     utf                     Pointer to UTF-8 output buffer.
  *     ocu                     Pointer to OSTA Compressed Unicode input buffer
@@ -99,43 +98,39 @@ static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize)
  *     November 12, 1997 - Andrew E. Mileski
  *     Written, tested, and released.
  */
-int udf_CS0toUTF8(struct ustr *utf_o, struct ustr *ocu_i)
+int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i)
 {
-       uint8_t *ocu;
-       uint32_t c;
+       const uint8_t *ocu;
        uint8_t cmp_id, ocu_len;
        int i;
 
-       ocu = ocu_i->u_name;
-
        ocu_len = ocu_i->u_len;
-       cmp_id = ocu_i->u_cmpID;
-       utf_o->u_len = 0;
-
        if (ocu_len == 0) {
                memset(utf_o, 0, sizeof(struct ustr));
-               utf_o->u_cmpID = 0;
-               utf_o->u_len = 0;
                return 0;
        }
 
-       if ((cmp_id != 8) && (cmp_id != 16)) {
+       cmp_id = ocu_i->u_cmpID;
+       if (cmp_id != 8 && cmp_id != 16) {
+               memset(utf_o, 0, sizeof(struct ustr));
                printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n",
                       cmp_id, ocu_i->u_name);
                return 0;
        }
 
+       ocu = ocu_i->u_name;
+       utf_o->u_len = 0;
        for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) {
 
                /* Expand OSTA compressed Unicode to Unicode */
-               c = ocu[i++];
+               uint32_t c = ocu[i++];
                if (cmp_id == 16)
                        c = (c << 8) | ocu[i++];
 
                /* Compress Unicode to UTF-8 */
-               if (c < 0x80U) {
+               if (c < 0x80U)
                        utf_o->u_name[utf_o->u_len++] = (uint8_t)c;
-               else if (c < 0x800U) {
+               else if (c < 0x800U) {
                        utf_o->u_name[utf_o->u_len++] =
                                                (uint8_t)(0xc0 | (c >> 6));
                        utf_o->u_name[utf_o->u_len++] =
@@ -255,35 +250,32 @@ error_out:
 }
 
 static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o,
-                       struct ustr *ocu_i)
+                       const struct ustr *ocu_i)
 {
-       uint8_t *ocu;
-       uint32_t c;
+       const uint8_t *ocu;
        uint8_t cmp_id, ocu_len;
        int i;
 
-       ocu = ocu_i->u_name;
 
        ocu_len = ocu_i->u_len;
-       cmp_id = ocu_i->u_cmpID;
-       utf_o->u_len = 0;
-
        if (ocu_len == 0) {
                memset(utf_o, 0, sizeof(struct ustr));
-               utf_o->u_cmpID = 0;
-               utf_o->u_len = 0;
                return 0;
        }
 
-       if ((cmp_id != 8) && (cmp_id != 16)) {
+       cmp_id = ocu_i->u_cmpID;
+       if (cmp_id != 8 && cmp_id != 16) {
+               memset(utf_o, 0, sizeof(struct ustr));
                printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n",
                       cmp_id, ocu_i->u_name);
                return 0;
        }
 
+       ocu = ocu_i->u_name;
+       utf_o->u_len = 0;
        for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) {
                /* Expand OSTA compressed Unicode to Unicode */
-               c = ocu[i++];
+               uint32_t c = ocu[i++];
                if (cmp_id == 16)
                        c = (c << 8) | ocu[i++];
 
@@ -463,7 +455,7 @@ static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName,
                } else if (newIndex > 250)
                        newIndex = 250;
                newName[newIndex++] = CRC_MARK;
-               valueCRC = udf_crc(fidName, fidNameLen, 0);
+               valueCRC = crc_itu_t(0, fidName, fidNameLen);
                newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12];
                newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8];
                newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4];
diff --git a/include/asm-sh/i2c-sh7760.h b/include/asm-sh/i2c-sh7760.h
new file mode 100644 (file)
index 0000000..2418211
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * MMIO/IRQ and platform data for SH7760 I2C channels
+ */
+
+#ifndef _I2C_SH7760_H_
+#define _I2C_SH7760_H_
+
+#define SH7760_I2C_DEVNAME     "sh7760-i2c"
+
+#define SH7760_I2C0_MMIO       0xFE140000
+#define SH7760_I2C0_MMIOEND    0xFE14003B
+#define SH7760_I2C0_IRQ                62
+
+#define SH7760_I2C1_MMIO       0xFE150000
+#define SH7760_I2C1_MMIOEND    0xFE15003B
+#define SH7760_I2C1_IRQ                63
+
+struct sh7760_i2c_platdata {
+       unsigned int speed_khz;
+};
+
+#endif
index b3d9ccd..cbb5ccb 100644 (file)
@@ -100,7 +100,7 @@ header-y += ixjuser.h
 header-y += jffs2.h
 header-y += keyctl.h
 header-y += limits.h
-header-y += lock_dlm_plock.h
+header-y += dlm_plock.h
 header-y += magic.h
 header-y += major.h
 header-y += matroxfb.h
@@ -150,6 +150,7 @@ header-y += tiocl.h
 header-y += tipc.h
 header-y += tipc_config.h
 header-y += toshiba.h
+header-y += udf_fs_i.h
 header-y += ultrasound.h
 header-y += un.h
 header-y += utime.h
@@ -210,7 +211,9 @@ unifdef-y += hdlcdrv.h
 unifdef-y += hdlc.h
 unifdef-y += hdreg.h
 unifdef-y += hdsmart.h
+unifdef-y += hid.h
 unifdef-y += hiddev.h
+unifdef-y += hidraw.h
 unifdef-y += hpet.h
 unifdef-y += i2c.h
 unifdef-y += i2c-dev.h
@@ -334,7 +337,6 @@ unifdef-y += time.h
 unifdef-y += timex.h
 unifdef-y += tty.h
 unifdef-y += types.h
-unifdef-y += udf_fs_i.h
 unifdef-y += udp.h
 unifdef-y += uinput.h
 unifdef-y += uio.h
index c743fbc..203a025 100644 (file)
 
 /* Lock levels and flags are here */
 #include <linux/dlmconstants.h>
-
-
-#define DLM_RESNAME_MAXLEN     64
-
+#include <linux/types.h>
 
 typedef void dlm_lockspace_t;
 
@@ -63,7 +60,7 @@ typedef void dlm_lockspace_t;
 
 struct dlm_lksb {
        int      sb_status;
-       uint32_t sb_lkid;
+       __u32    sb_lkid;
        char     sb_flags;
        char *   sb_lvbptr;
 };
index 9642277..c603450 100644 (file)
 *******************************************************************************
 ******************************************************************************/
 
+#ifndef _LINUX_DLM_DEVICE_H
+#define _LINUX_DLM_DEVICE_H
+
 /* This is the device interface for dlm, most users will use a library
  * interface.
  */
 
+#include <linux/dlm.h>
+#include <linux/types.h>
+
 #define DLM_USER_LVB_LEN       32
 
 /* Version of the device interface */
@@ -94,10 +100,9 @@ struct dlm_lock_result {
 #define DLM_USER_PURGE        6
 #define DLM_USER_DEADLOCK     7
 
-/* Arbitrary length restriction */
-#define MAX_LS_NAME_LEN 64
-
 /* Lockspace flags */
 #define DLM_USER_LSFLG_AUTOFREE   1
 #define DLM_USER_LSFLG_FORCEFREE  2
 
+#endif
+
diff --git a/include/linux/dlm_plock.h b/include/linux/dlm_plock.h
new file mode 100644 (file)
index 0000000..18d5fdb
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2005-2008 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ */
+
+#ifndef __DLM_PLOCK_DOT_H__
+#define __DLM_PLOCK_DOT_H__
+
+#define DLM_PLOCK_MISC_NAME            "dlm_plock"
+
+#define DLM_PLOCK_VERSION_MAJOR        1
+#define DLM_PLOCK_VERSION_MINOR        1
+#define DLM_PLOCK_VERSION_PATCH        0
+
+enum {
+       DLM_PLOCK_OP_LOCK = 1,
+       DLM_PLOCK_OP_UNLOCK,
+       DLM_PLOCK_OP_GET,
+};
+
+struct dlm_plock_info {
+       __u32 version[3];
+       __u8 optype;
+       __u8 ex;
+       __u8 wait;
+       __u8 pad;
+       __u32 pid;
+       __s32 nodeid;
+       __s32 rv;
+       __u32 fsid;
+       __u64 number;
+       __u64 start;
+       __u64 end;
+       __u64 owner;
+};
+
+#ifdef __KERNEL__
+int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+               int cmd, struct file_lock *fl);
+int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+               struct file_lock *fl);
+int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+               struct file_lock *fl);
+#endif /* __KERNEL__ */
+
+#endif
+
index fddb3d3..47bf08d 100644 (file)
  * Constants used by DLM interface.
  */
 
+#define DLM_LOCKSPACE_LEN       64
+#define DLM_RESNAME_MAXLEN      64
+
+
 /*
  * Lock Modes
  */
index 74ff575..d951ec4 100644 (file)
@@ -284,6 +284,7 @@ struct hid_item {
 #define HID_QUIRK_2WHEEL_MOUSE_HACK_B8         0x02000000
 #define HID_QUIRK_HWHEEL_WHEEL_INVERT          0x04000000
 #define HID_QUIRK_MICROSOFT_KEYS               0x08000000
+#define HID_QUIRK_FULLSPEED_INTERVAL           0x10000000
 
 /*
  * Separate quirks for runtime report descriptor fixup
@@ -296,6 +297,8 @@ struct hid_item {
 #define HID_QUIRK_RDESC_MACBOOK_JIS            0x00000010
 #define HID_QUIRK_RDESC_BUTTON_CONSUMER                0x00000020
 #define HID_QUIRK_RDESC_SAMSUNG_REMOTE         0x00000040
+#define HID_QUIRK_RDESC_MICROSOFT_RECV_1028    0x00000080
+#define HID_QUIRK_RDESC_SUNPLUS_WDESKTOP       0x00000100
 
 /*
  * This is the global environment of the parser. This information is
@@ -320,7 +323,7 @@ struct hid_global {
  * This is the local environment. It is persistent up the next main-item.
  */
 
-#define HID_MAX_USAGES                 8192
+#define HID_MAX_USAGES                 12288
 #define HID_DEFAULT_NUM_COLLECTIONS    16
 
 struct hid_local {
@@ -421,6 +424,7 @@ struct hid_control_fifo {
 #define HID_RESET_PENDING      4
 #define HID_SUSPENDED          5
 #define HID_CLEAR_HALT         6
+#define HID_DISCONNECTED       7
 
 struct hid_input {
        struct list_head list;
@@ -452,8 +456,6 @@ struct hid_device {                                                 /* device report descriptor */
        void *hidraw;
        int minor;                                                      /* Hiddev minor number */
 
-       wait_queue_head_t wait;                                         /* For sleeping */
-
        int open;                                                       /* is the device open by anyone? */
        char name[128];                                                 /* Device name */
        char phys[64];                                                  /* Device physical location */
@@ -530,14 +532,12 @@ int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int
 int hidinput_mapping_quirks(struct hid_usage *, struct input_dev *, unsigned long **, int *);
 int hidinput_event_quirks(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
 int hidinput_apple_event(struct hid_device *, struct input_dev *, struct hid_usage *, __s32);
-void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt);
 void hid_output_report(struct hid_report *report, __u8 *data);
 void hid_free_device(struct hid_device *device);
 struct hid_device *hid_parse_report(__u8 *start, unsigned size);
 
 /* HID quirks API */
 u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct);
-int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct, const u32 quirks);
 int usbhid_quirks_init(char **quirks_param);
 void usbhid_quirks_exit(void);
 void usbhid_fixup_report_descriptor(const u16, const u16, char *, unsigned, char **);
@@ -546,6 +546,7 @@ void usbhid_fixup_report_descriptor(const u16, const u16, char *, unsigned, char
 int hid_ff_init(struct hid_device *hid);
 
 int hid_lgff_init(struct hid_device *hid);
+int hid_lg2ff_init(struct hid_device *hid);
 int hid_plff_init(struct hid_device *hid);
 int hid_tmff_init(struct hid_device *hid);
 int hid_zpff_init(struct hid_device *hid);
@@ -566,7 +567,11 @@ static inline int hid_ff_init(struct hid_device *hid) { return -1; }
 #define dbg_hid_line(format, arg...) if (hid_debug) \
                                printk(format, ## arg)
 #else
-#define dbg_hid(format, arg...) do {} while (0)
+static inline int __attribute__((format(printf, 1, 2)))
+dbg_hid(const char *fmt, ...)
+{
+       return 0;
+}
 #define dbg_hid_line dbg_hid
 #endif
 
index 0536f29..dbb5c8c 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include <linux/hid.h>
+#include <linux/types.h>
 
 struct hidraw_report_descriptor {
        __u32 size;
index fce47c0..adcb3dc 100644 (file)
@@ -1,14 +1,41 @@
 #ifndef _LINUX_I2C_ALGO_PCA_H
 #define _LINUX_I2C_ALGO_PCA_H
 
+/* Clock speeds for the bus */
+#define I2C_PCA_CON_330kHz     0x00
+#define I2C_PCA_CON_288kHz     0x01
+#define I2C_PCA_CON_217kHz     0x02
+#define I2C_PCA_CON_146kHz     0x03
+#define I2C_PCA_CON_88kHz      0x04
+#define I2C_PCA_CON_59kHz      0x05
+#define I2C_PCA_CON_44kHz      0x06
+#define I2C_PCA_CON_36kHz      0x07
+
+/* PCA9564 registers */
+#define I2C_PCA_STA            0x00 /* STATUS  Read Only  */
+#define I2C_PCA_TO             0x00 /* TIMEOUT Write Only */
+#define I2C_PCA_DAT            0x01 /* DATA    Read/Write */
+#define I2C_PCA_ADR            0x02 /* OWN ADR Read/Write */
+#define I2C_PCA_CON            0x03 /* CONTROL Read/Write */
+
+#define I2C_PCA_CON_AA         0x80 /* Assert Acknowledge */
+#define I2C_PCA_CON_ENSIO      0x40 /* Enable */
+#define I2C_PCA_CON_STA                0x20 /* Start */
+#define I2C_PCA_CON_STO                0x10 /* Stop */
+#define I2C_PCA_CON_SI         0x08 /* Serial Interrupt */
+#define I2C_PCA_CON_CR         0x07 /* Clock Rate (MASK) */
+
 struct i2c_algo_pca_data {
-       int  (*get_own)                 (struct i2c_algo_pca_data *adap); /* Obtain own address */
-       int  (*get_clock)               (struct i2c_algo_pca_data *adap);
-       void (*write_byte)              (struct i2c_algo_pca_data *adap, int reg, int val);
-       int  (*read_byte)               (struct i2c_algo_pca_data *adap, int reg);
-       int  (*wait_for_interrupt)      (struct i2c_algo_pca_data *adap);
+       void                            *data;  /* private low level data */
+       void (*write_byte)              (void *data, int reg, int val);
+       int  (*read_byte)               (void *data, int reg);
+       int  (*wait_for_completion)     (void *data);
+       void (*reset_chip)              (void *data);
+       /* i2c_clock values are defined in linux/i2c-algo-pca.h */
+       unsigned int                    i2c_clock;
 };
 
 int i2c_pca_add_bus(struct i2c_adapter *);
+int i2c_pca_add_numbered_bus(struct i2c_adapter *);
 
 #endif /* _LINUX_I2C_ALGO_PCA_H */
diff --git a/include/linux/i2c-pca-platform.h b/include/linux/i2c-pca-platform.h
new file mode 100644 (file)
index 0000000..3d19187
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef I2C_PCA9564_PLATFORM_H
+#define I2C_PCA9564_PLATFORM_H
+
+struct i2c_pca9564_pf_platform_data {
+       int gpio;               /* pin to reset chip. driver will work when
+                                * not supplied (negative value), but it
+                                * cannot exit some error conditions then */
+       int i2c_clock_speed;    /* values are defined in linux/i2c-algo-pca.h */
+       int timeout;            /* timeout = this value * 10us */
+};
+
+#endif /* I2C_PCA9564_PLATFORM_H */
diff --git a/include/linux/lock_dlm_plock.h b/include/linux/lock_dlm_plock.h
deleted file mode 100644 (file)
index fc34151..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
- *
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU General Public License v.2.
- */
-
-#ifndef __LOCK_DLM_PLOCK_DOT_H__
-#define __LOCK_DLM_PLOCK_DOT_H__
-
-#define GDLM_PLOCK_MISC_NAME           "lock_dlm_plock"
-
-#define GDLM_PLOCK_VERSION_MAJOR       1
-#define GDLM_PLOCK_VERSION_MINOR       1
-#define GDLM_PLOCK_VERSION_PATCH       0
-
-enum {
-       GDLM_PLOCK_OP_LOCK = 1,
-       GDLM_PLOCK_OP_UNLOCK,
-       GDLM_PLOCK_OP_GET,
-};
-
-struct gdlm_plock_info {
-       __u32 version[3];
-       __u8 optype;
-       __u8 ex;
-       __u8 wait;
-       __u8 pad;
-       __u32 pid;
-       __s32 nodeid;
-       __s32 rv;
-       __u32 fsid;
-       __u64 number;
-       __u64 start;
-       __u64 end;
-       __u64 owner;
-};
-
-#endif
-
diff --git a/include/linux/udf_fs.h b/include/linux/udf_fs.h
deleted file mode 100644 (file)
index aa88654..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * udf_fs.h
- *
- * PURPOSE
- *  Included by fs/filesystems.c
- *
- * DESCRIPTION
- *  OSTA-UDF(tm) = Optical Storage Technology Association
- *  Universal Disk Format.
- *
- *  This code is based on version 2.50 of the UDF specification,
- *  and revision 3 of the ECMA 167 standard [equivalent to ISO 13346].
- *    http://www.osta.org/ *    http://www.ecma.ch/
- *    http://www.iso.org/
- *
- * COPYRIGHT
- *     This file is distributed under the terms of the GNU General Public
- *     License (GPL). Copies of the GPL can be obtained from:
- *             ftp://prep.ai.mit.edu/pub/gnu/GPL
- *     Each contributing author retains all rights to their own work.
- *
- *  (C) 1999-2004 Ben Fennema
- *  (C) 1999-2000 Stelias Computing Inc
- *
- * HISTORY
- *
- */
-
-#ifndef _UDF_FS_H
-#define _UDF_FS_H 1
-
-#define UDF_PREALLOCATE
-#define UDF_DEFAULT_PREALLOC_BLOCKS    8
-
-#undef UDFFS_DEBUG
-
-#ifdef UDFFS_DEBUG
-#define udf_debug(f, a...) \
-       do { \
-               printk (KERN_DEBUG "UDF-fs DEBUG %s:%d:%s: ", \
-                       __FILE__, __LINE__, __FUNCTION__); \
-               printk (f, ##a); \
-       } while (0)
-#else
-#define udf_debug(f, a...) /**/
-#endif
-
-#define udf_info(f, a...) \
-               printk (KERN_INFO "UDF-fs INFO " f, ##a);
-
-#endif /* _UDF_FS_H */
index ffaf056..3536965 100644 (file)
@@ -9,41 +9,10 @@
  *             ftp://prep.ai.mit.edu/pub/gnu/GPL
  *     Each contributing author retains all rights to their own work.
  */
-
 #ifndef _UDF_FS_I_H
 #define _UDF_FS_I_H 1
 
-#ifdef __KERNEL__
-
-struct udf_inode_info
-{
-       struct timespec         i_crtime;
-       /* Physical address of inode */
-       kernel_lb_addr          i_location;
-       __u64                   i_unique;
-       __u32                   i_lenEAttr;
-       __u32                   i_lenAlloc;
-       __u64                   i_lenExtents;
-       __u32                   i_next_alloc_block;
-       __u32                   i_next_alloc_goal;
-       unsigned                i_alloc_type : 3;
-       unsigned                i_efe : 1;
-       unsigned                i_use : 1;
-       unsigned                i_strat4096 : 1;
-       unsigned                reserved : 26;
-       union
-       {
-               short_ad        *i_sad;
-               long_ad         *i_lad;
-               __u8            *i_data;
-       } i_ext;
-       struct inode vfs_inode;
-};
-
-#endif
-
 /* exported IOCTLs, we have 'l', 0x40-0x7f */
-
 #define UDF_GETEASIZE   _IOR('l', 0x40, int)
 #define UDF_GETEABLOCK  _IOR('l', 0x41, void *)
 #define UDF_GETVOLIDENT _IOR('l', 0x42, void *)
diff --git a/include/linux/udf_fs_sb.h b/include/linux/udf_fs_sb.h
deleted file mode 100644 (file)
index 9bc4735..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * udf_fs_sb.h
- * 
- * This include file is for the Linux kernel/module.
- *
- * COPYRIGHT
- *     This file is distributed under the terms of the GNU General Public
- *     License (GPL). Copies of the GPL can be obtained from:
- *             ftp://prep.ai.mit.edu/pub/gnu/GPL
- *     Each contributing author retains all rights to their own work.
- */
-
-#ifndef _UDF_FS_SB_H
-#define _UDF_FS_SB_H 1
-
-#include <linux/mutex.h>
-
-#pragma pack(1)
-
-#define UDF_MAX_BLOCK_LOADED   8
-
-#define UDF_TYPE1_MAP15                        0x1511U
-#define UDF_VIRTUAL_MAP15              0x1512U
-#define UDF_VIRTUAL_MAP20              0x2012U
-#define UDF_SPARABLE_MAP15             0x1522U
-
-struct udf_sparing_data
-{
-       __u16   s_packet_len;
-       struct buffer_head *s_spar_map[4];
-};
-
-struct udf_virtual_data
-{
-       __u32   s_num_entries;
-       __u16   s_start_offset;
-};
-
-struct udf_bitmap
-{
-       __u32                   s_extLength;
-       __u32                   s_extPosition;
-       __u16                   s_nr_groups;
-       struct buffer_head      **s_block_bitmap;
-};
-
-struct udf_part_map
-{
-       union
-       {
-               struct udf_bitmap       *s_bitmap;
-               struct inode            *s_table;
-       } s_uspace;
-       union
-       {
-               struct udf_bitmap       *s_bitmap;
-               struct inode            *s_table;
-       } s_fspace;
-       __u32   s_partition_root;
-       __u32   s_partition_len;
-       __u16   s_partition_type;
-       __u16   s_partition_num;
-       union
-       {
-               struct udf_sparing_data s_sparing;
-               struct udf_virtual_data s_virtual;
-       } s_type_specific;
-       __u32   (*s_partition_func)(struct super_block *, __u32, __u16, __u32);
-       __u16   s_volumeseqnum;
-       __u16   s_partition_flags;
-};
-
-#pragma pack()
-
-struct udf_sb_info
-{
-       struct udf_part_map     *s_partmaps;
-       __u8                    s_volume_ident[32];
-
-       /* Overall info */
-       __u16                   s_partitions;
-       __u16                   s_partition;
-
-       /* Sector headers */
-       __s32                   s_session;
-       __u32                   s_anchor[4];
-       __u32                   s_last_block;
-
-       struct buffer_head      *s_lvid_bh;
-
-       /* Default permissions */
-       mode_t                  s_umask;
-       gid_t                   s_gid;
-       uid_t                   s_uid;
-
-       /* Root Info */
-       struct timespec         s_record_time;
-
-       /* Fileset Info */
-       __u16                   s_serial_number;
-
-       /* highest UDF revision we have recorded to this media */
-       __u16                   s_udfrev;
-
-       /* Miscellaneous flags */
-       __u32                   s_flags;
-
-       /* Encoding info */
-       struct nls_table        *s_nls_map;
-
-       /* VAT inode */
-       struct inode            *s_vat_inode;
-
-       struct mutex            s_alloc_mutex;
-};
-
-#endif /* _UDF_FS_SB_H */
index 57ba7ea..0014b03 100644 (file)
@@ -7035,6 +7035,7 @@ static int find_next_best_node(int node, nodemask_t *used_nodes)
 /**
  * sched_domain_node_span - get a cpumask for a node's sched_domain
  * @node: node whose cpumask we're constructing
+ * @span: resulting cpumask
  *
  * Given a node, construct a good cpumask for its sched_domain to span. It
  * should be one that prevents unnecessary balancing, but also spreads tasks
index 1d69f66..95a8ef4 100644 (file)
@@ -312,6 +312,7 @@ static inline int avc_reclaim_node(void)
                if (!spin_trylock_irqsave(&avc_cache.slots_lock[hvalue], flags))
                        continue;
 
+               rcu_read_lock();
                list_for_each_entry(node, &avc_cache.slots[hvalue], list) {
                        if (atomic_dec_and_test(&node->ae.used)) {
                                /* Recently Unused */
@@ -319,11 +320,13 @@ static inline int avc_reclaim_node(void)
                                avc_cache_stats_incr(reclaims);
                                ecx++;
                                if (ecx >= AVC_CACHE_RECLAIM) {
+                                       rcu_read_unlock();
                                        spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flags);
                                        goto out;
                                }
                        }
                }
+               rcu_read_unlock();
                spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flags);
        }
 out:
@@ -821,8 +824,14 @@ int avc_ss_reset(u32 seqno)
 
        for (i = 0; i < AVC_CACHE_SLOTS; i++) {
                spin_lock_irqsave(&avc_cache.slots_lock[i], flag);
+               /*
+                * With preemptable RCU, the outer spinlock does not
+                * prevent RCU grace periods from ending.
+                */
+               rcu_read_lock();
                list_for_each_entry(node, &avc_cache.slots[i], list)
                        avc_node_delete(node);
+               rcu_read_unlock();
                spin_unlock_irqrestore(&avc_cache.slots_lock[i], flag);
        }
 
index 1bf2543..33af321 100644 (file)
@@ -755,9 +755,18 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
        int set_context =       (oldsbsec->flags & CONTEXT_MNT);
        int set_rootcontext =   (oldsbsec->flags & ROOTCONTEXT_MNT);
 
-       /* we can't error, we can't save the info, this shouldn't get called
-        * this early in the boot process. */
-       BUG_ON(!ss_initialized);
+       /*
+        * if the parent was able to be mounted it clearly had no special lsm
+        * mount options.  thus we can safely put this sb on the list and deal
+        * with it later
+        */
+       if (!ss_initialized) {
+               spin_lock(&sb_security_lock);
+               if (list_empty(&newsbsec->list))
+                       list_add(&newsbsec->list, &superblock_security_head);
+               spin_unlock(&sb_security_lock);
+               return;
+       }
 
        /* how can we clone if the old one wasn't set up?? */
        BUG_ON(!oldsbsec->initialized);
index c658b84..b4e14bc 100644 (file)
@@ -239,11 +239,13 @@ static void sel_netif_kill(int ifindex)
 {
        struct sel_netif *netif;
 
+       rcu_read_lock();
        spin_lock_bh(&sel_netif_lock);
        netif = sel_netif_find(ifindex);
        if (netif)
                sel_netif_destroy(netif);
        spin_unlock_bh(&sel_netif_lock);
+       rcu_read_unlock();
 }
 
 /**