OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [tipar.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/* Hey EMACS -*- linux-c -*-
2
 *
3
 * tipar - low level driver for handling a parallel link cable designed
4
 * for Texas Instruments graphing calculators (http://lpg.ticalc.org).
5
 *
6
 * Copyright (C) 2000-2002, Romain Lievin <roms@lpg.ticalc.org>
7
 * under the terms of the GNU General Public License.
8
 *
9
 * Various fixes & clean-up from the Linux Kernel Mailing List
10
 * (Alan Cox, Richard B. Johnson, Christoph Hellwig).
11
 */
12
 
13
/* This driver should, in theory, work with any parallel port that has an
14
 * appropriate low-level driver; all I/O is done through the parport
15
 * abstraction layer.
16
 *
17
 * If this driver is built into the kernel, you can configure it using the
18
 * kernel command-line.  For example:
19
 *
20
 *      tipar=timeout,delay       (set timeout and delay)
21
 *
22
 * If the driver is loaded as a module, similar functionality is available
23
 * using module parameters.  The equivalent of the above commands would be:
24
 *
25
 *      # insmod tipar timeout=15 delay=10
26
 */
27
 
28
/* COMPATIBILITY WITH OLD KERNELS
29
 *
30
 * Usually, parallel cables were bound to ports at
31
 * particular I/O addresses, as follows:
32
 *
33
 *      tipar0             0x378
34
 *      tipar1             0x278
35
 *      tipar2             0x3bc
36
 *
37
 *
38
 * This driver, by default, binds tipar devices according to parport and
39
 * the minor number.
40
 *
41
 */
42
 
43
#include <linux/config.h>
44
#include <linux/module.h>
45
#include <linux/version.h>
46
#include <linux/types.h>
47
#include <linux/errno.h>
48
#include <linux/kernel.h>
49
#include <linux/sched.h>
50
#include <linux/delay.h>
51
#include <linux/fcntl.h>
52
#include <linux/fs.h>
53
#include <linux/init.h>
54
#include <asm/uaccess.h>
55
#include <linux/ioport.h>
56
#include <asm/io.h>
57
#include <asm/bitops.h>
58
#include <linux/devfs_fs_kernel.h>      /* DevFs support */
59
#include <linux/parport.h>      /* Our code depend on parport */
60
 
61
/*
62
 * TI definitions
63
 */
64
#include <linux/ticable.h>
65
 
66
/*
67
 * Version Information
68
 */
69
#define DRIVER_VERSION "1.18"
70
#define DRIVER_AUTHOR  "Romain Lievin <roms@lpg.ticalc.org>"
71
#define DRIVER_DESC    "Device driver for TI/PC parallel link cables"
72
#define DRIVER_LICENSE "GPL"
73
 
74
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)
75
# define minor(x) MINOR(x)
76
#endif
77
 
78
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
79
# define need_resched() (current->need_resched)
80
#endif
81
 
82
/* ----- global variables --------------------------------------------- */
83
 
84
struct tipar_struct {
85
        struct pardevice *dev;  /* Parport device entry */
86
};
87
 
88
#define PP_NO 3
89
static struct tipar_struct table[PP_NO];
90
 
91
static int delay = IO_DELAY;    /* inter-bit delay in microseconds */
92
static int timeout = TIMAXTIME; /* timeout in tenth of seconds     */
93
 
94
static devfs_handle_t devfs_handle;
95
static unsigned int tp_count;   /* tipar count */
96
static unsigned long opened;    /* opened devices */
97
 
98
/* --- macros for parport access -------------------------------------- */
99
 
100
#define r_dtr(x)        (parport_read_data(table[(x)].dev->port))
101
#define r_str(x)        (parport_read_status(table[(x)].dev->port))
102
#define w_ctr(x,y)      (parport_write_control(table[(x)].dev->port, (y)))
103
#define w_dtr(x,y)      (parport_write_data(table[(x)].dev->port, (y)))
104
 
105
/* --- setting states on the D-bus with the right timing: ------------- */
106
 
107
static inline void
108
outbyte(int value, int minor)
109
{
110
        w_dtr(minor, value);
111
}
112
 
113
static inline int
114
inbyte(int minor)
115
{
116
        return (r_str(minor));
117
}
118
 
119
static inline void
120
init_ti_parallel(int minor)
121
{
122
        outbyte(3, minor);
123
}
124
 
125
/* ----- global defines ----------------------------------------------- */
126
 
