Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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