Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.22-rc2 514 lines 9.8 kB view raw
1/* 2 * LCD, LED and Button interface for Cobalt 3 * 4 * This file is subject to the terms and conditions of the GNU General Public 5 * License. See the file "COPYING" in the main directory of this archive 6 * for more details. 7 * 8 * Copyright (C) 1996, 1997 by Andrew Bose 9 * 10 * Linux kernel version history: 11 * March 2001: Ported from 2.0.34 by Liam Davies 12 * 13 */ 14#include <linux/types.h> 15#include <linux/errno.h> 16#include <linux/miscdevice.h> 17#include <linux/slab.h> 18#include <linux/ioport.h> 19#include <linux/fcntl.h> 20#include <linux/mc146818rtc.h> 21#include <linux/netdevice.h> 22#include <linux/sched.h> 23#include <linux/delay.h> 24 25#include <asm/io.h> 26#include <asm/uaccess.h> 27#include <asm/system.h> 28#include <linux/delay.h> 29 30#include "lcd.h" 31 32static int lcd_ioctl(struct inode *inode, struct file *file, 33 unsigned int cmd, unsigned long arg); 34 35static unsigned int lcd_present = 1; 36 37/* used in arch/mips/cobalt/reset.c */ 38int led_state = 0; 39 40#if defined(CONFIG_TULIP) && 0 41 42#define MAX_INTERFACES 8 43static linkcheck_func_t linkcheck_callbacks[MAX_INTERFACES]; 44static void *linkcheck_cookies[MAX_INTERFACES]; 45 46int lcd_register_linkcheck_func(int iface_num, void *func, void *cookie) 47{ 48 if (iface_num < 0 || 49 iface_num >= MAX_INTERFACES || 50 linkcheck_callbacks[iface_num] != NULL) 51 return -1; 52 linkcheck_callbacks[iface_num] = (linkcheck_func_t) func; 53 linkcheck_cookies[iface_num] = cookie; 54 return 0; 55} 56#endif 57 58static int lcd_ioctl(struct inode *inode, struct file *file, 59 unsigned int cmd, unsigned long arg) 60{ 61 struct lcd_display button_display; 62 unsigned long address, a; 63 64 switch (cmd) { 65 case LCD_On: 66 udelay(150); 67 BusyCheck(); 68 LCDWriteInst(0x0F); 69 break; 70 71 case LCD_Off: 72 udelay(150); 73 BusyCheck(); 74 LCDWriteInst(0x08); 75 break; 76 77 case LCD_Reset: 78 udelay(150); 79 LCDWriteInst(0x3F); 80 udelay(150); 81 LCDWriteInst(0x3F); 82 udelay(150); 83 LCDWriteInst(0x3F); 84 udelay(150); 85 LCDWriteInst(0x3F); 86 udelay(150); 87 LCDWriteInst(0x01); 88 udelay(150); 89 LCDWriteInst(0x06); 90 break; 91 92 case LCD_Clear: 93 udelay(150); 94 BusyCheck(); 95 LCDWriteInst(0x01); 96 break; 97 98 case LCD_Cursor_Left: 99 udelay(150); 100 BusyCheck(); 101 LCDWriteInst(0x10); 102 break; 103 104 case LCD_Cursor_Right: 105 udelay(150); 106 BusyCheck(); 107 LCDWriteInst(0x14); 108 break; 109 110 case LCD_Cursor_Off: 111 udelay(150); 112 BusyCheck(); 113 LCDWriteInst(0x0C); 114 break; 115 116 case LCD_Cursor_On: 117 udelay(150); 118 BusyCheck(); 119 LCDWriteInst(0x0F); 120 break; 121 122 case LCD_Blink_Off: 123 udelay(150); 124 BusyCheck(); 125 LCDWriteInst(0x0E); 126 break; 127 128 case LCD_Get_Cursor_Pos:{ 129 struct lcd_display display; 130 131 udelay(150); 132 BusyCheck(); 133 display.cursor_address = (LCDReadInst); 134 display.cursor_address = 135 (display.cursor_address & 0x07F); 136 if (copy_to_user 137 ((struct lcd_display *) arg, &display, 138 sizeof(struct lcd_display))) 139 return -EFAULT; 140 141 break; 142 } 143 144 145 case LCD_Set_Cursor_Pos:{ 146 struct lcd_display display; 147 148 if (copy_from_user 149 (&display, (struct lcd_display *) arg, 150 sizeof(struct lcd_display))) 151 return -EFAULT; 152 153 a = (display.cursor_address | kLCD_Addr); 154 155 udelay(150); 156 BusyCheck(); 157 LCDWriteInst(a); 158 159 break; 160 } 161 162 case LCD_Get_Cursor:{ 163 struct lcd_display display; 164 165 udelay(150); 166 BusyCheck(); 167 display.character = LCDReadData; 168 169 if (copy_to_user 170 ((struct lcd_display *) arg, &display, 171 sizeof(struct lcd_display))) 172 return -EFAULT; 173 udelay(150); 174 BusyCheck(); 175 LCDWriteInst(0x10); 176 177 break; 178 } 179 180 case LCD_Set_Cursor:{ 181 struct lcd_display display; 182 183 if (copy_from_user 184 (&display, (struct lcd_display *) arg, 185 sizeof(struct lcd_display))) 186 return -EFAULT; 187 188 udelay(150); 189 BusyCheck(); 190 LCDWriteData(display.character); 191 udelay(150); 192 BusyCheck(); 193 LCDWriteInst(0x10); 194 195 break; 196 } 197 198 199 case LCD_Disp_Left: 200 udelay(150); 201 BusyCheck(); 202 LCDWriteInst(0x18); 203 break; 204 205 case LCD_Disp_Right: 206 udelay(150); 207 BusyCheck(); 208 LCDWriteInst(0x1C); 209 break; 210 211 case LCD_Home: 212 udelay(150); 213 BusyCheck(); 214 LCDWriteInst(0x02); 215 break; 216 217 case LCD_Write:{ 218 struct lcd_display display; 219 unsigned int index; 220 221 222 if (copy_from_user 223 (&display, (struct lcd_display *) arg, 224 sizeof(struct lcd_display))) 225 return -EFAULT; 226 227 udelay(150); 228 BusyCheck(); 229 LCDWriteInst(0x80); 230 udelay(150); 231 BusyCheck(); 232 233 for (index = 0; index < (display.size1); index++) { 234 udelay(150); 235 BusyCheck(); 236 LCDWriteData(display.line1[index]); 237 BusyCheck(); 238 } 239 240 udelay(150); 241 BusyCheck(); 242 LCDWriteInst(0xC0); 243 udelay(150); 244 BusyCheck(); 245 for (index = 0; index < (display.size2); index++) { 246 udelay(150); 247 BusyCheck(); 248 LCDWriteData(display.line2[index]); 249 } 250 251 break; 252 } 253 254 case LCD_Read:{ 255 struct lcd_display display; 256 257 BusyCheck(); 258 for (address = kDD_R00; address <= kDD_R01; 259 address++) { 260 a = (address | kLCD_Addr); 261 262 udelay(150); 263 BusyCheck(); 264 LCDWriteInst(a); 265 udelay(150); 266 BusyCheck(); 267 display.line1[address] = LCDReadData; 268 } 269 270 display.line1[0x27] = '\0'; 271 272 for (address = kDD_R10; address <= kDD_R11; 273 address++) { 274 a = (address | kLCD_Addr); 275 276 udelay(150); 277 BusyCheck(); 278 LCDWriteInst(a); 279 280 udelay(150); 281 BusyCheck(); 282 display.line2[address - 0x40] = 283 LCDReadData; 284 } 285 286 display.line2[0x27] = '\0'; 287 288 if (copy_to_user 289 ((struct lcd_display *) arg, &display, 290 sizeof(struct lcd_display))) 291 return -EFAULT; 292 break; 293 } 294 295// set all GPIO leds to led_display.leds 296 297 case LED_Set:{ 298 struct lcd_display led_display; 299 300 301 if (copy_from_user 302 (&led_display, (struct lcd_display *) arg, 303 sizeof(struct lcd_display))) 304 return -EFAULT; 305 306 led_state = led_display.leds; 307 LEDSet(led_state); 308 309 break; 310 } 311 312 313// set only bit led_display.leds 314 315 case LED_Bit_Set:{ 316 unsigned int i; 317 int bit = 1; 318 struct lcd_display led_display; 319 320 321 if (copy_from_user 322 (&led_display, (struct lcd_display *) arg, 323 sizeof(struct lcd_display))) 324 return -EFAULT; 325 326 for (i = 0; i < (int) led_display.leds; i++) { 327 bit = 2 * bit; 328 } 329 330 led_state = led_state | bit; 331 LEDSet(led_state); 332 break; 333 } 334 335// clear only bit led_display.leds 336 337 case LED_Bit_Clear:{ 338 unsigned int i; 339 int bit = 1; 340 struct lcd_display led_display; 341 342 343 if (copy_from_user 344 (&led_display, (struct lcd_display *) arg, 345 sizeof(struct lcd_display))) 346 return -EFAULT; 347 348 for (i = 0; i < (int) led_display.leds; i++) { 349 bit = 2 * bit; 350 } 351 352 led_state = led_state & ~bit; 353 LEDSet(led_state); 354 break; 355 } 356 357 358 case BUTTON_Read:{ 359 button_display.buttons = GPIRead; 360 if (copy_to_user 361 ((struct lcd_display *) arg, &button_display, 362 sizeof(struct lcd_display))) 363 return -EFAULT; 364 break; 365 } 366 367 case LINK_Check:{ 368 button_display.buttons = 369 *((volatile unsigned long *) (0xB0100060)); 370 if (copy_to_user 371 ((struct lcd_display *) arg, &button_display, 372 sizeof(struct lcd_display))) 373 return -EFAULT; 374 break; 375 } 376 377 case LINK_Check_2:{ 378 int iface_num; 379 380 /* panel-utils should pass in the desired interface status is wanted for 381 * in "buttons" of the structure. We will set this to non-zero if the 382 * link is in fact up for the requested interface. --DaveM 383 */ 384 if (copy_from_user 385 (&button_display, (struct lcd_display *) arg, 386 sizeof(button_display))) 387 return -EFAULT; 388 iface_num = button_display.buttons; 389#if defined(CONFIG_TULIP) && 0 390 if (iface_num >= 0 && 391 iface_num < MAX_INTERFACES && 392 linkcheck_callbacks[iface_num] != NULL) { 393 button_display.buttons = 394 linkcheck_callbacks[iface_num] 395 (linkcheck_cookies[iface_num]); 396 } else 397#endif 398 button_display.buttons = 0; 399 400 if (__copy_to_user 401 ((struct lcd_display *) arg, &button_display, 402 sizeof(struct lcd_display))) 403 return -EFAULT; 404 break; 405 } 406 407 default: 408 return -EINVAL; 409 410 } 411 412 return 0; 413 414} 415 416static int lcd_open(struct inode *inode, struct file *file) 417{ 418 if (!lcd_present) 419 return -ENXIO; 420 else 421 return 0; 422} 423 424/* Only RESET or NEXT counts as button pressed */ 425 426static inline int button_pressed(void) 427{ 428 unsigned long buttons = GPIRead; 429 430 if ((buttons == BUTTON_Next) || (buttons == BUTTON_Next_B) 431 || (buttons == BUTTON_Reset_B)) 432 return buttons; 433 return 0; 434} 435 436/* LED daemon sits on this and we wake him up once a key is pressed. */ 437 438static int lcd_waiters = 0; 439 440static ssize_t lcd_read(struct file *file, char *buf, 441 size_t count, loff_t *ofs) 442{ 443 long buttons_now; 444 445 if (lcd_waiters > 0) 446 return -EINVAL; 447 448 lcd_waiters++; 449 while (((buttons_now = (long) button_pressed()) == 0) && 450 !(signal_pending(current))) { 451 msleep_interruptible(2000); 452 } 453 lcd_waiters--; 454 455 if (signal_pending(current)) 456 return -ERESTARTSYS; 457 return buttons_now; 458} 459 460/* 461 * The various file operations we support. 462 */ 463 464static const struct file_operations lcd_fops = { 465 .read = lcd_read, 466 .ioctl = lcd_ioctl, 467 .open = lcd_open, 468}; 469 470static struct miscdevice lcd_dev = { 471 MISC_DYNAMIC_MINOR, 472 "lcd", 473 &lcd_fops 474}; 475 476static int lcd_init(void) 477{ 478 int ret; 479 unsigned long data; 480 481 pr_info("%s\n", LCD_DRIVER); 482 ret = misc_register(&lcd_dev); 483 if (ret) { 484 printk(KERN_WARNING LCD "Unable to register misc device.\n"); 485 return ret; 486 } 487 488 /* Check region? Naaah! Just snarf it up. */ 489/* request_region(RTC_PORT(0), RTC_IO_EXTENT, "lcd");*/ 490 491 udelay(150); 492 data = LCDReadData; 493 if ((data & 0x000000FF) == (0x00)) { 494 lcd_present = 0; 495 pr_info(LCD "LCD Not Present\n"); 496 } else { 497 lcd_present = 1; 498 WRITE_GAL(kGal_DevBank2PReg, kGal_DevBank2Cfg); 499 WRITE_GAL(kGal_DevBank3PReg, kGal_DevBank3Cfg); 500 } 501 502 return 0; 503} 504 505static void __exit lcd_exit(void) 506{ 507 misc_deregister(&lcd_dev); 508} 509 510module_init(lcd_init); 511module_exit(lcd_exit); 512 513MODULE_AUTHOR("Andrew Bose"); 514MODULE_LICENSE("GPL");