127
#define START(x) { x=jiffies+HZ/(timeout/10); }
128
#define WAIT(x)  { \
129
  if (time_before((x), jiffies)) return -1; \
130
  if (need_resched()) schedule(); }
131
 
132
/* ----- D-bus bit-banging functions ---------------------------------- */
133
 
134
/* D-bus protocol (45kbit/s max):
135
                    1                 0                      0
136
       _______        ______|______    __________|________    __________
137
Red  :        ________      |      ____          |        ____
138
       _        ____________|________      ______|__________       _____
139
White:  ________            |        ______      |          _______
140
*/
141
 
142
/* Try to transmit a byte on the specified port (-1 if error). */
143
static int
144
put_ti_parallel(int minor, unsigned char data)
145
{
146
        int bit;
147
        unsigned long max;
148
 
149
        for (bit = 0; bit < 8; bit++) {
150
                if (data & 1) {
151
                        outbyte(2, minor);
152
                        START(max);
153
                        do {
154
                                WAIT(max);
155
                        } while (inbyte(minor) & 0x10);
156
 
157
                        outbyte(3, minor);
158
                        START(max);
159
                        do {
160
                                WAIT(max);
161
                        } while (!(inbyte(minor) & 0x10));
162
                } else {
163
                        outbyte(1, minor);
164
                        START(max);
165
                        do {
166
                                WAIT(max);
167
                        } while (inbyte(minor) & 0x20);
168
 
169
                        outbyte(3, minor);
170
                        START(max);
171
                        do {
172
                                WAIT(max);
173
                        } while (!(inbyte(minor) & 0x20));
174
                }
175
 
176
                data >>= 1;
177
                udelay(delay);
178
 
179
                if (need_resched())
180
                        schedule();
181
        }
182
 
183
        return 0;
184
}
185
 
186
/* Receive a byte on the specified port or -1 if error. */
187
static int
188
get_ti_parallel(int minor)
189
{
190
        int bit;
191
        unsigned char v, data = 0;
192
        unsigned long max;
193
 
194
        for (bit = 0; bit < 8; bit++) {
195
                START(max);
196
                do {
197
                        WAIT(max);
198
                } while ((v = inbyte(minor) & 0x30) == 0x30);
199
 
200
                if (v == 0x10) {
201
                        data = (data >> 1) | 0x80;
202
                        outbyte(1, minor);
203
                        START(max);
204
                        do {
205
                                WAIT(max);
206
                        } while (!(inbyte(minor) & 0x20));
207
                        outbyte(3, minor);
208
                } else {
209
                        data = data >> 1;
210
                        outbyte(2, minor);
211
                        START(max);
212
                        do {
213
                                WAIT(max);
214
                        } while (!(inbyte(minor) & 0x10));
215
                        outbyte(3, minor);
216
                }
217
 
218
                udelay(delay);
219
                if (need_resched())
220
                        schedule();
221
        }
222
 
223
        return (int) data;
224
}
225
 
226
/* Try to detect a parallel link cable on the specified port */
227
static int
228
probe_ti_parallel(int minor)
229
{
230
        int i;
231
        int seq[] = { 0x00, 0x20, 0x10, 0x30 };
232
 
233
        for (i = 3; i >= 0; i--) {
234
                outbyte(3, minor);
235
                outbyte(i, minor);
236
                udelay(delay);
237
                /*printk(KERN_DEBUG "Probing -> %i: 0x%02x 0x%02x\n", i, data & 0x30, seq[i]); */
238
                if ((inbyte(minor) & 0x30) != seq[i]) {
239
                        outbyte(3, minor);
240
                        return -1;
241
                }
242
        }
243
 
244
        outbyte(3, minor);
245
        return 0;
246
}
247
 
248
/* ----- kernel module functions--------------------------------------- */
249
 
250
static int
251
tipar_open(struct inode *inode, struct file *file)
252
{
253
        unsigned int minor = minor(inode->i_rdev) - TIPAR_MINOR;
254
 
255
        if (minor > tp_count - 1)
256
                return -ENXIO;
257
 
258
        if (test_and_set_bit(minor, &opened))
259
                return -EBUSY;
260
 
261
        parport_claim_or_block(table[minor].dev);
262
        init_ti_parallel(minor);
263
        parport_release(table[minor].dev);
264
 
265
        return 0;
266
}
267
 
