File: /usr/src/linux/drivers/s390/char/hwc_rw.c
1 /*
2 * drivers/s390/char/hwc_rw.c
3 * driver: reading from and writing to system console on S/390 via HWC
4 *
5 * S390 version
6 * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Author(s): Martin Peschke <mpeschke@de.ibm.com>
8 *
9 *
10 *
11 *
12 *
13 *
14 */
15
16 #include <linux/kernel.h>
17 #include <linux/string.h>
18 #include <linux/errno.h>
19 #include <linux/ctype.h>
20 #include <linux/mm.h>
21 #include <linux/timer.h>
22 #include <linux/bootmem.h>
23 #include <linux/module.h>
24
25 #include <asm/ebcdic.h>
26 #include <asm/uaccess.h>
27 #include <asm/types.h>
28 #include <asm/bitops.h>
29 #include <asm/setup.h>
30 #include <asm/page.h>
31 #include <asm/s390_ext.h>
32 #include <asm/irq.h>
33
34 #ifndef MIN
35 #define MIN(a,b) (((a<b) ? a : b))
36 #endif
37
38 #define HWC_RW_PRINT_HEADER "hwc low level driver: "
39
40 #define USE_VM_DETECTION
41
42 #define DEFAULT_CASE_DELIMITER '%'
43
44 #undef DUMP_HWC_INIT_ERROR
45
46 #undef DUMP_HWC_WRITE_ERROR
47
48 #undef DUMP_HWC_WRITE_LIST_ERROR
49
50 #undef DUMP_HWC_READ_ERROR
51
52 #undef DUMP_HWCB_INPUT
53
54 #undef BUFFER_STRESS_TEST
55
56 typedef struct {
57 unsigned char *next;
58 unsigned short int mto_char_sum;
59 unsigned char mto_number;
60 unsigned char times_lost;
61 unsigned short int mto_number_lost;
62 unsigned long int mto_char_sum_lost;
63 } __attribute__ ((packed))
64
65 hwcb_list_t;
66
67 #define MAX_HWCB_ROOM (PAGE_SIZE - sizeof(hwcb_list_t))
68
69 #define MAX_MESSAGE_SIZE (MAX_HWCB_ROOM - sizeof(write_hwcb_t))
70
71 #define BUF_HWCB hwc_data.hwcb_list_tail
72 #define OUT_HWCB hwc_data.hwcb_list_head
73 #define ALL_HWCB_MTO hwc_data.mto_number
74 #define ALL_HWCB_CHAR hwc_data.mto_char_sum
75
76 #define _LIST(hwcb) ((hwcb_list_t*)(&(hwcb)[PAGE_SIZE-sizeof(hwcb_list_t)]))
77
78 #define _HWCB_CHAR(hwcb) (_LIST(hwcb)->mto_char_sum)
79
80 #define _HWCB_MTO(hwcb) (_LIST(hwcb)->mto_number)
81
82 #define _HWCB_CHAR_LOST(hwcb) (_LIST(hwcb)->mto_char_sum_lost)
83
84 #define _HWCB_MTO_LOST(hwcb) (_LIST(hwcb)->mto_number_lost)
85
86 #define _HWCB_TIMES_LOST(hwcb) (_LIST(hwcb)->times_lost)
87
88 #define _HWCB_NEXT(hwcb) (_LIST(hwcb)->next)
89
90 #define BUF_HWCB_CHAR _HWCB_CHAR(BUF_HWCB)
91
92 #define BUF_HWCB_MTO _HWCB_MTO(BUF_HWCB)
93
94 #define BUF_HWCB_NEXT _HWCB_NEXT(BUF_HWCB)
95
96 #define OUT_HWCB_CHAR _HWCB_CHAR(OUT_HWCB)
97
98 #define OUT_HWCB_MTO _HWCB_MTO(OUT_HWCB)
99
100 #define OUT_HWCB_NEXT _HWCB_NEXT(OUT_HWCB)
101
102 #define BUF_HWCB_CHAR_LOST _HWCB_CHAR_LOST(BUF_HWCB)
103
104 #define BUF_HWCB_MTO_LOST _HWCB_MTO_LOST(BUF_HWCB)
105
106 #define OUT_HWCB_CHAR_LOST _HWCB_CHAR_LOST(OUT_HWCB)
107
108 #define OUT_HWCB_MTO_LOST _HWCB_MTO_LOST(OUT_HWCB)
109
110 #define BUF_HWCB_TIMES_LOST _HWCB_TIMES_LOST(BUF_HWCB)
111
112 #include "hwc.h"
113
114 #define __HWC_RW_C__
115 #include "hwc_rw.h"
116 #undef __HWC_RW_C__
117
118 static unsigned char _obuf[MAX_HWCB_ROOM];
119
120 static unsigned char
121 _page[PAGE_SIZE] __attribute__ ((aligned (PAGE_SIZE)));
122
123 typedef unsigned long kmem_pages_t;
124
125 #define MAX_KMEM_PAGES (sizeof(kmem_pages_t) << 3)
126
127 #define HWC_WTIMER_RUNS 1
128 #define HWC_FLUSH 2
129 #define HWC_INIT 4
130 #define HWC_BROKEN 8
131 #define HWC_INTERRUPT 16
132 #define HWC_PTIMER_RUNS 32
133
134 static struct {
135
136 hwc_ioctls_t ioctls;
137
138 hwc_ioctls_t init_ioctls;
139
140 unsigned char *hwcb_list_head;
141
142 unsigned char *hwcb_list_tail;
143
144 unsigned short int mto_number;
145
146 unsigned int mto_char_sum;
147
148 unsigned char hwcb_count;
149
150 unsigned long kmem_start;
151
152 unsigned long kmem_end;
153
154 kmem_pages_t kmem_pages;
155
156 unsigned char *obuf;
157
158 unsigned short int obuf_cursor;
159
160 unsigned short int obuf_count;
161
162 unsigned short int obuf_start;
163
164 unsigned char *page;
165
166 u32 current_servc;
167
168 unsigned char *current_hwcb;
169
170 unsigned char write_nonprio:1;
171 unsigned char write_prio:1;
172 unsigned char read_nonprio:1;
173 unsigned char read_prio:1;
174 unsigned char read_statechange:1;
175
176 unsigned char flags;
177
178 hwc_high_level_calls_t *calls;
179
180 hwc_request_t *request;
181
182 spinlock_t lock;
183
184 struct timer_list write_timer;
185
186 struct timer_list poll_timer;
187 } hwc_data =
188 {
189 {
190 },
191 {
192 8,
193 0,
194 80,
195 1,
196 MAX_KMEM_PAGES,
197 MAX_KMEM_PAGES,
198
199 0,
200
201 0x6c
202
203 },
204 NULL,
205 NULL,
206 0,
207 0,
208 0,
209 0,
210 0,
211 0,
212 _obuf,
213 0,
214 0,
215 0,
216 _page,
217 0,
218 NULL,
219 0,
220 0,
221 0,
222 0,
223 0,
224 0,
225 NULL,
226 NULL
227
228 };
229
230 static unsigned long cr0 __attribute__ ((aligned (8)));
231 static unsigned long cr0_save __attribute__ ((aligned (8)));
232 static unsigned char psw_mask __attribute__ ((aligned (8)));
233
234 #define DELAYED_WRITE 0
235 #define IMMEDIATE_WRITE 1
236
237 static signed int do_hwc_write (int from_user, unsigned char *,
238 unsigned int,
239 unsigned char);
240
241 static asmlinkage int
242 internal_print (char write_time, char *fmt,...)
243 {
244 va_list args;
245 int i;
246 unsigned char buf[512];
247
248 va_start (args, fmt);
249 i = vsprintf (buf, fmt, args);
250 va_end (args);
251 return do_hwc_write (0, buf, i, write_time);
252 }
253
254 int
255 hwc_printk (const char *fmt,...)
256 {
257 va_list args;
258 int i;
259 unsigned char buf[512];
260 unsigned long flags;
261 int retval;
262
263 spin_lock_irqsave (&hwc_data.lock, flags);
264
265 i = vsprintf (buf, fmt, args);
266 va_end (args);
267 retval = do_hwc_write (0, buf, i, IMMEDIATE_WRITE);
268
269 spin_unlock_irqrestore (&hwc_data.lock, flags);
270
271 return retval;
272 }
273
274 #ifdef DUMP_HWCB_INPUT
275
276 static void
277 dump_storage_area (unsigned char *area, unsigned short int count)
278 {
279 unsigned short int index;
280 ioctl_nl_t old_final_nl;
281
282 if (!area || !count)
283 return;
284
285 old_final_nl = hwc_data.ioctls.final_nl;
286 hwc_data.ioctls.final_nl = 1;
287
288 internal_print (DELAYED_WRITE, "\n%8x ", area);
289
290 for (index = 0; index < count; index++) {
291
292 if (area[index] <= 0xF)
293 internal_print (DELAYED_WRITE, "0%x", area[index]);
294 else
295 internal_print (DELAYED_WRITE, "%x", area[index]);
296
297 if ((index & 0xF) == 0xF)
298 internal_print (DELAYED_WRITE, "\n%8x ",
299 &area[index + 1]);
300 else if ((index & 3) == 3)
301 internal_print (DELAYED_WRITE, " ");
302 }
303
304 internal_print (IMMEDIATE_WRITE, "\n");
305
306 hwc_data.ioctls.final_nl = old_final_nl;
307 }
308 #endif
309
310 static inline u32
311 service_call (
312 u32 hwc_command_word,
313 unsigned char hwcb[])
314 {
315 unsigned int condition_code = 1;
316
317 __asm__ __volatile__ ("L 1, 0(%0) \n\t"
318 "LRA 2, 0(%1) \n\t"
319 ".long 0xB2200012 \n\t"
320 :
321 :"a" (&hwc_command_word), "a" (hwcb)
322 :"1", "2", "memory");
323
324 __asm__ __volatile__ ("IPM %0 \n\t"
325 "SRL %0, 28 \n\t"
326 :"=r" (condition_code));
327
328 return condition_code;
329 }
330
331 static inline unsigned long
332 hwc_ext_int_param (void)
333 {
334 u32 param;
335
336 __asm__ __volatile__ ("L %0,128\n\t"
337 :"=r" (param));
338
339 return (unsigned long) param;
340 }
341
342 static int
343 prepare_write_hwcb (void)
344 {
345 write_hwcb_t *hwcb;
346
347 if (!BUF_HWCB)
348 return -ENOMEM;
349
350 BUF_HWCB_MTO = 0;
351 BUF_HWCB_CHAR = 0;
352
353 hwcb = (write_hwcb_t *) BUF_HWCB;
354
355 memcpy (hwcb, &write_hwcb_template, sizeof (write_hwcb_t));
356
357 return 0;
358 }
359
360 static int
361 sane_write_hwcb (void)
362 {
363 unsigned short int lost_msg;
364 unsigned int lost_char;
365 unsigned char lost_hwcb;
366 unsigned char *bad_addr;
367 unsigned long page;
368 int page_nr;
369
370 if (!OUT_HWCB)
371 return -ENOMEM;
372
373 if ((unsigned long) OUT_HWCB & 0xFFF) {
374
375 bad_addr = OUT_HWCB;
376
377 #ifdef DUMP_HWC_WRITE_LIST_ERROR
378 __asm__ ("LHI 1,0xe30\n\t"
379 "LRA 2,0(%0) \n\t"
380 "J .+0 \n\t"
381 :
382 : "a" (bad_addr)
383 : "1", "2");
384 #endif
385
386 hwc_data.kmem_pages = 0;
387 if ((unsigned long) BUF_HWCB & 0xFFF) {
388
389 lost_hwcb = hwc_data.hwcb_count;
390 lost_msg = ALL_HWCB_MTO;
391 lost_char = ALL_HWCB_CHAR;
392
393 OUT_HWCB = NULL;
394 BUF_HWCB = NULL;
395 ALL_HWCB_MTO = 0;
396 ALL_HWCB_CHAR = 0;
397 hwc_data.hwcb_count = 0;
398 } else {
399
400 lost_hwcb = hwc_data.hwcb_count - 1;
401 lost_msg = ALL_HWCB_MTO - BUF_HWCB_MTO;
402 lost_char = ALL_HWCB_CHAR - BUF_HWCB_CHAR;
403 OUT_HWCB = BUF_HWCB;
404 ALL_HWCB_MTO = BUF_HWCB_MTO;
405 ALL_HWCB_CHAR = BUF_HWCB_CHAR;
406 hwc_data.hwcb_count = 1;
407 page = (unsigned long) BUF_HWCB;
408
409 if (page >= hwc_data.kmem_start &&
410 page <= hwc_data.kmem_end) {
411
412 page_nr = (int)
413 ((page - hwc_data.kmem_start) >> 12);
414 set_bit (page_nr, &hwc_data.kmem_pages);
415 }
416 }
417
418 internal_print (
419 DELAYED_WRITE,
420 HWC_RW_PRINT_HEADER
421 "found invalid HWCB at address 0x%lx. List corrupted. "
422 "Lost %i HWCBs with %i characters within up to %i "
423 "messages. Saved %i HWCB with last %i characters i"
424 "within up to %i messages.\n",
425 (unsigned long) bad_addr,
426 lost_hwcb, lost_char, lost_msg,
427 hwc_data.hwcb_count,
428 ALL_HWCB_CHAR, ALL_HWCB_MTO);
429 }
430 return 0;
431 }
432
433 static int
434 reuse_write_hwcb (void)
435 {
436 int retval;
437
438 if (hwc_data.hwcb_count < 2)
439 #ifdef DUMP_HWC_WRITE_LIST_ERROR
440 __asm__ ("LHI 1,0xe31\n\t"
441 "LRA 2,0(%0)\n\t"
442 "LRA 3,0(%1)\n\t"
443 "J .+0 \n\t"
444 :
445 : "a" (BUF_HWCB), "a" (OUT_HWCB)
446 : "1", "2", "3");
447 #else
448 return -EPERM;
449 #endif
450
451 if (hwc_data.current_hwcb == OUT_HWCB) {
452
453 if (hwc_data.hwcb_count > 2) {
454
455 BUF_HWCB_NEXT = OUT_HWCB_NEXT;
456
457 BUF_HWCB = OUT_HWCB_NEXT;
458
459 OUT_HWCB_NEXT = BUF_HWCB_NEXT;
460
461 BUF_HWCB_NEXT = NULL;
462 }
463 } else {
464
465 BUF_HWCB_NEXT = OUT_HWCB;
466
467 BUF_HWCB = OUT_HWCB;
468
469 OUT_HWCB = OUT_HWCB_NEXT;
470
471 BUF_HWCB_NEXT = NULL;
472 }
473
474 BUF_HWCB_TIMES_LOST += 1;
475 BUF_HWCB_CHAR_LOST += BUF_HWCB_CHAR;
476 BUF_HWCB_MTO_LOST += BUF_HWCB_MTO;
477 ALL_HWCB_MTO -= BUF_HWCB_MTO;
478 ALL_HWCB_CHAR -= BUF_HWCB_CHAR;
479
480 retval = prepare_write_hwcb ();
481
482 if (hwc_data.hwcb_count == hwc_data.ioctls.max_hwcb)
483 internal_print (
484 DELAYED_WRITE,
485 HWC_RW_PRINT_HEADER
486 "reached my own limit of "
487 "allowed buffer space for output (%i HWCBs = %li "
488 "bytes), skipped content of oldest HWCB %i time(s) "
489 "(%i lines = %i characters)\n",
490 hwc_data.ioctls.max_hwcb,
491 hwc_data.ioctls.max_hwcb * PAGE_SIZE,
492 BUF_HWCB_TIMES_LOST,
493 BUF_HWCB_MTO_LOST,
494 BUF_HWCB_CHAR_LOST);
495 else
496 internal_print (
497 DELAYED_WRITE,
498 HWC_RW_PRINT_HEADER
499 "page allocation failed, "
500 "could not expand buffer for output (currently in "
501 "use: %i HWCBs = %li bytes), skipped content of "
502 "oldest HWCB %i time(s) (%i lines = %i characters)\n",
503 hwc_data.hwcb_count,
504 hwc_data.hwcb_count * PAGE_SIZE,
505 BUF_HWCB_TIMES_LOST,
506 BUF_HWCB_MTO_LOST,
507 BUF_HWCB_CHAR_LOST);
508
509 return retval;
510 }
511
512 static int
513 allocate_write_hwcb (void)
514 {
515 unsigned char *page;
516 int page_nr;
517
518 if (hwc_data.hwcb_count == hwc_data.ioctls.max_hwcb)
519 return -ENOMEM;
520
521 page_nr = find_first_zero_bit (&hwc_data.kmem_pages, MAX_KMEM_PAGES);
522 if (page_nr < hwc_data.ioctls.kmem_hwcb) {
523
524 page = (unsigned char *)
525 (hwc_data.kmem_start + (page_nr << 12));
526 set_bit (page_nr, &hwc_data.kmem_pages);
527 } else
528 page = (unsigned char *) __get_free_page (GFP_ATOMIC | GFP_DMA);
529
530 if (!page)
531 return -ENOMEM;
532
533 if (!OUT_HWCB)
534 OUT_HWCB = page;
535 else
536 BUF_HWCB_NEXT = page;
537
538 BUF_HWCB = page;
539
540 BUF_HWCB_NEXT = NULL;
541
542 hwc_data.hwcb_count++;
543
544 prepare_write_hwcb ();
545
546 BUF_HWCB_TIMES_LOST = 0;
547 BUF_HWCB_MTO_LOST = 0;
548 BUF_HWCB_CHAR_LOST = 0;
549
550 #ifdef BUFFER_STRESS_TEST
551
552 internal_print (
553 DELAYED_WRITE,
554 "*** " HWC_RW_PRINT_HEADER
555 "page #%i at 0x%x for buffering allocated. ***\n",
556 hwc_data.hwcb_count, page);
557
558 #endif
559
560 return 0;
561 }
562
563 static int
564 release_write_hwcb (void)
565 {
566 unsigned long page;
567 int page_nr;
568
569 if (!hwc_data.hwcb_count)
570 return -ENODATA;
571
572 if (hwc_data.hwcb_count == 1) {
573
574 prepare_write_hwcb ();
575
576 ALL_HWCB_CHAR = 0;
577 ALL_HWCB_MTO = 0;
578 BUF_HWCB_TIMES_LOST = 0;
579 BUF_HWCB_MTO_LOST = 0;
580 BUF_HWCB_CHAR_LOST = 0;
581 } else {
582 page = (unsigned long) OUT_HWCB;
583
584 ALL_HWCB_MTO -= OUT_HWCB_MTO;
585 ALL_HWCB_CHAR -= OUT_HWCB_CHAR;
586 hwc_data.hwcb_count--;
587
588 OUT_HWCB = OUT_HWCB_NEXT;
589
590 if (page >= hwc_data.kmem_start &&
591 page <= hwc_data.kmem_end) {
592 /*memset((void *) page, 0, PAGE_SIZE); */
593
594 page_nr = (int) ((page - hwc_data.kmem_start) >> 12);
595 clear_bit (page_nr, &hwc_data.kmem_pages);
596 } else
597 free_page (page);
598 #ifdef BUFFER_STRESS_TEST
599
600 internal_print (
601 DELAYED_WRITE,
602 "*** " HWC_RW_PRINT_HEADER
603 "page at 0x%x released, %i pages still in use ***\n",
604 page, hwc_data.hwcb_count);
605
606 #endif
607 }
608 return 0;
609 }
610
611 static int
612 add_mto (
613 unsigned char *message,
614 unsigned short int count)
615 {
616 unsigned short int mto_size;
617 write_hwcb_t *hwcb;
618 mto_t *mto;
619 void *dest;
620
621 if (!BUF_HWCB)
622 return -ENOMEM;
623
624 if (BUF_HWCB == hwc_data.current_hwcb)
625 return -ENOMEM;
626
627 mto_size = sizeof (mto_t) + count;
628
629 hwcb = (write_hwcb_t *) BUF_HWCB;
630
631 if ((MAX_HWCB_ROOM - hwcb->length) < mto_size)
632 return -ENOMEM;
633
634 mto = (mto_t *) (((unsigned long) hwcb) + hwcb->length);
635
636 memcpy (mto, &mto_template, sizeof (mto_t));
637
638 dest = (void *) (((unsigned long) mto) + sizeof (mto_t));
639
640 memcpy (dest, message, count);
641
642 mto->length += count;
643
644 hwcb->length += mto_size;
645 hwcb->msgbuf.length += mto_size;
646 hwcb->msgbuf.mdb.length += mto_size;
647
648 BUF_HWCB_MTO++;
649 ALL_HWCB_MTO++;
650 BUF_HWCB_CHAR += count;
651 ALL_HWCB_CHAR += count;
652
653 return count;
654 }
655
656 static int write_event_data_1 (void);
657
658 static void
659 do_poll_hwc (unsigned long data)
660 {
661 unsigned long flags;
662
663 spin_lock_irqsave (&hwc_data.lock, flags);
664
665 write_event_data_1 ();
666
667 spin_unlock_irqrestore (&hwc_data.lock, flags);
668 }
669
670 void
671 start_poll_hwc (void)
672 {
673 init_timer (&hwc_data.poll_timer);
674 hwc_data.poll_timer.function = do_poll_hwc;
675 hwc_data.poll_timer.data = (unsigned long) NULL;
676 hwc_data.poll_timer.expires = jiffies + 2 * HZ;
677 add_timer (&hwc_data.poll_timer);
678 hwc_data.flags |= HWC_PTIMER_RUNS;
679 }
680
681 static int
682 write_event_data_1 (void)
683 {
684 unsigned short int condition_code;
685 int retval;
686 write_hwcb_t *hwcb = (write_hwcb_t *) OUT_HWCB;
687
688 if ((!hwc_data.write_prio) &&
689 (!hwc_data.write_nonprio) &&
690 hwc_data.read_statechange)
691 return -EOPNOTSUPP;
692
693 if (hwc_data.current_servc)
694 return -EBUSY;
695
696 retval = sane_write_hwcb ();
697 if (retval < 0)
698 return -EIO;
699
700 if (!OUT_HWCB_MTO)
701 return -ENODATA;
702
703 if (!hwc_data.write_nonprio && hwc_data.write_prio)
704 hwcb->msgbuf.type = ET_PMsgCmd;
705 else
706 hwcb->msgbuf.type = ET_Msg;
707
708 condition_code = service_call (HWC_CMDW_WRITEDATA, OUT_HWCB);
709
710 #ifdef DUMP_HWC_WRITE_ERROR
711 if (condition_code != HWC_COMMAND_INITIATED)
712 __asm__ ("LHI 1,0xe20\n\t"
713 "L 2,0(%0)\n\t"
714 "LRA 3,0(%1)\n\t"
715 "J .+0 \n\t"
716 :
717 : "a" (&condition_code), "a" (OUT_HWCB)
718 : "1", "2", "3");
719 #endif
720
721 switch (condition_code) {
722 case HWC_COMMAND_INITIATED:
723 hwc_data.current_servc = HWC_CMDW_WRITEDATA;
724 hwc_data.current_hwcb = OUT_HWCB;
725 retval = condition_code;
726 break;
727 case HWC_BUSY:
728 retval = -EBUSY;
729 break;
730 case HWC_NOT_OPERATIONAL:
731 start_poll_hwc ();
732 default:
733 retval = -EIO;
734 }
735
736 return retval;
737 }
738
739 static void
740 flush_hwcbs (void)
741 {
742 while (hwc_data.hwcb_count > 1)
743 release_write_hwcb ();
744
745 release_write_hwcb ();
746
747 hwc_data.flags &= ~HWC_FLUSH;
748 }
749
750 static int
751 write_event_data_2 (u32 ext_int_param)
752 {
753 write_hwcb_t *hwcb;
754 int retval = 0;
755
756 #ifdef DUMP_HWC_WRITE_ERROR
757 if ((ext_int_param & HWC_EXT_INT_PARAM_ADDR)
758 != (unsigned long) hwc_data.current_hwcb) {
759 internal_print (
760 DELAYED_WRITE,
761 HWC_RW_PRINT_HEADER
762 "write_event_data_2 : "
763 "HWCB address does not fit "
764 "(expected: 0x%lx, got: 0x%lx).\n",
765 (unsigned long) hwc_data.current_hwcb,
766 ext_int_param);
767 return -EINVAL;
768 }
769 #endif
770
771 hwcb = (write_hwcb_t *) OUT_HWCB;
772
773 #ifdef DUMP_HWC_WRITE_LIST_ERROR
774 if (((unsigned char *) hwcb) != hwc_data.current_hwcb) {
775 __asm__ ("LHI 1,0xe22\n\t"
776 "LRA 2,0(%0)\n\t"
777 "LRA 3,0(%1)\n\t"
778 "LRA 4,0(%2)\n\t"
779 "LRA 5,0(%3)\n\t"
780 "J .+0 \n\t"
781 :
782 : "a" (OUT_HWCB),
783 "a" (hwc_data.current_hwcb),
784 "a" (BUF_HWCB),
785 "a" (hwcb)
786 : "1", "2", "3", "4", "5");
787 }
788 #endif
789
790 #ifdef DUMP_HWC_WRITE_ERROR
791 if (hwcb->response_code != 0x0020) {
792 __asm__ ("LHI 1,0xe21\n\t"
793 "LRA 2,0(%0)\n\t"
794 "LRA 3,0(%1)\n\t"
795 "LRA 4,0(%2)\n\t"
796 "LH 5,0(%3)\n\t"
797 "SRL 5,8\n\t"
798 "J .+0 \n\t"
799 :
800 : "a" (OUT_HWCB), "a" (hwc_data.current_hwcb),
801 "a" (BUF_HWCB),
802 "a" (&(hwc_data.hwcb_count))
803 : "1", "2", "3", "4", "5");
804 }
805 #endif
806
807 switch (hwcb->response_code) {
808 case 0x0020:
809
810 retval = OUT_HWCB_CHAR;
811 release_write_hwcb ();
812 break;
813 case 0x0040:
814 case 0x0340:
815 case 0x40F0:
816 if (!hwc_data.read_statechange) {
817 hwcb->response_code = 0;
818 start_poll_hwc ();
819 }
820 retval = -EIO;
821 break;
822 default:
823 internal_print (
824 DELAYED_WRITE,
825 HWC_RW_PRINT_HEADER
826 "write_event_data_2 : "
827 "failed operation "
828 "(response code: 0x%x "
829 "HWCB address: 0x%x).\n",
830 hwcb->response_code,
831 hwcb);
832 retval = -EIO;
833 }
834
835 if (retval == -EIO) {
836
837 hwcb->control_mask[0] = 0;
838 hwcb->control_mask[1] = 0;
839 hwcb->control_mask[2] = 0;
840 hwcb->response_code = 0;
841 }
842 hwc_data.current_servc = 0;
843 hwc_data.current_hwcb = NULL;
844
845 if (hwc_data.flags & HWC_FLUSH)
846 flush_hwcbs ();
847
848 return retval;
849 }
850
851 static void
852 do_put_line (
853 unsigned char *message,
854 unsigned short count)
855 {
856
857 if (add_mto (message, count) != count) {
858
859 if (allocate_write_hwcb () < 0)
860 reuse_write_hwcb ();
861
862 #ifdef DUMP_HWC_WRITE_LIST_ERROR
863 if (add_mto (message, count) != count)
864 __asm__ ("LHI 1,0xe32\n\t"
865 "LRA 2,0(%0)\n\t"
866 "L 3,0(%1)\n\t"
867 "LRA 4,0(%2)\n\t"
868 "LRA 5,0(%3)\n\t"
869 "J .+0 \n\t"
870 :
871 : "a" (message), "a" (&hwc_data.kmem_pages),
872 "a" (BUF_HWCB), "a" (OUT_HWCB)
873 : "1", "2", "3", "4", "5");
874 #else
875 add_mto (message, count);
876 #endif
877 }
878 }
879
880 static void
881 put_line (
882 unsigned char *message,
883 unsigned short count)
884 {
885
886 if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_WTIMER_RUNS)) {
887 del_timer (&hwc_data.write_timer);
888 hwc_data.flags &= ~HWC_WTIMER_RUNS;
889 }
890 hwc_data.obuf_start += count;
891
892 do_put_line (message, count);
893
894 hwc_data.obuf_start -= count;
895 }
896
897 static void
898 set_alarm (void)
899 {
900 write_hwcb_t *hwcb;
901
902 if ((!BUF_HWCB) || (BUF_HWCB == hwc_data.current_hwcb))
903 allocate_write_hwcb ();
904
905 hwcb = (write_hwcb_t *) BUF_HWCB;
906 hwcb->msgbuf.mdb.mdb_body.go.general_msg_flags |= GMF_SndAlrm;
907 }
908
909 static void
910 hwc_write_timeout (unsigned long data)
911 {
912 unsigned long flags;
913
914 spin_lock_irqsave (&hwc_data.lock, flags);
915
916 hwc_data.obuf_start = hwc_data.obuf_count;
917 if (hwc_data.obuf_count)
918 put_line (hwc_data.obuf, hwc_data.obuf_count);
919 hwc_data.obuf_start = 0;
920
921 hwc_data.obuf_cursor = 0;
922 hwc_data.obuf_count = 0;
923
924 write_event_data_1 ();
925
926 spin_unlock_irqrestore (&hwc_data.lock, flags);
927 }
928
929 static int
930 do_hwc_write (
931 int from_user,
932 unsigned char *msg,
933 unsigned int count,
934 unsigned char write_time)
935 {
936 unsigned int i_msg = 0;
937 unsigned short int spaces = 0;
938 unsigned int processed_characters = 0;
939 unsigned char ch;
940 unsigned short int obuf_count;
941 unsigned short int obuf_cursor;
942 unsigned short int obuf_columns;
943
944 if (hwc_data.obuf_start) {
945 obuf_cursor = 0;
946 obuf_count = 0;
947 obuf_columns = MIN (hwc_data.ioctls.columns,
948 MAX_MESSAGE_SIZE - hwc_data.obuf_start);
949 } else {
950 obuf_cursor = hwc_data.obuf_cursor;
951 obuf_count = hwc_data.obuf_count;
952 obuf_columns = hwc_data.ioctls.columns;
953 }
954
955 for (i_msg = 0; i_msg < count; i_msg++) {
956 if (from_user)
957 get_user (ch, msg + i_msg);
958 else
959 ch = msg[i_msg];
960
961 processed_characters++;
962
963 if ((obuf_cursor == obuf_columns) &&
964
965 (ch != '\n') &&
966
967 (ch != '\t')) {
968 put_line (&hwc_data.obuf[hwc_data.obuf_start],
969 obuf_columns);
970 obuf_cursor = 0;
971 obuf_count = 0;
972 }
973 switch (ch) {
974
975 case '\n':
976
977 put_line (&hwc_data.obuf[hwc_data.obuf_start],
978 obuf_count);
979 obuf_cursor = 0;
980 obuf_count = 0;
981 break;
982
983 case '\a':
984
985 hwc_data.obuf_start += obuf_count;
986 set_alarm ();
987 hwc_data.obuf_start -= obuf_count;
988
989 break;
990
991 case '\t':
992
993 do {
994 if (obuf_cursor < obuf_columns) {
995 hwc_data.obuf[hwc_data.obuf_start +
996 obuf_cursor]
997 = HWC_ASCEBC (' ');
998 obuf_cursor++;
999 } else
1000 break;
1001 } while (obuf_cursor % hwc_data.ioctls.width_htab);
1002
1003 break;
1004
1005 case '\f':
1006 case '\v':
1007
1008 spaces = obuf_cursor;
1009 put_line (&hwc_data.obuf[hwc_data.obuf_start],
1010 obuf_count);
1011 obuf_count = obuf_cursor;
1012 while (spaces) {
1013 hwc_data.obuf[hwc_data.obuf_start +
1014 obuf_cursor - spaces]
1015 = HWC_ASCEBC (' ');
1016 spaces--;
1017 }
1018
1019 break;
1020
1021 case '\b':
1022
1023 if (obuf_cursor)
1024 obuf_cursor--;
1025 break;
1026
1027 case '\r':
1028
1029 obuf_cursor = 0;
1030 break;
1031
1032 case 0x00:
1033
1034 put_line (&hwc_data.obuf[hwc_data.obuf_start],
1035 obuf_count);
1036 obuf_cursor = 0;
1037 obuf_count = 0;
1038 goto out;
1039
1040 default:
1041
1042 if (isprint (ch))
1043 hwc_data.obuf[hwc_data.obuf_start +
1044 obuf_cursor++]
1045 = HWC_ASCEBC (ch);
1046 }
1047 if (obuf_cursor > obuf_count)
1048 obuf_count = obuf_cursor;
1049 }
1050
1051 if (obuf_cursor) {
1052
1053 if (hwc_data.obuf_start ||
1054 (hwc_data.ioctls.final_nl == 0)) {
1055
1056 put_line (&hwc_data.obuf[hwc_data.obuf_start],
1057 obuf_count);
1058 obuf_cursor = 0;
1059 obuf_count = 0;
1060 } else {
1061
1062 if (hwc_data.ioctls.final_nl > 0) {
1063
1064 if (hwc_data.flags & HWC_WTIMER_RUNS) {
1065
1066 mod_timer (&hwc_data.write_timer,
1067 jiffies + hwc_data.ioctls.final_nl * HZ / 10);
1068 } else {
1069
1070 init_timer (&hwc_data.write_timer);
1071 hwc_data.write_timer.function =
1072 hwc_write_timeout;
1073 hwc_data.write_timer.data =
1074 (unsigned long) NULL;
1075 hwc_data.write_timer.expires =
1076 jiffies +
1077 hwc_data.ioctls.final_nl * HZ / 10;
1078 add_timer (&hwc_data.write_timer);
1079 hwc_data.flags |= HWC_WTIMER_RUNS;
1080 }
1081 } else;
1082
1083 }
1084 } else;
1085
1086 out:
1087
1088 if (!hwc_data.obuf_start) {
1089 hwc_data.obuf_cursor = obuf_cursor;
1090 hwc_data.obuf_count = obuf_count;
1091 }
1092 if (write_time == IMMEDIATE_WRITE)
1093 write_event_data_1 ();
1094
1095 return processed_characters;
1096 }
1097
1098 signed int
1099 hwc_write (int from_user, const unsigned char *msg, unsigned int count)
1100 {
1101 unsigned long flags;
1102 int retval;
1103
1104 spin_lock_irqsave (&hwc_data.lock, flags);
1105
1106 retval = do_hwc_write (from_user, (unsigned char *) msg,
1107 count, IMMEDIATE_WRITE);
1108
1109 spin_unlock_irqrestore (&hwc_data.lock, flags);
1110
1111 return retval;
1112 }
1113
1114 unsigned int
1115 hwc_chars_in_buffer (unsigned char flag)
1116 {
1117 unsigned short int number = 0;
1118 unsigned long flags;
1119
1120 spin_lock_irqsave (&hwc_data.lock, flags);
1121
1122 if (flag & IN_HWCB)
1123 number += ALL_HWCB_CHAR;
1124
1125 if (flag & IN_WRITE_BUF)
1126 number += hwc_data.obuf_cursor;
1127
1128 spin_unlock_irqrestore (&hwc_data.lock, flags);
1129
1130 return number;
1131 }
1132
1133 static inline int
1134 nr_setbits (kmem_pages_t arg)
1135 {
1136 int i;
1137 int nr = 0;
1138
1139 for (i = 0; i < (sizeof (arg) << 3); i++) {
1140 if (arg & 1)
1141 nr++;
1142 arg >>= 1;
1143 }
1144
1145 return nr;
1146 }
1147
1148 unsigned int
1149 hwc_write_room (unsigned char flag)
1150 {
1151 unsigned int number = 0;
1152 unsigned long flags;
1153 write_hwcb_t *hwcb;
1154
1155 spin_lock_irqsave (&hwc_data.lock, flags);
1156
1157 if (flag & IN_HWCB) {
1158
1159 if (BUF_HWCB) {
1160 hwcb = (write_hwcb_t *) BUF_HWCB;
1161 number += MAX_HWCB_ROOM - hwcb->length;
1162 }
1163 number += (hwc_data.ioctls.kmem_hwcb -
1164 nr_setbits (hwc_data.kmem_pages)) *
1165 (MAX_HWCB_ROOM -
1166 (sizeof (write_hwcb_t) + sizeof (mto_t)));
1167 }
1168 if (flag & IN_WRITE_BUF)
1169 number += MAX_HWCB_ROOM - hwc_data.obuf_cursor;
1170
1171 spin_unlock_irqrestore (&hwc_data.lock, flags);
1172
1173 return number;
1174 }
1175
1176 void
1177 hwc_flush_buffer (unsigned char flag)
1178 {
1179 unsigned long flags;
1180
1181 spin_lock_irqsave (&hwc_data.lock, flags);
1182
1183 if (flag & IN_HWCB) {
1184 if (hwc_data.current_servc != HWC_CMDW_WRITEDATA)
1185 flush_hwcbs ();
1186 else
1187 hwc_data.flags |= HWC_FLUSH;
1188 }
1189 if (flag & IN_WRITE_BUF) {
1190 hwc_data.obuf_cursor = 0;
1191 hwc_data.obuf_count = 0;
1192 }
1193 spin_unlock_irqrestore (&hwc_data.lock, flags);
1194 }
1195
1196 unsigned short int
1197 seperate_cases (unsigned char *buf, unsigned short int count)
1198 {
1199
1200 unsigned short int i_in;
1201
1202 unsigned short int i_out = 0;
1203
1204 unsigned char _case = 0;
1205
1206 for (i_in = 0; i_in < count; i_in++) {
1207
1208 if (buf[i_in] == hwc_data.ioctls.delim) {
1209
1210 if ((i_in + 1 < count) &&
1211 (buf[i_in + 1] == hwc_data.ioctls.delim)) {
1212
1213 buf[i_out] = hwc_data.ioctls.delim;
1214
1215 i_out++;
1216
1217 i_in++;
1218
1219 } else
1220 _case = ~_case;
1221
1222 } else {
1223
1224 if (_case) {
1225
1226 if (hwc_data.ioctls.tolower)
1227 buf[i_out] = _ebc_toupper[buf[i_in]];
1228
1229 else
1230 buf[i_out] = _ebc_tolower[buf[i_in]];
1231
1232 } else
1233 buf[i_out] = buf[i_in];
1234
1235 i_out++;
1236 }
1237 }
1238
1239 return i_out;
1240 }
1241
1242 #ifdef DUMP_HWCB_INPUT
1243
1244 static int
1245 gds_vector_name (u16 id, unsigned char name[])
1246 {
1247 int retval = 0;
1248
1249 switch (id) {
1250 case GDS_ID_MDSMU:
1251 name = "Multiple Domain Support Message Unit";
1252 break;
1253 case GDS_ID_MDSRouteInfo:
1254 name = "MDS Routing Information";
1255 break;
1256 case GDS_ID_AgUnWrkCorr:
1257 name = "Agent Unit of Work Correlator";
1258 break;
1259 case GDS_ID_SNACondReport:
1260 name = "SNA Condition Report";
1261 break;
1262 case GDS_ID_CPMSU:
1263 name = "CP Management Services Unit";
1264 break;
1265 case GDS_ID_RoutTargInstr:
1266 name = "Routing and Targeting Instructions";
1267 break;
1268 case GDS_ID_OpReq:
1269 name = "Operate Request";
1270 break;
1271 case GDS_ID_TextCmd:
1272 name = "Text Command";
1273 break;
1274
1275 default:
1276 name = "unknown GDS variable";
1277 retval = -EINVAL;
1278 }
1279
1280 return retval;
1281 }
1282 #endif
1283
1284 inline static gds_vector_t *
1285 find_gds_vector (
1286 gds_vector_t * start, void *end, u16 id)
1287 {
1288 gds_vector_t *vec;
1289 gds_vector_t *retval = NULL;
1290
1291 vec = start;
1292
1293 while (((void *) vec) < end) {
1294 if (vec->gds_id == id) {
1295
1296 #ifdef DUMP_HWCB_INPUT
1297 int retval_name;
1298 unsigned char name[64];
1299
1300 retval_name = gds_vector_name (id, name);
1301 internal_print (
1302 DELAYED_WRITE,
1303 HWC_RW_PRINT_HEADER
1304 "%s at 0x%x up to 0x%x, length: %d",
1305 name,
1306 (unsigned long) vec,
1307 ((unsigned long) vec) + vec->length - 1,
1308 vec->length);
1309 if (retval_name < 0)
1310 internal_print (
1311 IMMEDIATE_WRITE,
1312 ", id: 0x%x\n",
1313 vec->gds_id);
1314 else
1315 internal_print (
1316 IMMEDIATE_WRITE,
1317 "\n");
1318 #endif
1319
1320 retval = vec;
1321 break;
1322 }
1323 vec = (gds_vector_t *) (((unsigned long) vec) + vec->length);
1324 }
1325
1326 return retval;
1327 }
1328
1329 inline static gds_subvector_t *
1330 find_gds_subvector (
1331 gds_subvector_t * start, void *end, u8 key)
1332 {
1333 gds_subvector_t *subvec;
1334 gds_subvector_t *retval = NULL;
1335
1336 subvec = start;
1337
1338 while (((void *) subvec) < end) {
1339 if (subvec->key == key) {
1340 retval = subvec;
1341 break;
1342 }
1343 subvec = (gds_subvector_t *)
1344 (((unsigned long) subvec) + subvec->length);
1345 }
1346
1347 return retval;
1348 }
1349
1350 inline static int
1351 get_input (void *start, void *end)
1352 {
1353 int count;
1354
1355 count = ((unsigned long) end) - ((unsigned long) start);
1356
1357 if (hwc_data.ioctls.tolower)
1358 EBC_TOLOWER (start, count);
1359
1360 if (hwc_data.ioctls.delim)
1361 count = seperate_cases (start, count);
1362
1363 HWC_EBCASC_STR (start, count);
1364
1365 if (hwc_data.ioctls.echo)
1366 do_hwc_write (0, start, count, IMMEDIATE_WRITE);
1367
1368 if (hwc_data.calls != NULL)
1369 if (hwc_data.calls->move_input != NULL)
1370 (hwc_data.calls->move_input) (start, count);
1371
1372 return count;
1373 }
1374
1375 inline static int
1376 eval_selfdeftextmsg (gds_subvector_t * start, void *end)
1377 {
1378 gds_subvector_t *subvec;
1379 void *subvec_data;
1380 void *subvec_end;
1381 int retval = 0;
1382
1383 subvec = start;
1384
1385 while (((void *) subvec) < end) {
1386 subvec = find_gds_subvector (subvec, end, 0x30);
1387 if (!subvec)
1388 break;
1389 subvec_data = (void *)
1390 (((unsigned long) subvec) +
1391 sizeof (gds_subvector_t));
1392 subvec_end = (void *)
1393 (((unsigned long) subvec) + subvec->length);
1394 retval += get_input (subvec_data, subvec_end);
1395 subvec = (gds_subvector_t *) subvec_end;
1396 }
1397
1398 return retval;
1399 }
1400
1401 inline static int
1402 eval_textcmd (gds_subvector_t * start, void *end)
1403 {
1404 gds_subvector_t *subvec;
1405 gds_subvector_t *subvec_data;
1406 void *subvec_end;
1407 int retval = 0;
1408
1409 subvec = start;
1410
1411 while (((void *) subvec) < end) {
1412 subvec = find_gds_subvector (
1413 subvec, end, GDS_KEY_SelfDefTextMsg);
1414 if (!subvec)
1415 break;
1416 subvec_data = (gds_subvector_t *)
1417 (((unsigned long) subvec) +
1418 sizeof (gds_subvector_t));
1419 subvec_end = (void *)
1420 (((unsigned long) subvec) + subvec->length);
1421 retval += eval_selfdeftextmsg (subvec_data, subvec_end);
1422 subvec = (gds_subvector_t *) subvec_end;
1423 }
1424
1425 return retval;
1426 }
1427
1428 inline static int
1429 eval_cpmsu (gds_vector_t * start, void *end)
1430 {
1431 gds_vector_t *vec;
1432 gds_subvector_t *vec_data;
1433 void *vec_end;
1434 int retval = 0;
1435
1436 vec = start;
1437
1438 while (((void *) vec) < end) {
1439 vec = find_gds_vector (vec, end, GDS_ID_TextCmd);
1440 if (!vec)
1441 break;
1442 vec_data = (gds_subvector_t *)
1443 (((unsigned long) vec) + sizeof (gds_vector_t));
1444 vec_end = (void *) (((unsigned long) vec) + vec->length);
1445 retval += eval_textcmd (vec_data, vec_end);
1446 vec = (gds_vector_t *) vec_end;
1447 }
1448
1449 return retval;
1450 }
1451
1452 inline static int
1453 eval_mdsmu (gds_vector_t * start, void *end)
1454 {
1455 gds_vector_t *vec;
1456 gds_vector_t *vec_data;
1457 void *vec_end;
1458 int retval = 0;
1459
1460 vec = find_gds_vector (start, end, GDS_ID_CPMSU);
1461 if (vec) {
1462 vec_data = (gds_vector_t *)
1463 (((unsigned long) vec) + sizeof (gds_vector_t));
1464 vec_end = (void *) (((unsigned long) vec) + vec->length);
1465 retval = eval_cpmsu (vec_data, vec_end);
1466 }
1467 return retval;
1468 }
1469
1470 static int
1471 eval_evbuf (gds_vector_t * start, void *end)
1472 {
1473 gds_vector_t *vec;
1474 gds_vector_t *vec_data;
1475 void *vec_end;
1476 int retval = 0;
1477
1478 vec = find_gds_vector (start, end, GDS_ID_MDSMU);
1479 if (vec) {
1480 vec_data = (gds_vector_t *)
1481 (((unsigned long) vec) + sizeof (gds_vector_t));
1482 vec_end = (void *) (((unsigned long) vec) + vec->length);
1483 retval = eval_mdsmu (vec_data, vec_end);
1484 }
1485 return retval;
1486 }
1487
1488 static inline int
1489 eval_hwc_receive_mask (_hwcb_mask_t mask)
1490 {
1491
1492 hwc_data.write_nonprio
1493 = ((mask & ET_Msg_Mask) == ET_Msg_Mask);
1494
1495 hwc_data.write_prio
1496 = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask);
1497
1498 if (hwc_data.write_prio || hwc_data.write_nonprio) {
1499 internal_print (
1500 DELAYED_WRITE,
1501 HWC_RW_PRINT_HEADER
1502 "can write messages\n");
1503 return 0;
1504 } else {
1505 internal_print (
1506 DELAYED_WRITE,
1507 HWC_RW_PRINT_HEADER
1508 "can not write messages\n");
1509 return -1;
1510 }
1511 }
1512
1513 static inline int
1514 eval_hwc_send_mask (_hwcb_mask_t mask)
1515 {
1516
1517 hwc_data.read_statechange
1518 = ((mask & ET_StateChange_Mask) == ET_StateChange_Mask);
1519 if (hwc_data.read_statechange)
1520 internal_print (
1521 DELAYED_WRITE,
1522 HWC_RW_PRINT_HEADER
1523 "can read state change notifications\n");
1524 else
1525 internal_print (
1526 DELAYED_WRITE,
1527 HWC_RW_PRINT_HEADER
1528 "can not read state change notifications\n");
1529
1530 hwc_data.read_nonprio
1531 = ((mask & ET_OpCmd_Mask) == ET_OpCmd_Mask);
1532 if (hwc_data.read_nonprio)
1533 internal_print (
1534 DELAYED_WRITE,
1535 HWC_RW_PRINT_HEADER
1536 "can read commands\n");
1537
1538 hwc_data.read_prio
1539 = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask);
1540 if (hwc_data.read_prio)
1541 internal_print (
1542 DELAYED_WRITE,
1543 HWC_RW_PRINT_HEADER
1544 "can read priority commands\n");
1545
1546 if (hwc_data.read_prio || hwc_data.read_nonprio) {
1547 return 0;
1548 } else {
1549 internal_print (
1550 DELAYED_WRITE,
1551 HWC_RW_PRINT_HEADER
1552 "can not read commands from operator\n");
1553 return -1;
1554 }
1555 }
1556
1557 static int
1558 eval_statechangebuf (statechangebuf_t * scbuf)
1559 {
1560 int retval = 0;
1561
1562 internal_print (
1563 DELAYED_WRITE,
1564 HWC_RW_PRINT_HEADER
1565 "HWC state change detected\n");
1566
1567 if (scbuf->validity_hwc_active_facility_mask) {
1568
1569 }
1570 if (scbuf->validity_hwc_receive_mask) {
1571
1572 if (scbuf->mask_length != 4) {
1573 #ifdef DUMP_HWC_INIT_ERROR
1574 __asm__ ("LHI 1,0xe50\n\t"
1575 "LRA 2,0(%0)\n\t"
1576 "J .+0 \n\t"
1577 :
1578 : "a" (scbuf)
1579 : "1", "2");
1580 #endif
1581 } else {
1582
1583 retval += eval_hwc_receive_mask
1584 (scbuf->hwc_receive_mask);
1585 }
1586 }
1587 if (scbuf->validity_hwc_send_mask) {
1588
1589 if (scbuf->mask_length != 4) {
1590 #ifdef DUMP_HWC_INIT_ERROR
1591 __asm__ ("LHI 1,0xe51\n\t"
1592 "LRA 2,0(%0)\n\t"
1593 "J .+0 \n\t"
1594 :
1595 : "a" (scbuf)
1596 : "1", "2");
1597 #endif
1598 } else {
1599
1600 retval += eval_hwc_send_mask
1601 (scbuf->hwc_send_mask);
1602 }
1603 }
1604 if (scbuf->validity_read_data_function_mask) {
1605
1606 }
1607 return retval;
1608 }
1609
1610 static int
1611 process_evbufs (void *start, void *end)
1612 {
1613 int retval = 0;
1614 evbuf_t *evbuf;
1615 void *evbuf_end;
1616 gds_vector_t *evbuf_data;
1617
1618 evbuf = (evbuf_t *) start;
1619 while (((void *) evbuf) < end) {
1620 evbuf_data = (gds_vector_t *)
1621 (((unsigned long) evbuf) + sizeof (evbuf_t));
1622 evbuf_end = (void *) (((unsigned long) evbuf) + evbuf->length);
1623 switch (evbuf->type) {
1624 case ET_OpCmd:
1625 case ET_CntlProgOpCmd:
1626 case ET_PMsgCmd:
1627 #ifdef DUMP_HWCB_INPUT
1628
1629 internal_print (
1630 DELAYED_WRITE,
1631 HWC_RW_PRINT_HEADER
1632 "event buffer "
1633 "at 0x%x up to 0x%x, length: %d\n",
1634 (unsigned long) evbuf,
1635 (unsigned long) (evbuf_end - 1),
1636 evbuf->length);
1637 dump_storage_area ((void *) evbuf, evbuf->length);
1638 #endif
1639 retval += eval_evbuf (evbuf_data, evbuf_end);
1640 break;
1641 case ET_StateChange:
1642 retval += eval_statechangebuf
1643 ((statechangebuf_t *) evbuf);
1644 break;
1645 default:
1646 internal_print (
1647 DELAYED_WRITE,
1648 HWC_RW_PRINT_HEADER
1649 "unconditional read: "
1650 "unknown event buffer found, "
1651 "type 0x%x",
1652 evbuf->type);
1653 retval = -ENOSYS;
1654 }
1655 evbuf = (evbuf_t *) evbuf_end;
1656 }
1657 return retval;
1658 }
1659
1660 static int
1661 unconditional_read_1 (void)
1662 {
1663 unsigned short int condition_code;
1664 read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page;
1665 int retval;
1666
1667 #if 0
1668
1669 if ((!hwc_data.read_prio) && (!hwc_data.read_nonprio))
1670 return -EOPNOTSUPP;
1671
1672 if (hwc_data.current_servc)
1673 return -EBUSY;
1674 #endif
1675
1676 memset (hwcb, 0x00, PAGE_SIZE);
1677 memcpy (hwcb, &read_hwcb_template, sizeof (read_hwcb_t));
1678
1679 condition_code = service_call (HWC_CMDW_READDATA, hwc_data.page);
1680
1681 #ifdef DUMP_HWC_READ_ERROR
1682 if (condition_code == HWC_NOT_OPERATIONAL)
1683 __asm__ ("LHI 1,0xe40\n\t"
1684 "L 2,0(%0)\n\t"
1685 "LRA 3,0(%1)\n\t"
1686 "J .+0 \n\t"
1687 :
1688 : "a" (&condition_code), "a" (hwc_data.page)
1689 : "1", "2", "3");
1690 #endif
1691
1692 switch (condition_code) {
1693 case HWC_COMMAND_INITIATED:
1694 hwc_data.current_servc = HWC_CMDW_READDATA;
1695 hwc_data.current_hwcb = hwc_data.page;
1696 retval = condition_code;
1697 break;
1698 case HWC_BUSY:
1699 retval = -EBUSY;
1700 break;
1701 default:
1702 retval = -EIO;
1703 }
1704
1705 return retval;
1706 }
1707
1708 static int
1709 unconditional_read_2 (u32 ext_int_param)
1710 {
1711 read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page;
1712
1713 #ifdef DUMP_HWC_READ_ERROR
1714 if ((hwcb->response_code != 0x0020) &&
1715 (hwcb->response_code != 0x0220) &&
1716 (hwcb->response_code != 0x60F0) &&
1717 (hwcb->response_code != 0x62F0))
1718 __asm__ ("LHI 1,0xe41\n\t"
1719 "LRA 2,0(%0)\n\t"
1720 "L 3,0(%1)\n\t"
1721 "J .+0\n\t"
1722 :
1723 : "a" (hwc_data.page), "a" (&(hwcb->response_code))
1724 : "1", "2", "3");
1725 #endif
1726
1727 hwc_data.current_servc = 0;
1728 hwc_data.current_hwcb = NULL;
1729
1730 switch (hwcb->response_code) {
1731
1732 case 0x0020:
1733 case 0x0220:
1734 return process_evbufs (
1735 (void *) (((unsigned long) hwcb) + sizeof (read_hwcb_t)),
1736 (void *) (((unsigned long) hwcb) + hwcb->length));
1737
1738 case 0x60F0:
1739 case 0x62F0:
1740 internal_print (
1741 IMMEDIATE_WRITE,
1742 HWC_RW_PRINT_HEADER
1743 "unconditional read: "
1744 "got interrupt and tried to read input, "
1745 "but nothing found (response code=0x%x).\n",
1746 hwcb->response_code);
1747 return 0;
1748
1749 case 0x0100:
1750 internal_print (
1751 IMMEDIATE_WRITE,
1752 HWC_RW_PRINT_HEADER
1753 "unconditional read: HWCB boundary violation - this "
1754 "must not occur in a correct driver, please contact "
1755 "author\n");
1756 return -EIO;
1757
1758 case 0x0300:
1759 internal_print (
1760 IMMEDIATE_WRITE,
1761 HWC_RW_PRINT_HEADER
1762 "unconditional read: "
1763 "insufficient HWCB length - this must not occur in a "
1764 "correct driver, please contact author\n");
1765 return -EIO;
1766
1767 case 0x01F0:
1768 internal_print (
1769 IMMEDIATE_WRITE,
1770 HWC_RW_PRINT_HEADER
1771 "unconditional read: "
1772 "invalid command - this must not occur in a correct "
1773 "driver, please contact author\n");
1774 return -EIO;
1775
1776 case 0x40F0:
1777 internal_print (
1778 IMMEDIATE_WRITE,
1779 HWC_RW_PRINT_HEADER
1780 "unconditional read: invalid function code\n");
1781 return -EIO;
1782
1783 case 0x70F0:
1784 internal_print (
1785 IMMEDIATE_WRITE,
1786 HWC_RW_PRINT_HEADER
1787 "unconditional read: invalid selection mask\n");
1788 return -EIO;
1789
1790 case 0x0040:
1791 internal_print (
1792 IMMEDIATE_WRITE,
1793 HWC_RW_PRINT_HEADER
1794 "unconditional read: HWC equipment check\n");
1795 return -EIO;
1796
1797 default:
1798 internal_print (
1799 IMMEDIATE_WRITE,
1800 HWC_RW_PRINT_HEADER
1801 "unconditional read: invalid response code %x - this "
1802 "must not occur in a correct driver, please contact "
1803 "author\n",
1804 hwcb->response_code);
1805 return -EIO;
1806 }
1807 }
1808
1809 static int
1810 write_event_mask_1 (void)
1811 {
1812 unsigned int condition_code;
1813 int retval;
1814
1815 condition_code = service_call (HWC_CMDW_WRITEMASK, hwc_data.page);
1816
1817 #ifdef DUMP_HWC_INIT_ERROR
1818
1819 if (condition_code == HWC_NOT_OPERATIONAL)
1820 __asm__ ("LHI 1,0xe10\n\t"
1821 "L 2,0(%0)\n\t"
1822 "LRA 3,0(%1)\n\t"
1823 "J .+0\n\t"
1824 :
1825 : "a" (&condition_code), "a" (hwc_data.page)
1826 : "1", "2", "3");
1827 #endif
1828
1829 switch (condition_code) {
1830 case HWC_COMMAND_INITIATED:
1831 hwc_data.current_servc = HWC_CMDW_WRITEMASK;
1832 hwc_data.current_hwcb = hwc_data.page;
1833 retval = condition_code;
1834 break;
1835 case HWC_BUSY:
1836 retval = -EBUSY;
1837 break;
1838 default:
1839 retval = -EIO;
1840 }
1841
1842 return retval;
1843 }
1844
1845 static int
1846 write_event_mask_2 (u32 ext_int_param)
1847 {
1848 init_hwcb_t *hwcb = (init_hwcb_t *) hwc_data.page;
1849 int retval = 0;
1850
1851 if (hwcb->response_code != 0x0020) {
1852 #ifdef DUMP_HWC_INIT_ERROR
1853 __asm__ ("LHI 1,0xe11\n\t"
1854 "LRA 2,0(%0)\n\t"
1855 "L 3,0(%1)\n\t"
1856 "J .+0\n\t"
1857 :
1858 : "a" (hwcb), "a" (&(hwcb->response_code))
1859 : "1", "2", "3");
1860 #else
1861 retval = -1;
1862 #endif
1863 } else {
1864 if (hwcb->mask_length != 4) {
1865 #ifdef DUMP_HWC_INIT_ERROR
1866 __asm__ ("LHI 1,0xe52\n\t"
1867 "LRA 2,0(%0)\n\t"
1868 "J .+0 \n\t"
1869 :
1870 : "a" (hwcb)
1871 : "1", "2");
1872 #endif
1873 } else {
1874 retval += eval_hwc_receive_mask
1875 (hwcb->hwc_receive_mask);
1876 retval += eval_hwc_send_mask (hwcb->hwc_send_mask);
1877 }
1878 }
1879
1880 hwc_data.current_servc = 0;
1881 hwc_data.current_hwcb = NULL;
1882
1883 return retval;
1884 }
1885
1886 static int
1887 set_hwc_ioctls (hwc_ioctls_t * ioctls, char correct)
1888 {
1889 int retval = 0;
1890 hwc_ioctls_t tmp;
1891
1892 if (ioctls->width_htab > MAX_MESSAGE_SIZE) {
1893 if (correct)
1894 tmp.width_htab = MAX_MESSAGE_SIZE;
1895 else
1896 retval = -EINVAL;
1897 } else
1898 tmp.width_htab = ioctls->width_htab;
1899
1900 tmp.echo = ioctls->echo;
1901
1902 if (ioctls->columns > MAX_MESSAGE_SIZE) {
1903 if (correct)
1904 tmp.columns = MAX_MESSAGE_SIZE;
1905 else
1906 retval = -EINVAL;
1907 } else
1908 tmp.columns = ioctls->columns;
1909
1910 tmp.final_nl = ioctls->final_nl;
1911
1912 if (ioctls->max_hwcb < 2) {
1913 if (correct)
1914 tmp.max_hwcb = 2;
1915 else
1916 retval = -EINVAL;
1917 } else
1918 tmp.max_hwcb = ioctls->max_hwcb;
1919
1920 tmp.tolower = ioctls->tolower;
1921
1922 if (ioctls->kmem_hwcb > ioctls->max_hwcb) {
1923 if (correct)
1924 tmp.kmem_hwcb = ioctls->max_hwcb;
1925 else
1926 retval = -EINVAL;
1927 } else
1928 tmp.kmem_hwcb = ioctls->kmem_hwcb;
1929
1930 if (ioctls->kmem_hwcb > MAX_KMEM_PAGES) {
1931 if (correct)
1932 ioctls->kmem_hwcb = MAX_KMEM_PAGES;
1933 else
1934 retval = -EINVAL;
1935 }
1936 if (ioctls->kmem_hwcb < 2) {
1937 if (correct)
1938 ioctls->kmem_hwcb = 2;
1939 else
1940 retval = -EINVAL;
1941 }
1942 tmp.delim = ioctls->delim;
1943
1944 if (!(retval < 0))
1945 hwc_data.ioctls = tmp;
1946
1947 return retval;
1948 }
1949
1950 int
1951 do_hwc_init (void)
1952 {
1953 int retval;
1954
1955 memcpy (hwc_data.page, &init_hwcb_template, sizeof (init_hwcb_t));
1956
1957 do {
1958
1959 retval = write_event_mask_1 ();
1960
1961 if (retval == -EBUSY) {
1962
1963 hwc_data.flags |= HWC_INIT;
1964
1965 __ctl_store (cr0, 0, 0);
1966 cr0_save = cr0;
1967 cr0 |= 0x00000200;
1968 cr0 &= 0xFFFFF3AC;
1969 __ctl_load (cr0, 0, 0);
1970
1971 asm volatile ("STOSM %0,0x01"
1972 :"=m" (psw_mask)::"memory");
1973
1974 while (!(hwc_data.flags & HWC_INTERRUPT))
1975 barrier ();
1976
1977 asm volatile ("STNSM %0,0xFE"
1978 :"=m" (psw_mask)::"memory");
1979
1980 __ctl_load (cr0_save, 0, 0);
1981
1982 hwc_data.flags &= ~HWC_INIT;
1983 }
1984 } while (retval == -EBUSY);
1985
1986 if (retval == -EIO) {
1987 hwc_data.flags |= HWC_BROKEN;
1988 printk (HWC_RW_PRINT_HEADER "HWC not operational\n");
1989 }
1990 return retval;
1991 }
1992
1993 void hwc_interrupt_handler (struct pt_regs *regs, __u16 code);
1994
1995 int
1996 hwc_init (void)
1997 {
1998 int retval;
1999
2000 #ifdef BUFFER_STRESS_TEST
2001
2002 init_hwcb_t *hwcb;
2003 int i;
2004
2005 #endif
2006
2007 if (register_external_interrupt (0x2401, hwc_interrupt_handler) != 0)
2008 panic ("Couldn't request external interrupts 0x2401");
2009
2010 spin_lock_init (&hwc_data.lock);
2011
2012 #ifdef USE_VM_DETECTION
2013
2014 if (MACHINE_IS_VM) {
2015
2016 if (hwc_data.init_ioctls.columns > 76)
2017 hwc_data.init_ioctls.columns = 76;
2018 hwc_data.init_ioctls.tolower = 1;
2019 if (!hwc_data.init_ioctls.delim)
2020 hwc_data.init_ioctls.delim = DEFAULT_CASE_DELIMITER;
2021 } else {
2022 hwc_data.init_ioctls.tolower = 0;
2023 hwc_data.init_ioctls.delim = 0;
2024 }
2025 #endif
2026 retval = set_hwc_ioctls (&hwc_data.init_ioctls, 1);
2027
2028 hwc_data.kmem_start = (unsigned long)
2029 alloc_bootmem_low_pages (hwc_data.ioctls.kmem_hwcb * PAGE_SIZE);
2030 hwc_data.kmem_end = hwc_data.kmem_start +
2031 hwc_data.ioctls.kmem_hwcb * PAGE_SIZE - 1;
2032
2033 retval = do_hwc_init ();
2034
2035 ctl_set_bit (0, 9);
2036
2037 #ifdef BUFFER_STRESS_TEST
2038
2039 internal_print (
2040 DELAYED_WRITE,
2041 HWC_RW_PRINT_HEADER
2042 "use %i bytes for buffering.\n",
2043 hwc_data.ioctls.kmem_hwcb * PAGE_SIZE);
2044 for (i = 0; i < 500; i++) {
2045 hwcb = (init_hwcb_t *) BUF_HWCB;
2046 internal_print (
2047 DELAYED_WRITE,
2048 HWC_RW_PRINT_HEADER
2049 "This is stress test message #%i, free: %i bytes\n",
2050 i,
2051 MAX_HWCB_ROOM - (hwcb->length + sizeof (mto_t)));
2052 }
2053
2054 #endif
2055
2056 return /*retval */ 0;
2057 }
2058
2059 signed int
2060 hwc_register_calls (hwc_high_level_calls_t * calls)
2061 {
2062 if (calls == NULL)
2063 return -EINVAL;
2064
2065 if (hwc_data.calls != NULL)
2066 return -EBUSY;
2067
2068 hwc_data.calls = calls;
2069 return 0;
2070 }
2071
2072 signed int
2073 hwc_unregister_calls (hwc_high_level_calls_t * calls)
2074 {
2075 if (hwc_data.calls == NULL)
2076 return -EINVAL;
2077
2078 if (calls != hwc_data.calls)
2079 return -EINVAL;
2080
2081 hwc_data.calls = NULL;
2082 return 0;
2083 }
2084
2085 int
2086 hwc_send (hwc_request_t * req)
2087 {
2088 unsigned long flags;
2089 int retval;
2090 int cc;
2091
2092 spin_lock_irqsave (&hwc_data.lock, flags);
2093 if (!req || !req->callback || !req->block) {
2094 retval = -EINVAL;
2095 goto unlock;
2096 }
2097 if (hwc_data.request) {
2098 retval = -ENOTSUPP;
2099 goto unlock;
2100 }
2101 hwc_data.request = req;
2102 cc = service_call (req->word, req->block);
2103 switch (cc) {
2104 case 0:
2105 hwc_data.current_servc = req->word;
2106 hwc_data.current_hwcb = req->block;
2107 retval = 0;
2108 break;
2109 case 2:
2110 retval = -EBUSY;
2111 break;
2112 default:
2113 retval = -ENOSYS;
2114
2115 }
2116 unlock:
2117 spin_unlock_irqrestore (&hwc_data.lock, flags);
2118 return retval;
2119 }
2120
2121 EXPORT_SYMBOL (hwc_send);
2122
2123 void
2124 do_hwc_callback (u32 ext_int_param)
2125 {
2126 if (!hwc_data.request || !hwc_data.request->callback)
2127 return;
2128 if ((ext_int_param & HWC_EXT_INT_PARAM_ADDR)
2129 != (unsigned long) hwc_data.request->block)
2130 return;
2131 hwc_data.request->callback (hwc_data.request);
2132 hwc_data.request = NULL;
2133 hwc_data.current_hwcb = NULL;
2134 hwc_data.current_servc = 0;
2135 }
2136
2137 void
2138 hwc_do_interrupt (u32 ext_int_param)
2139 {
2140 u32 finished_hwcb = ext_int_param & HWC_EXT_INT_PARAM_ADDR;
2141 u32 evbuf_pending = ext_int_param & HWC_EXT_INT_PARAM_PEND;
2142
2143 if (hwc_data.flags & HWC_PTIMER_RUNS) {
2144 del_timer (&hwc_data.poll_timer);
2145 hwc_data.flags &= ~HWC_PTIMER_RUNS;
2146 }
2147 if (finished_hwcb) {
2148
2149 if ((unsigned long) hwc_data.current_hwcb != finished_hwcb) {
2150 internal_print (
2151 DELAYED_WRITE,
2152 HWC_RW_PRINT_HEADER
2153 "interrupt: mismatch: "
2154 "ext. int param. (0x%x) vs. "
2155 "current HWCB (0x%x)\n",
2156 ext_int_param,
2157 hwc_data.current_hwcb);
2158 } else {
2159 if (hwc_data.request) {
2160
2161 do_hwc_callback (ext_int_param);
2162 } else {
2163
2164 switch (hwc_data.current_servc) {
2165
2166 case HWC_CMDW_WRITEMASK:
2167
2168 write_event_mask_2 (ext_int_param);
2169 break;
2170
2171 case HWC_CMDW_WRITEDATA:
2172
2173 write_event_data_2 (ext_int_param);
2174 break;
2175
2176 case HWC_CMDW_READDATA:
2177
2178 unconditional_read_2 (ext_int_param);
2179 break;
2180 default:
2181 }
2182 }
2183 }
2184 } else {
2185
2186 if (hwc_data.current_hwcb) {
2187 internal_print (
2188 DELAYED_WRITE,
2189 HWC_RW_PRINT_HEADER
2190 "interrupt: mismatch: "
2191 "ext. int. param. (0x%x) vs. "
2192 "current HWCB (0x%x)\n",
2193 ext_int_param,
2194 hwc_data.current_hwcb);
2195 }
2196 }
2197
2198 if (evbuf_pending) {
2199
2200 unconditional_read_1 ();
2201 } else {
2202
2203 write_event_data_1 ();
2204 }
2205
2206 if (!hwc_data.calls || !hwc_data.calls->wake_up)
2207 return;
2208 (hwc_data.calls->wake_up) ();
2209 }
2210
2211 void
2212 hwc_interrupt_handler (struct pt_regs *regs, __u16 code)
2213 {
2214 int cpu = smp_processor_id ();
2215
2216 u32 ext_int_param = hwc_ext_int_param ();
2217
2218 irq_enter (cpu, 0x2401);
2219
2220 if (hwc_data.flags & HWC_INIT) {
2221
2222 hwc_data.flags |= HWC_INTERRUPT;
2223 } else if (hwc_data.flags & HWC_BROKEN) {
2224
2225 if (!do_hwc_init ()) {
2226 hwc_data.flags &= ~HWC_BROKEN;
2227 internal_print (DELAYED_WRITE,
2228 HWC_RW_PRINT_HEADER
2229 "delayed HWC setup after"
2230 " temporary breakdown"
2231 " (ext. int. parameter=0x%x)\n",
2232 ext_int_param);
2233 }
2234 } else {
2235 spin_lock (&hwc_data.lock);
2236 hwc_do_interrupt (ext_int_param);
2237 spin_unlock (&hwc_data.lock);
2238 }
2239 irq_exit (cpu, 0x2401);
2240 }
2241
2242 void
2243 hwc_unblank (void)
2244 {
2245
2246 spin_lock (&hwc_data.lock);
2247 spin_unlock (&hwc_data.lock);
2248
2249 __ctl_store (cr0, 0, 0);
2250 cr0_save = cr0;
2251 cr0 |= 0x00000200;
2252 cr0 &= 0xFFFFF3AC;
2253 __ctl_load (cr0, 0, 0);
2254
2255 asm volatile ("STOSM %0,0x01":"=m" (psw_mask)::"memory");
2256
2257 while (ALL_HWCB_CHAR)
2258 barrier ();
2259
2260 asm volatile ("STNSM %0,0xFE":"=m" (psw_mask)::"memory");
2261
2262 __ctl_load (cr0_save, 0, 0);
2263 }
2264
2265 int
2266 hwc_ioctl (unsigned int cmd, unsigned long arg)
2267 {
2268 hwc_ioctls_t tmp = hwc_data.ioctls;
2269 int retval = 0;
2270 unsigned long flags;
2271 unsigned int obuf;
2272
2273 spin_lock_irqsave (&hwc_data.lock, flags);
2274
2275 switch (cmd) {
2276
2277 case TIOCHWCSHTAB:
2278 if (get_user (tmp.width_htab, (ioctl_htab_t *) arg))
2279 goto fault;
2280 break;
2281
2282 case TIOCHWCSECHO:
2283 if (get_user (tmp.echo, (ioctl_echo_t *) arg))
2284 goto fault;
2285 break;
2286
2287 case TIOCHWCSCOLS:
2288 if (get_user (tmp.columns, (ioctl_cols_t *) arg))
2289 goto fault;
2290 break;
2291
2292 case TIOCHWCSNL:
2293 if (get_user (tmp.final_nl, (ioctl_nl_t *) arg))
2294 goto fault;
2295 break;
2296
2297 case TIOCHWCSOBUF:
2298 if (get_user (obuf, (unsigned int *) arg))
2299 goto fault;
2300 if (obuf & 0xFFF)
2301 tmp.max_hwcb = (((obuf | 0xFFF) + 1) >> 12);
2302 else
2303 tmp.max_hwcb = (obuf >> 12);
2304 break;
2305
2306 case TIOCHWCSCASE:
2307 if (get_user (tmp.tolower, (ioctl_case_t *) arg))
2308 goto fault;
2309 break;
2310
2311 case TIOCHWCSDELIM:
2312 if (get_user (tmp.delim, (ioctl_delim_t *) arg))
2313 goto fault;
2314 break;
2315
2316 case TIOCHWCSINIT:
2317 retval = set_hwc_ioctls (&hwc_data.init_ioctls, 1);
2318 break;
2319
2320 case TIOCHWCGHTAB:
2321 if (put_user (tmp.width_htab, (ioctl_htab_t *) arg))
2322 goto fault;
2323 break;
2324
2325 case TIOCHWCGECHO:
2326 if (put_user (tmp.echo, (ioctl_echo_t *) arg))
2327 goto fault;
2328 break;
2329
2330 case TIOCHWCGCOLS:
2331 if (put_user (tmp.columns, (ioctl_cols_t *) arg))
2332 goto fault;
2333 break;
2334
2335 case TIOCHWCGNL:
2336 if (put_user (tmp.final_nl, (ioctl_nl_t *) arg))
2337 goto fault;
2338 break;
2339
2340 case TIOCHWCGOBUF:
2341 if (put_user (tmp.max_hwcb, (ioctl_obuf_t *) arg))
2342 goto fault;
2343 break;
2344
2345 case TIOCHWCGKBUF:
2346 if (put_user (tmp.kmem_hwcb, (ioctl_obuf_t *) arg))
2347 goto fault;
2348 break;
2349
2350 case TIOCHWCGCASE:
2351 if (put_user (tmp.tolower, (ioctl_case_t *) arg))
2352 goto fault;
2353 break;
2354
2355 case TIOCHWCGDELIM:
2356 if (put_user (tmp.delim, (ioctl_delim_t *) arg))
2357 goto fault;
2358 break;
2359 #if 0
2360
2361 case TIOCHWCGINIT:
2362 if (put_user (&hwc_data.init_ioctls, (hwc_ioctls_t *) arg))
2363 goto fault;
2364 break;
2365
2366 case TIOCHWCGCURR:
2367 if (put_user (&hwc_data.ioctls, (hwc_ioctls_t *) arg))
2368 goto fault;
2369 break;
2370 #endif
2371
2372 default:
2373 goto noioctlcmd;
2374 }
2375
2376 if (_IOC_DIR (cmd) == _IOC_WRITE)
2377 retval = set_hwc_ioctls (&tmp, 0);
2378
2379 goto out;
2380
2381 fault:
2382 retval = -EFAULT;
2383 goto out;
2384 noioctlcmd:
2385 retval = -ENOIOCTLCMD;
2386 out:
2387 spin_unlock_irqrestore (&hwc_data.lock, flags);
2388 return retval;
2389 }
2390