root/i2c/trunk/kernel/i2c-elektor.c @ 3317

Revision 3317, 6.3 KB (checked in by frodo, 15 years ago)

Second part of Kyösti Mälkki's patches

MOD_{INC,DEC}_USE_COUNT should now really be fail-safe.

I wrote in email to Kyösti about this:

If I understand it correctly, the scheme you propose is as follows:

  • Each struct i2c_algorithm variable has inc_use and dec_use hooks in it.
  • The hooks should do a MOD_{INC,DEC}_USE_COUNT in the appropriate adapter modules (of course, these can only be done in the module which needs to be locked)
  • The struct i2c_driver had already similar hooks, for locking the client modules
  • The i2c_{inc,dec}_use_client function should *not* be called when a client is (de)registered; instead, it should only be called when a resource is used that makes it impossible to remove the client and its adapter. For example, the opening of a /proc file or the moving into a /proc directory owned by the client driver. I have applied the changes to i2c-core and i2c.h as in your patch, as well as to i2c-algo-bit. I saw you added MOD_INC_USE_COUNT to the algorithm drivers. That means we can't remove an algorithm module if an adapter module is still connected to it. Perhaps we should do the same as the in the case a driver module is deleted: scan for connected adapters and remove them one by one (including their clients, of course). What do you think? As i2c-algo-pcf is structured similar to i2c-algo-bit, I saw no reason not to apply the same patches to it, including the MOD_{INC,DEC}_USE_COUNT patch. If you know of a reason why I should not have done this, please tell me and/or revert the changes. I know this will break PCF adapter drivers; well, too bad :-) All included adapter drivers have been patched to do MOD_{INC,DEV}_USE_COUNT calls.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* ------------------------------------------------------------------------- */
