Commit 03a652ca authored by Linus Torvalds's avatar Linus Torvalds

Merge http://linux-acpi.bkbits.net/linux-acpi

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 034004ee 16943d2e
...@@ -65,7 +65,7 @@ rename: no yes (all) (see below) ...@@ -65,7 +65,7 @@ rename: no yes (all) (see below)
readlink: no no readlink: no no
follow_link: no no follow_link: no no
truncate: no yes (see below) truncate: no yes (see below)
setattr: yes if ATTR_SIZE setattr: no yes
permission: yes no permission: yes no
getattr: (see below) getattr: (see below)
revalidate: no (see below) revalidate: no (see below)
......
...@@ -116,3 +116,10 @@ FS_LITTER is gone - just remove it from fs_flags. ...@@ -116,3 +116,10 @@ FS_LITTER is gone - just remove it from fs_flags.
FS_SINGLE is gone (actually, that had happened back when ->get_sb() FS_SINGLE is gone (actually, that had happened back when ->get_sb()
went in - and hadn't been documented ;-/). Just remove it from fs_flags went in - and hadn't been documented ;-/). Just remove it from fs_flags
(and see ->get_sb() entry for other actions). (and see ->get_sb() entry for other actions).
---
[mandatory]
->setattr() is called without BKL now. Caller _always_ holds ->i_sem, so
watch for ->i_sem-grabbing code that might be used by your ->setattr().
Callers of notify_change() need ->i_sem now.
...@@ -90,6 +90,31 @@ CONFIG_IEEE1394_RAWIO ...@@ -90,6 +90,31 @@ CONFIG_IEEE1394_RAWIO
say M here and read <file:Documentation/modules.txt>. The module say M here and read <file:Documentation/modules.txt>. The module
will be called raw1394.o. will be called raw1394.o.
CONFIG_IEEE1394_ETH1394
Extremely Experimental! This driver is a Linux specific way to use your
IEEE1394 Host as an Ethernet type device. This is _NOT_ IP1394.
CONFIG_IEEE1394_AMDTP
This option enables the Audio & Music Data Transmission Protocol
(IEC61883-6) driver, which implements audio transmission over
IEEE1394.
The userspace interface is documented in amdtp.h.
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. The module
will be called amdtp.o.
CONFIG_IEEE1394_CMP
This option enables the Connection Management Procedures
(IEC61883-1) driver, which implements input and output plugs.
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. The module
will be called amdtp.o.
CONFIG_IEEE1394_VERBOSEDEBUG CONFIG_IEEE1394_VERBOSEDEBUG
If you say Y here, you will get very verbose debugging logs from the If you say Y here, you will get very verbose debugging logs from the
subsystem which includes a dump of the header of every sent and subsystem which includes a dump of the header of every sent and
...@@ -99,4 +124,3 @@ CONFIG_IEEE1394_VERBOSEDEBUG ...@@ -99,4 +124,3 @@ CONFIG_IEEE1394_VERBOSEDEBUG
Say Y if you really want or need the debugging output, everyone else Say Y if you really want or need the debugging output, everyone else
says N. says N.
...@@ -19,8 +19,14 @@ if [ "$CONFIG_PCI" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then ...@@ -19,8 +19,14 @@ if [ "$CONFIG_PCI" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
comment "Protocol Drivers" comment "Protocol Drivers"
dep_tristate ' OHCI-1394 Video support' CONFIG_IEEE1394_VIDEO1394 $CONFIG_IEEE1394_OHCI1394 dep_tristate ' OHCI-1394 Video support' CONFIG_IEEE1394_VIDEO1394 $CONFIG_IEEE1394_OHCI1394
dep_tristate ' SBP-2 support (Harddisks etc.)' CONFIG_IEEE1394_SBP2 $CONFIG_SCSI $CONFIG_IEEE1394 dep_tristate ' SBP-2 support (Harddisks etc.)' CONFIG_IEEE1394_SBP2 $CONFIG_SCSI $CONFIG_IEEE1394
dep_tristate ' Ethernet over 1394' CONFIG_IEEE1394_ETH1394 $CONFIG_IEEE1394
dep_tristate ' OHCI-DV I/O support' CONFIG_IEEE1394_DV1394 $CONFIG_IEEE1394_OHCI1394 dep_tristate ' OHCI-DV I/O support' CONFIG_IEEE1394_DV1394 $CONFIG_IEEE1394_OHCI1394
dep_tristate ' Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394 dep_tristate ' Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394
dep_tristate ' IEC61883-1 Plug support' CONFIG_IEEE1394_CMP $CONFIG_IEEE1394
if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then
dep_tristate ' IEC61883-6 (Audio transmission) support' CONFIG_IEEE1394_AMDTP $CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394_CMP
fi
bool 'Excessive debugging output' CONFIG_IEEE1394_VERBOSEDEBUG bool 'Excessive debugging output' CONFIG_IEEE1394_VERBOSEDEBUG
fi fi
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
O_TARGET := ieee1394drv.o O_TARGET := ieee1394drv.o
export-objs := ieee1394_core.o ohci1394.o export-objs := ieee1394_core.o ohci1394.o cmp.o
list-multi := ieee1394.o list-multi := ieee1394.o
ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \ ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
...@@ -17,6 +17,9 @@ obj-$(CONFIG_IEEE1394_VIDEO1394) += video1394.o ...@@ -17,6 +17,9 @@ obj-$(CONFIG_IEEE1394_VIDEO1394) += video1394.o
obj-$(CONFIG_IEEE1394_RAWIO) += raw1394.o obj-$(CONFIG_IEEE1394_RAWIO) += raw1394.o
obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o
obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o
obj-$(CONFIG_IEEE1394_ETH1394) += eth1394.o
obj-$(CONFIG_IEEE1394_AMDTP) += amdtp.o
obj-$(CONFIG_IEEE1394_CMP) += cmp.o
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
......
This diff is collapsed.
/* -*- c-basic-offset: 8 -*- */
#ifndef __AMDTP_H
#define __AMDTP_H
#include <asm/ioctl.h>
#include <asm/types.h>
/* The userspace interface for the Audio & Music Data Transmission
* Protocol driver is really simple. First, open /dev/amdtp, use the
* ioctl to configure format, rate, dimension and either plug or
* channel, then start writing samples.
*
* The formats supported by the driver are listed below.
* AMDTP_FORMAT_RAW corresponds to the AM824 raw format, which can
* carry any number of channels, so use this if you're streaming
* multichannel audio. The AMDTP_FORMAT_IEC958_PCM corresponds to the
* AM824 IEC958 encapsulation without the IEC958 data bit set, using
* AMDTP_FORMAT_IEC958_AC3 will transmit the samples with the data bit
* set, suitable for transmitting compressed AC-3 audio.
*
* The rate field specifies the transmission rate; supported values are
* AMDTP_RATE_32KHZ, AMDTP_RATE_44K1HZ and AMDTP_RATE_48KHZ.
*
* The dimension field specifies the dimension of the signal, that is,
* the number of audio channels. Only AMDTP_FORMAT_RAW supports
* settings greater than 2.
*
* The last thing to specify is either the isochronous channel to use
* or the output plug to connect to. If you know what channel the
* destination device will listen on, you can specify the channel
* directly and use the AMDTP_IOC_CHANNEL ioctl. However, if the
* destination device chooses the channel and uses the IEC61883-1 plug
* mechanism, you can specify an output plug to connect to. The
* driver will pick up the channel number from the plug once the
* destination device locks the output plug control register. In this
* case set the plug field and use the AMDTP_IOC_PLUG ioctl.
*
* Having configured the interface, the driver now accepts writes of
* regular 16 bit signed little endian samples, with the channels
* interleaved. For example, 4 channels would look like:
*
* | sample 0 | sample 1 ...
* | ch. 0 | ch. 1 | ch. 2 | ch. 3 | ch. 0 | ...
* | lsb | msb | lsb | msb | lsb | msb | lsb | msb | lsb | msb | ...
*
*/
/* We use '#' for our ioctl magic number because it's cool. */
#define AMDTP_IOC_CHANNEL _IOW('#', 0, sizeof (struct amdtp_ioctl))
#define AMDTP_IOC_PLUG _IOW('#', 1, sizeof (struct amdtp_ioctl))
#define AMDTP_IOC_PING _IOW('#', 2, sizeof (struct amdtp_ioctl))
#define AMDTP_IOC_ZAP _IO('#', 3)
enum {
AMDTP_FORMAT_RAW,
AMDTP_FORMAT_IEC958_PCM,
AMDTP_FORMAT_IEC958_AC3
};
enum {
AMDTP_RATE_32KHZ,
AMDTP_RATE_44K1HZ,
AMDTP_RATE_48KHZ,
};
struct amdtp_ioctl {
__u32 format;
__u32 rate;
__u32 dimension;
union { __u32 channel; __u32 plug; } u;
};
#endif /* __AMDTP_H */
/* -*- c-basic-offset: 8 -*-
*
* cmp.c - Connection Management Procedures
* Copyright (C) 2001 Kristian Hgsberg
*
* 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.
*/
/* TODO
* ----
*
* - Implement IEC61883-1 output plugs and connection management.
* This should probably be part of the general subsystem, as it could
* be shared with dv1394.
*
* - Add IEC61883 unit directory when loading this module. This
* requires a run-time changeable config rom.
*/
#include <linux/module.h>
#include <linux/list.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/wait.h>
#include "hosts.h"
#include "highlevel.h"
#include "ieee1394.h"
#include "ieee1394_core.h"
#include "cmp.h"
struct plug {
union {
struct cmp_pcr pcr;
quadlet_t quadlet;
} u;
void (*update)(struct cmp_pcr *plug, void *data);
void *data;
};
struct cmp_host {
struct hpsb_host *host;
union {
struct cmp_mpr ompr;
quadlet_t ompr_quadlet;
} u;
struct plug opcr[2];
union {
struct cmp_mpr impr;
quadlet_t impr_quadlet;
} v;
struct plug ipcr[2];
struct list_head link;
};
enum {
CMP_P2P_CONNECTION,
CMP_BC_CONNECTION
};
#define CSR_PCR_MAP 0x900
#define CSR_PCR_MAP_END 0x9fc
static struct hpsb_highlevel *cmp_highlevel;
static LIST_HEAD(host_list);
static spinlock_t host_list_lock = SPIN_LOCK_UNLOCKED;
static struct cmp_host *
lookup_cmp_host(struct hpsb_host *host)
{
struct cmp_host *ch;
struct list_head *lh;
unsigned long flags;
ch = NULL;
spin_lock_irqsave(&host_list_lock, flags);
list_for_each(lh, &host_list) {
ch = list_entry(lh, struct cmp_host, link);
if (ch->host == host)
break;
}
spin_unlock_irqrestore(&host_list_lock, flags);
if (lh == &host_list)
return NULL;
else
return ch;
}
struct cmp_pcr *
cmp_register_opcr(struct hpsb_host *host, int opcr_number, int payload,
void (*update)(struct cmp_pcr *pcr, void *data),
void *data)
{
struct cmp_host *ch;
struct plug *plug;
ch = lookup_cmp_host(host);
if (opcr_number >= ch->u.ompr.nplugs ||
ch->opcr[opcr_number].update != NULL)
return NULL;
plug = &ch->opcr[opcr_number];
plug->u.pcr.online = 1;
plug->u.pcr.bcast_count = 0;
plug->u.pcr.p2p_count = 0;
plug->u.pcr.overhead = 0;
plug->u.pcr.payload = payload;
plug->update = update;
plug->data = data;
return &plug->u.pcr;
}
void cmp_unregister_opcr(struct hpsb_host *host, struct cmp_pcr *opcr)
{
struct cmp_host *ch;
struct plug *plug;
ch = lookup_cmp_host(host);
plug = (struct plug *)opcr;
if (plug - ch->opcr >= ch->u.ompr.nplugs) BUG();
plug->u.pcr.online = 0;
plug->update = NULL;
}
static void reset_plugs(struct cmp_host *ch)
{
int i;
ch->u.ompr.non_persistent_ext = 0xff;
for (i = 0; i < ch->u.ompr.nplugs; i++) {
ch->opcr[i].u.pcr.bcast_count = 0;
ch->opcr[i].u.pcr.p2p_count = 0;
ch->opcr[i].u.pcr.overhead = 0;
}
}
static void cmp_add_host(struct hpsb_host *host)
{
struct cmp_host *ch;
ch = kmalloc(sizeof *ch, SLAB_KERNEL);
if (ch == NULL) {
HPSB_ERR("Failed to allocate cmp_host");
return;
}
memset(ch, 0, sizeof *ch);
ch->host = host;
ch->u.ompr.rate = SPEED_100;
ch->u.ompr.bcast_channel_base = 63;
ch->u.ompr.nplugs = 2;
reset_plugs(ch);
spin_lock_irq(&host_list_lock);
list_add_tail(&ch->link, &host_list);
spin_unlock_irq(&host_list_lock);
}
static void cmp_host_reset(struct hpsb_host *host)
{
struct cmp_host *ch;
ch = lookup_cmp_host(host);
if (ch == NULL) BUG();
reset_plugs(ch);
}
static void cmp_remove_host(struct hpsb_host *host)
{
struct cmp_host *ch;
ch = lookup_cmp_host(host);
if (ch == NULL) BUG();
spin_lock_irq(&host_list_lock);
list_del(&ch->link);
spin_unlock_irq(&host_list_lock);
kfree(ch);
}
static int pcr_read(struct hpsb_host *host, int nodeid, quadlet_t *buf,
u64 addr, unsigned int length)
{
int csraddr = addr - CSR_REGISTER_BASE;
int plug;
struct cmp_host *ch;
if (length != 4)
return RCODE_TYPE_ERROR;
ch = lookup_cmp_host(host);
if (csraddr == 0x900) {
*buf = cpu_to_be32(ch->u.ompr_quadlet);
return RCODE_COMPLETE;
}
else if (csraddr < 0x904 + ch->u.ompr.nplugs * 4) {
plug = (csraddr - 0x904) / 4;
*buf = cpu_to_be32(ch->opcr[plug].u.quadlet);
return RCODE_COMPLETE;
}
else if (csraddr < 0x980) {
return RCODE_ADDRESS_ERROR;
}
else if (csraddr == 0x980) {
*buf = cpu_to_be32(ch->v.impr_quadlet);
return RCODE_COMPLETE;
}
else if (csraddr < 0x984 + ch->v.impr.nplugs * 4) {
plug = (csraddr - 0x984) / 4;
*buf = cpu_to_be32(ch->ipcr[plug].u.quadlet);
return RCODE_COMPLETE;
}
else
return RCODE_ADDRESS_ERROR;
}
static int pcr_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
u64 addr, quadlet_t data, quadlet_t arg, int extcode)
{
int csraddr = addr - CSR_REGISTER_BASE;
int plug;
struct cmp_host *ch;
ch = lookup_cmp_host(host);
if (extcode != EXTCODE_COMPARE_SWAP)
return RCODE_TYPE_ERROR;
if (csraddr == 0x900) {
/* FIXME: Ignore writes to bits 30-31 and 0-7 */
*store = cpu_to_be32(ch->u.ompr_quadlet);
if (arg == cpu_to_be32(ch->u.ompr_quadlet))
ch->u.ompr_quadlet = be32_to_cpu(data);
return RCODE_COMPLETE;
}
if (csraddr < 0x904 + ch->u.ompr.nplugs * 4) {
plug = (csraddr - 0x904) / 4;
*store = cpu_to_be32(ch->opcr[plug].u.quadlet);
if (arg == *store)
ch->opcr[plug].u.quadlet = be32_to_cpu(data);
if (be32_to_cpu(*store) != ch->opcr[plug].u.quadlet &&
ch->opcr[plug].update != NULL)
ch->opcr[plug].update(&ch->opcr[plug].u.pcr,
ch->opcr[plug].data);
return RCODE_COMPLETE;
}
else if (csraddr < 0x980) {
return RCODE_ADDRESS_ERROR;
}
else if (csraddr == 0x980) {
/* FIXME: Ignore writes to bits 24-31 and 0-7 */
*store = cpu_to_be32(ch->u.ompr_quadlet);
if (arg == cpu_to_be32(ch->u.ompr_quadlet))
ch->u.ompr_quadlet = be32_to_cpu(data);
return RCODE_COMPLETE;
}
else if (csraddr < 0x984 + ch->v.impr.nplugs * 4) {
plug = (csraddr - 0x984) / 4;
*store = cpu_to_be32(ch->ipcr[plug].u.quadlet);
if (arg == *store)
ch->ipcr[plug].u.quadlet = be32_to_cpu(data);
if (be32_to_cpu(*store) != ch->ipcr[plug].u.quadlet &&
ch->ipcr[plug].update != NULL)
ch->ipcr[plug].update(&ch->ipcr[plug].u.pcr,
ch->ipcr[plug].data);
return RCODE_COMPLETE;
}
else
return RCODE_ADDRESS_ERROR;
}
static struct hpsb_highlevel_ops cmp_highlevel_ops = {
add_host: cmp_add_host,
remove_host: cmp_remove_host,
host_reset: cmp_host_reset,
};
static struct hpsb_address_ops pcr_ops = {
read: pcr_read,
lock: pcr_lock,
};
/* Module interface */
MODULE_AUTHOR("Kristian Hogsberg <hogsberg@users.sf.net>");
MODULE_DESCRIPTION("Connection Management Procedures (CMP)");
MODULE_SUPPORTED_DEVICE("cmp");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(cmp_register_opcr);
EXPORT_SYMBOL(cmp_unregister_opcr);
static int __init cmp_init_module (void)
{
cmp_highlevel = hpsb_register_highlevel ("cmp",
&cmp_highlevel_ops);
if (cmp_highlevel == NULL) {
HPSB_ERR("cmp: unable to register highlevel ops");
return -EIO;
}
hpsb_register_addrspace(cmp_highlevel, &pcr_ops,
CSR_REGISTER_BASE + CSR_PCR_MAP,
CSR_REGISTER_BASE + CSR_PCR_MAP_END);
HPSB_INFO("Loaded CMP driver");
return 0;
}
static void __exit cmp_exit_module (void)
{
hpsb_unregister_highlevel(cmp_highlevel);
HPSB_INFO("Unloaded CMP driver");
}
module_init(cmp_init_module);
module_exit(cmp_exit_module);
#ifndef __CMP_H
#define __CMP_H
struct cmp_mpr {
u32 nplugs:5;
u32 reserved:3;
u32 persistent_ext:8;
u32 non_persistent_ext:8;
u32 bcast_channel_base:6;
u32 rate:2;
} __attribute__((packed));
struct cmp_pcr {
u32 payload:10;
u32 overhead:4;
u32 speed:2;
u32 channel:6;
u32 reserved:2;
u32 p2p_count:6;
u32 bcast_count:1;
u32 online:1;
} __attribute__((packed));
struct cmp_pcr *cmp_register_opcr(struct hpsb_host *host, int plug,
int payload,
void (*update)(struct cmp_pcr *plug,
void *data),
void *data);
void cmp_unregister_opcr(struct hpsb_host *host, struct cmp_pcr *plug);
#endif /* __CMP_H */
...@@ -412,6 +412,10 @@ static inline dma_addr_t dma_offset_to_bus(struct dma_region *dma, unsigned long ...@@ -412,6 +412,10 @@ static inline dma_addr_t dma_offset_to_bus(struct dma_region *dma, unsigned long
/* struct video_card contains all data associated with one instance /* struct video_card contains all data associated with one instance
of the dv1394 driver of the dv1394 driver
*/ */
enum modes {
MODE_RECEIVE,
MODE_TRANSMIT
};
struct video_card { struct video_card {
...@@ -574,6 +578,7 @@ struct video_card { ...@@ -574,6 +578,7 @@ struct video_card {
unsigned int current_packet; unsigned int current_packet;
int first_frame; /* received first start frame marker? */ int first_frame; /* received first start frame marker? */
enum modes mode;
}; };
/* /*
......
This diff is collapsed.
This diff is collapsed.
/*
* eth1394.h -- Ethernet driver for Linux IEEE-1394 Subsystem
*
* Copyright (C) 2000 Bonin Franck <boninf@free.fr>
* (C) 2001 Ben Collins <bcollins@debian.org>
*
* Mainly based on work by Emanuel Pirker and Andreas E. Bombe
*
* 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.
*/
#ifndef __ETH1394_H
#define __ETH1394_H
/* Register for incoming packets. This is 8192 bytes, which supports up to
* 1600mbs. We'll need to change this if that ever becomes "small" :) */
#define ETHER1394_REGION_ADDR_LEN 8192
#define ETHER1394_REGION_ADDR 0xfffff0200000ULL
#define ETHER1394_REGION_ADDR_END (ETHER1394_REGION_ADDR + ETHER1394_REGION_ADDR_LEN)
/* Node set == 64 */
#define NODE_SET (ALL_NODES + 1)
/* Private structure for our ethernet driver */
struct eth1394_priv {
struct net_device_stats stats; /* Device stats */
struct hpsb_host *host; /* The card for this dev */
unsigned char max_rec[NODE_SET];/* Max payload per node */
unsigned char sspd[NODE_SET]; /* Max speed per node */
u16 fifo_hi[ALL_NODES]; /* 16bit hi fifo offset per node */
u32 fifo_lo[ALL_NODES]; /* 32bit lo fifo offset per node */
u64 eui[ALL_NODES]; /* EUI-64 per node */
spinlock_t lock; /* Private lock */
};
struct host_info {
struct list_head list;
struct hpsb_host *host;
struct net_device *dev;
};
/* This is our task struct. It's used for the complete_tq callback. */
struct packet_task {
struct sk_buff *skb; /* Socket buffer we are sending */
nodeid_t dest_node; /* Destination of the packet */
u64 addr; /* Address */
struct tq_struct tq; /* The task */
};
/* IP1394 headers */
#include <asm/byteorder.h>
/* Unfragmented */
#if defined __BIG_ENDIAN_BITFIELD
struct eth1394_uf_hdr {
u8 lf:2;
u16 res:14;
u16 ether_type; /* Ethernet packet type */
} __attribute__((packed));
#elif defined __LITTLE_ENDIAN_BITFIELD
struct eth1394_uf_hdr {
u16 res:14;
u8 lf:2;
u16 ether_type;
} __attribute__((packed));
#else
#error Unknown bit field type
#endif
/* First fragment */
#if defined __BIG_ENDIAN_BITFIELD
struct eth1394_ff_hdr {
u8 lf:2;
u8 res1:2;
u16 dg_size:12; /* Datagram size */
u16 ether_type; /* Ethernet packet type */
u16 dgl; /* Datagram label */
u16 res2;
} __attribute__((packed));
#elif defined __LITTLE_ENDIAN_BITFIELD
struct eth1394_ff_hdr {
u16 dg_size:12;
u8 res1:2;
u8 lf:2;
u16 ether_type;
u16 dgl;
u16 res2;
} __attribute__((packed));
#else
#error Unknown bit field type
#endif
/* XXX: Subsequent fragments, including last */
#if defined __BIG_ENDIAN_BITFIELD
struct eth1394_sf_hdr {
u8 lf:2;
u8 res1:2;
u16 dg_size:12; /* Datagram size */
u8 res2:6;
u16 fg_off:10; /* Fragment offset */
u16 dgl; /* Datagram label */
u16 res3;
} __attribute__((packed));
#elif defined __LITTLE_ENDIAN_BITFIELD
struct eth1394_sf_hdr {
u16 dg_size:12;
u8 res1:2;
u8 lf:2;
u16 fg_off:10;
u8 res2:6;
u16 dgl;
u16 res3;
} __attribute__((packed));
#else
#error Unknown bit field type
#endif
#if defined __BIG_ENDIAN_BITFIELD
struct eth1394_common_hdr {
u8 lf:2;
u16 pad1:14;
} __attribute__((packed));
#elif defined __LITTLE_ENDIAN_BITFIELD
struct eth1394_common_hdr {
u16 pad1:14;
u8 lf:2;
} __attribute__((packed));
#else
#error Unknown bit field type
#endif
struct eth1394_hdr_words {
u16 word1;
u16 word2;
u16 word3;
u16 word4;
};
union eth1394_hdr {
struct eth1394_common_hdr common;
struct eth1394_uf_hdr uf;
struct eth1394_ff_hdr ff;
struct eth1394_sf_hdr sf;
struct eth1394_hdr_words words;
};
/* End of IP1394 headers */
/* Fragment types */
#define ETH1394_HDR_LF_UF 0 /* unfragmented */
#define ETH1394_HDR_LF_FF 1 /* first fragment */
#define ETH1394_HDR_LF_LF 2 /* last fragment */
#define ETH1394_HDR_LF_IF 3 /* interior fragment */
#define IP1394_HW_ADDR_LEN 16 /* As per RFC */
/* Our arp packet (ARPHRD_IEEE1394) */
struct eth1394_arp {
u16 hw_type; /* 0x0018 */
u16 proto_type; /* 0x0806 */
u8 hw_addr_len; /* 16 */
u8 ip_addr_len; /* 4 */
u16 opcode; /* ARP Opcode */
/* Above is exactly the same format as struct arphdr */
u64 s_uniq_id; /* Sender's 64bit EUI */
u8 max_rec; /* Sender's max packet size */
u8 sspd; /* Sender's max speed */
u16 fifo_hi; /* hi 16bits of sender's FIFO addr */
u32 fifo_lo; /* lo 32bits of sender's FIFO addr */
u32 sip; /* Sender's IP Address */
u32 tip; /* IP Address of requested hw addr */
};
/* Network timeout */
#define ETHER1394_TIMEOUT 100000
#endif /* __ETH1394_H */
...@@ -43,6 +43,16 @@ static struct hpsb_host_operations dummy_ops = { ...@@ -43,6 +43,16 @@ static struct hpsb_host_operations dummy_ops = {
devctl: dummy_devctl devctl: dummy_devctl
}; };
/**
* hpsb_ref_host - increase reference count for host controller.
* @host: the host controller
*
* Increase the reference count for the specified host controller.
* When holding a reference to a host, the memory allocated for the
* host struct will not be freed and the host is guaranteed to be in a
* consistent state. The driver may be unloaded or the controller may
* be removed (PCMCIA), but the host struct will remain valid.
*/
int hpsb_ref_host(struct hpsb_host *host) int hpsb_ref_host(struct hpsb_host *host)
{ {
...@@ -53,10 +63,9 @@ int hpsb_ref_host(struct hpsb_host *host) ...@@ -53,10 +63,9 @@ int hpsb_ref_host(struct hpsb_host *host)
spin_lock_irqsave(&hosts_lock, flags); spin_lock_irqsave(&hosts_lock, flags);
list_for_each(lh, &hosts) { list_for_each(lh, &hosts) {
if (host == list_entry(lh, struct hpsb_host, host_list)) { if (host == list_entry(lh, struct hpsb_host, host_list)) {
if (host->ops->devctl(host, MODIFY_USAGE, 1)) { host->ops->devctl(host, MODIFY_USAGE, 1);
host->refcount++; host->refcount++;
retval = 1; retval = 1;
}
break; break;
} }
} }
...@@ -65,6 +74,15 @@ int hpsb_ref_host(struct hpsb_host *host) ...@@ -65,6 +74,15 @@ int hpsb_ref_host(struct hpsb_host *host)
return retval; return retval;
} }
/**
* hpsb_unref_host - decrease reference count for host controller.
* @host: the host controller
*
* Decrease the reference count for the specified host controller.
* When the reference count reaches zero, the memory allocated for the
* &hpsb_host will be freed.
*/
void hpsb_unref_host(struct hpsb_host *host) void hpsb_unref_host(struct hpsb_host *host)
{ {
unsigned long flags; unsigned long flags;
...@@ -74,23 +92,44 @@ void hpsb_unref_host(struct hpsb_host *host) ...@@ -74,23 +92,44 @@ void hpsb_unref_host(struct hpsb_host *host)
spin_lock_irqsave(&hosts_lock, flags); spin_lock_irqsave(&hosts_lock, flags);
host->refcount--; host->refcount--;
if (!host->refcount && !host->is_shutdown) if (!host->refcount && host->is_shutdown)
kfree(host); kfree(host);
spin_unlock_irqrestore(&hosts_lock, flags); spin_unlock_irqrestore(&hosts_lock, flags);
} }
/**
* hpsb_alloc_host - allocate a new host controller.
* @drv: the driver that will manage the host controller
* @extra: number of extra bytes to allocate for the driver
*
* Allocate a &hpsb_host and initialize the general subsystem specific
* fields. If the driver needs to store per host data, as drivers
* usually do, the amount of memory required can be specified by the
* @extra parameter. Once allocated, the driver should initialize the
* driver specific parts, enable the controller and make it available
* to the general subsystem using hpsb_add_host().
*
* The &hpsb_host is allocated with an single initial reference
* belonging to the driver. Once the driver is done with the struct,
* for example, when the driver is unloaded, it should release this
* reference using hpsb_unref_host().
*
* Return Value: a pointer to the &hpsb_host if succesful, %NULL if
* no memory was available.
*/
struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra) struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra)
{ {
struct hpsb_host *h; struct hpsb_host *h;
h = kmalloc(sizeof(struct hpsb_host) + extra, SLAB_KERNEL); h = kmalloc(sizeof(struct hpsb_host) + extra, SLAB_KERNEL);
if (!h) return NULL; if (!h) return NULL;
memset(h, 0, sizeof(struct hpsb_host));
memset(h, 0, sizeof(struct hpsb_host) + extra); h->hostdata = h + 1;
h->driver = drv; h->driver = drv;
h->ops = drv->ops; h->ops = drv->ops;
h->hostdata = h + 1; h->refcount = 1;
INIT_LIST_HEAD(&h->pending_packets); INIT_LIST_HEAD(&h->pending_packets);
spin_lock_init(&h->pending_pkt_lock); spin_lock_init(&h->pending_pkt_lock);
...@@ -134,9 +173,7 @@ void hpsb_remove_host(struct hpsb_host *host) ...@@ -134,9 +173,7 @@ void hpsb_remove_host(struct hpsb_host *host)
spin_lock_irqsave(&hosts_lock, flags); spin_lock_irqsave(&hosts_lock, flags);
list_del(&host->driver_list); list_del(&host->driver_list);
list_del(&host->host_list); list_del(&host->host_list);
drv->number_of_hosts--; drv->number_of_hosts--;
if (!host->refcount) kfree(host);
spin_unlock_irqrestore(&hosts_lock, flags); spin_unlock_irqrestore(&hosts_lock, flags);
} }
......
...@@ -36,6 +36,7 @@ struct hpsb_host { ...@@ -36,6 +36,7 @@ struct hpsb_host {
int node_count; /* number of identified nodes on this bus */ int node_count; /* number of identified nodes on this bus */
int selfid_count; /* total number of SelfIDs received */ int selfid_count; /* total number of SelfIDs received */
int nodes_active; /* number of nodes that are actually active */
nodeid_t node_id; /* node ID of this host */ nodeid_t node_id; /* node ID of this host */
nodeid_t irm_id; /* ID of this bus' isochronous resource manager */ nodeid_t irm_id; /* ID of this bus' isochronous resource manager */
......
...@@ -41,6 +41,10 @@ MODULE_PARM(disable_nodemgr, "i"); ...@@ -41,6 +41,10 @@ MODULE_PARM(disable_nodemgr, "i");
MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality."); MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality.");
static int disable_nodemgr = 0; static int disable_nodemgr = 0;
MODULE_PARM(disable_hotplug, "i");
MODULE_PARM_DESC(disable_hotplug, "Disable hotplug for detected nodes.");
static int disable_hotplug = 0;
/* We are GPL, so treat us special */ /* We are GPL, so treat us special */
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -108,7 +112,7 @@ struct hpsb_packet *alloc_hpsb_packet(size_t data_size) ...@@ -108,7 +112,7 @@ struct hpsb_packet *alloc_hpsb_packet(size_t data_size)
packet->data_size = data_size; packet->data_size = data_size;
} }
INIT_TQ_HEAD(packet->complete_tq); INIT_LIST_HEAD(&packet->complete_tq);
INIT_LIST_HEAD(&packet->list); INIT_LIST_HEAD(&packet->list);
sema_init(&packet->state_change, 0); sema_init(&packet->state_change, 0);
packet->state = hpsb_unused; packet->state = hpsb_unused;
...@@ -177,6 +181,8 @@ static int check_selfids(struct hpsb_host *host) ...@@ -177,6 +181,8 @@ static int check_selfids(struct hpsb_host *host)
struct ext_selfid *esid; struct ext_selfid *esid;
int esid_seq = 23; int esid_seq = 23;
host->nodes_active = 0;
while (rest_of_selfids--) { while (rest_of_selfids--) {
if (!sid->extended) { if (!sid->extended) {
nodeid++; nodeid++;
...@@ -188,7 +194,9 @@ static int check_selfids(struct hpsb_host *host) ...@@ -188,7 +194,9 @@ static int check_selfids(struct hpsb_host *host)
return 0; return 0;
} }
if (sid->contender && sid->link_active) { if (sid->link_active) {
host->nodes_active++;
if (sid->contender)
host->irm_id = LOCAL_BUS | sid->phy_id; host->irm_id = LOCAL_BUS | sid->phy_id;
} }
} else { } else {
...@@ -224,7 +232,8 @@ static int check_selfids(struct hpsb_host *host) ...@@ -224,7 +232,8 @@ static int check_selfids(struct hpsb_host *host)
return 0; return 0;
} }
return nodeid + 1; host->node_count = nodeid + 1;
return 1;
} }
static void build_speed_map(struct hpsb_host *host, int nodecount) static void build_speed_map(struct hpsb_host *host, int nodecount)
...@@ -322,8 +331,7 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot) ...@@ -322,8 +331,7 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
host->node_id = LOCAL_BUS | phyid; host->node_id = LOCAL_BUS | phyid;
host->is_root = isroot; host->is_root = isroot;
host->node_count = check_selfids(host); if (!check_selfids(host)) {
if (!host->node_count) {
if (host->reset_retries++ < 20) { if (host->reset_retries++ < 20) {
/* selfid stage did not complete without error */ /* selfid stage did not complete without error */
HPSB_NOTICE("Error in SelfID stage, resetting"); HPSB_NOTICE("Error in SelfID stage, resetting");
...@@ -803,7 +811,7 @@ static rwlock_t ieee1394_chardevs_lock = RW_LOCK_UNLOCKED; ...@@ -803,7 +811,7 @@ static rwlock_t ieee1394_chardevs_lock = RW_LOCK_UNLOCKED;
static int ieee1394_dispatch_open(struct inode *inode, struct file *file); static int ieee1394_dispatch_open(struct inode *inode, struct file *file);
static struct file_operations ieee1394_chardev_ops = { static struct file_operations ieee1394_chardev_ops = {
OWNER_THIS_MODULE owner: THIS_MODULE,
open: ieee1394_dispatch_open, open: ieee1394_dispatch_open,
}; };
...@@ -828,8 +836,6 @@ int ieee1394_register_chardev(int blocknum, ...@@ -828,8 +836,6 @@ int ieee1394_register_chardev(int blocknum,
ieee1394_chardevs[blocknum].module = module; ieee1394_chardevs[blocknum].module = module;
retval = 0; retval = 0;
V22_COMPAT_MOD_INC_USE_COUNT;
} else { } else {
/* block already taken */ /* block already taken */
retval = -EBUSY; retval = -EBUSY;
...@@ -851,7 +857,6 @@ void ieee1394_unregister_chardev(int blocknum) ...@@ -851,7 +857,6 @@ void ieee1394_unregister_chardev(int blocknum)
if(ieee1394_chardevs[blocknum].file_ops) { if(ieee1394_chardevs[blocknum].file_ops) {
ieee1394_chardevs[blocknum].file_ops = NULL; ieee1394_chardevs[blocknum].file_ops = NULL;
ieee1394_chardevs[blocknum].module = NULL; ieee1394_chardevs[blocknum].module = NULL;
V22_COMPAT_MOD_DEC_USE_COUNT;
} }
write_unlock(&ieee1394_chardevs_lock); write_unlock(&ieee1394_chardevs_lock);
...@@ -868,12 +873,6 @@ static int ieee1394_dispatch_open(struct inode *inode, struct file *file) ...@@ -868,12 +873,6 @@ static int ieee1394_dispatch_open(struct inode *inode, struct file *file)
/* /*
Maintaining correct module reference counts is tricky here! Maintaining correct module reference counts is tricky here!
For Linux v2.2:
The task-specific driver is expected to maintain its own
reference count via V22_COMPAT_MOD_[INC,DEC]_USE_COUNT.
We don't need to do anything special.
For Linux v2.4 and later: For Linux v2.4 and later:
The key thing to remember is that the VFS increments the The key thing to remember is that the VFS increments the
...@@ -894,17 +893,10 @@ static int ieee1394_dispatch_open(struct inode *inode, struct file *file) ...@@ -894,17 +893,10 @@ static int ieee1394_dispatch_open(struct inode *inode, struct file *file)
*/ */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
/* 2.2 */
#define INCREF(mod) do {} while (0)
#define DECREF(mod) do {} while (0)
#else
/* 2.4 */
#define INCREF(mod_) do { struct module *mod = (struct module*) mod_; \ #define INCREF(mod_) do { struct module *mod = (struct module*) mod_; \
if(mod != NULL) __MOD_INC_USE_COUNT(mod); } while(0) if(mod != NULL) __MOD_INC_USE_COUNT(mod); } while(0)
#define DECREF(mod_) do { struct module *mod = (struct module*) mod_; \ #define DECREF(mod_) do { struct module *mod = (struct module*) mod_; \
if(mod != NULL) __MOD_DEC_USE_COUNT(mod); } while(0) if(mod != NULL) __MOD_DEC_USE_COUNT(mod); } while(0)
#endif
/* shift away lower four bits of the minor /* shift away lower four bits of the minor
to get the index of the ieee1394_driver to get the index of the ieee1394_driver
...@@ -1013,7 +1005,7 @@ static int __init ieee1394_init(void) ...@@ -1013,7 +1005,7 @@ static int __init ieee1394_init(void)
init_hpsb_highlevel(); init_hpsb_highlevel();
init_csr(); init_csr();
if (!disable_nodemgr) if (!disable_nodemgr)
init_ieee1394_nodemgr(); init_ieee1394_nodemgr(disable_hotplug);
else else
HPSB_INFO("nodemgr functionality disabled"); HPSB_INFO("nodemgr functionality disabled");
...@@ -1099,8 +1091,10 @@ EXPORT_SYMBOL(highlevel_host_reset); ...@@ -1099,8 +1091,10 @@ EXPORT_SYMBOL(highlevel_host_reset);
EXPORT_SYMBOL(hpsb_guid_get_entry); EXPORT_SYMBOL(hpsb_guid_get_entry);
EXPORT_SYMBOL(hpsb_nodeid_get_entry); EXPORT_SYMBOL(hpsb_nodeid_get_entry);
EXPORT_SYMBOL(hpsb_get_host_by_ne); EXPORT_SYMBOL(hpsb_node_fill_packet);
EXPORT_SYMBOL(hpsb_guid_fill_packet); EXPORT_SYMBOL(hpsb_node_read);
EXPORT_SYMBOL(hpsb_node_write);
EXPORT_SYMBOL(hpsb_node_lock);
EXPORT_SYMBOL(hpsb_register_protocol); EXPORT_SYMBOL(hpsb_register_protocol);
EXPORT_SYMBOL(hpsb_unregister_protocol); EXPORT_SYMBOL(hpsb_unregister_protocol);
EXPORT_SYMBOL(hpsb_release_unit_directory); EXPORT_SYMBOL(hpsb_release_unit_directory);
......
...@@ -415,8 +415,8 @@ struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, ...@@ -415,8 +415,8 @@ struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host,
* avoid in kernel buffers for user space callers * avoid in kernel buffers for user space callers
*/ */
int hpsb_read(struct hpsb_host *host, nodeid_t node, u64 addr, int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
quadlet_t *buffer, size_t length) u64 addr, quadlet_t *buffer, size_t length)
{ {
struct hpsb_packet *packet; struct hpsb_packet *packet;
int retval = 0; int retval = 0;
...@@ -447,7 +447,7 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, u64 addr, ...@@ -447,7 +447,7 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, u64 addr,
return -ENOMEM; return -ENOMEM;
} }
packet->generation = get_hpsb_generation(host); packet->generation = generation;
if (!hpsb_send_packet(packet)) { if (!hpsb_send_packet(packet)) {
retval = -EINVAL; retval = -EINVAL;
goto hpsb_read_fail; goto hpsb_read_fail;
...@@ -496,8 +496,8 @@ struct hpsb_packet *hpsb_make_packet (struct hpsb_host *host, nodeid_t node, ...@@ -496,8 +496,8 @@ struct hpsb_packet *hpsb_make_packet (struct hpsb_host *host, nodeid_t node,
return packet; return packet;
} }
int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr, int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
quadlet_t *buffer, size_t length) u64 addr, quadlet_t *buffer, size_t length)
{ {
struct hpsb_packet *packet; struct hpsb_packet *packet;
int retval; int retval;
...@@ -522,7 +522,7 @@ int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr, ...@@ -522,7 +522,7 @@ int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr,
if (!packet) if (!packet)
return -ENOMEM; return -ENOMEM;
packet->generation = get_hpsb_generation(host); packet->generation = generation;
if (!hpsb_send_packet(packet)) { if (!hpsb_send_packet(packet)) {
retval = -EINVAL; retval = -EINVAL;
goto hpsb_write_fail; goto hpsb_write_fail;
...@@ -541,8 +541,8 @@ int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr, ...@@ -541,8 +541,8 @@ int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr,
/* We need a hpsb_lock64 function for the 64 bit equivalent. Probably. */ /* We need a hpsb_lock64 function for the 64 bit equivalent. Probably. */
int hpsb_lock(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode, int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
quadlet_t *data, quadlet_t arg) u64 addr, int extcode, quadlet_t *data, quadlet_t arg)
{ {
struct hpsb_packet *packet; struct hpsb_packet *packet;
int retval = 0, length; int retval = 0, length;
...@@ -588,7 +588,7 @@ int hpsb_lock(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode, ...@@ -588,7 +588,7 @@ int hpsb_lock(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode,
} }
fill_async_lock(packet, addr, extcode, length); fill_async_lock(packet, addr, extcode, length);
packet->generation = get_hpsb_generation(host); packet->generation = generation;
if (!hpsb_send_packet(packet)) { if (!hpsb_send_packet(packet)) {
retval = -EINVAL; retval = -EINVAL;
goto hpsb_lock_fail; goto hpsb_lock_fail;
......
...@@ -63,14 +63,16 @@ int hpsb_packet_success(struct hpsb_packet *packet); ...@@ -63,14 +63,16 @@ int hpsb_packet_success(struct hpsb_packet *packet);
* The generic read, write and lock functions. All recognize the local node ID * The generic read, write and lock functions. All recognize the local node ID
* and act accordingly. Read and write automatically use quadlet commands if * and act accordingly. Read and write automatically use quadlet commands if
* length == 4 and and block commands otherwise (however, they do not yet * length == 4 and and block commands otherwise (however, they do not yet
* support lengths that are not a multiple of 4). * support lengths that are not a multiple of 4). You must explicitly specifiy
* the generation for which the node ID is valid, to avoid sending packets to
* the wrong nodes when we race with a bus reset.
*/ */
int hpsb_read(struct hpsb_host *host, nodeid_t node, u64 addr, int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
quadlet_t *buffer, size_t length); u64 addr, quadlet_t *buffer, size_t length);
int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr, int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
quadlet_t *buffer, size_t length); u64 addr, quadlet_t *buffer, size_t length);
int hpsb_lock(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode, int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
quadlet_t *data, quadlet_t arg); u64 addr, int extcode, quadlet_t *data, quadlet_t arg);
/* Generic packet creation. Used by hpsb_write. Also useful for protocol /* Generic packet creation. Used by hpsb_write. Also useful for protocol
* drivers that want to implement their own hpsb_write replacement. */ * drivers that want to implement their own hpsb_write replacement. */
......
...@@ -10,17 +10,6 @@ ...@@ -10,17 +10,6 @@
#include <asm/byteorder.h> #include <asm/byteorder.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
#include "linux22compat.h"
#else
#define V22_COMPAT_MOD_INC_USE_COUNT do {} while (0)
#define V22_COMPAT_MOD_DEC_USE_COUNT do {} while (0)
#define OWNER_THIS_MODULE owner: THIS_MODULE,
#define INIT_TQ_LINK(tq) INIT_LIST_HEAD(&(tq).list)
#define INIT_TQ_HEAD(tq) INIT_LIST_HEAD(&(tq))
#endif
/* The great kdev_t changeover in 2.5.x */ /* The great kdev_t changeover in 2.5.x */
#include <linux/kdev_t.h> #include <linux/kdev_t.h>
#ifndef minor #ifndef minor
...@@ -48,11 +37,7 @@ ...@@ -48,11 +37,7 @@
#endif /* Linux version < 2.4.12 */ #endif /* Linux version < 2.4.12 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18)
#include <asm/spinlock.h>
#else
#include <linux/spinlock.h> #include <linux/spinlock.h>
#endif
#ifndef list_for_each_safe #ifndef list_for_each_safe
#define list_for_each_safe(pos, n, head) \ #define list_for_each_safe(pos, n, head) \
...@@ -61,6 +46,10 @@ ...@@ -61,6 +46,10 @@
#endif #endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5)
#define pte_offset_kernel pte_offset
#endif
#ifndef MIN #ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif #endif
...@@ -78,7 +67,8 @@ typedef u16 nodeid_t; ...@@ -78,7 +67,8 @@ typedef u16 nodeid_t;
#define LOCAL_BUS 0xffc0 #define LOCAL_BUS 0xffc0
#define ALL_NODES 0x003f #define ALL_NODES 0x003f
#define NODE_BUS_FMT "%d:%d" /* Can be used to consistently print a node/bus ID. */
#define NODE_BUS_FMT "%02d:%04d"
#define NODE_BUS_ARGS(nodeid) \ #define NODE_BUS_ARGS(nodeid) \
(nodeid & NODE_MASK), ((nodeid & BUS_MASK) >> 6) (nodeid & NODE_MASK), ((nodeid & BUS_MASK) >> 6)
......
This diff is collapsed.
...@@ -125,7 +125,7 @@ struct node_entry { ...@@ -125,7 +125,7 @@ struct node_entry {
struct hpsb_host *host; /* Host this node is attached to */ struct hpsb_host *host; /* Host this node is attached to */
nodeid_t nodeid; /* NodeID */ nodeid_t nodeid; /* NodeID */
struct bus_options busopt; /* Bus Options */ struct bus_options busopt; /* Bus Options */
atomic_t generation; /* Synced with hpsb generation */ unsigned int generation; /* Synced with hpsb generation */
/* The following is read from the config rom */ /* The following is read from the config rom */
u32 vendor_id; u32 vendor_id;
...@@ -138,7 +138,7 @@ struct node_entry { ...@@ -138,7 +138,7 @@ struct node_entry {
static inline int hpsb_node_entry_valid(struct node_entry *ne) static inline int hpsb_node_entry_valid(struct node_entry *ne)
{ {
return atomic_read(&ne->generation) == get_hpsb_generation(ne->host); return ne->generation == get_hpsb_generation(ne->host);
} }
/* /*
...@@ -170,10 +170,17 @@ struct hpsb_host *hpsb_get_host_by_ne(struct node_entry *ne); ...@@ -170,10 +170,17 @@ struct hpsb_host *hpsb_get_host_by_ne(struct node_entry *ne);
* number). It will at least reliably fail so that you don't accidentally and * number). It will at least reliably fail so that you don't accidentally and
* unknowingly send your packet to the wrong node. * unknowingly send your packet to the wrong node.
*/ */
int hpsb_guid_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt); void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt);
int hpsb_node_read(struct node_entry *ne, u64 addr,
quadlet_t *buffer, size_t length);
int hpsb_node_write(struct node_entry *ne, u64 addr,
quadlet_t *buffer, size_t length);
int hpsb_node_lock(struct node_entry *ne, u64 addr,
int extcode, quadlet_t *data, quadlet_t arg);
void init_ieee1394_nodemgr(void);
void init_ieee1394_nodemgr(int disable_hotplug);
void cleanup_ieee1394_nodemgr(void); void cleanup_ieee1394_nodemgr(void);
#endif /* _IEEE1394_NODEMGR_H */ #endif /* _IEEE1394_NODEMGR_H */
...@@ -96,7 +96,6 @@ ...@@ -96,7 +96,6 @@
#include <linux/poll.h> #include <linux/poll.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <asm/io.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/tqueue.h> #include <linux/tqueue.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -161,7 +160,7 @@ printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args) ...@@ -161,7 +160,7 @@ printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args)
printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args) printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
static char version[] __devinitdata = static char version[] __devinitdata =
"$Revision: 1.91 $ Ben Collins <bcollins@debian.org>"; "$Revision: 1.101 $ Ben Collins <bcollins@debian.org>";
/* Module Parameters */ /* Module Parameters */
MODULE_PARM(attempt_root,"i"); MODULE_PARM(attempt_root,"i");
...@@ -487,7 +486,6 @@ static void ohci_init_config_rom(struct ti_ohci *ohci); ...@@ -487,7 +486,6 @@ static void ohci_init_config_rom(struct ti_ohci *ohci);
/* Global initialization */ /* Global initialization */
static void ohci_initialize(struct ti_ohci *ohci) static void ohci_initialize(struct ti_ohci *ohci)
{ {
int i;
quadlet_t buf; quadlet_t buf;
spin_lock_init(&ohci->phy_reg_lock); spin_lock_init(&ohci->phy_reg_lock);
...@@ -535,14 +533,6 @@ static void ohci_initialize(struct ti_ohci *ohci) ...@@ -535,14 +533,6 @@ static void ohci_initialize(struct ti_ohci *ohci)
/* Don't accept phy packets into AR request context */ /* Don't accept phy packets into AR request context */
reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400); reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
/* Initialize IR dma */
for (i=0;i<ohci->nb_iso_rcv_ctx;i++) {
reg_write(ohci, OHCI1394_IsoRcvContextControlClear+32*i,
0xffffffff);
reg_write(ohci, OHCI1394_IsoRcvContextMatch+32*i, 0);
reg_write(ohci, OHCI1394_IsoRcvCommandPtr+32*i, 0);
}
/* Set bufferFill, isochHeader, multichannel for IR context */ /* Set bufferFill, isochHeader, multichannel for IR context */
reg_write(ohci, OHCI1394_IsoRcvContextControlSet, 0xd0000000); reg_write(ohci, OHCI1394_IsoRcvContextControlSet, 0xd0000000);
...@@ -553,13 +543,6 @@ static void ohci_initialize(struct ti_ohci *ohci) ...@@ -553,13 +543,6 @@ static void ohci_initialize(struct ti_ohci *ohci)
reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff); reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff); reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
/* Initialize IT dma */
for (i=0;i<ohci->nb_iso_xmit_ctx;i++) {
reg_write(ohci, OHCI1394_IsoXmitContextControlClear+32*i,
0xffffffff);
reg_write(ohci, OHCI1394_IsoXmitCommandPtr+32*i, 0);
}
/* Clear the interrupt mask */ /* Clear the interrupt mask */
reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff); reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff); reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
...@@ -615,7 +598,8 @@ static void ohci_initialize(struct ti_ohci *ohci) ...@@ -615,7 +598,8 @@ static void ohci_initialize(struct ti_ohci *ohci)
OHCI1394_respTxComplete | OHCI1394_respTxComplete |
OHCI1394_reqTxComplete | OHCI1394_reqTxComplete |
OHCI1394_isochRx | OHCI1394_isochRx |
OHCI1394_isochTx); OHCI1394_isochTx |
OHCI1394_cycleInconsistent);
/* Enable link */ /* Enable link */
reg_write(ohci, OHCI1394_HCControlSet, 0x00020000); reg_write(ohci, OHCI1394_HCControlSet, 0x00020000);
...@@ -936,6 +920,7 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) ...@@ -936,6 +920,7 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
} else { } else {
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
} }
retval = 1;
break; break;
case ISO_LISTEN_CHANNEL: case ISO_LISTEN_CHANNEL:
...@@ -1098,6 +1083,14 @@ static void ohci_irq_handler(int irq, void *dev_id, ...@@ -1098,6 +1083,14 @@ static void ohci_irq_handler(int irq, void *dev_id,
return; return;
} }
if (event & OHCI1394_cycleInconsistent) {
/* We subscribe to the cycleInconsistent event only to
* clear the corresponding event bit... otherwise,
* isochronous cycleMatch DMA wont work. */
DBGMSG(ohci->id, "OHCI1394_cycleInconsistent");
event &= ~OHCI1394_cycleInconsistent;
}
if (event & OHCI1394_busReset) { if (event & OHCI1394_busReset) {
/* The busReset event bit can't be cleared during the /* The busReset event bit can't be cleared during the
* selfID phase, so we disable busReset interrupts, to * selfID phase, so we disable busReset interrupts, to
...@@ -1265,8 +1258,8 @@ static void ohci_irq_handler(int irq, void *dev_id, ...@@ -1265,8 +1258,8 @@ static void ohci_irq_handler(int irq, void *dev_id,
/* Finally, we clear the busReset event and reenable /* Finally, we clear the busReset event and reenable
* the busReset interrupt. */ * the busReset interrupt. */
spin_lock_irqsave(&ohci->event_lock, flags); spin_lock_irqsave(&ohci->event_lock, flags);
reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset);
reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset);
spin_unlock_irqrestore(&ohci->event_lock, flags); spin_unlock_irqrestore(&ohci->event_lock, flags);
event &= ~OHCI1394_selfIDComplete; event &= ~OHCI1394_selfIDComplete;
} }
...@@ -1509,6 +1502,15 @@ static void dma_trm_tasklet (unsigned long data) ...@@ -1509,6 +1502,15 @@ static void dma_trm_tasklet (unsigned long data)
/* this packet hasn't been sent yet*/ /* this packet hasn't been sent yet*/
break; break;
if (!(ack & 0x10)) {
/* XXX: This is an OHCI evt_* code. We need to handle
* this specially! For right now, we just fake an
* ackx_send_error. */
PRINT(KERN_DEBUG, ohci->id, "Received OHCI evt_* error 0x%x",
ack & 0xf);
ack = (ack & 0xffe0) | ACK_BUSY_A;
}
#ifdef OHCI1394_DEBUG #ifdef OHCI1394_DEBUG
if (datasize) if (datasize)
DBGMSG(ohci->id, DBGMSG(ohci->id,
...@@ -1942,7 +1944,8 @@ static void ohci_init_config_rom(struct ti_ohci *ohci) ...@@ -1942,7 +1944,8 @@ static void ohci_init_config_rom(struct ti_ohci *ohci)
/* Root directory */ /* Root directory */
cf_unit_begin(&cr, 1); cf_unit_begin(&cr, 1);
cf_put_keyval(&cr, 0x03, 0x00005e); /* Vendor ID */ /* Vendor ID */
cf_put_keyval(&cr, 0x03, reg_read(ohci,OHCI1394_VendorID) & 0xFFFFFF);
cf_put_refer(&cr, 0x81, 2); /* Textual description unit */ cf_put_refer(&cr, 0x81, 2); /* Textual description unit */
cf_put_keyval(&cr, 0x0c, 0x0083c0); /* Node capabilities */ cf_put_keyval(&cr, 0x0c, 0x0083c0); /* Node capabilities */
/* NOTE: Add other unit referers here, and append at bottom */ /* NOTE: Add other unit referers here, and append at bottom */
...@@ -2287,7 +2290,7 @@ static void __devexit ohci1394_pci_remove(struct pci_dev *pdev) ...@@ -2287,7 +2290,7 @@ static void __devexit ohci1394_pci_remove(struct pci_dev *pdev)
#endif /* CONFIG_ALL_PPC */ #endif /* CONFIG_ALL_PPC */
pci_set_drvdata(ohci->dev, NULL); pci_set_drvdata(ohci->dev, NULL);
kfree(ohci); hpsb_unref_host(ohci->host);
} }
#define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10) #define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#define _OHCI1394_H #define _OHCI1394_H
#include "ieee1394_types.h" #include "ieee1394_types.h"
#include <asm/io.h>
#define OHCI1394_DRIVER_NAME "ohci1394" #define OHCI1394_DRIVER_NAME "ohci1394"
...@@ -192,7 +193,7 @@ struct ti_ohci { ...@@ -192,7 +193,7 @@ struct ti_ohci {
/* IRQ hooks, for video1394 and dv1394 */ /* IRQ hooks, for video1394 and dv1394 */
#define OHCI1394_MAX_IRQ_HOOKS 4 #define OHCI1394_MAX_IRQ_HOOKS 16
struct ohci1394_irq_hook { struct ohci1394_irq_hook {
void (*irq_handler) (int card, quadlet_t isoRecvEvent, void (*irq_handler) (int card, quadlet_t isoRecvEvent,
...@@ -314,7 +315,7 @@ static inline u32 reg_read(const struct ti_ohci *ohci, int offset) ...@@ -314,7 +315,7 @@ static inline u32 reg_read(const struct ti_ohci *ohci, int offset)
#define OHCI1394_AsRspRcvCommandPtr 0x1EC #define OHCI1394_AsRspRcvCommandPtr 0x1EC
/* Isochronous transmit registers */ /* Isochronous transmit registers */
/* Add (32 * n) for context n */ /* Add (16 * n) for context n */
#define OHCI1394_IsoXmitContextBase 0x200 #define OHCI1394_IsoXmitContextBase 0x200
#define OHCI1394_IsoXmitContextControlSet 0x200 #define OHCI1394_IsoXmitContextControlSet 0x200
#define OHCI1394_IsoXmitContextControlClear 0x204 #define OHCI1394_IsoXmitContextControlClear 0x204
...@@ -363,6 +364,28 @@ static inline u32 reg_read(const struct ti_ohci *ohci, int offset) ...@@ -363,6 +364,28 @@ static inline u32 reg_read(const struct ti_ohci *ohci, int offset)
#define DMA_CTL_BRANCH 0x000c0000 #define DMA_CTL_BRANCH 0x000c0000
#define DMA_CTL_WAIT 0x00030000 #define DMA_CTL_WAIT 0x00030000
/* OHCI evt_* error types, table 3-2 of the OHCI 1.1 spec. */
#define EVT_NO_STATUS 0x0 /* No event status */
#define EVT_RESERVED 0x1 /* Reserved, not used !!! */
#define EVT_LONG_PACKET 0x2 /* The revc data was longer than the buf */
#define EVT_MISSING_ACK 0x3 /* A subaction gap was detected before an ack
arrived, or recv'd ack had a parity error */
#define EVT_UNDERRUN 0x4 /* Underrun on corresponding FIFO, packet
truncated */
#define EVT_OVERRUN 0x5 /* A recv FIFO overflowed on reception of ISO
packet */
#define EVT_DESCRIPTOR_READ 0x6 /* An unrecoverable error occured while host was
reading a descriptor block */
#define EVT_DATA_READ 0x7 /* An error occured while host controller was
attempting to read from host memory in the data
stage of descriptor processing */
#define EVT_DATA_WRITE 0x8 /* An error occured while host controller was
attempting to write either during the data stage
of descriptor processing, or when processing a single
16-bit host memory write */
#define EVT_BUS_RESET 0x9 /* Identifies a PHY packet in the recv buffer as
being a synthesized bus reset packet */
#define OHCI1394_TCODE_PHY 0xE #define OHCI1394_TCODE_PHY 0xE
void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg); void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg);
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/smp_lock.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -56,6 +55,7 @@ ...@@ -56,6 +55,7 @@
#define PRINTD(level, card, fmt, args...) do {} while (0) #define PRINTD(level, card, fmt, args...) do {} while (0)
#endif #endif
static struct hpsb_host_driver *lynx_driver; static struct hpsb_host_driver *lynx_driver;
static unsigned int card_id; static unsigned int card_id;
...@@ -614,7 +614,7 @@ static ssize_t mem_write(struct file*, const char*, size_t, loff_t*); ...@@ -614,7 +614,7 @@ static ssize_t mem_write(struct file*, const char*, size_t, loff_t*);
static struct file_operations aux_ops = { static struct file_operations aux_ops = {
OWNER_THIS_MODULE owner: THIS_MODULE,
read: mem_read, read: mem_read,
write: mem_write, write: mem_write,
poll: aux_poll, poll: aux_poll,
...@@ -639,42 +639,31 @@ static int mem_open(struct inode *inode, struct file *file) ...@@ -639,42 +639,31 @@ static int mem_open(struct inode *inode, struct file *file)
enum { t_rom, t_aux, t_ram } type; enum { t_rom, t_aux, t_ram } type;
struct memdata *md; struct memdata *md;
V22_COMPAT_MOD_INC_USE_COUNT;
if (cid < PCILYNX_MINOR_AUX_START) { if (cid < PCILYNX_MINOR_AUX_START) {
/* just for completeness */ /* just for completeness */
V22_COMPAT_MOD_DEC_USE_COUNT;
return -ENXIO; return -ENXIO;
} else if (cid < PCILYNX_MINOR_ROM_START) { } else if (cid < PCILYNX_MINOR_ROM_START) {
cid -= PCILYNX_MINOR_AUX_START; cid -= PCILYNX_MINOR_AUX_START;
if (cid >= num_of_cards || !cards[cid].aux_port) { if (cid >= num_of_cards || !cards[cid].aux_port)
V22_COMPAT_MOD_DEC_USE_COUNT;
return -ENXIO; return -ENXIO;
}
type = t_aux; type = t_aux;
} else if (cid < PCILYNX_MINOR_RAM_START) { } else if (cid < PCILYNX_MINOR_RAM_START) {
cid -= PCILYNX_MINOR_ROM_START; cid -= PCILYNX_MINOR_ROM_START;
if (cid >= num_of_cards || !cards[cid].local_rom) { if (cid >= num_of_cards || !cards[cid].local_rom)
V22_COMPAT_MOD_DEC_USE_COUNT;
return -ENXIO; return -ENXIO;
}
type = t_rom; type = t_rom;
} else { } else {
/* WARNING: Know what you are doing when opening RAM. /* WARNING: Know what you are doing when opening RAM.
* It is currently used inside the driver! */ * It is currently used inside the driver! */
cid -= PCILYNX_MINOR_RAM_START; cid -= PCILYNX_MINOR_RAM_START;
if (cid >= num_of_cards || !cards[cid].local_ram) { if (cid >= num_of_cards || !cards[cid].local_ram)
V22_COMPAT_MOD_DEC_USE_COUNT;
return -ENXIO; return -ENXIO;
}
type = t_ram; type = t_ram;
} }
md = (struct memdata *)kmalloc(sizeof(struct memdata), SLAB_KERNEL); md = (struct memdata *)kmalloc(sizeof(struct memdata), SLAB_KERNEL);
if (md == NULL) { if (md == NULL)
V22_COMPAT_MOD_DEC_USE_COUNT;
return -ENOMEM; return -ENOMEM;
}
md->lynx = &cards[cid]; md->lynx = &cards[cid];
md->cid = cid; md->cid = cid;
...@@ -700,11 +689,7 @@ static int mem_open(struct inode *inode, struct file *file) ...@@ -700,11 +689,7 @@ static int mem_open(struct inode *inode, struct file *file)
static int mem_release(struct inode *inode, struct file *file) static int mem_release(struct inode *inode, struct file *file)
{ {
struct memdata *md = (struct memdata *)file->private_data; kfree(file->private_data);
kfree(md);
V22_COMPAT_MOD_DEC_USE_COUNT;
return 0; return 0;
} }
...@@ -732,9 +717,8 @@ static unsigned int aux_poll(struct file *file, poll_table *pt) ...@@ -732,9 +717,8 @@ static unsigned int aux_poll(struct file *file, poll_table *pt)
loff_t mem_llseek(struct file *file, loff_t offs, int orig) loff_t mem_llseek(struct file *file, loff_t offs, int orig)
{ {
loff_t newoffs = -1; loff_t newoffs;
lock_kernel();
switch (orig) { switch (orig) {
case 0: case 0:
newoffs = offs; newoffs = offs;
...@@ -744,14 +728,13 @@ loff_t mem_llseek(struct file *file, loff_t offs, int orig) ...@@ -744,14 +728,13 @@ loff_t mem_llseek(struct file *file, loff_t offs, int orig)
break; break;
case 2: case 2:
newoffs = PCILYNX_MAX_MEMORY + 1 + offs; newoffs = PCILYNX_MAX_MEMORY + 1 + offs;
} break;
default:
if (newoffs < 0 || newoffs > PCILYNX_MAX_MEMORY + 1) {
unlock_kernel();
return -EINVAL; return -EINVAL;
} }
unlock_kernel(); if (newoffs < 0 || newoffs > PCILYNX_MAX_MEMORY + 1) return -EINVAL;
file->f_pos = newoffs; file->f_pos = newoffs;
return newoffs; return newoffs;
} }
...@@ -1229,7 +1212,7 @@ static void remove_card(struct pci_dev *dev) ...@@ -1229,7 +1212,7 @@ static void remove_card(struct pci_dev *dev)
} }
tasklet_kill(&lynx->iso_rcv.tq); tasklet_kill(&lynx->iso_rcv.tq);
kfree(lynx); hpsb_unref_host(lynx->host);
} }
......
...@@ -21,10 +21,7 @@ ...@@ -21,10 +21,7 @@
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
#include <linux/devfs_fs_kernel.h> #include <linux/devfs_fs_kernel.h>
#endif
#include "ieee1394.h" #include "ieee1394.h"
#include "ieee1394_types.h" #include "ieee1394_types.h"
...@@ -919,13 +916,9 @@ static int raw1394_open(struct inode *inode, struct file *file) ...@@ -919,13 +916,9 @@ static int raw1394_open(struct inode *inode, struct file *file)
return -ENXIO; return -ENXIO;
} }
V22_COMPAT_MOD_INC_USE_COUNT;
fi = kmalloc(sizeof(struct file_info), SLAB_KERNEL); fi = kmalloc(sizeof(struct file_info), SLAB_KERNEL);
if (fi == NULL) { if (fi == NULL)
V22_COMPAT_MOD_DEC_USE_COUNT;
return -ENOMEM; return -ENOMEM;
}
memset(fi, 0, sizeof(struct file_info)); memset(fi, 0, sizeof(struct file_info));
...@@ -988,7 +981,6 @@ static int raw1394_release(struct inode *inode, struct file *file) ...@@ -988,7 +981,6 @@ static int raw1394_release(struct inode *inode, struct file *file)
kfree(fi); kfree(fi);
V22_COMPAT_MOD_DEC_USE_COUNT;
return 0; return 0;
} }
...@@ -1001,7 +993,7 @@ static struct hpsb_highlevel_ops hl_ops = { ...@@ -1001,7 +993,7 @@ static struct hpsb_highlevel_ops hl_ops = {
}; };
static struct file_operations file_ops = { static struct file_operations file_ops = {
OWNER_THIS_MODULE owner: THIS_MODULE,
read: raw1394_read, read: raw1394_read,
write: raw1394_write, write: raw1394_write,
poll: raw1394_poll, poll: raw1394_poll,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -119,6 +119,7 @@ static int setattr_mask(unsigned int ia_valid) ...@@ -119,6 +119,7 @@ static int setattr_mask(unsigned int ia_valid)
int notify_change(struct dentry * dentry, struct iattr * attr) int notify_change(struct dentry * dentry, struct iattr * attr)
{ {
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
mode_t mode = inode->i_mode;
int error; int error;
time_t now = CURRENT_TIME; time_t now = CURRENT_TIME;
unsigned int ia_valid = attr->ia_valid; unsigned int ia_valid = attr->ia_valid;
...@@ -131,8 +132,25 @@ int notify_change(struct dentry * dentry, struct iattr * attr) ...@@ -131,8 +132,25 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
attr->ia_atime = now; attr->ia_atime = now;
if (!(ia_valid & ATTR_MTIME_SET)) if (!(ia_valid & ATTR_MTIME_SET))
attr->ia_mtime = now; attr->ia_mtime = now;
if (ia_valid & ATTR_KILL_SUID) {
if (mode & S_ISUID) {
if (!ia_valid & ATTR_MODE) {
ia_valid = attr->ia_valid |= ATTR_MODE;
attr->ia_mode = inode->i_mode;
}
attr->ia_mode &= ~S_ISUID;
}
}
if (ia_valid & ATTR_KILL_SGID) {
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
if (!ia_valid & ATTR_MODE) {
ia_valid = attr->ia_valid |= ATTR_MODE;
attr->ia_mode = inode->i_mode;
}
attr->ia_mode &= ~S_ISGID;
}
}
down(&inode->i_sem);
if (inode->i_op && inode->i_op->setattr) if (inode->i_op && inode->i_op->setattr)
error = inode->i_op->setattr(dentry, attr); error = inode->i_op->setattr(dentry, attr);
else { else {
...@@ -145,7 +163,6 @@ int notify_change(struct dentry * dentry, struct iattr * attr) ...@@ -145,7 +163,6 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
error = inode_setattr(inode, attr); error = inode_setattr(inode, attr);
} }
} }
up(&inode->i_sem);
if (!error) { if (!error) {
unsigned long dn_mask = setattr_mask(ia_valid); unsigned long dn_mask = setattr_mask(ia_valid);
if (dn_mask) if (dn_mask)
......
...@@ -2377,6 +2377,8 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -2377,6 +2377,8 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)
return error; return error;
} }
lock_kernel();
if (attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) { if (attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) {
handle_t *handle; handle_t *handle;
...@@ -2404,6 +2406,7 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -2404,6 +2406,7 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)
err_out: err_out:
ext3_std_error(inode->i_sb, error); ext3_std_error(inode->i_sb, error);
unlock_kernel();
if (!error) if (!error)
error = rc; error = rc;
return error; return error;
......
...@@ -1086,7 +1086,8 @@ int fat_notify_change(struct dentry * dentry, struct iattr * attr) ...@@ -1086,7 +1086,8 @@ int fat_notify_change(struct dentry * dentry, struct iattr * attr)
error = 0; error = 0;
goto out; goto out;
} }
if( error = inode_setattr(inode, attr) ) error = inode_setattr(inode, attr);
if (error)
goto out; goto out;
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment