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