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/i386/i386/elan-mmcr.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  * ----------------------------------------------------------------------------
    3  * "THE BEER-WARE LICENSE" (Revision 42):
    4  * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
    5  * can do whatever you want with this stuff. If we meet some day, and you think
    6  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
    7  * ----------------------------------------------------------------------------
    8  *
    9  * $FreeBSD: releng/5.0/sys/i386/i386/elan-mmcr.c 103482 2002-09-17 11:47:38Z phk $
   10  *
   11  * The AMD Elan sc520 is a system-on-chip gadget which is used in embedded
   12  * kind of things, see www.soekris.com for instance, and it has a few quirks
   13  * we need to deal with.
   14  * Unfortunately we cannot identify the gadget by CPUID output because it
   15  * depends on strapping options and only the stepping field may be useful
   16  * and those are undocumented from AMDs side.
   17  *
   18  * So instead we recognize the on-chip host-PCI bridge and call back from
   19  * sys/i386/pci/pci_bus.c to here if we find it.
   20  */
   21 
   22 #include <sys/param.h>
   23 #include <sys/systm.h>
   24 #include <sys/kernel.h>
   25 #include <sys/conf.h>
   26 #include <sys/sysctl.h>
   27 #include <sys/timetc.h>
   28 #include <sys/proc.h>
   29 #include <sys/uio.h>
   30 #include <sys/lock.h>
   31 #include <sys/mutex.h>
   32 #include <sys/malloc.h>
   33 
   34 #include <machine/md_var.h>
   35 
   36 #include <vm/vm.h>
   37 #include <vm/pmap.h>
   38 
   39 uint16_t *elan_mmcr;
   40 
   41 /* Relating to the /dev/soekris-errled */
   42 static struct mtx errled_mtx;
   43 static char *errled;
   44 static struct callout_handle errled_h = CALLOUT_HANDLE_INITIALIZER(&errled_h);
   45 static void timeout_errled(void *);
   46 
   47 static unsigned
   48 elan_get_timecount(struct timecounter *tc)
   49 {
   50         return (elan_mmcr[0xc84 / 2]);
   51 }
   52 
   53 static struct timecounter elan_timecounter = {
   54         elan_get_timecount,
   55         0,
   56         0xffff,
   57         33333333 / 4,
   58         "ELAN"
   59 };
   60 
   61 void
   62 init_AMD_Elan_sc520(void)
   63 {
   64         u_int new;
   65         int i;
   66 
   67         if (bootverbose)
   68                 printf("Doing h0h0magic for AMD Elan sc520\n");
   69         elan_mmcr = pmap_mapdev(0xfffef000, 0x1000);
   70 
   71         /*-
   72          * The i8254 is driven with a nonstandard frequency which is
   73          * derived thusly:
   74          *   f = 32768 * 45 * 25 / 31 = 1189161.29...
   75          * We use the sysctl to get the timecounter etc into whack.
   76          */
   77         
   78         new = 1189161;
   79         i = kernel_sysctlbyname(&thread0, "machdep.i8254_freq", 
   80             NULL, 0, 
   81             &new, sizeof new, 
   82             NULL);
   83         if (bootverbose)
   84                 printf("sysctl machdep.i8254_freq=%d returns %d\n", new, i);
   85 
   86         /* Start GP timer #2 and use it as timecounter, hz permitting */
   87         elan_mmcr[0xc82 / 2] = 0xc001;
   88         tc_init(&elan_timecounter);
   89 }
   90 
   91 
   92 /*
   93  * Device driver initialization stuff
   94  */
   95 
   96 static d_write_t elan_write;
   97 static d_ioctl_t elan_ioctl;
   98 static d_mmap_t elan_mmap;
   99 
  100 #define ELAN_MMCR       0
  101 #define ELAN_ERRLED     1
  102 
  103 #define CDEV_MAJOR 100                  /* Share with xrpu */
  104 static struct cdevsw elan_cdevsw = {
  105         /* open */      nullopen,
  106         /* close */     nullclose,
  107         /* read */      noread,
  108         /* write */     elan_write,
  109         /* ioctl */     elan_ioctl,
  110         /* poll */      nopoll,
  111         /* mmap */      elan_mmap,
  112         /* strategy */  nostrategy,
  113         /* name */      "elan",
  114         /* maj */       CDEV_MAJOR,
  115         /* dump */      nodump,
  116         /* psize */     nopsize,
  117         /* flags */     0,
  118 };
  119 
  120 static void
  121 elan_drvinit(void)
  122 {
  123 
  124         if (elan_mmcr == NULL)
  125                 return;
  126         printf("Elan-mmcr driver: MMCR at %p\n", elan_mmcr);
  127         make_dev(&elan_cdevsw, ELAN_MMCR,
  128             UID_ROOT, GID_WHEEL, 0600, "elan-mmcr");
  129         make_dev(&elan_cdevsw, ELAN_ERRLED,
  130             UID_ROOT, GID_WHEEL, 0600, "soekris-errled");
  131         mtx_init(&errled_mtx, "Elan-errled", MTX_DEF, 0);
  132         return;
  133 }
  134 
  135 SYSINIT(elan, SI_SUB_PSEUDO, SI_ORDER_MIDDLE+CDEV_MAJOR,elan_drvinit,NULL);
  136 
  137 #define LED_ON()        do {elan_mmcr[0xc34 / 2] = 0x200;} while(0)
  138 #define LED_OFF()       do {elan_mmcr[0xc38 / 2] = 0x200;} while(0)
  139 
  140 static void
  141 timeout_errled(void *p)
  142 {
  143         static enum {NOTHING, FLASH, DIGIT} mode;
  144         static int count, cnt2, state;
  145 
  146         mtx_lock(&errled_mtx);
  147         if (p != NULL) {
  148                 mode = NOTHING;
  149                 /* Our instructions changed */
  150                 if (*errled == '1') {                   /* Turn LED on */
  151                         LED_ON();
  152                 } else if (*errled == '') {            /* Turn LED off */
  153                         LED_OFF();
  154                 } else if (*errled == 'f') {            /* Flash */
  155                         mode = FLASH;
  156                         cnt2 = 10;
  157                         if (errled[1] >= '1' && errled[1] <= '9')               
  158                                 cnt2 = errled[1] - '';
  159                         cnt2 = hz / cnt2;
  160                         LED_ON();
  161                         errled_h = timeout(timeout_errled, NULL, cnt2);
  162                 } else if (*errled == 'd') {            /* Digit */
  163                         mode = DIGIT;
  164                         count = 0;
  165                         cnt2 = 0;
  166                         state = 0;
  167                         LED_OFF();
  168                         errled_h = timeout(timeout_errled, NULL, hz/10);
  169                 }
  170         } else if (mode == FLASH) {
  171                 if (count) 
  172                         LED_ON();
  173                 else
  174                         LED_OFF();
  175                 count = !count;
  176                 errled_h = timeout(timeout_errled, NULL, cnt2);
  177         } else if (mode == DIGIT) {
  178                 if (cnt2 > 0) {
  179                         if (state) {
  180                                 LED_OFF();
  181                                 state = 0;
  182                                 cnt2--;
  183                         } else {
  184                                 LED_ON();
  185                                 state = 1;
  186                         }
  187                         errled_h = timeout(timeout_errled, NULL, hz/5);
  188                 } else {
  189                         do 
  190                                 count++;
  191                         while (errled[count] != '\0' &&
  192                             (errled[count] < '' || errled[count] > '9'));
  193                         if (errled[count] == '\0') {
  194                                 count = 0;
  195                                 errled_h = timeout(timeout_errled, NULL, hz * 2);
  196                         } else {
  197                                 cnt2 = errled[count] - '';
  198                                 state = 0;
  199                                 errled_h = timeout(timeout_errled, NULL, hz);
  200                         }
  201                 }
  202         }
  203         mtx_unlock(&errled_mtx);
  204         return;
  205 }
  206 
  207 /*
  208  * The write function is used for the error-LED.
  209  */
  210 
  211 static int
  212 elan_write(dev_t dev, struct uio *uio, int ioflag)
  213 {
  214         int error;
  215         char *s, *q;
  216 
  217         if (minor(dev) != ELAN_ERRLED)
  218                 return (EOPNOTSUPP);
  219 
  220         if (uio->uio_resid > 512)
  221                 return (EINVAL);
  222         s = malloc(uio->uio_resid + 1, M_DEVBUF, M_WAITOK);
  223         if (s == NULL)
  224                 return (ENOMEM);
  225         untimeout(timeout_errled, NULL, errled_h);
  226         s[uio->uio_resid] = '\0';
  227         error = uiomove(s, uio->uio_resid, uio);
  228         if (error) {
  229                 free(s, M_DEVBUF);
  230                 return (error);
  231         }
  232         mtx_lock(&errled_mtx);
  233         q = errled;
  234         errled = s;
  235         mtx_unlock(&errled_mtx);
  236         if (q != NULL)
  237                 free(q, M_DEVBUF);
  238         timeout_errled(errled);
  239 
  240         return(0);
  241 }
  242 
  243 static int
  244 elan_mmap(dev_t dev, vm_offset_t offset, int nprot)
  245 {
  246 
  247         if (minor(dev) != ELAN_MMCR)
  248                 return (EOPNOTSUPP);
  249         if (offset >= 0x1000) 
  250                 return (-1);
  251         return (i386_btop(0xfffef000));
  252 }
  253 
  254 static int
  255 elan_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct  thread *tdr)
  256 {
  257         return(ENOENT);
  258 }
  259 

Cache object: 891bc188a29888890558235e3764f948


[ 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.