The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ppbus/immio.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1998 Nicolas Souchu
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * $FreeBSD$
   27  *
   28  */
   29 
   30 /*
   31  * Iomega ZIP+ Matchmaker Parallel Port Interface driver
   32  *
   33  * Thanks to David Campbell work on the Linux driver and the Iomega specs
   34  * Thanks to Thiebault Moeglin for the drive
   35  */
   36 #ifdef KERNEL
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/malloc.h>
   40 #include <sys/buf.h>
   41 
   42 #include <machine/clock.h>
   43 
   44 #endif  /* KERNEL */
   45 
   46 #ifdef  KERNEL
   47 #include <sys/kernel.h>
   48 #endif /*KERNEL */
   49 
   50 #include "opt_vpo.h"
   51 
   52 #include <dev/ppbus/ppbconf.h>
   53 #include <dev/ppbus/ppb_msq.h>
   54 #include <dev/ppbus/vpoio.h>
   55 #include <dev/ppbus/ppb_1284.h>
   56 
   57 #define VP0_SELTMO              5000    /* select timeout */
   58 #define VP0_FAST_SPINTMO        500000  /* wait status timeout */
   59 #define VP0_LOW_SPINTMO         5000000 /* wait status timeout */
   60 
   61 #define VP0_SECTOR_SIZE 512
   62 
   63 /*
   64  * Microcode to execute very fast I/O sequences at the lowest bus level.
   65  */
   66 
   67 #define SELECT_TARGET           MS_PARAM(6, 1, MS_TYP_CHA)
   68 
   69 #define DECLARE_SELECT_MICROSEQUENCE                                    \
   70 struct ppb_microseq select_microseq[] = {                               \
   71         MS_CASS(0xc),                                                   \
   72         /* first, check there is nothing holding onto the bus */        \
   73         MS_SET(VP0_SELTMO),                                             \
   74 /* _loop: */                                                            \
   75         MS_BRCLEAR(0x8, 3 /* _ready */),                                \
   76         MS_DBRA(-1 /* _loop */),                                        \
   77         MS_RET(2),                      /* bus busy */                  \
   78 /* _ready: */                                                           \
   79         MS_CASS(0x4),                                                   \
   80         MS_DASS(MS_UNKNOWN /* 0x80 | 1 << target */),                   \
   81         MS_DELAY(1),                                                    \
   82         MS_CASS(0xc),                                                   \
   83         MS_CASS(0xd),                                                   \
   84         /* now, wait until the drive is ready */                        \
   85         MS_SET(VP0_SELTMO),                                             \
   86 /* loop: */                                                             \
   87         MS_BRSET(0x8, 4 /* ready */),                                   \
   88         MS_DBRA(-1 /* loop */),                                         \
   89 /* error: */                                                            \
   90         MS_CASS(0xc),                                                   \
   91         MS_RET(VP0_ESELECT_TIMEOUT),                                    \
   92 /* ready: */                                                            \
   93         MS_CASS(0xc),                                                   \
   94         MS_RET(0)                                                       \
   95 }
   96 
   97 static struct ppb_microseq transfer_epilog[] = {
   98         MS_CASS(0x4),
   99         MS_CASS(0xc),
  100         MS_CASS(0xe),
  101         MS_CASS(0x4),
  102         MS_RET(0)
  103 };
  104 
  105 #define CPP_S1          MS_PARAM(10, 2, MS_TYP_PTR)
  106 #define CPP_S2          MS_PARAM(13, 2, MS_TYP_PTR)
  107 #define CPP_S3          MS_PARAM(16, 2, MS_TYP_PTR)
  108 #define CPP_PARAM       MS_PARAM(17, 1, MS_TYP_CHA)
  109 
  110 #define DECLARE_CPP_MICROSEQ \
  111 struct ppb_microseq cpp_microseq[] = {                                  \
  112         MS_CASS(0x0c), MS_DELAY(2),                                     \
  113         MS_DASS(0xaa), MS_DELAY(10),                                    \
  114         MS_DASS(0x55), MS_DELAY(10),                                    \
  115         MS_DASS(0x00), MS_DELAY(10),                                    \
  116         MS_DASS(0xff), MS_DELAY(10),                                    \
  117         MS_RFETCH(MS_REG_STR, 0xb8, MS_UNKNOWN /* &s1 */),              \
  118         MS_DASS(0x87), MS_DELAY(10),                                    \
  119         MS_RFETCH(MS_REG_STR, 0xb8, MS_UNKNOWN /* &s2 */),              \
  120         MS_DASS(0x78), MS_DELAY(10),                                    \
  121         MS_RFETCH(MS_REG_STR, 0x38, MS_UNKNOWN /* &s3 */),              \
  122         MS_DASS(MS_UNKNOWN /* param */),                                \
  123         MS_DELAY(2),                                                    \
  124         MS_CASS(0x0c), MS_DELAY(10),                                    \
  125         MS_CASS(0x0d), MS_DELAY(2),                                     \
  126         MS_CASS(0x0c), MS_DELAY(10),                                    \
  127         MS_DASS(0xff), MS_DELAY(10),                                    \
  128         MS_RET(0)                                                       \
  129 }
  130 
  131 #define NEGOCIATED_MODE         MS_PARAM(2, 1, MS_TYP_CHA)
  132 
  133 #define DECLARE_NEGOCIATE_MICROSEQ \
  134 static struct ppb_microseq negociate_microseq[] = {                     \
  135         MS_CASS(0x4),                                                   \
  136         MS_DELAY(5),                                                    \
  137         MS_DASS(MS_UNKNOWN /* mode */),                                 \
  138         MS_DELAY(100),                                                  \
  139         MS_CASS(0x6),                                                   \
  140         MS_DELAY(5),                                                    \
  141         MS_BRSET(0x20, 6 /* continue */),                               \
  142         MS_DELAY(5),                                                    \
  143         MS_CASS(0x7),                                                   \
  144         MS_DELAY(5),                                                    \
  145         MS_CASS(0x6),                                                   \
  146         MS_RET(VP0_ENEGOCIATE),                                         \
  147 /* continue: */                                                         \
  148         MS_DELAY(5),                                                    \
  149         MS_CASS(0x7),                                                   \
  150         MS_DELAY(5),                                                    \
  151         MS_CASS(0x6),                                                   \
  152         MS_RET(0)                                                       \
  153 }
  154 
  155 static struct ppb_microseq reset_microseq[] = {
  156         MS_CASS(0x04),
  157         MS_DASS(0x40),
  158         MS_DELAY(1),
  159         MS_CASS(0x0c),
  160         MS_CASS(0x0d),
  161         MS_DELAY(50),
  162         MS_CASS(0x0c),
  163         MS_CASS(0x04),
  164         MS_RET(0)
  165 };
  166 
  167 /*
  168  * nibble_inbyte_hook()
  169  *
  170  * Formats high and low nibble into a character
  171  */
  172 static int
  173 nibble_inbyte_hook (void *p, char *ptr)
  174 {
  175         struct vpo_nibble *s = (struct vpo_nibble *)p;
  176 
  177         /* increment the buffer pointer */
  178         *ptr = ((s->l >> 4) & 0x0f) + (s->h & 0xf0);
  179 
  180         return (0);
  181 }
  182 
  183 /*
  184  * Macro used to initialize each vpoio_data structure during
  185  * low level attachment
  186  *
  187  * XXX should be converted to ppb_MS_init_msq()
  188  */
  189 #define INIT_NIBBLE_INBYTE_SUBMICROSEQ(vpo) {                   \
  190         (vpo)->vpo_nibble_inbyte_msq[6].arg[2].p =              \
  191                         (void *)&(vpo)->vpo_nibble.h;           \
  192         (vpo)->vpo_nibble_inbyte_msq[3].arg[2].p =              \
  193                         (void *)&(vpo)->vpo_nibble.l;           \
  194         (vpo)->vpo_nibble_inbyte_msq[9].arg[0].f =              \
  195                         nibble_inbyte_hook;                     \
  196         (vpo)->vpo_nibble_inbyte_msq[9].arg[1].p =              \
  197                         (void *)&(vpo)->vpo_nibble;             \
  198 }
  199 
  200 /*
  201  * This is the sub-microseqence for MS_GET in NIBBLE mode
  202  * Retrieve the two nibbles and call the C function to generate the character
  203  * and store it in the buffer (see nibble_inbyte_hook())
  204  */
  205 static struct ppb_microseq nibble_inbyte_submicroseq[] = {
  206           MS_CASS(0x4),
  207 
  208 /* loop: */
  209           MS_CASS(0x6),
  210           MS_DELAY(1),
  211           MS_RFETCH(MS_REG_STR, MS_FETCH_ALL, MS_UNKNOWN /* low nibble */),
  212           MS_CASS(0x5),
  213           MS_DELAY(1),
  214           MS_RFETCH(MS_REG_STR, MS_FETCH_ALL, MS_UNKNOWN /* high nibble */),
  215           MS_CASS(0x4),
  216           MS_DELAY(1),
  217 
  218           /* do a C call to format the received nibbles */
  219           MS_C_CALL(MS_UNKNOWN /* C hook */, MS_UNKNOWN /* param */),
  220           MS_DBRA(-6 /* loop */),
  221           MS_RET(0)
  222 };
  223 
  224 /*
  225  * This is the sub-microseqence for MS_GET in PS2 mode
  226  */
  227 static struct ppb_microseq ps2_inbyte_submicroseq[] = {
  228           MS_CASS(0x4),
  229 
  230 /* loop: */
  231           MS_CASS(PCD | 0x6),
  232           MS_RFETCH_P(1, MS_REG_DTR, MS_FETCH_ALL),
  233           MS_CASS(PCD | 0x5),
  234           MS_DBRA(-3 /* loop */),
  235 
  236           MS_RET(0)
  237 };
  238 
  239 /*
  240  * This is the sub-microsequence for MS_PUT in both NIBBLE and PS2 modes
  241  */
  242 static struct ppb_microseq spp_outbyte_submicroseq[] = {
  243           MS_CASS(0x4),
  244 
  245 /* loop: */
  246           MS_RASSERT_P(1, MS_REG_DTR), 
  247           MS_CASS(0x5),
  248           MS_DBRA(1),                           /* decrement counter */
  249           MS_RASSERT_P(1, MS_REG_DTR), 
  250           MS_CASS(0x0),
  251           MS_DBRA(-5 /* loop */),
  252 
  253           /* return from the put call */
  254           MS_CASS(0x4),
  255           MS_RET(0)
  256 };
  257 
  258 /* EPP 1.7 microsequences, ptr and len set at runtime */
  259 static struct ppb_microseq epp17_outstr[] = {
  260           MS_CASS(0x4),
  261           MS_RASSERT_P(MS_ACCUM, MS_REG_EPP), 
  262           MS_CASS(0xc),
  263           MS_RET(0),
  264 };
  265 
  266 static struct ppb_microseq epp17_instr[] = {
  267           MS_CASS(PCD | 0x4),
  268           MS_RFETCH_P(MS_ACCUM, MS_REG_EPP, MS_FETCH_ALL), 
  269           MS_CASS(PCD | 0xc),
  270           MS_RET(0),
  271 };
  272 
  273 static int
  274 imm_disconnect(struct vpoio_data *vpo, int *connected, int release_bus)
  275 {
  276         DECLARE_CPP_MICROSEQ;
  277 
  278         char s1, s2, s3;
  279         int ret;
  280 
  281         /* all should be ok */
  282         if (connected)
  283                 *connected = 0;
  284 
  285         ppb_MS_init_msq(cpp_microseq, 4, CPP_S1, (void *)&s1,
  286                         CPP_S2, (void *)&s2, CPP_S3, (void *)&s3,
  287                         CPP_PARAM, 0x30);
  288 
  289         ppb_MS_microseq(&vpo->vpo_dev, cpp_microseq, &ret);
  290 
  291         if ((s1 != (char)0xb8 || s2 != (char)0x18 || s3 != (char)0x38)) {
  292                 if (bootverbose)
  293                         printf("imm%d: (disconnect) s1=0x%x s2=0x%x, s3=0x%x\n",
  294                                 vpo->vpo_unit, s1 & 0xff, s2 & 0xff, s3 & 0xff);
  295                 if (connected)
  296                         *connected = VP0_ECONNECT;
  297         }
  298 
  299         if (release_bus)
  300                 return (ppb_release_bus(&vpo->vpo_dev));
  301         else
  302                 return (0);
  303 }
  304 
  305 /*
  306  * how  : PPB_WAIT or PPB_DONTWAIT
  307  */
  308 static int
  309 imm_connect(struct vpoio_data *vpo, int how, int *disconnected, int request_bus)
  310 {
  311         DECLARE_CPP_MICROSEQ;
  312 
  313         char s1, s2, s3;
  314         int error;
  315         int ret;
  316 
  317         /* all should be ok */
  318         if (disconnected)
  319                 *disconnected = 0;
  320 
  321         if (request_bus)
  322                 if ((error = ppb_request_bus(&vpo->vpo_dev, how)))
  323                         return (error);
  324 
  325         ppb_MS_init_msq(cpp_microseq, 3, CPP_S1, (void *)&s1,
  326                         CPP_S2, (void *)&s2, CPP_S3, (void *)&s3);
  327 
  328         /* select device 0 in compatible mode */
  329         ppb_MS_init_msq(cpp_microseq, 1, CPP_PARAM, 0xe0);
  330         ppb_MS_microseq(&vpo->vpo_dev, cpp_microseq, &ret);
  331 
  332         /* disconnect all devices */
  333         ppb_MS_init_msq(cpp_microseq, 1, CPP_PARAM, 0x30);
  334         ppb_MS_microseq(&vpo->vpo_dev, cpp_microseq, &ret);
  335 
  336         if (PPB_IN_EPP_MODE(&vpo->vpo_dev))
  337                 ppb_MS_init_msq(cpp_microseq, 1, CPP_PARAM, 0x28);
  338         else
  339                 ppb_MS_init_msq(cpp_microseq, 1, CPP_PARAM, 0xe0);
  340 
  341         ppb_MS_microseq(&vpo->vpo_dev, cpp_microseq, &ret);
  342 
  343         if ((s1 != (char)0xb8 || s2 != (char)0x18 || s3 != (char)0x30)) {
  344                 if (bootverbose)
  345                         printf("imm%d: (connect) s1=0x%x s2=0x%x, s3=0x%x\n",
  346                                 vpo->vpo_unit, s1 & 0xff, s2 & 0xff, s3 & 0xff);
  347                 if (disconnected)
  348                         *disconnected = VP0_ECONNECT;
  349         }
  350 
  351         return (0);
  352 }
  353 
  354 /*
  355  * imm_detect()
  356  *
  357  * Detect and initialise the VP0 adapter.
  358  */
  359 static int
  360 imm_detect(struct vpoio_data *vpo)
  361 {
  362         int error;
  363 
  364         if ((error = ppb_request_bus(&vpo->vpo_dev, PPB_DONTWAIT)))
  365                 return (error);
  366 
  367         /* disconnect the drive, keep the bus */
  368         imm_disconnect(vpo, NULL, 0);
  369 
  370         /* we already have the bus, just connect */
  371         imm_connect(vpo, PPB_DONTWAIT, &error, 0);
  372 
  373         if (error) {
  374                 if (bootverbose)
  375                         printf("imm%d: can't connect to the drive\n",
  376                                 vpo->vpo_unit);
  377                 goto error;
  378         }
  379 
  380         /* send SCSI reset signal */
  381         ppb_MS_microseq(&vpo->vpo_dev, reset_microseq, NULL);
  382 
  383         /* release the bus now */
  384         imm_disconnect(vpo, &error, 1);
  385 
  386         /* ensure we are disconnected or daisy chained peripheral 
  387          * may cause serious problem to the disk */
  388 
  389         if (error) {
  390                 if (bootverbose)
  391                         printf("imm%d: can't disconnect from the drive\n",
  392                                 vpo->vpo_unit);
  393                 goto error;
  394         }
  395 
  396         return (0);
  397 
  398 error:
  399         ppb_release_bus(&vpo->vpo_dev);
  400         return (VP0_EINITFAILED);
  401 }
  402 
  403 /*
  404  * imm_outstr()
  405  */
  406 static int
  407 imm_outstr(struct vpoio_data *vpo, char *buffer, int size)
  408 {
  409         int error = 0;
  410 
  411         if (PPB_IN_EPP_MODE(&vpo->vpo_dev))
  412                 ppb_reset_epp_timeout(&vpo->vpo_dev);
  413 
  414         ppb_MS_exec(&vpo->vpo_dev, MS_OP_PUT, buffer, size, MS_UNKNOWN, &error);
  415 
  416         return (error);
  417 }
  418 
  419 /*
  420  * imm_instr()
  421  */
  422 static int
  423 imm_instr(struct vpoio_data *vpo, char *buffer, int size)
  424 {
  425         int error = 0;
  426 
  427         if (PPB_IN_EPP_MODE(&vpo->vpo_dev))
  428                 ppb_reset_epp_timeout(&vpo->vpo_dev);
  429 
  430         ppb_MS_exec(&vpo->vpo_dev, MS_OP_GET, buffer, size, MS_UNKNOWN, &error);
  431 
  432         return (error);
  433 }
  434 
  435 static char
  436 imm_select(struct vpoio_data *vpo, int initiator, int target)
  437 {
  438         DECLARE_SELECT_MICROSEQUENCE;
  439         int ret;
  440 
  441         /* initialize the select microsequence */
  442         ppb_MS_init_msq(select_microseq, 1,
  443                         SELECT_TARGET, 1 << initiator | 1 << target);
  444                                 
  445         ppb_MS_microseq(&vpo->vpo_dev, select_microseq, &ret);
  446 
  447         return (ret);
  448 }
  449 
  450 /*
  451  * imm_wait()
  452  *
  453  * H_SELIN must be low.
  454  *
  455  * XXX should be ported to microseq
  456  */
  457 static char
  458 imm_wait(struct vpoio_data *vpo, int tmo)
  459 {
  460 
  461         register int    k;
  462         register char   r;
  463 
  464         ppb_wctr(&vpo->vpo_dev, 0xc);
  465 
  466         /* XXX should be ported to microseq */
  467         k = 0;
  468         while (!((r = ppb_rstr(&vpo->vpo_dev)) & 0x80) && (k++ < tmo))
  469                 DELAY(1);
  470 
  471         /*
  472          * Return some status information.
  473          * Semantics :  0x88 = ZIP+ wants more data
  474          *              0x98 = ZIP+ wants to send more data
  475          *              0xa8 = ZIP+ wants command
  476          *              0xb8 = end of transfer, ZIP+ is sending status
  477          */
  478         ppb_wctr(&vpo->vpo_dev, 0x4);
  479         if (k < tmo)
  480           return (r & 0xb8);
  481 
  482         return (0);                        /* command timed out */      
  483 }
  484 
  485 static int
  486 imm_negociate(struct vpoio_data *vpo)
  487 {
  488         DECLARE_NEGOCIATE_MICROSEQ;
  489         int negociate_mode;
  490         int ret;
  491 
  492         if (PPB_IN_NIBBLE_MODE(&vpo->vpo_dev))
  493                 negociate_mode = 0;
  494         else if (PPB_IN_PS2_MODE(&vpo->vpo_dev))
  495                 negociate_mode = 1;
  496         else
  497                 return (0);
  498 
  499 #if 0 /* XXX use standalone code not to depend on ppb_1284 code yet */
  500         ret = ppb_1284_negociate(&vpo->vpo_dev, negociate_mode);
  501 
  502         if (ret)
  503                 return (VP0_ENEGOCIATE);
  504 #endif
  505         
  506         ppb_MS_init_msq(negociate_microseq, 1, NEGOCIATED_MODE, negociate_mode);
  507 
  508         ppb_MS_microseq(&vpo->vpo_dev, negociate_microseq, &ret);
  509 
  510         return (ret);
  511 }
  512 
  513 /*
  514  * imm_probe()
  515  *
  516  * Low level probe of vpo device
  517  *
  518  */
  519 struct ppb_device *
  520 imm_probe(struct ppb_data *ppb, struct vpoio_data *vpo)
  521 {
  522 
  523         /* ppbus dependent initialisation */
  524         vpo->vpo_dev.id_unit = vpo->vpo_unit;
  525         vpo->vpo_dev.name = "vpo";
  526         vpo->vpo_dev.ppb = ppb;
  527 
  528         /* now, try to initialise the drive */
  529         if (imm_detect(vpo)) {
  530                 return (NULL);
  531         }
  532 
  533         return (&vpo->vpo_dev);
  534 }
  535 
  536 /*
  537  * imm_attach()
  538  *
  539  * Low level attachment of vpo device
  540  *
  541  */
  542 int
  543 imm_attach(struct vpoio_data *vpo)
  544 {
  545         int epp;
  546 
  547         /*
  548          * Report ourselves
  549          */
  550         printf("imm%d: <Iomega Matchmaker Parallel to SCSI interface> on ppbus %d\n",
  551                 vpo->vpo_dev.id_unit, vpo->vpo_dev.ppb->ppb_link->adapter_unit);
  552 
  553         /*
  554          * Initialize microsequence code
  555          */
  556         vpo->vpo_nibble_inbyte_msq = (struct ppb_microseq *)malloc(
  557                 sizeof(nibble_inbyte_submicroseq), M_DEVBUF, M_NOWAIT);
  558 
  559         if (!vpo->vpo_nibble_inbyte_msq)
  560                 return (0);
  561 
  562         bcopy((void *)nibble_inbyte_submicroseq,
  563                 (void *)vpo->vpo_nibble_inbyte_msq,
  564                 sizeof(nibble_inbyte_submicroseq));
  565 
  566         INIT_NIBBLE_INBYTE_SUBMICROSEQ(vpo);
  567 
  568         /*
  569          * Initialize mode dependent in/out microsequences
  570          */
  571         ppb_request_bus(&vpo->vpo_dev, PPB_WAIT);
  572 
  573         /* enter NIBBLE mode to configure submsq */
  574         if (ppb_set_mode(&vpo->vpo_dev, PPB_NIBBLE) != -1) {
  575 
  576                 ppb_MS_GET_init(&vpo->vpo_dev, vpo->vpo_nibble_inbyte_msq);
  577                 ppb_MS_PUT_init(&vpo->vpo_dev, spp_outbyte_submicroseq);
  578         }
  579 
  580         /* enter PS2 mode to configure submsq */
  581         if (ppb_set_mode(&vpo->vpo_dev, PPB_PS2) != -1) {
  582 
  583                 ppb_MS_GET_init(&vpo->vpo_dev, ps2_inbyte_submicroseq);
  584                 ppb_MS_PUT_init(&vpo->vpo_dev, spp_outbyte_submicroseq);
  585         }
  586 
  587         epp = ppb_get_epp_protocol(&vpo->vpo_dev);
  588 
  589         /* enter EPP mode to configure submsq */
  590         if (ppb_set_mode(&vpo->vpo_dev, PPB_EPP) != -1) {
  591 
  592                 switch (epp) {
  593                 case EPP_1_9:
  594                 case EPP_1_7:
  595                         ppb_MS_GET_init(&vpo->vpo_dev, epp17_instr);
  596                         ppb_MS_PUT_init(&vpo->vpo_dev, epp17_outstr);
  597                         break;
  598                 default:
  599                         panic("%s: unknown EPP protocol (0x%x)", __FUNCTION__,
  600                                 epp);
  601                 }
  602         }
  603 
  604         /* try to enter EPP or PS/2 mode, NIBBLE otherwise */
  605         if (ppb_set_mode(&vpo->vpo_dev, PPB_EPP) != -1) {
  606                 switch (epp) {
  607                 case EPP_1_9:
  608                         printf("imm%d: EPP 1.9 mode\n", vpo->vpo_unit);
  609                         break;
  610                 case EPP_1_7:
  611                         printf("imm%d: EPP 1.7 mode\n", vpo->vpo_unit);
  612                         break;
  613                 default:
  614                         panic("%s: unknown EPP protocol (0x%x)", __FUNCTION__,
  615                                 epp);
  616                 }
  617         } else if (ppb_set_mode(&vpo->vpo_dev, PPB_PS2) != -1)
  618                 printf("imm%d: PS2 mode\n", vpo->vpo_unit);
  619 
  620         else if (ppb_set_mode(&vpo->vpo_dev, PPB_NIBBLE) != -1)
  621                 printf("imm%d: NIBBLE mode\n", vpo->vpo_unit);
  622 
  623         else {
  624                 printf("imm%d: can't enter NIBBLE, PS2 or EPP mode\n",
  625                         vpo->vpo_unit);
  626 
  627                 ppb_release_bus(&vpo->vpo_dev);
  628 
  629                 free(vpo->vpo_nibble_inbyte_msq, M_DEVBUF);
  630                 return (0);
  631         }
  632 
  633         ppb_release_bus(&vpo->vpo_dev);
  634 
  635         return (1);
  636 }
  637 
  638 /*
  639  * imm_reset_bus()
  640  *
  641  */
  642 int
  643 imm_reset_bus(struct vpoio_data *vpo)
  644 {
  645         int disconnected;
  646 
  647         /* first, connect to the drive and request the bus */
  648         imm_connect(vpo, PPB_WAIT|PPB_INTR, &disconnected, 1);
  649 
  650         if (!disconnected) {
  651 
  652                 /* reset the SCSI bus */
  653                 ppb_MS_microseq(&vpo->vpo_dev, reset_microseq, NULL);
  654 
  655                 /* then disconnect */
  656                 imm_disconnect(vpo, NULL, 1);
  657         }
  658 
  659         return (0);
  660 }
  661 
  662 /*
  663  * imm_do_scsi()
  664  *
  665  * Send an SCSI command
  666  *
  667  */
  668 int 
  669 imm_do_scsi(struct vpoio_data *vpo, int host, int target, char *command,
  670                 int clen, char *buffer, int blen, int *result, int *count,
  671                 int *ret)
  672 {
  673 
  674         register char r;
  675         char l, h = 0;
  676         int len, error = 0, not_connected = 0;
  677         register int k;
  678         int negociated = 0;
  679 
  680         /*
  681          * enter disk state, allocate the ppbus
  682          *
  683          * XXX
  684          * Should we allow this call to be interruptible?
  685          * The only way to report the interruption is to return
  686          * EIO do upper SCSI code :^(
  687          */
  688         if ((error = imm_connect(vpo, PPB_WAIT|PPB_INTR, &not_connected, 1)))
  689                 return (error);
  690 
  691         if (not_connected) {
  692                 *ret = VP0_ECONNECT; goto error;
  693         }
  694 
  695         /*
  696          * Select the drive ...
  697          */
  698         if ((*ret = imm_select(vpo,host,target)))
  699                 goto error;
  700 
  701         /*
  702          * Send the command ...
  703          */
  704         for (k = 0; k < clen; k+=2) {
  705                 if (imm_wait(vpo, VP0_FAST_SPINTMO) != (char)0xa8) {
  706                         *ret = VP0_ECMD_TIMEOUT;
  707                         goto error;
  708                 }
  709                 if (imm_outstr(vpo, &command[k], 2)) {
  710                         *ret = VP0_EPPDATA_TIMEOUT;
  711                         goto error;
  712                 }
  713         }
  714 
  715         if (!(r = imm_wait(vpo, VP0_LOW_SPINTMO))) {
  716                 *ret = VP0_ESTATUS_TIMEOUT; goto error;
  717         }
  718 
  719         if ((r & 0x30) == 0x10) {
  720                 if (imm_negociate(vpo)) {
  721                         *ret = VP0_ENEGOCIATE;
  722                         goto error;
  723                 } else
  724                         negociated = 1;
  725         }
  726 
  727         /* 
  728          * Complete transfer ... 
  729          */
  730         *count = 0;
  731         for (;;) {
  732 
  733                 if (!(r = imm_wait(vpo, VP0_LOW_SPINTMO))) {
  734                         *ret = VP0_ESTATUS_TIMEOUT; goto error;
  735                 }
  736 
  737                 /* stop when the ZIP+ wants to send status */
  738                 if (r == (char)0xb8)
  739                         break;
  740 
  741                 if (*count >= blen) {
  742                         *ret = VP0_EDATA_OVERFLOW;
  743                         goto error;
  744                 }
  745 
  746                 /* ZIP+ wants to send data? */
  747                 if (r == (char)0x88) {
  748                         len = (((blen - *count) >= VP0_SECTOR_SIZE)) ?
  749                                 VP0_SECTOR_SIZE : 2;
  750 
  751                         error = imm_outstr(vpo, &buffer[*count], len);
  752                 } else {
  753                         if (!PPB_IN_EPP_MODE(&vpo->vpo_dev))
  754                                 len = 1;
  755                         else
  756                                 len = (((blen - *count) >= VP0_SECTOR_SIZE)) ?
  757                                         VP0_SECTOR_SIZE : 1;
  758 
  759                         error = imm_instr(vpo, &buffer[*count], len);
  760                 }
  761 
  762                 if (error) {
  763                         *ret = error;
  764                         goto error;
  765                 }
  766 
  767                 *count += len;
  768         }
  769 
  770         if ((PPB_IN_NIBBLE_MODE(&vpo->vpo_dev) ||
  771                         PPB_IN_PS2_MODE(&vpo->vpo_dev)) && negociated)
  772                 ppb_MS_microseq(&vpo->vpo_dev, transfer_epilog, NULL);
  773 
  774         /*
  775          * Retrieve status ...
  776          */
  777         if (imm_negociate(vpo)) {
  778                 *ret = VP0_ENEGOCIATE;
  779                 goto error;
  780         } else
  781                 negociated = 1;
  782 
  783         if (imm_instr(vpo, &l, 1)) {
  784                 *ret = VP0_EOTHER; goto error;
  785         }
  786 
  787         /* check if the ZIP+ wants to send more status */
  788         if (imm_wait(vpo, VP0_FAST_SPINTMO) == (char)0xb8)
  789                 if (imm_instr(vpo, &h, 1)) {
  790                         *ret = VP0_EOTHER+2; goto error;
  791                 }
  792 
  793         *result = ((int) h << 8) | ((int) l & 0xff);
  794 
  795 error:
  796         if ((PPB_IN_NIBBLE_MODE(&vpo->vpo_dev) ||
  797                         PPB_IN_PS2_MODE(&vpo->vpo_dev)) && negociated)
  798                 ppb_MS_microseq(&vpo->vpo_dev, transfer_epilog, NULL);
  799 
  800         /* return to printer state, release the ppbus */
  801         imm_disconnect(vpo, NULL, 1);
  802 
  803         return (0);
  804 }

Cache object: e8ed1002345819b5b94b920d16fbbacf


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.