root/i2c/trunk/kernel/i2c-philips-par.c @ 3317

Revision 3317, 5.2 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-lp.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
23#include <linux/kernel.h>
24#include <linux/ioport.h>
25#include <linux/module.h>
26#if LINUX_VERSION_CODE >= 0x020135
27#include <linux/init.h>
28#else
29#define __init
30#endif
31#include <asm/io.h>
32#include <linux/stddef.h>
33
34#include "i2c.h"
35#include "i2c-algo-bit.h"
36
37#define DEFAULT_BASE 0x378
38static int base=0;
39
40/* Note: all we need to know is the base address of the parallel port, so
41 * instead of having a dedicated struct to store this value, we store this
42 * int in the pointer field (=bit_lp_ops.data) itself.
43 */
44
45/* Note2: as the hw that implements the i2c bus on the parallel port is
46 * incompatible with other epp stuff etc., we access the port exclusively
47 * and don't cooperate with parport functions.
48 */
49
50/* ----- global defines ----------------------------------------------- */
51#define DEB(x)          /* should be reasonable open, close &c.         */
52#define DEB2(x)         /* low level debugging - very slow              */
53#define DEBE(x) x       /* error messages                               */
54
55/* ----- printer port defines ------------------------------------------*/
56                                        /* Pin Port  Inverted   name    */
57#define I2C_ON          0x20            /* 12 status N  paper           */
58                                        /* ... only for phil. not used  */
59#define I2C_SDA         0x80            /*  9 data   N  data7           */
60#define I2C_SCL         0x08            /* 17 ctrl   N  dsel            */
61
62#define I2C_SDAIN       0x80            /* 11 stat   Y  busy            */
63#define I2C_SCLIN       0x08            /* 15 stat   Y  enable          */
64
65#define I2C_DMASK       0x7f
66#define I2C_CMASK       0xf7
67
68/* --- Convenience defines for the parallel port:                       */
69#define BASE    (unsigned int)(data)
70#define DATA    BASE                    /* Centronics data port         */
71#define STAT    (BASE+1)                /* Centronics status port       */
72#define CTRL    (BASE+2)                /* Centronics control port      */
73
74/* ----- local functions ---------------------------------------------- */
75
76void bit_lp_setscl(void *data, int state)
77{
78        /*be cautious about state of the control register -
79                touch only the one bit needed*/
80        if (state) {
81                outb(inb(CTRL)|I2C_SCL,   CTRL);
82        } else {
83                outb(inb(CTRL)&I2C_CMASK, CTRL);
84        }
85}
86
87void bit_lp_setsda(void *data, int state)
88{
89        if (state) {
90                outb(I2C_DMASK , DATA);
91        } else {
92                outb(I2C_SDA , DATA);
93        }
94}
95
96int bit_lp_getscl(void *data)
97{
98        return ( 0 != ( (inb(STAT)) & I2C_SCLIN ) );
99}
100
101int bit_lp_getsda(void *data)
102{
103        return ( 0 != ( (inb(STAT)) & I2C_SDAIN ) );
104}
105
106int bit_lp_init(void)
107{
108        if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) {
109                return -ENODEV;
110        } else {
111                request_region(base,(base == 0x3bc)? 3 : 8,
112                        "i2c (parallel port adapter)");
113                /* reset hardware to sane state */
114                bit_lp_setsda((void*)base,1);
115                bit_lp_setscl((void*)base,1);
116        }
117        return 0;
118}
119
120void bit_lp_exit(void)
121{
122        release_region( base , (base == 0x3bc)? 3 : 8 );
123}
124
125int bit_lp_reg(struct i2c_client *client)
126{
127        return 0;
128}
129
130int bit_lp_unreg(struct i2c_client *client)
131{
132        return 0;
133}
134
135static void bit_lp_inc_use(struct bit_adapter *adap)
136{
137  MOD_INC_USE_COUNT;
138}
139
140static void bit_lp_dec_use(struct bit_adapter *adap)
141{
142  MOD_DEC_USE_COUNT;
143}
144
145/* ------------------------------------------------------------------------
146 * Encapsulate the above functions in the correct operations structure.
147 * This is only done when more than one hardware adapter is supported.
148 */
149struct bit_adapter bit_lp_ops = {
150        "Philips Parallel port adapter",
151        HW_B_LP,
152        NULL,
153        bit_lp_setsda,
154        bit_lp_setscl,
155        bit_lp_getsda,
156        bit_lp_getscl,
157        bit_lp_reg,
158        bit_lp_unreg,
159        bit_lp_inc_use,
160        bit_lp_dec_use,
161        80, 80, 100,            /*      waits, timeout */
162};
163
164
165int __init bitlp_init(void)
166{
167        if (base==0) {
168                /* probe some values */
169                base=DEFAULT_BASE;
170                bit_lp_ops.data=(void*)DEFAULT_BASE;
171                if (bit_lp_init()==0) {
172                        i2c_bit_add_bus(&bit_lp_ops);
173                } else {
174                        return -ENODEV;
175                }
176        } else {
177                bit_lp_ops.data=(void*)base;
178                if (bit_lp_init()==0) {
179                        i2c_bit_add_bus(&bit_lp_ops);
180                } else {
181                        return -ENODEV;
182                }
183        }
184        printk("bit_lp: found device at %#x.\n",base);
185        return 0;
186}
187
188#ifdef MODULE
189MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
190MODULE_DESCRIPTION("I2C-Bus adapter routines for Philips parallel port adapter");
191
192MODULE_PARM(base, "i");
193
194EXPORT_NO_SYMBOLS;
195
196int init_module(void) 
197{
198        return bitlp_init();
199}
200
201void cleanup_module(void) 
202{
203        i2c_bit_del_bus(&bit_lp_ops);
204        bit_lp_exit();
205}
206
207#endif
208
209
210
Note: See TracBrowser for help on using the browser.