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

Revision 480, 8.2 KB (checked in by kmalkki, 14 years ago)

(Kyösti) : Fix the Read Word bug, again..

  • 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    break;
131  case SMBUS_BYTE_DATA:
132    if (read_write == SMBUS_READ)
133      msg[1].len = 1;
134    else {
135      msg[0].len = 2;
136      msgbuf0[1] = data->byte;
137    }
138    break;
139  case SMBUS_WORD_DATA:
140    if (read_write == SMBUS_READ)
141      msg[1].len = 2;
142    else {
143      msg[0].len=3;
144      msgbuf0[1] = data->word & 0xff;
145      msgbuf0[2] = (data->word >> 8) & 0xff;
146    }
147    break;
148  case SMBUS_PROC_CALL:
149    num = 2; /* Special case */
150    msg[0].len = 3;
151    msg[1].len = 2;
152    msgbuf0[1] = data->word & 0xff;
153    msgbuf0[2] = (data->word >> 8) & 0xff;
154    break;
155  case SMBUS_BLOCK_DATA:
156    if (read_write == SMBUS_READ) {
157      printk("smbus.o: Block read not supported under I2C emulation!\n");
158      return -1;
159    } else {
160      msg[1].len = data->block[0] + 1;
161      if (msg[1].len > 32) {
162        printk("smbus.o: smbus_access called with invalid block write "
163               "size (%d)\n",msg[1].len);
164        return -1;
165      }
166      for (i = 1; i <= msg[1].len; i++)
167        msgbuf0[i] = data->block[i];
168    }
169    break;
170  default:
171    printk("smbus.o: smbus_access called with invalid size (%d)\n",size);
172    return -1;
173  }
174   
175  if (i2c_transfer(adapter, msg, num) < 0)
176    return -1;
177
178  if(read_write == SMBUS_READ)
179    switch(size) {
180    case SMBUS_BYTE:
181      data->byte = msgbuf0[0];
182      break;
183    case SMBUS_BYTE_DATA:
184      data->byte = msgbuf1[0];
185      break;
186    case SMBUS_WORD_DATA:
187    case SMBUS_PROC_CALL:
188      data->word = msgbuf1[0] | (msgbuf1[1] << 8);
189      break;
190  }
191  return 0;
192}
193
194/* Algorithm master_xfer call-back implementation. Can't do that... */
195int smbus_master_xfer (struct smbus_adapter *adap, struct i2c_msg msgs[], 
196                       int num)
197{
198#ifdef DEBUG
199  printk("smbus.o: smbus_master_xfer called for adapter `%s' "
200         "(no i2c level access possible!)\n",
201         adap->name);
202#endif
203  return -1;
204}
205
206/* Algorithm slave_send call-back implementation. Can't do that... */
207int smbus_slave_send (struct smbus_adapter *adap, char *data, int len)
208{
209#ifdef DEBUG
210  printk("smbus.o: smbus_slave_send called for adapter `%s' "
211         "(no i2c level access possible!)\n",
212         adap->name);
213#endif
214  return -1;
215}
216
217/* Algorithm slave_recv call-back implementation. Can't do that... */
218int smbus_slave_recv (struct smbus_adapter *adap, char *data, int len)
219{
220#ifdef DEBUG
221  printk("smbus.o: smbus_slave_recv called for adapter `%s' "
222         "(no i2c level access possible!)\n",
223         adap->name);
224#endif
225  return -1;
226}
227
228/* Here we can put additional calls to modify the workings of the algorithm.
229   But right now, there is no need for that. */
230int smbus_algo_control (struct smbus_adapter *adap, unsigned int cmd, 
231                         unsigned long arg)
232{
233  return 0;
234}
235
236/* Ehm... This is called when a client is registered to an adapter. We could
237   do all kinds of neat stuff here like, ehm - returning success? */
238int smbus_client_register (struct smbus_client *client)
239{
240  return 0;
241}
242 
243int smbus_client_unregister (struct smbus_client *client)
244{
245  return 0;
246}
247
248int smbus_init(void)
249{
250  int res;
251  printk("smbus.o version %s (%s)\n",LM_VERSION,LM_DATE);
252  if ((res = smbus_add_algorithm(&smbus_algorithm)))
253    printk("smbus.o: Algorithm registration failed, module not inserted.\n");
254  else
255    printk("smbus.o initialized\n");
256  return res;
257}
258
259int smbus_cleanup(void)
260{
261  int res;
262  if ((res = smbus_del_algorithm(&smbus_algorithm)))
263    printk("smbus.o: Algorithm deregistration failed, module not removed\n");
264  return res;
265}
266
267/* OK, this will for now _only_ compile as a module, but this is neat for
268   later, if we want to compile it straight into the kernel */
269#ifdef MODULE
270
271MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
272MODULE_DESCRIPTION("System Management Bus (SMBus) access");
273
274int init_module(void)
275{
276  return smbus_init();
277}
278
279int cleanup_module(void)
280{
281  return smbus_cleanup();
282}
283
284#endif /* MODULE */
Note: See TracBrowser for help on using the browser.