2/* pcf-isa.c i2c-hw access for PCF8584 style isa bus adapters                */
3/* ------------------------------------------------------------------------- */
4/*   Copyright (C) 1995-97 Simon G. Vogl
5                   1998-99 Hans Berglund
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
20/* ------------------------------------------------------------------------- */
21
22#include <linux/kernel.h>
23#include <linux/ioport.h>
24#include <linux/module.h>
25#include <linux/delay.h>
26#include <linux/malloc.h>
27#include <linux/version.h>
28#if LINUX_VERSION_CODE >= 0x020135
29#include <linux/init.h>
30#else
31#define __init
32#endif
33#include <asm/irq.h>
34#include <asm/io.h>
35
36#include "i2c.h"
37#include "i2c-algo-pcf.h"
38#include "i2c-elektor.h"
39#include "pcf8584.h"
40
41#define DEFAULT_BASE 0x300
42#define DEFAULT_IRQ      0
43#define DEFAULT_CLOCK 0x1c
44#define DEFAULT_OWN   0x55
45
46static int base  = 0;
47static int irq   = 0;
48static int clock = 0;
49static int own   = 0;
50static int i2c_debug=0;
51static struct pcf_isa gpi;
52static struct wait_queue *pcf_wait = NULL;
53static int pcf_pending;
54
55
56/* ----- global defines ----------------------------------------------- */
57#define DEB(x)  if (i2c_debug>=1) x
58#define DEB2(x) if (i2c_debug>=2) x
59#define DEB3(x) if (i2c_debug>=3) x
60#define DEBE(x) x       /* error messages                               */
61
62
63/* --- Convenience defines for the i2c port:                    */
64#define BASE    ((struct pcf_isa *)(data))->pi_base
65#define DATA    BASE                    /* Adapter data port            */
66#define CTRL    (BASE+1)                /* Adapter control port         */
67
68/* ----- local functions ---------------------------------------------- */
69
70static void pcf_isa_setbyte(void *data, int ctl, int val)
71{
72   if (ctl) {
73      if (gpi.pi_irq > 0) {
74         DEB3(printk("Write control 0x%x\n", val|PCF_ENI));
75         outb(val | PCF_ENI, CTRL);
76      } else {
77         DEB3(printk("Write control 0x%x\n", val));
78         outb(val, CTRL);
79      }
80   } else {
81      DEB3(printk("Write data 0x%x\n", val));
82      outb(val, DATA);
83   }
84}
85
86static int pcf_isa_getbyte(void *data, int ctl)
87{
88   int val;
89
90   if (ctl) {
91      val = inb(CTRL);
92      DEB3(printk("Read control 0x%x\n", val));
93   } else {
94      val = inb(DATA);
95      DEB3(printk("Read data 0x%x\n", val));
96   }
97   return (val);
98}
99
100static int pcf_isa_getown(void *data)
101{
102   return (gpi.pi_own);
103}
104
105
106static int pcf_isa_getclock(void *data)
107{
108   return (gpi.pi_clock);
109}
110
111
112
113#if LINUX_VERSION_CODE < 0x02017f
114static void schedule_timeout(int j)
115{
116        current->state   = TASK_INTERRUPTIBLE;
117        current->timeout = jiffies + j;
118        schedule();
119}
120#endif
121
122#if 0
123static void pcf_isa_sleep(unsigned long timeout)
124{
125        schedule_timeout( timeout * HZ);
126}
127#endif
128
129
130static void pcf_isa_waitforpin(void) {
131
132   int timeout = 2;
133
134   if (gpi.pi_irq > 0) {
135      cli();
136      if (pcf_pending == 0) {
137#if LINUX_VERSION_CODE < 0x02017f
138         current->timeout = jiffies + timeout * HZ;
139         interruptible_sleep_on(&pcf_wait);
140#else
141         interruptible_sleep_on_timeout(&pcf_wait, timeout*HZ );
142#endif
143      }
144      else
145         pcf_pending = 0;
146      sti();
147#if LINUX_VERSION_CODE < 0x02017f
148      current->timeout = 0;
149#endif
150   }
151   else {
152      udelay(100);
153   }
154}
155
156
157static void pcf_isa_handler(int this_irq, void *dev_id, struct pt_regs *regs) {
158
159   pcf_pending = 1;
160   wake_up_interruptible(&pcf_wait);
161}
162
163
164static int pcf_isa_init(void)
165{
166   if (check_region(gpi.pi_base, 2) < 0 ) {
167      return -ENODEV;
168   } else {
169      request_region(gpi.pi_base, 2, "i2c (isa bus adapter)");
170   }
171   if (gpi.pi_irq > 0) {
172      if (request_irq(gpi.pi_irq, pcf_isa_handler, 0, "PCF8584", 0) < 0) {
173         printk("Request irq%d failed\n", gpi.pi_irq);
174         gpi.pi_irq = 0;
175      }
176      else
177         enable_irq(gpi.pi_irq);
178   }
179   return 0;
180}
181
182
183static void pcf_isa_exit(void)
184{
185   if (gpi.pi_irq > 0) {
186      disable_irq(gpi.pi_irq);
187      free_irq(gpi.pi_irq, 0);
188   }
189   release_region(gpi.pi_base , 2);
190}
191
192
193static int pcf_isa_reg(struct i2c_client *client)
194{
195        return 0;
196}
197
198
199static int pcf_isa_unreg(struct i2c_client *client)
200{
201        return 0;
202}
203
204static void pcf_isa_inc_use(struct pcf_adapter *adap)
205{
206#ifdef MODULE
207  MOD_INC_USE_COUNT;
208#endif
209}
210
211static void pcf_isa_dec_use(struct pcf_adapter *adap)
212{
213#ifdef MODULE
214  MOD_DEC_USE_COUNT;
215#endif
216}
217
218
219/* ------------------------------------------------------------------------
220 * Encapsulate the above functions in the correct operations structure.
221 * This is only done when more than one hardware adapter is supported.
222 */
223struct pcf_adapter pcf_isa_ops = {
224        "PCF8584 ISA adapter",
225        HW_P_ELEK,
226        NULL,
227        pcf_isa_setbyte,
228        pcf_isa_getbyte,
229        pcf_isa_getown,
230        pcf_isa_getclock,
231        pcf_isa_waitforpin,
232        pcf_isa_reg,
233        pcf_isa_unreg,
234        pcf_isa_inc_use,
235        pcf_isa_dec_use,
236        80, 80, 100,            /*      waits, timeout */
237};
238
239int __init pcfisa_init(void) 
240{
241
242   struct pcf_isa *pisa = &gpi;
243
244   if (base == 0)
245      pisa->pi_base = DEFAULT_BASE;
246   else
247      pisa->pi_base = base;
248
249   if (irq == 0)
250      pisa->pi_irq = DEFAULT_IRQ;
251   else
252      pisa->pi_irq = irq;
253
254   if (clock == 0)
255      pisa->pi_clock = DEFAULT_CLOCK;
256   else
257      pisa->pi_clock = clock;
258
259   if (own == 0)
260      pisa->pi_own = DEFAULT_OWN;
261   else
262      pisa->pi_own = own;
263
264   pcf_isa_ops.data = (void *)pisa;
265   if (pcf_isa_init() == 0) {
266      i2c_pcf_add_bus(&pcf_isa_ops);
267   } else {
268      return -ENODEV;
269   }
270   printk("pcf_isa: found device at %#x.\n", pisa->pi_base);
271   return 0;
272}
273
274
275#ifdef MODULE
276MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
277MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter");
278
279MODULE_PARM(base, "i");
280MODULE_PARM(irq, "i");
281MODULE_PARM(clock, "i");
282MODULE_PARM(own, "i");
283
284EXPORT_NO_SYMBOLS;
285
286int init_module(void) 
287{
288   return pcfisa_init();
289}
290
291void cleanup_module(void) 
292{
293        i2c_pcf_del_bus(&pcf_isa_ops);
294        pcf_isa_exit();
295}
296
297#endif
298
299
Note: See TracBrowser for help on using the browser.