mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-28 23:23:55 +08:00
Merge branch 'i2c-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6
* 'i2c-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6: i2c/eeprom: Recognize VGN as a valid Sony Vaio name prefix i2c/eeprom: Hide Sony Vaio serial numbers i2c-pasemi: Fix NACK detection i2c-pasemi: Replace obsolete "driverfs" reference with "sysfs" i2c: Make i2c_check_addr static i2c-dev: Unbound new-style i2c clients aren't busy i2c-dev: "how does it work" comments
This commit is contained in:
commit
ecefe4a1c3
@ -51,6 +51,7 @@ struct pasemi_smbus {
|
|||||||
#define MRXFIFO_DATA_M 0x000000ff
|
#define MRXFIFO_DATA_M 0x000000ff
|
||||||
|
|
||||||
#define SMSTA_XEN 0x08000000
|
#define SMSTA_XEN 0x08000000
|
||||||
|
#define SMSTA_MTN 0x00200000
|
||||||
|
|
||||||
#define CTL_MRR 0x00000400
|
#define CTL_MRR 0x00000400
|
||||||
#define CTL_MTR 0x00000200
|
#define CTL_MTR 0x00000200
|
||||||
@ -98,6 +99,10 @@ static unsigned int pasemi_smb_waitready(struct pasemi_smbus *smbus)
|
|||||||
status = reg_read(smbus, REG_SMSTA);
|
status = reg_read(smbus, REG_SMSTA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Got NACK? */
|
||||||
|
if (status & SMSTA_MTN)
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
if (timeout < 0) {
|
if (timeout < 0) {
|
||||||
dev_warn(&smbus->dev->dev, "Timeout, status 0x%08x\n", status);
|
dev_warn(&smbus->dev->dev, "Timeout, status 0x%08x\n", status);
|
||||||
reg_write(smbus, REG_SMSTA, status);
|
reg_write(smbus, REG_SMSTA, status);
|
||||||
@ -364,7 +369,7 @@ static int __devinit pasemi_smb_probe(struct pci_dev *dev,
|
|||||||
smbus->adapter.algo = &smbus_algorithm;
|
smbus->adapter.algo = &smbus_algorithm;
|
||||||
smbus->adapter.algo_data = smbus;
|
smbus->adapter.algo_data = smbus;
|
||||||
|
|
||||||
/* set up the driverfs linkage to our parent device */
|
/* set up the sysfs linkage to our parent device */
|
||||||
smbus->adapter.dev.parent = &dev->dev;
|
smbus->adapter.dev.parent = &dev->dev;
|
||||||
|
|
||||||
reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
|
reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
|
||||||
|
@ -128,13 +128,20 @@ static ssize_t eeprom_read(struct kobject *kobj, struct bin_attribute *bin_attr,
|
|||||||
for (slice = off >> 5; slice <= (off + count - 1) >> 5; slice++)
|
for (slice = off >> 5; slice <= (off + count - 1) >> 5; slice++)
|
||||||
eeprom_update_client(client, slice);
|
eeprom_update_client(client, slice);
|
||||||
|
|
||||||
/* Hide Vaio security settings to regular users (16 first bytes) */
|
/* Hide Vaio private settings to regular users:
|
||||||
if (data->nature == VAIO && off < 16 && !capable(CAP_SYS_ADMIN)) {
|
- BIOS passwords: bytes 0x00 to 0x0f
|
||||||
size_t in_row1 = 16 - off;
|
- UUID: bytes 0x10 to 0x1f
|
||||||
in_row1 = min(in_row1, count);
|
- Serial number: 0xc0 to 0xdf */
|
||||||
memset(buf, 0, in_row1);
|
if (data->nature == VAIO && !capable(CAP_SYS_ADMIN)) {
|
||||||
if (count - in_row1 > 0)
|
int i;
|
||||||
memcpy(buf + in_row1, &data->data[16], count - in_row1);
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
if ((off + i <= 0x1f) ||
|
||||||
|
(off + i >= 0xc0 && off + i <= 0xdf))
|
||||||
|
buf[i] = 0;
|
||||||
|
else
|
||||||
|
buf[i] = data->data[off + i];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
memcpy(buf, &data->data[off], count);
|
memcpy(buf, &data->data[off], count);
|
||||||
}
|
}
|
||||||
@ -197,14 +204,18 @@ static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
goto exit_kfree;
|
goto exit_kfree;
|
||||||
|
|
||||||
/* Detect the Vaio nature of EEPROMs.
|
/* Detect the Vaio nature of EEPROMs.
|
||||||
We use the "PCG-" prefix as the signature. */
|
We use the "PCG-" or "VGN-" prefix as the signature. */
|
||||||
if (address == 0x57) {
|
if (address == 0x57) {
|
||||||
if (i2c_smbus_read_byte_data(new_client, 0x80) == 'P'
|
char name[4];
|
||||||
&& i2c_smbus_read_byte(new_client) == 'C'
|
|
||||||
&& i2c_smbus_read_byte(new_client) == 'G'
|
name[0] = i2c_smbus_read_byte_data(new_client, 0x80);
|
||||||
&& i2c_smbus_read_byte(new_client) == '-') {
|
name[1] = i2c_smbus_read_byte(new_client);
|
||||||
|
name[2] = i2c_smbus_read_byte(new_client);
|
||||||
|
name[3] = i2c_smbus_read_byte(new_client);
|
||||||
|
|
||||||
|
if (!memcmp(name, "PCG-", 4) || !memcmp(name, "VGN-", 4)) {
|
||||||
dev_info(&new_client->dev, "Vaio EEPROM detected, "
|
dev_info(&new_client->dev, "Vaio EEPROM detected, "
|
||||||
"enabling password protection\n");
|
"enabling privacy protection\n");
|
||||||
data->nature = VAIO;
|
data->nature = VAIO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -673,7 +673,7 @@ static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i2c_check_addr(struct i2c_adapter *adapter, int addr)
|
static int i2c_check_addr(struct i2c_adapter *adapter, int addr)
|
||||||
{
|
{
|
||||||
int rval;
|
int rval;
|
||||||
|
|
||||||
@ -683,7 +683,6 @@ int i2c_check_addr(struct i2c_adapter *adapter, int addr)
|
|||||||
|
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(i2c_check_addr);
|
|
||||||
|
|
||||||
int i2c_attach_client(struct i2c_client *client)
|
int i2c_attach_client(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
|
@ -38,6 +38,15 @@
|
|||||||
|
|
||||||
static struct i2c_driver i2cdev_driver;
|
static struct i2c_driver i2cdev_driver;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An i2c_dev represents an i2c_adapter ... an I2C or SMBus master, not a
|
||||||
|
* slave (i2c_client) with which messages will be exchanged. It's coupled
|
||||||
|
* with a character special file which is accessed by user mode drivers.
|
||||||
|
*
|
||||||
|
* The list of i2c_dev structures is parallel to the i2c_adapter lists
|
||||||
|
* maintained by the driver model, and is updated using notifications
|
||||||
|
* delivered to the i2cdev_driver.
|
||||||
|
*/
|
||||||
struct i2c_dev {
|
struct i2c_dev {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct i2c_adapter *adap;
|
struct i2c_adapter *adap;
|
||||||
@ -103,6 +112,25 @@ static ssize_t show_adapter_name(struct device *dev,
|
|||||||
}
|
}
|
||||||
static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
|
static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* After opening an instance of this character special file, a file
|
||||||
|
* descriptor starts out associated only with an i2c_adapter (and bus).
|
||||||
|
*
|
||||||
|
* Using the I2C_RDWR ioctl(), you can then *immediately* issue i2c_msg
|
||||||
|
* traffic to any devices on the bus used by that adapter. That's because
|
||||||
|
* the i2c_msg vectors embed all the addressing information they need, and
|
||||||
|
* are submitted directly to an i2c_adapter. However, SMBus-only adapters
|
||||||
|
* don't support that interface.
|
||||||
|
*
|
||||||
|
* To use read()/write() system calls on that file descriptor, or to use
|
||||||
|
* SMBus interfaces (and work with SMBus-only hosts!), you must first issue
|
||||||
|
* an I2C_SLAVE (or I2C_SLAVE_FORCE) ioctl. That configures an anonymous
|
||||||
|
* (never registered) i2c_client so it holds the addressing information
|
||||||
|
* needed by those system calls and by this SMBus interface.
|
||||||
|
*/
|
||||||
|
|
||||||
static ssize_t i2cdev_read (struct file *file, char __user *buf, size_t count,
|
static ssize_t i2cdev_read (struct file *file, char __user *buf, size_t count,
|
||||||
loff_t *offset)
|
loff_t *offset)
|
||||||
{
|
{
|
||||||
@ -154,6 +182,29 @@ static ssize_t i2cdev_write (struct file *file, const char __user *buf, size_t c
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This address checking function differs from the one in i2c-core
|
||||||
|
in that it considers an address with a registered device, but no
|
||||||
|
bounded driver, as NOT busy. */
|
||||||
|
static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
|
||||||
|
{
|
||||||
|
struct list_head *item;
|
||||||
|
struct i2c_client *client;
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
mutex_lock(&adapter->clist_lock);
|
||||||
|
list_for_each(item, &adapter->clients) {
|
||||||
|
client = list_entry(item, struct i2c_client, list);
|
||||||
|
if (client->addr == addr) {
|
||||||
|
if (client->driver)
|
||||||
|
res = -EBUSY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mutex_unlock(&adapter->clist_lock);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
static int i2cdev_ioctl(struct inode *inode, struct file *file,
|
static int i2cdev_ioctl(struct inode *inode, struct file *file,
|
||||||
unsigned int cmd, unsigned long arg)
|
unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
@ -172,11 +223,22 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
|
|||||||
switch ( cmd ) {
|
switch ( cmd ) {
|
||||||
case I2C_SLAVE:
|
case I2C_SLAVE:
|
||||||
case I2C_SLAVE_FORCE:
|
case I2C_SLAVE_FORCE:
|
||||||
|
/* NOTE: devices set up to work with "new style" drivers
|
||||||
|
* can't use I2C_SLAVE, even when the device node is not
|
||||||
|
* bound to a driver. Only I2C_SLAVE_FORCE will work.
|
||||||
|
*
|
||||||
|
* Setting the PEC flag here won't affect kernel drivers,
|
||||||
|
* which will be using the i2c_client node registered with
|
||||||
|
* the driver model core. Likewise, when that client has
|
||||||
|
* the PEC flag already set, the i2c-dev driver won't see
|
||||||
|
* (or use) this setting.
|
||||||
|
*/
|
||||||
if ((arg > 0x3ff) ||
|
if ((arg > 0x3ff) ||
|
||||||
(((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
|
(((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if ((cmd == I2C_SLAVE) && i2c_check_addr(client->adapter,arg))
|
if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
/* REVISIT: address could become busy later */
|
||||||
client->addr = arg;
|
client->addr = arg;
|
||||||
return 0;
|
return 0;
|
||||||
case I2C_TENBIT:
|
case I2C_TENBIT:
|
||||||
@ -386,6 +448,13 @@ static int i2cdev_open(struct inode *inode, struct file *file)
|
|||||||
if (!adap)
|
if (!adap)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
/* This creates an anonymous i2c_client, which may later be
|
||||||
|
* pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.
|
||||||
|
*
|
||||||
|
* This client is ** NEVER REGISTERED ** with the driver model
|
||||||
|
* or I2C core code!! It just holds private copies of addressing
|
||||||
|
* information and maybe a PEC flag.
|
||||||
|
*/
|
||||||
client = kzalloc(sizeof(*client), GFP_KERNEL);
|
client = kzalloc(sizeof(*client), GFP_KERNEL);
|
||||||
if (!client) {
|
if (!client) {
|
||||||
i2c_put_adapter(adap);
|
i2c_put_adapter(adap);
|
||||||
@ -394,7 +463,6 @@ static int i2cdev_open(struct inode *inode, struct file *file)
|
|||||||
snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
|
snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
|
||||||
client->driver = &i2cdev_driver;
|
client->driver = &i2cdev_driver;
|
||||||
|
|
||||||
/* registered with adapter, passed as client to user */
|
|
||||||
client->adapter = adap;
|
client->adapter = adap;
|
||||||
file->private_data = client;
|
file->private_data = client;
|
||||||
|
|
||||||
@ -422,6 +490,14 @@ static const struct file_operations i2cdev_fops = {
|
|||||||
.release = i2cdev_release,
|
.release = i2cdev_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The legacy "i2cdev_driver" is used primarily to get notifications when
|
||||||
|
* I2C adapters are added or removed, so that each one gets an i2c_dev
|
||||||
|
* and is thus made available to userspace driver code.
|
||||||
|
*/
|
||||||
|
|
||||||
static struct class *i2c_dev_class;
|
static struct class *i2c_dev_class;
|
||||||
|
|
||||||
static int i2cdev_attach_adapter(struct i2c_adapter *adap)
|
static int i2cdev_attach_adapter(struct i2c_adapter *adap)
|
||||||
@ -486,6 +562,12 @@ static struct i2c_driver i2cdev_driver = {
|
|||||||
.detach_client = i2cdev_detach_client,
|
.detach_client = i2cdev_detach_client,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* module load/unload record keeping
|
||||||
|
*/
|
||||||
|
|
||||||
static int __init i2c_dev_init(void)
|
static int __init i2c_dev_init(void)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
@ -400,11 +400,6 @@ extern int i2c_release_client(struct i2c_client *);
|
|||||||
extern void i2c_clients_command(struct i2c_adapter *adap,
|
extern void i2c_clients_command(struct i2c_adapter *adap,
|
||||||
unsigned int cmd, void *arg);
|
unsigned int cmd, void *arg);
|
||||||
|
|
||||||
/* returns -EBUSY if address has been taken, 0 if not. Note that the only
|
|
||||||
other place at which this is called is within i2c_attach_client; so
|
|
||||||
you can cheat by simply not registering. Not recommended, of course! */
|
|
||||||
extern int i2c_check_addr (struct i2c_adapter *adapter, int addr);
|
|
||||||
|
|
||||||
/* Detect function. It iterates over all possible addresses itself.
|
/* Detect function. It iterates over all possible addresses itself.
|
||||||
* It will only call found_proc if some client is connected at the
|
* It will only call found_proc if some client is connected at the
|
||||||
* specific address (unless a 'force' matched);
|
* specific address (unless a 'force' matched);
|
||||||
|
Loading…
Reference in New Issue
Block a user