268
static int
269
tipar_close(struct inode *inode, struct file *file)
270
{
271
        unsigned int minor = minor(inode->i_rdev) - TIPAR_MINOR;
272
 
273
        if (minor > tp_count - 1)
274
                return -ENXIO;
275
 
276
        clear_bit(minor, &opened);
277
 
278
        return 0;
279
}
280
 
281
static ssize_t
282
tipar_write(struct file *file, const char *buf, size_t count, loff_t * ppos)
283
{
284
        unsigned int minor =
285
            minor(file->f_dentry->d_inode->i_rdev) - TIPAR_MINOR;
286
        ssize_t n;
287
 
288
        parport_claim_or_block(table[minor].dev);
289
 
290
        for (n = 0; n < count; n++) {
291
                unsigned char b;
292
 
293
                if (get_user(b, buf + n)) {
294
                        n = -EFAULT;
295
                        goto out;
296
                }
297
 
298
                if (put_ti_parallel(minor, b) == -1) {
299
                        init_ti_parallel(minor);
300
                        n = -ETIMEDOUT;
301
                        goto out;
302
                }
303
        }
304
      out:
305
        parport_release(table[minor].dev);
306
        return n;
307
}
308
 
309
static ssize_t
310
tipar_read(struct file *file, char *buf, size_t count, loff_t * ppos)
311
{
312
        int b = 0;
313
        unsigned int minor =
314
            minor(file->f_dentry->d_inode->i_rdev) - TIPAR_MINOR;
315
        ssize_t retval = 0;
316
        ssize_t n = 0;
317
 
318
        if (count == 0)
319
                return 0;
320
 
321
        if (ppos != &file->f_pos)
322
                return -ESPIPE;
323
 
324
        parport_claim_or_block(table[minor].dev);
325
 
326
        while (n < count) {
327
                b = get_ti_parallel(minor);
328
                if (b == -1) {
329
                        init_ti_parallel(minor);
330
                        retval = -ETIMEDOUT;
331
                        goto out;
332
                } else {
333
                        if (put_user(b, ((unsigned char *) buf) + n)) {
334
                                retval = -EFAULT;
335
                                break;
336
                        } else
337
                                retval = ++n;
338
                }
339
 
340
                /* Non-blocking mode : try again ! */
341
                if (file->f_flags & O_NONBLOCK) {
342
                        retval = -EAGAIN;
343
                        goto out;
344
                }
345
 
346
                /* Signal pending, try again ! */
347
                if (signal_pending(current)) {
348
                        retval = -ERESTARTSYS;
349
                        goto out;
350
                }
351
 
352
                if (need_resched())
353
                        schedule();
354
        }
355
 
356
      out:
357
        parport_release(table[minor].dev);
358
        return retval;
359
}
360
 
361
static int
362
tipar_ioctl(struct inode *inode, struct file *file,
363
            unsigned int cmd, unsigned long arg)
364
{
365
        int retval = 0;
366
 
367
        switch (cmd) {
368
        case IOCTL_TIPAR_DELAY:
369
          delay = (int)arg;    //get_user(delay, &arg);
370
          break;
371
        case IOCTL_TIPAR_TIMEOUT:
372
          timeout = (int)arg;  //get_user(timeout, &arg);
373
          break;
374
        default:
375
                retval = -ENOTTY;
376
                break;
377
        }
378
 
379
        return retval;
380
}
381
 
382
/* ----- kernel module registering ------------------------------------ */
383
 
384
static struct file_operations tipar_fops = {
385
        owner:THIS_MODULE,
386
        llseek:no_llseek,
387
        read:tipar_read,
388
        write:tipar_write,
389
        ioctl:tipar_ioctl,
390
        open:tipar_open,
391
        release:tipar_close,
392
};
393
 
394
/* --- initialisation code ------------------------------------- */
395
 
396
#ifndef MODULE
397
/*      You must set these - there is no sane way to probe for this cable.
398
 *      You can use 'tipar=timeout,delay' to set these now. */
399
static int __init
400
tipar_setup(char *str)
401
{
402
        int ints[2];
403
 
404
        str = get_options(str, ARRAY_SIZE(ints), ints);
405
 
406
        if (ints[0] > 0) {
407
                timeout = ints[1];
408
                if (ints[0] > 1) {
409
                        delay = ints[2];
410
                }
411
        }
412
 
413
        return 1;
414
}
415
#endif
416
 
