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

Revision 3317, 5.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/* bit-elv.c i2c-hw access for philips style parallel port adapters          */
3/* ------------------------------------------------------------------------- */
4/*   Copyright (C) 1995-97 Simon G. Vogl
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/* -------------------------------------------------------------------------
20static char rcsid[] = "$Id$";
21   ------------------------------------------------------------------------- */
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/delay.h>
25#include <linux/malloc.h>
26#include <linux/version.h>
27#if LINUX_VERSION_CODE >= 0x020135
28#include <linux/init.h>
29#else
30#define __init
31#endif
32
33#if LINUX_VERSION_CODE >= 0x020100
34#  include <asm/uaccess.h>
35#else
36#  include <asm/segment.h>
37#endif
38
39#include <linux/ioport.h>
40#include <asm/io.h>
41#include <linux/errno.h>
42#include "i2c.h"
43#include "i2c-algo-bit.h"
44
45#define DEFAULT_BASE 0x378
46static int base=0;
47static unsigned char PortData = 0;
48
49/* ----- global defines ----------------------------------------------- */
50#define DEB(x)          /* should be reasonable open, close &c.         */
51#define DEB2(x)         /* low level debugging - very slow              */
52#define DEBE(x) x       /* error messages                               */
53#define DEBINIT(x) x    /* detection status messages                    */
54
55/* --- Convenience defines for the parallel port:                       */
56#define BASE    (unsigned int)(data)
57#define DATA    BASE                    /* Centronics data port         */
58#define STAT    (BASE+1)                /* Centronics status port       */
59#define CTRL    (BASE+2)                /* Centronics control port      */
60
61
62/* ----- local functions ---------------------------------------------- */
63
64
65void bit_elv_setscl(void *data, int state)
66{
67        if (state) {
68                PortData &= 0xfe;
69        } else {
70                PortData |=1;
71        }
72        outb(PortData, DATA);
73}
74
75void bit_elv_setsda(void *data, int state)
76{
77        if (state) {
78                PortData &=0xfd;
79        } else {
80                PortData |=2;
81        }
82        outb(PortData, DATA);
83} 
84
85int bit_elv_getscl(void *data)
86{
87        return ( 0 == ( (inb_p(STAT)) & 0x08 ) );
88}
89
90int bit_elv_getsda(void *data)
91{
92        return ( 0 == ( (inb_p(STAT)) & 0x40 ) );
93}
94
95int bit_elv_init(void)
96{
97        if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) {
98                return -ENODEV; 
99        } else {
100                                                /* test for ELV adap.   */
101                if (inb(base+1) & 0x80) {       /* BUSY should be high  */
102                        DEBINIT(printk("i2c ELV: Busy was low.\n"));
103                        return -ENODEV;
104                } else {
105                        outb(0x0c,base+2);      /* SLCT auf low         */
106                        udelay(400);
107                        if ( !(inb(base+1) && 0x10) ) {
108                                outb(0x04,base+2);
109                                DEBINIT(printk("i2c ELV: Select was high.\n"));
110                                return -ENODEV;
111                        }
112                }
113                request_region(base,(base == 0x3bc)? 3 : 8,
114                        "i2c (ELV adapter)");
115                PortData = 0;
116                bit_elv_setsda((void*)base,1);
117                bit_elv_setscl((void*)base,1);
118        }
119        return 0;
120}
121
122void bit_elv_exit(void)
123{
124        release_region( base , (base == 0x3bc)? 3 : 8 );
125}
126
127int bit_elv_reg(struct i2c_client *client)
128{
129        return 0;
130}
131
132int bit_elv_unreg(struct i2c_client *client)
133{
134        return 0;
135}
136
137static void bit_elv_inc_use(struct bit_adapter *adap)
138{
139#ifdef MODULE
140  MOD_INC_USE_COUNT;
141#endif
142}
143
144static void bit_elv_dec_use(struct bit_adapter *adap)
145{
146#ifdef MODULE
147  MOD_DEC_USE_COUNT;
148#endif
149}
150
151/* ------------------------------------------------------------------------
152 * Encapsulate the above functions in the correct operations structure.
153 * This is only done when more than one hardware adapter is supported.
154 */
155struct bit_adapter bit_elv_ops = {
156        "ELV Parallel port adaptor",
157        HW_B_ELV,
158        NULL,
159        bit_elv_setsda,
160        bit_elv_setscl,
161        bit_elv_getsda,
162        bit_elv_getscl,
163        bit_elv_reg,
164        bit_elv_unreg, 
165        bit_elv_inc_use,
166        bit_elv_dec_use,
167        80, 80, 100,            /*      waits, timeout */
168};
169
170
171int  __init bitelv_init(void)
172{
173        if (base==0) {
174                /* probe some values */
175                base=DEFAULT_BASE;
176                bit_elv_ops.data=(void*)DEFAULT_BASE;
177                if (bit_elv_init()==0) {
178                        i2c_bit_add_bus(&bit_elv_ops);
179                } else {
180                        return -ENODEV;
181                }
182        } else {
183                bit_elv_ops.data=(void*)base;
184                if (bit_elv_init()==0) {
185                        i2c_bit_add_bus(&bit_elv_ops);
186                } else {
187                        return -ENODEV;
188                }
189        }
190        printk("bit_elv: found device at %#x.\n",base);
191        return 0;
192}
193
194
195#ifdef MODULE
196MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
197MODULE_DESCRIPTION("I2C-Bus adapter routines for ELV parallel port adapter")
198;
199
200MODULE_PARM(base, "i");
201
202EXPORT_NO_SYMBOLS;
203
204int init_module(void)
205{
206        return bitelv_init();
207}
208
209void cleanup_module(void)
210{
211        i2c_bit_del_bus(&bit_elv_ops);
212        bit_elv_exit();
213}
214
215#endif
Note: See TracBrowser for help on using the browser.