From d470409a6d855b6c9fbb2a6724958d492149e362 Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Wed, 7 Aug 2002 20:47:07 -0700 Subject: Change DEVICE_ATTR, BUS_ATTR, and DRIVER_ATTR macros to not take a '_str' parameter, and just __stringify the name instead. Update all the users of the macros. --- include/linux/device.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/device.h b/include/linux/device.h index 9706d94ff7b6..c6f13cf24dba 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -93,9 +93,9 @@ struct bus_attribute { ssize_t (*store)(struct bus_type *, const char * buf, size_t count, loff_t off); }; -#define BUS_ATTR(_name,_str,_mode,_show,_store) \ +#define BUS_ATTR(_name,_mode,_show,_store) \ struct bus_attribute bus_attr_##_name = { \ - .attr = {.name = _str, .mode = _mode }, \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ .show = _show, \ .store = _store, \ }; @@ -150,9 +150,9 @@ struct driver_attribute { ssize_t (*store)(struct device_driver *, const char * buf, size_t count, loff_t off); }; -#define DRIVER_ATTR(_name,_str,_mode,_show,_store) \ +#define DRIVER_ATTR(_name,_mode,_show,_store) \ struct driver_attribute driver_attr_##_name = { \ - .attr = {.name = _str, .mode = _mode }, \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ .show = _show, \ .store = _store, \ }; @@ -222,13 +222,14 @@ struct device_attribute { ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off); }; -#define DEVICE_ATTR(_name,_str,_mode,_show,_store) \ +#define DEVICE_ATTR(_name,_mode,_show,_store) \ struct device_attribute dev_attr_##_name = { \ - .attr = {.name = _str, .mode = _mode }, \ + .attr = {.name = __stringify(_name), .mode = _mode }, \ .show = _show, \ .store = _store, \ }; + extern int device_create_file(struct device *device, struct device_attribute * entry); extern void device_remove_file(struct device * dev, struct device_attribute * attr); -- cgit v1.2.3 From d8b2993cbe5e4a58038e65a2d99b7b396281ba9f Mon Sep 17 00:00:00 2001 From: Patrick Mochel Date: Mon, 12 Aug 2002 00:50:03 -0700 Subject: Update device model locking This updates the device model locking to use device_lock when accessing all lists (the global list, the bus' lists and the drivers' lists). Before the latter two would use their own rwlocks. This also updates get_device() to return a pointer to the struct device if it can successfully increment the reference count. Between these two changes, this should prevent anything gaining an invalid reference to a device that is in the process of being removed: If a device is being removed, it's reference count is 0, but it hasn't necessarily hasn't been removed from its bus's list. If the bus list iterator attempts to access the device, it will take the lock, but will continue on to the next device because the refcount is 0 (and drop the lock). Well, theoretically; the bus iterators still need to be changed, but that's coming next.. --- drivers/base/base.h | 2 ++ drivers/base/bus.c | 26 +++++++++++++------------- drivers/base/core.c | 38 +++++++++++++++++++++++++++++--------- drivers/base/driver.c | 25 +++++++++++-------------- drivers/base/power.c | 6 +++--- include/linux/device.h | 7 +------ 6 files changed, 59 insertions(+), 45 deletions(-) (limited to 'include') diff --git a/drivers/base/base.h b/drivers/base/base.h index c2a1f9b1e9af..2ba238eba033 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -9,6 +9,8 @@ extern struct device device_root; extern spinlock_t device_lock; +extern struct device * get_device_locked(struct device *); + extern int bus_add_device(struct device * dev); extern void bus_remove_device(struct device * dev); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index e85af605a07f..c10532e28fb8 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -42,12 +42,12 @@ int bus_for_each_dev(struct bus_type * bus, void * data, int error = 0; get_bus(bus); - read_lock(&bus->lock); + spin_lock(&device_lock); node = bus->devices.next; while (node != &bus->devices) { next = list_entry(node,struct device,bus_list); - get_device(next); - read_unlock(&bus->lock); + get_device_locked(next); + spin_unlock(&device_lock); if (dev) put_device(dev); @@ -56,10 +56,10 @@ int bus_for_each_dev(struct bus_type * bus, void * data, put_device(dev); break; } - read_lock(&bus->lock); + spin_lock(&device_lock); node = dev->bus_list.next; } - read_unlock(&bus->lock); + spin_unlock(&device_lock); if (dev) put_device(dev); put_bus(bus); @@ -77,12 +77,12 @@ int bus_for_each_drv(struct bus_type * bus, void * data, /* pin bus in memory */ get_bus(bus); - read_lock(&bus->lock); + spin_lock(&device_lock); node = bus->drivers.next; while (node != &bus->drivers) { next = list_entry(node,struct device_driver,bus_list); get_driver(next); - read_unlock(&bus->lock); + spin_unlock(&device_lock); if (drv) put_driver(drv); @@ -91,10 +91,10 @@ int bus_for_each_drv(struct bus_type * bus, void * data, put_driver(drv); break; } - read_lock(&bus->lock); + spin_lock(&device_lock); node = drv->bus_list.next; } - read_unlock(&bus->lock); + spin_unlock(&device_lock); if (drv) put_driver(drv); put_bus(bus); @@ -115,9 +115,9 @@ int bus_add_device(struct device * dev) if (dev->bus) { pr_debug("registering %s with bus '%s'\n",dev->bus_id,dev->bus->name); get_bus(dev->bus); - write_lock(&dev->bus->lock); + spin_lock(&device_lock); list_add_tail(&dev->bus_list,&dev->bus->devices); - write_unlock(&dev->bus->lock); + spin_unlock(&device_lock); device_bus_link(dev); } return 0; @@ -134,9 +134,9 @@ void bus_remove_device(struct device * dev) { if (dev->bus) { device_remove_symlink(&dev->bus->device_dir,dev->bus_id); - write_lock(&dev->bus->lock); + spin_lock(&device_lock); list_del_init(&dev->bus_list); - write_unlock(&dev->bus->lock); + spin_unlock(&device_lock); put_bus(dev->bus); } } diff --git a/drivers/base/core.c b/drivers/base/core.c index 9d04145d5ac2..c3b275b0b2e9 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -53,9 +53,9 @@ static int found_match(struct device * dev, struct device_driver * drv) pr_debug("bound device '%s' to driver '%s'\n", dev->bus_id,drv->name); - write_lock(&drv->lock); + spin_lock(&device_lock); list_add_tail(&dev->driver_list,&drv->devices); - write_unlock(&drv->lock); + spin_unlock(&device_lock); goto Done; @@ -154,13 +154,13 @@ void driver_detach(struct device_driver * drv) struct list_head * node; int error = 0; - write_lock(&drv->lock); + spin_lock(&device_lock); node = drv->devices.next; while (node != &drv->devices) { next = list_entry(node,struct device,driver_list); - get_device(next); + get_device_locked(next); list_del_init(&next->driver_list); - write_unlock(&drv->lock); + spin_unlock(&device_lock); if (dev) put_device(dev); @@ -169,10 +169,10 @@ void driver_detach(struct device_driver * drv) put_device(dev); break; } - write_lock(&drv->lock); + spin_lock(&device_lock); node = drv->devices.next; } - write_unlock(&drv->lock); + spin_unlock(&device_lock); if (dev) put_device(dev); } @@ -202,12 +202,12 @@ int device_register(struct device *dev) spin_lock_init(&dev->lock); atomic_set(&dev->refcount,2); - spin_lock(&device_lock); if (dev != &device_root) { if (!dev->parent) dev->parent = &device_root; get_device(dev->parent); + spin_lock(&device_lock); if (list_empty(&dev->parent->children)) prev_dev = dev->parent; else @@ -215,8 +215,8 @@ int device_register(struct device *dev) list_add(&dev->g_list, &prev_dev->g_list); list_add_tail(&dev->node,&dev->parent->children); + spin_unlock(&device_lock); } - spin_unlock(&device_lock); pr_debug("DEV: registering device: ID = '%s', name = %s\n", dev->bus_id, dev->name); @@ -240,6 +240,25 @@ int device_register(struct device *dev) return error; } +struct device * get_device_locked(struct device * dev) +{ + struct device * ret = dev; + if (dev && atomic_read(&dev->refcount)) + atomic_inc(&dev->refcount); + else + ret = NULL; + return ret; +} + +struct device * get_device(struct device * dev) +{ + struct device * ret; + spin_lock(&device_lock); + ret = get_device_locked(dev); + spin_unlock(&device_lock); + return ret; +} + /** * put_device - decrement reference count, and clean up when it hits 0 * @dev: device in question @@ -296,4 +315,5 @@ static int __init device_init(void) core_initcall(device_init); EXPORT_SYMBOL(device_register); +EXPORT_SYMBOL(get_device); EXPORT_SYMBOL(put_device); diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 2b4aa02a0683..138e5a3ff80d 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -19,12 +19,12 @@ int driver_for_each_dev(struct device_driver * drv, void * data, int (*callback) int error = 0; get_driver(drv); - read_lock(&drv->lock); + spin_lock(&device_lock); node = drv->devices.next; while (node != &drv->devices) { next = list_entry(node,struct device,driver_list); - get_device(next); - read_unlock(&drv->lock); + get_device_locked(next); + spin_unlock(&device_lock); if (dev) put_device(dev); @@ -33,10 +33,10 @@ int driver_for_each_dev(struct device_driver * drv, void * data, int (*callback) put_device(dev); break; } - read_lock(&drv->lock); + spin_lock(&device_lock); node = dev->driver_list.next; } - read_unlock(&drv->lock); + spin_unlock(&device_lock); if (dev) put_device(dev); put_driver(drv); @@ -60,9 +60,9 @@ int driver_register(struct device_driver * drv) atomic_set(&drv->refcount,2); rwlock_init(&drv->lock); INIT_LIST_HEAD(&drv->devices); - write_lock(&drv->bus->lock); + spin_lock(&device_lock); list_add(&drv->bus_list,&drv->bus->drivers); - write_unlock(&drv->bus->lock); + spin_unlock(&device_lock); driver_make_dir(drv); driver_attach(drv); put_driver(drv); @@ -81,10 +81,10 @@ static void __remove_driver(struct device_driver * drv) void remove_driver(struct device_driver * drv) { - write_lock(&drv->bus->lock); + spin_lock(&device_lock); atomic_set(&drv->refcount,0); list_del_init(&drv->bus_list); - write_unlock(&drv->bus->lock); + spin_unlock(&device_lock); __remove_driver(drv); } @@ -94,13 +94,10 @@ void remove_driver(struct device_driver * drv) */ void put_driver(struct device_driver * drv) { - write_lock(&drv->bus->lock); - if (!atomic_dec_and_test(&drv->refcount)) { - write_unlock(&drv->bus->lock); + if (!atomic_dec_and_lock(&drv->refcount,&device_lock)) return; - } list_del_init(&drv->bus_list); - write_unlock(&drv->bus->lock); + spin_unlock(&device_lock); __remove_driver(drv); } diff --git a/drivers/base/power.c b/drivers/base/power.c index f916cb838b30..9faa611a065a 100644 --- a/drivers/base/power.c +++ b/drivers/base/power.c @@ -36,7 +36,7 @@ int device_suspend(u32 state, u32 level) spin_lock(&device_lock); dev = g_list_to_dev(prev->g_list.next); while(dev != &device_root && !error) { - get_device(dev); + get_device_locked(dev); spin_unlock(&device_lock); put_device(prev); @@ -71,7 +71,7 @@ void device_resume(u32 level) spin_lock(&device_lock); dev = g_list_to_dev(prev->g_list.prev); while(dev != &device_root) { - get_device(dev); + get_device_locked(dev); spin_unlock(&device_lock); put_device(prev); @@ -108,7 +108,7 @@ void device_shutdown(void) spin_lock(&device_lock); dev = g_list_to_dev(prev->g_list.next); while(dev != &device_root) { - get_device(dev); + dev = get_device_locked(dev); spin_unlock(&device_lock); put_device(prev); diff --git a/include/linux/device.h b/include/linux/device.h index c6f13cf24dba..c33eae266026 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -261,12 +261,7 @@ static inline void unlock_device(struct device * dev) * get_device - atomically increment the reference count for the device. * */ -static inline void get_device(struct device * dev) -{ - BUG_ON(!atomic_read(&dev->refcount)); - atomic_inc(&dev->refcount); -} - +extern struct device * get_device(struct device * dev); extern void put_device(struct device * dev); /* drivers/base/sys.c */ -- cgit v1.2.3 From 8e4f2fd31bf737abb392e694898a1496157623b5 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 13 Aug 2002 01:04:37 -0700 Subject: [PATCH] fix ARCH_HAS_PREFETCH include/linux/prefetch.h does a strange thing: if the arch doesn't have the prefectch functions, this header defines no-op version of them and then defines ARCH_HAS_PREFETCH. So there's no way for mainline code to know if the architecture *really* has prefetch instructions. This information loss is unfortunate. Examples: for (i = 0; i < N; i++) prefetch(foo[i]); Problem is, if `prefetch' is a no-op, the compiler will still generate an empty busy-wait loop. Which it must do. We need to know the truth about ARCH_HAS_PREFETCH to correctly elide that loop. --- include/linux/prefetch.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'include') diff --git a/include/linux/prefetch.h b/include/linux/prefetch.h index 8d7d3ffeb481..73c4a344156b 100644 --- a/include/linux/prefetch.h +++ b/include/linux/prefetch.h @@ -39,17 +39,14 @@ */ #ifndef ARCH_HAS_PREFETCH -#define ARCH_HAS_PREFETCH static inline void prefetch(const void *x) {;} #endif #ifndef ARCH_HAS_PREFETCHW -#define ARCH_HAS_PREFETCHW static inline void prefetchw(const void *x) {;} #endif #ifndef ARCH_HAS_SPINLOCK_PREFETCH -#define ARCH_HAS_SPINLOCK_PREFETCH #define spin_lock_prefetch(x) prefetchw(x) #endif -- cgit v1.2.3 From 208e1d7ad4c13609de767f4883111a000f093a97 Mon Sep 17 00:00:00 2001 From: Albert Cranford Date: Tue, 13 Aug 2002 06:04:30 -0700 Subject: [PATCH] i2c updates 2/4 Please apply the two of four tested patches that update 2.5.31 with these I2C changes: o Support for SMBus 2.0 PEC Packet Error Checking o New adapter-i2c-frodo for SA 1110 board o New adapter-i2c-rpx for embeded MPC8XX o Replace depreciated cli()&sti() with spin_{un}lock_irq() o Updated documentation --- drivers/i2c/i2c-core.c | 212 ++++++++++++++++++++++++++++++++++++++++++++---- drivers/i2c/i2c-dev.c | 17 +++- drivers/i2c/i2c-proc.c | 48 ++++++++++- include/linux/i2c-dev.h | 25 +++++- include/linux/i2c-id.h | 22 ++++- include/linux/i2c.h | 44 ++++++++-- 6 files changed, 336 insertions(+), 32 deletions(-) (limited to 'include') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 94e12ce68671..977369688e8c 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -18,9 +18,10 @@ /* ------------------------------------------------------------------------- */ /* With some changes from Kyösti Mälkki . - All SMBus-related things are written by Frodo Looijaard */ + All SMBus-related things are written by Frodo Looijaard + SMBus 2.0 support by Mark Studebaker */ -/* $Id: i2c-core.c,v 1.73 2002/03/03 17:37:44 mds Exp $ */ +/* $Id: i2c-core.c,v 1.83 2002/07/08 01:37:15 mds Exp $ */ #include #include @@ -371,7 +372,7 @@ int i2c_del_driver(struct i2c_driver *driver) struct i2c_client *client = adap->clients[j]; if (client != NULL && client->driver == driver) { - DEB2(printk("i2c-core.o: " + DEB2(printk(KERN_DEBUG "i2c-core.o: " "detaching client %s:\n", client->name)); if ((res = driver-> @@ -1002,6 +1003,123 @@ int i2c_adapter_id(struct i2c_adapter *adap) /* The SMBus parts */ +#define POLY (0x1070U << 3) +static u8 +crc8(u16 data) +{ + int i; + + for(i = 0; i < 8; i++) { + if (data & 0x8000) + data = data ^ POLY; + data = data << 1; + } + return (u8)(data >> 8); +} + +/* CRC over count bytes in the first array plus the bytes in the rest + array if it is non-null. rest[0] is the (length of rest) - 1 + and is included. */ +u8 i2c_smbus_partial_pec(u8 crc, int count, u8 *first, u8 *rest) +{ + int i; + + for(i = 0; i < count; i++) + crc = crc8((crc ^ first[i]) << 8); + if(rest != NULL) + for(i = 0; i <= rest[0]; i++) + crc = crc8((crc ^ rest[i]) << 8); + return crc; +} + +u8 i2c_smbus_pec(int count, u8 *first, u8 *rest) +{ + return i2c_smbus_partial_pec(0, count, first, rest); +} + +/* Returns new "size" (transaction type) + Note that we convert byte to byte_data and byte_data to word_data + rather than invent new xxx_PEC transactions. */ +int i2c_smbus_add_pec(u16 addr, u8 command, int size, + union i2c_smbus_data *data) +{ + u8 buf[3]; + + buf[0] = addr << 1; + buf[1] = command; + switch(size) { + case I2C_SMBUS_BYTE: + data->byte = i2c_smbus_pec(2, buf, NULL); + size = I2C_SMBUS_BYTE_DATA; + break; + case I2C_SMBUS_BYTE_DATA: + buf[2] = data->byte; + data->word = buf[2] || + (i2c_smbus_pec(3, buf, NULL) << 8); + size = I2C_SMBUS_WORD_DATA; + break; + case I2C_SMBUS_WORD_DATA: + /* unsupported */ + break; + case I2C_SMBUS_BLOCK_DATA: + data->block[data->block[0] + 1] = + i2c_smbus_pec(2, buf, data->block); + size = I2C_SMBUS_BLOCK_DATA_PEC; + break; + } + return size; +} + +int i2c_smbus_check_pec(u16 addr, u8 command, int size, u8 partial, + union i2c_smbus_data *data) +{ + u8 buf[3], rpec, cpec; + + buf[1] = command; + switch(size) { + case I2C_SMBUS_BYTE_DATA: + buf[0] = (addr << 1) | 1; + cpec = i2c_smbus_pec(2, buf, NULL); + rpec = data->byte; + break; + case I2C_SMBUS_WORD_DATA: + buf[0] = (addr << 1) | 1; + buf[2] = data->word & 0xff; + cpec = i2c_smbus_pec(3, buf, NULL); + rpec = data->word >> 8; + break; + case I2C_SMBUS_WORD_DATA_PEC: + /* unsupported */ + cpec = rpec = 0; + break; + case I2C_SMBUS_PROC_CALL_PEC: + /* unsupported */ + cpec = rpec = 0; + break; + case I2C_SMBUS_BLOCK_DATA_PEC: + buf[0] = (addr << 1); + buf[2] = (addr << 1) | 1; + cpec = i2c_smbus_pec(3, buf, data->block); + rpec = data->block[data->block[0] + 1]; + break; + case I2C_SMBUS_BLOCK_PROC_CALL_PEC: + buf[0] = (addr << 1) | 1; + rpec = i2c_smbus_partial_pec(partial, 1, + buf, data->block); + cpec = data->block[data->block[0] + 1]; + break; + default: + cpec = rpec = 0; + break; + } + if(rpec != cpec) { + DEB(printk(KERN_DEBUG "i2c-core.o: Bad PEC 0x%02x vs. 0x%02x\n", + rpec, cpec)); + return -1; + } + return 0; +} + extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value) { return i2c_smbus_xfer(client->adapter,client->addr,client->flags, @@ -1020,8 +1138,9 @@ extern s32 i2c_smbus_read_byte(struct i2c_client * client) extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value) { + union i2c_smbus_data data; /* only for PEC */ return i2c_smbus_xfer(client->adapter,client->addr,client->flags, - I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,NULL); + I2C_SMBUS_WRITE,value, I2C_SMBUS_BYTE,&data); } extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command) @@ -1099,8 +1218,8 @@ extern s32 i2c_smbus_write_block_data(struct i2c_client * client, { union i2c_smbus_data data; int i; - if (length > 32) - length = 32; + if (length > I2C_SMBUS_BLOCK_MAX) + length = I2C_SMBUS_BLOCK_MAX; for (i = 1; i <= length; i++) data.block[i] = values[i-1]; data.block[0] = length; @@ -1109,6 +1228,26 @@ extern s32 i2c_smbus_write_block_data(struct i2c_client * client, I2C_SMBUS_BLOCK_DATA,&data); } +/* Returns the number of read bytes */ +extern s32 i2c_smbus_block_process_call(struct i2c_client * client, + u8 command, u8 length, u8 *values) +{ + union i2c_smbus_data data; + int i; + if (length > I2C_SMBUS_BLOCK_MAX - 1) + return -1; + data.block[0] = length; + for (i = 1; i <= length; i++) + data.block[i] = values[i-1]; + if(i2c_smbus_xfer(client->adapter,client->addr,client->flags, + I2C_SMBUS_WRITE, command, + I2C_SMBUS_BLOCK_PROC_CALL, &data)) + return -1; + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; +} + /* Returns the number of read bytes */ extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, u8 command, u8 *values) @@ -1131,8 +1270,8 @@ extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client, { union i2c_smbus_data data; int i; - if (length > 32) - length = 32; + if (length > I2C_SMBUS_I2C_BLOCK_MAX) + length = I2C_SMBUS_I2C_BLOCK_MAX; for (i = 1; i <= length; i++) data.block[i] = values[i-1]; data.block[0] = length; @@ -1194,34 +1333,43 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, break; case I2C_SMBUS_PROC_CALL: num = 2; /* Special case */ + read_write = I2C_SMBUS_READ; msg[0].len = 3; msg[1].len = 2; msgbuf0[1] = data->word & 0xff; msgbuf0[2] = (data->word >> 8) & 0xff; break; case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_BLOCK_DATA_PEC: if (read_write == I2C_SMBUS_READ) { - printk(KERN_ERR "i2c-core.o: Block read not supported under " - "I2C emulation!\n"); - return -1; + printk(KERN_ERR "i2c-core.o: Block read not supported " + "under I2C emulation!\n"); + return -1; } else { msg[0].len = data->block[0] + 2; - if (msg[0].len > 34) { + if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) { printk(KERN_ERR "i2c-core.o: smbus_access called with " "invalid block write size (%d)\n", data->block[0]); return -1; } + if(size == I2C_SMBUS_BLOCK_DATA_PEC) + (msg[0].len)++; for (i = 1; i <= msg[0].len; i++) msgbuf0[i] = data->block[i-1]; } break; + case I2C_SMBUS_BLOCK_PROC_CALL: + case I2C_SMBUS_BLOCK_PROC_CALL_PEC: + printk(KERN_ERR "i2c-core.o: Block process call not supported " + "under I2C emulation!\n"); + return -1; case I2C_SMBUS_I2C_BLOCK_DATA: if (read_write == I2C_SMBUS_READ) { - msg[1].len = 32; + msg[1].len = I2C_SMBUS_I2C_BLOCK_MAX; } else { msg[0].len = data->block[0] + 2; - if (msg[0].len > 34) { + if (msg[0].len > I2C_SMBUS_I2C_BLOCK_MAX + 2) { printk("i2c-core.o: i2c_smbus_xfer_emulated called with " "invalid block write size (%d)\n", data->block[0]); @@ -1254,8 +1402,8 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, break; case I2C_SMBUS_I2C_BLOCK_DATA: /* fixed at 32 for now */ - data->block[0] = 32; - for (i = 0; i < 32; i++) + data->block[0] = I2C_SMBUS_I2C_BLOCK_MAX; + for (i = 0; i < I2C_SMBUS_I2C_BLOCK_MAX; i++) data->block[i+1] = msgbuf1[i]; break; } @@ -1268,7 +1416,29 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, union i2c_smbus_data * data) { s32 res; - flags = flags & I2C_M_TEN; + int swpec = 0; + u8 partial = 0; + + flags &= I2C_M_TEN | I2C_CLIENT_PEC; + if((flags & I2C_CLIENT_PEC) && + !(i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HWPEC_CALC))) { + swpec = 1; + if(read_write == I2C_SMBUS_READ && + size == I2C_SMBUS_BLOCK_DATA) + size = I2C_SMBUS_BLOCK_DATA_PEC; + else if(size == I2C_SMBUS_PROC_CALL) + size = I2C_SMBUS_PROC_CALL_PEC; + else if(size == I2C_SMBUS_BLOCK_PROC_CALL) { + i2c_smbus_add_pec(addr, command, + I2C_SMBUS_BLOCK_DATA, data); + partial = data->block[data->block[0] + 1]; + size = I2C_SMBUS_BLOCK_PROC_CALL_PEC; + } else if(read_write == I2C_SMBUS_WRITE && + size != I2C_SMBUS_QUICK && + size != I2C_SMBUS_I2C_BLOCK_DATA) + size = i2c_smbus_add_pec(addr, command, size, data); + } + if (adapter->algo->smbus_xfer) { I2C_LOCK(adapter); res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write, @@ -1277,6 +1447,14 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, } else res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, command,size,data); + + if(res >= 0 && swpec && + size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA && + (read_write == I2C_SMBUS_READ || size == I2C_SMBUS_PROC_CALL_PEC || + size == I2C_SMBUS_BLOCK_PROC_CALL_PEC)) { + if(i2c_smbus_check_pec(addr, command, size, partial, data)) + return -1; + } return res; } diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index a6b93f4c580f..be9fa743f258 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -28,7 +28,7 @@ /* The devfs code is contributed by Philipp Matthias Hahn */ -/* $Id: i2c-dev.c,v 1.44 2001/11/19 18:45:02 mds Exp $ */ +/* $Id: i2c-dev.c,v 1.46 2002/07/06 02:07:39 mds Exp $ */ #include #include @@ -236,6 +236,12 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, else client->flags &= ~I2C_M_TEN; return 0; + case I2C_PEC: + if (arg) + client->flags |= I2C_CLIENT_PEC; + else + client->flags &= ~I2C_CLIENT_PEC; + return 0; case I2C_FUNCS: funcs = i2c_get_functionality(client->adapter); return (copy_to_user((unsigned long *)arg,&funcs, @@ -312,7 +318,8 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, (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_DATA)) { + (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) && + (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) { #ifdef DEBUG printk(KERN_DEBUG "i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n", data_arg.size); @@ -355,10 +362,11 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || (data_arg.size == I2C_SMBUS_PROC_CALL)) datasize = sizeof(data_arg.data->word); - else /* size == I2C_SMBUS_BLOCK_DATA */ + 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.read_write == I2C_SMBUS_WRITE)) { if (copy_from_user(&temp, data_arg.data, datasize)) return -EFAULT; @@ -367,6 +375,7 @@ int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, 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; @@ -535,6 +544,8 @@ int i2cdev_cleanup(void) return 0; } +EXPORT_NO_SYMBOLS; + #ifdef MODULE MODULE_AUTHOR("Frodo Looijaard and Simon G. Vogl "); diff --git a/drivers/i2c/i2c-proc.c b/drivers/i2c/i2c-proc.c index c82c6bbff3e4..e9997dfb1d17 100644 --- a/drivers/i2c/i2c-proc.c +++ b/drivers/i2c/i2c-proc.c @@ -60,6 +60,7 @@ int __init sensors_init(void); static struct ctl_table_header *i2c_entries[SENSORS_ENTRY_MAX]; static struct i2c_client *i2c_clients[SENSORS_ENTRY_MAX]; +static unsigned short i2c_inodes[SENSORS_ENTRY_MAX]; static ctl_table sysctl_table[] = { {CTL_DEV, "dev", NULL, 0, 0555}, @@ -172,7 +173,7 @@ int i2c_register_entry(struct i2c_client *client, const char *prefix, printk(KERN_ERR "i2c-proc.o: error: sysctl interface not supported by kernel!\n"); kfree(new_table); kfree(name); - return -ENOMEM; + return -EPERM; } i2c_entries[id - 256] = new_header; @@ -188,6 +189,8 @@ int i2c_register_entry(struct i2c_client *client, const char *prefix, return id; } #endif /* DEBUG */ + i2c_inodes[id - 256] = + new_header->ctl_table->child->child->de->low_ino; new_header->ctl_table->child->child->de->owner = controlling_mod; return id; @@ -210,6 +213,49 @@ void i2c_deregister_entry(int id) } } +/* Monitor access for /proc/sys/dev/sensors; make unloading i2c-proc.o + impossible if some process still uses it or some file in it */ +void i2c_fill_inode(struct inode *inode, int fill) +{ + if (fill) + MOD_INC_USE_COUNT; + else + MOD_DEC_USE_COUNT; +} + +/* Monitor access for /proc/sys/dev/sensors/ directories; make unloading + the corresponding module impossible if some process still uses it or + some file in it */ +void i2c_dir_fill_inode(struct inode *inode, int fill) +{ + int i; + struct i2c_client *client; + +#ifdef DEBUG + if (!inode) { + printk(KERN_ERR "i2c-proc.o: Warning: inode NULL in fill_inode()\n"); + return; + } +#endif /* def DEBUG */ + + for (i = 0; i < SENSORS_ENTRY_MAX; i++) + if (i2c_clients[i] + && (i2c_inodes[i] == inode->i_ino)) break; +#ifdef DEBUG + if (i == SENSORS_ENTRY_MAX) { + printk + (KERN_ERR "i2c-proc.o: Warning: inode (%ld) not found in fill_inode()\n", + inode->i_ino); + return; + } +#endif /* def DEBUG */ + client = i2c_clients[i]; + if (fill) + client->driver->inc_use(client); + else + client->driver->dec_use(client); +} + int i2c_proc_chips(ctl_table * ctl, int write, struct file *filp, void *buffer, size_t * lenp) { diff --git a/include/linux/i2c-dev.h b/include/linux/i2c-dev.h index 4c67640b9c91..ee6ddba913bb 100644 --- a/include/linux/i2c-dev.h +++ b/include/linux/i2c-dev.h @@ -19,7 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: i2c-dev.h,v 1.10 2001/11/19 19:01:46 mds Exp $ */ +/* $Id: i2c-dev.h,v 1.11 2002/07/07 15:42:47 mds Exp $ */ #ifndef I2C_DEV_H #define I2C_DEV_H @@ -144,7 +144,7 @@ static inline __s32 i2c_smbus_read_block_data(int file, __u8 command, else { for (i = 1; i <= data.block[0]; i++) values[i-1] = data.block[i]; - return data.block[0]; + return data.block[0]; } } @@ -192,6 +192,27 @@ static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, I2C_SMBUS_I2C_BLOCK_DATA, &data); } +/* Returns the number of read bytes */ +static inline __s32 i2c_smbus_block_process_call(int file, __u8 command, + __u8 length, __u8 *values) +{ + union i2c_smbus_data data; + int i; + if (length > 32) + length = 32; + for (i = 1; i <= length; i++) + data.block[i] = values[i-1]; + data.block[0] = length; + if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command, + I2C_SMBUS_BLOCK_PROC_CALL,&data)) + return -1; + else { + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; + } +} + #endif /* ndef __KERNEL__ */ #endif diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 039fb3640431..a914758c8f33 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -20,7 +20,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ------------------------------------------------------------------------- */ -/* $Id: i2c-id.h,v 1.41 2002/03/11 07:18:55 simon Exp $ */ +/* $Id: i2c-id.h,v 1.52 2002/07/10 13:28:44 abz Exp $ */ #ifndef I2C_ID_H #define I2C_ID_H @@ -90,8 +90,12 @@ #define I2C_DRIVERID_DRP3510 43 /* ADR decoder (Astra Radio) */ #define I2C_DRIVERID_SP5055 44 /* Satellite tuner */ #define I2C_DRIVERID_STV0030 45 /* Multipurpose switch */ -#define I2C_DRIVERID_SAA7108 46 /* video decoder, image scaler */ - +#define I2C_DRIVERID_SAA7108 46 /* video decoder, image scaler */ +#define I2C_DRIVERID_DS1307 47 /* DS1307 real time clock */ +#define I2C_DRIVERID_ADV717x 48 /* ADV 7175/7176 video encoder */ +#define I2C_DRIVERID_ZR36067 49 /* Zoran 36067 video encoder */ +#define I2C_DRIVERID_ZR36120 50 /* Zoran 36120 video encoder */ +#define I2C_DRIVERID_24LC32A 51 /* Microchip 24LC32A 32k EEPROM */ @@ -102,6 +106,8 @@ #define I2C_DRIVERID_I2CDEV 900 #define I2C_DRIVERID_I2CPROC 901 +#define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */ +#define I2C_DRIVERID_ALERT 903 /* SMBus Alert Responder Client */ /* IDs -- Use DRIVERIDs 1000-1999 for sensors. These were originally in sensors.h in the lm_sensors package */ @@ -134,6 +140,9 @@ #define I2C_DRIVERID_FSCPOS 1028 #define I2C_DRIVERID_FSCSCY 1029 #define I2C_DRIVERID_PCF8591 1030 +#define I2C_DRIVERID_SMSC47M1 1031 +#define I2C_DRIVERID_VT1211 1032 +#define I2C_DRIVERID_LM92 1033 /* * ---- Adapter types ---------------------------------------------------- @@ -155,6 +164,7 @@ #define I2C_ALGO_EC 0x100000 /* ACPI embedded controller */ #define I2C_ALGO_MPC8XX 0x110000 /* MPC8xx PowerPC I2C algorithm */ +#define I2C_ALGO_OCP 0x120000 /* IBM or otherwise On-chip I2C algorithm */ #define I2C_ALGO_EXP 0x800000 /* experimental */ @@ -182,9 +192,11 @@ #define I2C_HW_B_I810 0x0a /* Intel I810 */ #define I2C_HW_B_VOO 0x0b /* 3dfx Voodoo 3 / Banshee */ #define I2C_HW_B_PPORT 0x0c /* Primitive parallel port adapter */ +#define I2C_HW_B_SAVG 0x0d /* Savage 4 */ #define I2C_HW_B_RIVA 0x10 /* Riva based graphics cards */ #define I2C_HW_B_IOC 0x11 /* IOC bit-wiggling */ #define I2C_HW_B_TSUNA 0x12 /* DEC Tsunami chipset */ +#define I2C_HW_B_FRODO 0x13 /* 2d3D, Inc. SA-1110 Development Board */ /* --- PCF 8584 based algorithms */ #define I2C_HW_P_LP 0x00 /* Parallel port interface */ @@ -200,6 +212,10 @@ /* --- ITE based algorithms */ #define I2C_HW_I_IIC 0x00 /* controller on the ITE */ +/* --- PowerPC on-chip adapters */ +#define I2C_HW_OCP 0x00 /* IBM on-chip I2C adapter */ + + /* --- SMBus only adapters */ #define I2C_HW_SMBUS_PIIX4 0x00 #define I2C_HW_SMBUS_ALI15X3 0x01 diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 7bb812551f6c..920e64b79c80 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -23,13 +23,13 @@ /* With some changes from Kyösti Mälkki and Frodo Looijaard */ -/* $Id: i2c.h,v 1.50 2002/03/23 00:53:38 phil Exp $ */ +/* $Id: i2c.h,v 1.59 2002/07/19 20:53:45 phil Exp $ */ #ifndef I2C_H #define I2C_H -#define I2C_DATE "20020322" -#define I2C_VERSION "2.6.3" +#define I2C_DATE "20020719" +#define I2C_VERSION "2.6.4" #include /* id values of adapters et. al. */ #include @@ -280,6 +280,9 @@ struct i2c_adapter { #define I2C_CLIENT_ALLOW_USE 0x01 /* Client allows access */ #define I2C_CLIENT_ALLOW_MULTIPLE_USE 0x02 /* Allow multiple access-locks */ /* on an i2c_client */ +#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */ +#define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */ + /* Must equal I2C_M_TEN below */ /* i2c_client_address_data is the struct for holding default client * addresses for a driver and for the parameters supplied on the @@ -395,6 +398,12 @@ struct i2c_msg { #define I2C_FUNC_I2C 0x00000001 #define I2C_FUNC_10BIT_ADDR 0x00000002 #define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART} */ +#define I2C_FUNC_SMBUS_HWPEC_CALC 0x00000008 /* SMBus 2.0 */ +#define I2C_FUNC_SMBUS_READ_WORD_DATA_PEC 0x00000800 /* SMBus 2.0 */ +#define I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC 0x00001000 /* SMBus 2.0 */ +#define I2C_FUNC_SMBUS_PROC_CALL_PEC 0x00002000 /* SMBus 2.0 */ +#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL_PEC 0x00004000 /* SMBus 2.0 */ +#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */ #define I2C_FUNC_SMBUS_QUICK 0x00010000 #define I2C_FUNC_SMBUS_READ_BYTE 0x00020000 #define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000 @@ -409,6 +418,8 @@ struct i2c_msg { #define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */ #define I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 0x10000000 /* I2C-like block xfer */ #define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 0x20000000 /* w/ 2-byte reg. addr. */ +#define I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC 0x40000000 /* SMBus 2.0 */ +#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC 0x80000000 /* SMBus 2.0 */ #define I2C_FUNC_SMBUS_BYTE I2C_FUNC_SMBUS_READ_BYTE | \ I2C_FUNC_SMBUS_WRITE_BYTE @@ -422,6 +433,17 @@ struct i2c_msg { I2C_FUNC_SMBUS_WRITE_I2C_BLOCK #define I2C_FUNC_SMBUS_I2C_BLOCK_2 I2C_FUNC_SMBUS_READ_I2C_BLOCK_2 | \ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 +#define I2C_FUNC_SMBUS_BLOCK_DATA_PEC I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC | \ + I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC +#define I2C_FUNC_SMBUS_WORD_DATA_PEC I2C_FUNC_SMBUS_READ_WORD_DATA_PEC | \ + I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC + +#define I2C_FUNC_SMBUS_READ_BYTE_PEC I2C_FUNC_SMBUS_READ_BYTE_DATA +#define I2C_FUNC_SMBUS_WRITE_BYTE_PEC I2C_FUNC_SMBUS_WRITE_BYTE_DATA +#define I2C_FUNC_SMBUS_READ_BYTE_DATA_PEC I2C_FUNC_SMBUS_READ_WORD_DATA +#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA_PEC I2C_FUNC_SMBUS_WRITE_WORD_DATA +#define I2C_FUNC_SMBUS_BYTE_PEC I2C_FUNC_SMBUS_BYTE_DATA +#define I2C_FUNC_SMBUS_BYTE_DATA_PEC I2C_FUNC_SMBUS_WORD_DATA #define I2C_FUNC_SMBUS_EMUL I2C_FUNC_SMBUS_QUICK | \ I2C_FUNC_SMBUS_BYTE | \ @@ -429,16 +451,20 @@ struct i2c_msg { I2C_FUNC_SMBUS_WORD_DATA | \ I2C_FUNC_SMBUS_PROC_CALL | \ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \ - I2C_FUNC_SMBUS_I2C_BLOCK | \ - I2C_FUNC_SMBUS_I2C_BLOCK_2 + I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | \ + I2C_FUNC_SMBUS_I2C_BLOCK /* * Data for SMBus Messages */ +#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ +#define I2C_SMBUS_I2C_BLOCK_MAX 32 /* Not specified but we use same structure */ union i2c_smbus_data { __u8 byte; __u16 word; - __u8 block[33]; /* block[0] is used for length */ + __u8 block[I2C_SMBUS_BLOCK_MAX + 3]; /* block[0] is used for length */ + /* one more for read length in block process call */ + /* and one more for PEC */ }; /* smbus_access read or write markers */ @@ -454,6 +480,11 @@ union i2c_smbus_data { #define I2C_SMBUS_PROC_CALL 4 #define I2C_SMBUS_BLOCK_DATA 5 #define I2C_SMBUS_I2C_BLOCK_DATA 6 +#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ +#define I2C_SMBUS_BLOCK_DATA_PEC 8 /* SMBus 2.0 */ +#define I2C_SMBUS_PROC_CALL_PEC 9 /* SMBus 2.0 */ +#define I2C_SMBUS_BLOCK_PROC_CALL_PEC 10 /* SMBus 2.0 */ +#define I2C_SMBUS_WORD_DATA_PEC 11 /* SMBus 2.0 */ /* ----- commands for the ioctl like i2c_command call: @@ -479,6 +510,7 @@ union i2c_smbus_data { #define I2C_FUNCS 0x0705 /* Get the adapter functionality */ #define I2C_RDWR 0x0707 /* Combined R/W transfer (one stop only)*/ +#define I2C_PEC 0x0708 /* != 0 for SMBus PEC */ #if 0 #define I2C_ACK_TEST 0x0710 /* See if a slave is at a specific address */ #endif -- cgit v1.2.3 From fcc6fcc61d5d2e32f689bbfcacd031e4c3d40268 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 13 Aug 2002 06:27:23 -0700 Subject: [PATCH] add FP exception mode prctl This patch that adds a prctl so that processes can set their floating-point exception mode on PPC and on PPC64. We need this because the FP exception mode is controlled by bits in the machine state register, which can only be accessed by the kernel, and because the exception mode setting interacts with the lazy FPU save/restore that the kernel does. --- include/linux/prctl.h | 8 ++++++++ kernel/sys.c | 13 +++++++++++++ 2 files changed, 21 insertions(+) (limited to 'include') diff --git a/include/linux/prctl.h b/include/linux/prctl.h index bbe6c00bfbd3..2cc14f5e5396 100644 --- a/include/linux/prctl.h +++ b/include/linux/prctl.h @@ -26,4 +26,12 @@ # define PR_FPEMU_NOPRINT 1 /* silently emulate fp operations accesses */ # define PR_FPEMU_SIGFPE 2 /* don't emulate fp operations, send SIGFPE instead */ +/* Get/set floating-point exception mode (if meaningful) */ +#define PR_GET_FPEXC 11 +#define PR_SET_FPEXC 12 +# define PR_FP_EXC_DISABLED 0 /* FP exceptions disabled */ +# define PR_FP_EXC_NONRECOV 1 /* async non-recoverable exc. mode */ +# define PR_FP_EXC_ASYNC 2 /* async recoverable exception mode */ +# define PR_FP_EXC_PRECISE 3 /* precise exception mode */ + #endif /* _LINUX_PRCTL_H */ diff --git a/kernel/sys.c b/kernel/sys.c index 316a63de74ea..8a6d5da46335 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -37,6 +37,12 @@ #ifndef GET_FPEMU_CTL # define GET_FPEMU_CTL(a,b) (-EINVAL) #endif +#ifndef SET_FPEXC_CTL +# define SET_FPEXC_CTL(a,b) (-EINVAL) +#endif +#ifndef GET_FPEXC_CTL +# define GET_FPEXC_CTL(a,b) (-EINVAL) +#endif /* * this is where the system-wide overflow UID and GID are defined, for @@ -1283,6 +1289,13 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, case PR_GET_FPEMU: error = GET_FPEMU_CTL(current, arg2); break; + case PR_SET_FPEXC: + error = SET_FPEXC_CTL(current, arg2); + break; + case PR_GET_FPEXC: + error = GET_FPEXC_CTL(current, arg2); + break; + case PR_GET_KEEPCAPS: if (current->keep_capabilities) -- cgit v1.2.3