417
/*
418
 * Register our module into parport.
419
 * Pass also 2 callbacks functions to parport: a pre-emptive function and an
420
 * interrupt handler function (unused).
421
 * Display a message such "tipar0: using parport0 (polling)".
422
 */
423
static int
424
tipar_register(int nr, struct parport *port)
425
{
426
        char name[8];
427
 
428
        /* Register our module into parport */
429
        table[nr].dev = parport_register_device(port, "tipar",
430
                                                NULL, NULL, NULL, 0,
431
                                                (void *) &table[nr]);
432
 
433
        if (table[nr].dev == NULL)
434
                return 1;
435
 
436
        /* Use devfs, tree: /dev/ticables/par/[0..2] */
437
        sprintf(name, "%d", nr);
438
        printk
439
            ("tipar: registering to devfs : major = %d, minor = %d, node = %s\n",
440
             TISER_MAJOR, (TIPAR_MINOR + nr), name);
441
        devfs_register(devfs_handle, name, DEVFS_FL_DEFAULT, TIPAR_MAJOR,
442
                       TIPAR_MINOR + nr, S_IFCHR | S_IRUGO | S_IWUGO,
443
                       &tipar_fops, NULL);
444
 
445
        /* Display informations */
446
        printk(KERN_INFO "tipar%d: using %s (%s).\n", nr, port->name,
447
               (port->irq ==
448
                PARPORT_IRQ_NONE) ? "polling" : "interrupt-driven");
449
 
450
        if (probe_ti_parallel(nr) != -1)
451
                printk("tipar%d: link cable found !\n", nr);
452
        else
453
                printk("tipar%d: link cable not found.\n", nr);
454
 
455
        return 0;
456
}
457
 
458
static void
459
tipar_attach(struct parport *port)
460
{
461
        if (tp_count == PP_NO) {
462
                printk("tipar: ignoring parallel port (max. %d)\n", PP_NO);
463
                return;
464
        }
465
 
466
        if (!tipar_register(tp_count, port))
467
                tp_count++;
468
}
469
 
470
static void
471
tipar_detach(struct parport *port)
472
{
473
        /* Nothing to do */
474
}
475
 
476
static struct parport_driver tipar_driver = {
477
        "tipar",
478
        tipar_attach,
479
        tipar_detach,
480
        NULL
481
};
482
 
483
int __init
484
tipar_init_module(void)
485
{
486
        printk("tipar: parallel link cable driver, version %s\n",
487
               DRIVER_VERSION);
488
 
489
        if (devfs_register_chrdev(TIPAR_MAJOR, "tipar", &tipar_fops)) {
490
                printk("tipar: unable to get major %d\n", TIPAR_MAJOR);
491
                return -EIO;
492
        }
493
 
494
        /* Use devfs with tree: /dev/ticables/par/[0..2] */
495
        devfs_handle = devfs_mk_dir(NULL, "ticables/par", NULL);
496
 
497
        if (parport_register_driver(&tipar_driver)) {
498
                printk("tipar: unable to register with parport\n");
499
                return -EIO;
500
        }
501
 
502
        return 0;
503
}
504
 
505
void __exit
506
tipar_cleanup_module(void)
507
{
508
        unsigned int i;
509
 
510
        /* Unregistering module */
511
        parport_unregister_driver(&tipar_driver);
512
 
513
        devfs_unregister(devfs_handle);
514
        devfs_unregister_chrdev(TIPAR_MAJOR, "tipar");
515
 
516
        for (i = 0; i < PP_NO; i++) {
517
                if (table[i].dev == NULL)
518
                        continue;
519
                parport_unregister_device(table[i].dev);
520
        }
521
 
522
        printk("tipar: module unloaded !\n");
523
}
524
 
525
/* --------------------------------------------------------------------- */
526
 
527
__setup("tipar=", tipar_setup);
528
module_init(tipar_init_module);
529
module_exit(tipar_cleanup_module);
530
 
531
MODULE_AUTHOR(DRIVER_AUTHOR);
532
MODULE_DESCRIPTION(DRIVER_DESC);
533
MODULE_LICENSE(DRIVER_LICENSE);
534
 
535
EXPORT_NO_SYMBOLS;
536
 
537
MODULE_PARM(timeout, "i");
538
MODULE_PARM_DESC(timeout, "Timeout (default=1.5 seconds)");
539
MODULE_PARM(delay, "i");
540
MODULE_PARM_DESC(delay, "Inter-bit delay (default=10 microseconds)");

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.