root/lm-sensors/trunk/kernel/smbus.c @ 481

Revision 481, 8.2 KB (checked in by frodo, 14 years ago)

Small SMBUS read byte fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    smbus.c - Part of lm_sensors, Linux kernel modules for hardware
3              monitoring
4    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21#include <linux/module.h>
22#include <linux/kernel.h>
23#include <linux/stddef.h>
24#include <asm/system.h>
25
26#include "compat.h"
27
28#include "i2c.h"
29#ifdef I2C_SPINLOCK
30#include <asm/spinlock.h>
31#else
32#if LINUX_VERSION_CODE < KERNEL_VERSION(2,0,19)
33#include <linux/sched.h>
34#else
35#include <asm/semaphore.h>
36#endif
37#endif
38
39#include "version.h"
40#include "smbus.h"
41
42static s32 smbus_access_i2c (struct i2c_adapter * adapter, u8 addr,
43                             char read_write, u8 command, int size,
44                             union smbus_data * data);
45
46static int smbus_master_xfer (struct smbus_adapter *adap,
47                              struct i2c_msg msgs[], int num);
48static int smbus_slave_send (struct smbus_adapter *adap, char *data, int len);
49static int smbus_slave_recv (struct smbus_adapter *adap, char *data, int len);
50static int smbus_algo_control (struct smbus_adapter *adap, unsigned int cmd, 
51                               unsigned long arg);
52static int smbus_client_register (struct smbus_client *client);
53static int smbus_client_unregister (struct smbus_client *client);
54
55static int smbus_init(void);
56static int smbus_cleanup(void);
57
58#ifdef MODULE
59extern int init_module(void);
60extern int cleanup_module(void);
61#endif /* MODULE */
62
63/* This is the actual algorithm we define */
64struct smbus_algorithm smbus_algorithm = {
65  /* name */            "Non-I2C SMBus adapter",
66  /* id */              ALGO_SMBUS,
67  /* master_xfer */     &smbus_master_xfer,
68  /* slave_send */      &smbus_slave_send,
69  /* slave_rcv */       &smbus_slave_recv,
70  /* algo_control */    &smbus_algo_control,
71  /* client_register */ &smbus_client_register,
72  /* client_unregister*/&smbus_client_unregister
73};
74
75
76/* OK, so you want to access a bus using the SMBus protocols. Well, it either
77   is registered as a SMBus-only adapter (like the PIIX4), or we need to
78   simulate the SMBus commands using the i2c access routines.
79   We do all locking here, so you can ignore that in the adapter-specific
80   smbus_accesss routine. */
81s32 smbus_access (struct i2c_adapter * adapter, u8 addr, char read_write,
82                  u8 command, int size, union smbus_data * data)
83{
84  int res;
85  if ((adapter->id & ALGO_MASK) == ALGO_SMBUS) {
86#ifdef I2C_SPINLOCK
87    spin_lock_irqsave(&adapter->lock,adapter->lockflags);
88#else
89    down(&adapter->lock);
90#endif
91    res = ((struct smbus_adapter *) adapter) -> 
92           smbus_access(addr,read_write,command,size,data);
93#ifdef I2C_SPINLOCK
94    spin_unlock_irqrestore(&adapter->lock,adapter->lockflags);
95#else
96    up(&adapter->lock);
97#endif
98  } else 
99    res = smbus_access_i2c(adapter,addr,read_write,command,size,data);
100  return res;
101}
102 
103/* Simulate a SMBus command using the i2c protocol
104   No checking of paramters is done!  */
105s32 smbus_access_i2c(struct i2c_adapter * adapter, u8 addr, char read_write,
106                     u8 command, int size, union smbus_data * data)
107{
108  /* So we need to generate a series of msgs. In the case of writing, we
109     need to use only one message; when reading, we need two. We initialize
110     most things with sane defaults, to keep the code below somewhat
111     simpler. */
112  unsigned char msgbuf0[33];
113  unsigned char msgbuf1[33];
114  int num = read_write == SMBUS_READ?2:1;
115  struct i2c_msg msg[2] = { { addr, 0, 1, msgbuf0 }, 
116                            { addr, I2C_M_RD, 0, msgbuf1 }
117                          };
118  int i;
119
120  msgbuf0[0] = command;
121  switch(size) {
122  case SMBUS_QUICK:
123    msg[0].len = 0;
124    num = 1; /* Special case: The read/write field is used as data */
125    break;
126  case SMBUS_BYTE:
127    if (read_write == SMBUS_READ) {
128      /* Special case: only a read! */
129      msg[0].flags = I2C_M_RD;
130      num = 1;
131    }
132    break;
133  case SMBUS_BYTE_DATA:
134    if (read_write == SMBUS_READ)
135      msg[1].len = 1;
136    else {
137      msg[0].len = 2;
138      msgbuf0[1] = data->byte;
139    }
140    break;
141  case SMBUS_WORD_DATA:
142    if (read_write == SMBUS_READ)
143      msg[1].len = 2;
144    else {
145      msg[0].len=3;
146      msgbuf0[1] = data->word & 0xff;
147      msgbuf0[2] = (data->word >> 8) & 0xff;
148    }
149    break;
150  case SMBUS_PROC_CALL:
151    num = 2; /* Special case */
152    msg[0].len = 3;
153    msg[1].len = 2;
154    msgbuf0[1] = data->word & 0xff;
155    msgbuf0[2] = (data->word >> 8) & 0xff;
156    break;
157  case SMBUS_BLOCK_DATA:
158    if (read_write == SMBUS_READ) {
159      printk("smbus.o: Block read not supported under I2C emulation!\n");
160      return -1;
161    } else {
162      msg[1].len = data->block[0] + 1;
163      if (msg[1].len > 32) {
164        printk("smbus.o: smbus_access called with invalid block write "
165               "size (%d)\n",msg[1].len);
166        return -1;
167      }
168      for (i = 1; i <= msg[1].len; i++)
169        msgbuf0[i] = data->block[i];
170    }
171    break;
172  default:
173    printk("smbus.o: smbus_access called with invalid size (%d)\n",size);
174    return -1;
175  }
176   
177  if (i2c_transfer(adapter, msg, num) < 0)
178    return -1;
179
180  if(read_write == SMBUS_READ)
181    switch(size) {
182    case SMBUS_BYTE:
183      data->byte = msgbuf0[0];
184      break;
185    case SMBUS_BYTE_DATA:
186      data->byte = msgbuf1[0];
187      break;
188    case SMBUS_WORD_DATA:
189    case SMBUS_PROC_CALL:
190      data->word = msgbuf1[0] | (msgbuf1[1] << 8);
191      break;
192  }
193  return 0;
194}
195
196/* Algorithm master_xfer call-back implementation. Can't do that... */
197int smbus_master_xfer (struct smbus_adapter *adap, struct i2c_msg msgs[], 
198                       int num)
199{
200#ifdef DEBUG
201  printk("smbus.o: smbus_master_xfer called for adapter `%s' "
202         "(no i2c level access possible!)\n",
203         adap->name);
204#endif
205  return -1;
206}
207
208/* Algorithm slave_send call-back implementation. Can't do that... */
209int smbus_slave_send (struct smbus_adapter *adap, char *data, int len)
210{
211#ifdef DEBUG
212  printk("smbus.o: smbus_slave_send called for adapter `%s' "
213         "(no i2c level access possible!)\n",
214         adap->name);
215#endif
216  return -1;
217}
218
219/* Algorithm slave_recv call-back implementation. Can't do that... */
220int smbus_slave_recv (struct smbus_adapter *adap, char *data, int len)
221{
222#ifdef DEBUG
223  printk("smbus.o: smbus_slave_recv called for adapter `%s' "
224         "(no i2c level access possible!)\n",
225         adap->name);
226#endif
227  return -1;
228}
229
230/* Here we can put additional calls to modify the workings of the algorithm.
231   But right now, there is no need for that. */
232int smbus_algo_control (struct smbus_adapter *adap, unsigned int cmd, 
233                         unsigned long arg)
234{
235  return 0;
236}
237
238/* Ehm... This is called when a client is registered to an adapter. We could
239   do all kinds of neat stuff here like, ehm - returning success? */
240int smbus_client_register (struct smbus_client *client)
241{
242  return 0;
243}
244 
245int smbus_client_unregister (struct smbus_client *client)
246{
247  return 0;
248}
249
250int smbus_init(void)
251{
252  int res;
253  printk("smbus.o version %s (%s)\n",LM_VERSION,LM_DATE);
254  if ((res = smbus_add_algorithm(&smbus_algorithm)))
255    printk("smbus.o: Algorithm registration failed, module not inserted.\n");
256  else
257    printk("smbus.o initialized\n");
258  return res;
259}
260
261int smbus_cleanup(void)
262{
263  int res;
264  if ((res = smbus_del_algorithm(&smbus_algorithm)))
265    printk("smbus.o: Algorithm deregistration failed, module not removed\n");
266  return res;
267}
268
269/* OK, this will for now _only_ compile as a module, but this is neat for
270   later, if we want to compile it straight into the kernel */
271#ifdef MODULE
272
273MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
274MODULE_DESCRIPTION("System Management Bus (SMBus) access");
275
276int init_module(void)
277{
278  return smbus_init();
279}
280
281int cleanup_module(void)
282{
283  return smbus_cleanup();
284}
285
286#endif /* MODULE */
Note: See TracBrowser for help on using the browser.