1101214Smarkm#!/bin/sh 268506Sjulian# This writes a skeleton driver and puts it into the kernel tree for you. 368506Sjulian# It also adds FOO and files.FOO configuration files so you can compile 468506Sjulian# a kernel with your FOO driver linked in. 568506Sjulian# To do so: 675517Sbrian# cd /usr/src; make buildkernel KERNCONF=FOO 722195Sjulian# 868506Sjulian# More interestingly, it creates a modules/foo directory 968506Sjulian# which it populates, to allow you to compile a FOO module 1075517Sbrian# which can be linked with your presently running kernel (if you feel brave). 1168506Sjulian# To do so: 1268506Sjulian# cd /sys/modules/foo; make depend; make; make install; kldload foo 1332468Sjulian# 14101214Smarkm# arg1 to this script is expected to be lowercase "foo" 15161023Srik# arg2 path to the kernel sources, "/sys" if omitted 1668506Sjulian# 1722195Sjulian# Trust me, RUN THIS SCRIPT :) 1868506Sjulian# 1970165Simp# TODO: 2070165Simp# o generate foo_isa.c, foo_pci.c, foo_pccard.c, foo_cardbus.c, and foovar.h 2170165Simp# o Put pccard stuff in here. 2270165Simp# 2367505Sjulian# $FreeBSD$" 2422195Sjulian# 2568606Sjulian# 26120708Sddsif [ "X${1}" = "X" ]; then 27120708Sdds echo "Hey, how about some help here... give me a device name!" 2822195Sjulian exit 1 2922195Sjulianfi 30161023Srikif [ "X${2}" = "X" ]; then 31161023Srik TOP=`cd /sys; pwd -P` 32161023Srik echo "Using ${TOP} as the path to the kernel sources!" 33161023Srikelse 34161023Srik TOP=${2} 35161023Srikfi 36101214SmarkmUPPER=`echo ${1} |tr "[:lower:]" "[:upper:]"` 3722195Sjulian 3867657SjulianRCS_KEYWORD=FreeBSD 3967657Sjulian 40120708Sddsif [ -d ${TOP}/modules/${1} ]; then 4168506Sjulian echo "There appears to already be a module called ${1}" 4268506Sjulian echo -n "Should it be overwritten? [Y]" 4368506Sjulian read VAL 44120708Sdds if [ "-z" "$VAL" ]; then 45120708Sdds VAL=YES 4668506Sjulian fi 47101214Smarkm case ${VAL} in 4868506Sjulian [yY]*) 49120708Sdds echo "Cleaning up from prior runs" 50120708Sdds rm -rf ${TOP}/dev/${1} 51120708Sdds rm -rf ${TOP}/modules/${1} 52161023Srik rm ${TOP}/conf/files.${UPPER} 53120708Sdds rm ${TOP}/i386/conf/${UPPER} 54120708Sdds rm ${TOP}/sys/${1}io.h 55120708Sdds ;; 5668506Sjulian *) 57120708Sdds exit 1 58120708Sdds ;; 5968506Sjulian esac 6068506Sjulianfi 6168506Sjulian 6268506Sjulianecho "The following files will be created:" 6367505Sjulianecho ${TOP}/modules/${1} 64161023Srikecho ${TOP}/conf/files.${UPPER} 6567505Sjulianecho ${TOP}/i386/conf/${UPPER} 6667505Sjulianecho ${TOP}/dev/${1} 6767505Sjulianecho ${TOP}/dev/${1}/${1}.c 6867505Sjulianecho ${TOP}/sys/${1}io.h 6967505Sjulianecho ${TOP}/modules/${1} 7067505Sjulianecho ${TOP}/modules/${1}/Makefile 7167505Sjulian 7267505Sjulian mkdir ${TOP}/modules/${1} 7332468Sjulian 7467505Sjulian####################################################################### 7567505Sjulian####################################################################### 7667505Sjulian# 7767505Sjulian# Create configuration information needed to create a kernel 7867505Sjulian# containing this driver. 7967505Sjulian# 8067505Sjulian# Not really needed if we are going to do this as a module. 8167505Sjulian####################################################################### 8267505Sjulian# First add the file to a local file list. 8367505Sjulian####################################################################### 8467505Sjulian 85161023Srikcat >${TOP}/conf/files.${UPPER} <<DONE 8667653Sjuliandev/${1}/${1}.c optional ${1} 8722195SjulianDONE 8822195Sjulian 8967505Sjulian####################################################################### 9067505Sjulian# Then create a configuration file for a kernel that contains this driver. 9167505Sjulian####################################################################### 9267505Sjuliancat >${TOP}/i386/conf/${UPPER} <<DONE 9322195Sjulian# Configuration file for kernel type: ${UPPER} 94101214Smarkm# \$${RCS_KEYWORD}$ 95161023Srik 96161118Srikfiles "${TOP}/conf/files.${UPPER}" 97161118Srik 98161023Srikinclude GENERIC 99161023Srik 100161023Srikident ${UPPER} 101161023Srik 10222195SjulianDONE 10322195Sjulian 10467505Sjuliancat >>${TOP}/i386/conf/${UPPER} <<DONE 105161118Srik# trust me, you'll need this 106161118Srikoptions KDB 107161118Srikoptions DDB 10867653Sjuliandevice ${1} 10922195SjulianDONE 11022195Sjulian 111120708Sddsif [ ! -d ${TOP}/dev/${1} ]; then 11267505Sjulian mkdir -p ${TOP}/dev/${1} 11367505Sjulianfi 11467505Sjulian 11567505Sjuliancat >${TOP}/dev/${1}/${1}.c <<DONE 11622195Sjulian/* 11767657Sjulian * Copyright (c) [year] [your name] 11867657Sjulian * All rights reserved. 11922195Sjulian * 12067657Sjulian * Redistribution and use in source and binary forms, with or without 12167657Sjulian * modification, are permitted provided that the following conditions 12267657Sjulian * are met: 12367657Sjulian * 1. Redistributions of source code must retain the above copyright 12467657Sjulian * notice, this list of conditions and the following disclaimer. 12567657Sjulian * 2. Redistributions in binary form must reproduce the above copyright 12667657Sjulian * notice, this list of conditions and the following disclaimer in the 12767657Sjulian * documentation and/or other materials provided with the distribution. 12867657Sjulian * 12967657Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 13067657Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 13167657Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 13267657Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 13367657Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 13467657Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 13567657Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 13667657Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 13767657Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 13867657Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 13967657Sjulian * SUCH DAMAGE. 14022195Sjulian */ 14122195Sjulian 14268533Sjulian/* 14368533Sjulian * http://www.daemonnews.org/200008/isa.html is required reading. 14468533Sjulian * hopefully it will make it's way into the handbook. 14568533Sjulian */ 14622195Sjulian 147101214Smarkm#include <sys/cdefs.h> 148101214Smarkm__FBSDID("\$${RCS_KEYWORD}$"); 149101214Smarkm 15022195Sjulian#include <sys/param.h> 15122195Sjulian#include <sys/systm.h> 15267505Sjulian#include <sys/conf.h> /* cdevsw stuff */ 15322195Sjulian#include <sys/kernel.h> /* SYSINIT stuff */ 15467505Sjulian#include <sys/uio.h> /* SYSINIT stuff */ 15522195Sjulian#include <sys/malloc.h> /* malloc region definitions */ 15667505Sjulian#include <sys/module.h> 15767505Sjulian#include <sys/bus.h> 15886327Sarr#include <sys/proc.h> 159101214Smarkm#include <sys/time.h> 160101214Smarkm#include <sys/${1}io.h> /* ${1} IOCTL definitions */ 161101214Smarkm 16267505Sjulian#include <machine/bus.h> 16367505Sjulian#include <machine/resource.h> 164120707Sdds#include <sys/rman.h> 16567505Sjulian 166120707Sdds#include <dev/pci/pcireg.h> 167120707Sdds#include <dev/pci/pcivar.h> 16868606Sjulian 16967505Sjulian#include <isa/isavar.h> 170101214Smarkm 17167505Sjulian#include "isa_if.h" 17222195Sjulian 173120708Sdds/* XXX These should be defined in terms of bus-space ops. */ 17468506Sjulian#define ${UPPER}_INB(port) inb(port_start) 17568506Sjulian#define ${UPPER}_OUTB(port, val) ( port_start, (val)) 17667505Sjulian#define SOME_PORT 123 17767505Sjulian#define EXPECTED_VALUE 0x42 17822195Sjulian 17975517Sbrian/* 18075517Sbrian * The softc is automatically allocated by the parent bus using the 181120708Sdds * size specified in the driver_t declaration below. 18275517Sbrian */ 18370165Simp#define DEV2SOFTC(dev) ((struct ${1}_softc *) (dev)->si_drv1) 18470165Simp#define DEVICE2SOFTC(dev) ((struct ${1}_softc *) device_get_softc(dev)) 18570165Simp 186101214Smarkm/* 187120708Sdds * Device specific misc defines. 18868606Sjulian */ 18968606Sjulian#define BUFFERSIZE 1024 19068606Sjulian#define NUMPORTS 4 191120708Sdds#define MEMSIZE (4 * 1024) /* Imaginable h/w buffer size. */ 19222195Sjulian 19368606Sjulian/* 194120708Sdds * One of these per allocated device. 19568606Sjulian */ 19668606Sjulianstruct ${1}_softc { 19768606Sjulian bus_space_tag_t bt; 19868606Sjulian bus_space_handle_t bh; 19968606Sjulian int rid_ioport; 20068606Sjulian int rid_memory; 20168606Sjulian int rid_irq; 20268606Sjulian int rid_drq; 203120708Sdds struct resource* res_ioport; /* Resource for port range. */ 204120708Sdds struct resource* res_memory; /* Resource for mem range. */ 205120708Sdds struct resource* res_irq; /* Resource for irq range. */ 206120708Sdds struct resource* res_drq; /* Resource for dma channel. */ 20768606Sjulian device_t device; 208161022Srik struct cdev *dev; 20968606Sjulian void *intr_cookie; 210120708Sdds void *vaddr; /* Virtual address of mem resource. */ 211120708Sdds char buffer[BUFFERSIZE]; /* If we need to buffer something. */ 212101214Smarkm}; 21368606Sjulian 214120708Sdds/* Function prototypes (these should all be static). */ 21567653Sjulianstatic int ${1}_deallocate_resources(device_t device); 21667653Sjulianstatic int ${1}_allocate_resources(device_t device); 21770165Simpstatic int ${1}_attach(device_t device, struct ${1}_softc *scp); 21870165Simpstatic int ${1}_detach(device_t device, struct ${1}_softc *scp); 21967505Sjulian 22067505Sjulianstatic d_open_t ${1}open; 22167505Sjulianstatic d_close_t ${1}close; 22267505Sjulianstatic d_read_t ${1}read; 22367505Sjulianstatic d_write_t ${1}write; 22467505Sjulianstatic d_ioctl_t ${1}ioctl; 22567505Sjulianstatic d_mmap_t ${1}mmap; 22667505Sjulianstatic d_poll_t ${1}poll; 22767568Sjulianstatic void ${1}intr(void *arg); 228101214Smarkm 22922195Sjulianstatic struct cdevsw ${1}_cdevsw = { 230161022Srik .d_version = D_VERSION, 231120707Sdds .d_open = ${1}open, 232120707Sdds .d_close = ${1}close, 233120707Sdds .d_read = ${1}read, 234120707Sdds .d_write = ${1}write, 235120707Sdds .d_ioctl = ${1}ioctl, 236120707Sdds .d_poll = ${1}poll, 237120707Sdds .d_mmap = ${1}mmap, 238120707Sdds .d_name = "${1}", 23967505Sjulian}; 24068630Sjulian 24168630Sjulianstatic devclass_t ${1}_devclass; 242101214Smarkm 24370165Simp/* 244120708Sdds ****************************************** 245120708Sdds * ISA Attachment structures and functions. 246120708Sdds ****************************************** 24770165Simp */ 24868606Sjulianstatic void ${1}_isa_identify (driver_t *, device_t); 24968606Sjulianstatic int ${1}_isa_probe (device_t); 25068606Sjulianstatic int ${1}_isa_attach (device_t); 25168606Sjulianstatic int ${1}_isa_detach (device_t); 25222195Sjulian 25367505Sjulianstatic struct isa_pnp_id ${1}_ids[] = { 25468533Sjulian {0x12345678, "ABCco Widget"}, 25568533Sjulian {0xfedcba98, "shining moon Widget ripoff"}, 25668533Sjulian {0, NULL} 25767505Sjulian}; 25867505Sjulian 25967505Sjulianstatic device_method_t ${1}_methods[] = { 26068506Sjulian DEVMETHOD(device_identify, ${1}_isa_identify), 26167505Sjulian DEVMETHOD(device_probe, ${1}_isa_probe), 26267505Sjulian DEVMETHOD(device_attach, ${1}_isa_attach), 26367505Sjulian DEVMETHOD(device_detach, ${1}_isa_detach), 264227844Smarius DEVMETHOD_END 26567505Sjulian}; 26667505Sjulian 26767505Sjulianstatic driver_t ${1}_isa_driver = { 26867505Sjulian "${1}", 26967505Sjulian ${1}_methods, 27067505Sjulian sizeof (struct ${1}_softc) 27167505Sjulian}; 27267505Sjulian 27367505SjulianDRIVER_MODULE(${1}, isa, ${1}_isa_driver, ${1}_devclass, 0, 0); 27467505Sjulian 27568506Sjulian/* 27668506Sjulian * Here list some port addresses we might expect our widget to appear at: 27770165Simp * This list should only be used for cards that have some non-destructive 27870165Simp * (to other cards) way of probing these address. Otherwise the driver 27970165Simp * should not go looking for instances of itself, but instead rely on 28070165Simp * the hints file. Strange failures for people with other cards might 28170165Simp * result. 28268506Sjulian */ 28368506Sjulianstatic struct localhints { 28468506Sjulian int ioport; 28568506Sjulian int irq; 28668506Sjulian int drq; 28768506Sjulian int mem; 28868506Sjulian} res[] = { 28968506Sjulian { 0x210, 11, 2, 0xcd000}, 29068506Sjulian { 0x310, 12, 3, 0xdd000}, 29168506Sjulian { 0x320, 9, 6, 0xd4000}, 29268506Sjulian {0,0,0,0} 29368506Sjulian}; 29467505Sjulian 295120708Sdds#define MAXHINTS 10 /* Just an arbitrary safety limit. */ 29667505Sjulian/* 29768533Sjulian * Called once when the driver is somehow connected with the bus, 29868533Sjulian * (Either linked in and the bus is started, or loaded as a module). 29968533Sjulian * 30068533Sjulian * The aim of this routine in an ISA driver is to add child entries to 30168533Sjulian * the parent bus so that it looks as if the devices were detected by 30275517Sbrian * some pnp-like method, or at least mentioned in the hints. 30368533Sjulian * 30468533Sjulian * For NON-PNP "dumb" devices: 30568533Sjulian * Add entries into the bus's list of likely devices, so that 30668506Sjulian * our 'probe routine' will be called for them. 30768506Sjulian * This is similar to what the 'hints' code achieves, except this is 30868506Sjulian * loadable with the driver. 30968533Sjulian * In the 'dumb' case we end up with more children than needed but 31068533Sjulian * some (or all) of them will fail probe() and only waste a little memory. 31168533Sjulian * 31268533Sjulian * For NON-PNP "Smart" devices: 31368533Sjulian * If the device has a NON-PNP way of being detected and setting/sensing 31468533Sjulian * the card, then do that here and add a child for each set of 315101214Smarkm * hardware found. 31668533Sjulian * 31768533Sjulian * For PNP devices: 31868533Sjulian * If the device is always PNP capable then this function can be removed. 31970165Simp * The ISA PNP system will have automatically added it to the system and 32070165Simp * so your identify routine needn't do anything. 32168533Sjulian * 32275517Sbrian * If the device is mentioned in the 'hints' file then this 32375517Sbrian * function can be removed. All devices mentioned in the hints 32468533Sjulian * file get added as children for probing, whether or not the 32568533Sjulian * driver is linked in. So even as a module it MAY still be there. 32668533Sjulian * See isa/isahint.c for hints being added in. 32768506Sjulian */ 32868506Sjulianstatic void 32968506Sjulian${1}_isa_identify (driver_t *driver, device_t parent) 33068506Sjulian{ 33168506Sjulian u_int32_t irq=0; 33268506Sjulian u_int32_t ioport; 33368506Sjulian device_t child; 33468506Sjulian int i; 33568506Sjulian 33668506Sjulian /* 33768506Sjulian * If we've already got ${UPPER} attached somehow, don't try again. 33868533Sjulian * Maybe it was in the hints file. or it was loaded before. 33968506Sjulian */ 34068506Sjulian if (device_find_child(parent, "${1}", 0)) { 34168506Sjulian printf("${UPPER}: already attached\n"); 34268506Sjulian return; 34368506Sjulian } 344120708Sdds/* XXX Look at dev/acpica/acpi_isa.c for use of ISA_ADD_CONFIG() macro. */ 345120708Sdds/* XXX What is ISA_SET_CONFIG_CALLBACK(parent, child, pnpbios_set_config, 0)? */ 34668506Sjulian for (i = 0; i < MAXHINTS; i++) { 34768748Sjulian 34868748Sjulian ioport = res[i].ioport; 34968748Sjulian irq = res[i].irq; 350101214Smarkm if ((ioport == 0) && (irq == 0)) 351120708Sdds return; /* We've added all our local hints. */ 35268506Sjulian 35368506Sjulian child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "${1}", -1); 35468506Sjulian bus_set_resource(child, SYS_RES_IOPORT, 0, ioport, NUMPORTS); 35568506Sjulian bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1); 35668506Sjulian bus_set_resource(child, SYS_RES_DRQ, 0, res[i].drq, 1); 35768506Sjulian bus_set_resource(child, SYS_RES_MEMORY, 0, res[i].mem, MEMSIZE); 35868506Sjulian 35968506Sjulian#if 0 36068506Sjulian /* 36168506Sjulian * If we wanted to pretend PNP found it 36268506Sjulian * we could do this, and put matching entries 36368506Sjulian * in the PNP table, but I think it's probably too hacky. 36468506Sjulian * As you see, some people have done it though. 365120708Sdds * Basically EISA (remember that?) would do this I think. 36668506Sjulian */ 36768506Sjulian isa_set_vendorid(child, PNP_EISAID("ESS1888")); 36868506Sjulian isa_set_logicalid(child, PNP_EISAID("ESS1888")); 36968506Sjulian#endif 37068506Sjulian } 37168533Sjulian#if 0 37270165Simp /* 37370165Simp * Do some smart probing (e.g. like the lnc driver) 37470165Simp * and add a child for each one found. 37570165Simp */ 37668533Sjulian#endif 37768506Sjulian 37868506Sjulian return; 37968506Sjulian} 38068506Sjulian/* 38167505Sjulian * The ISA code calls this for each device it knows about, 38267505Sjulian * whether via the PNP code or via the hints etc. 383101214Smarkm * If the device nas no PNP capabilities, remove all the 38468533Sjulian * PNP entries, but keep the call to ISA_PNP_PROBE() 38568533Sjulian * As it will guard against accidentally recognising 38668533Sjulian * foreign hardware. This is because we will be called to check against 38768533Sjulian * ALL PNP hardware. 38867505Sjulian */ 38922195Sjulianstatic int 39067505Sjulian${1}_isa_probe (device_t device) 39122195Sjulian{ 39267505Sjulian int error; 39368506Sjulian device_t parent = device_get_parent(device); 39470165Simp struct ${1}_softc *scp = DEVICE2SOFTC(device); 39568506Sjulian u_long port_start, port_count; 39622195Sjulian 39767505Sjulian bzero(scp, sizeof(*scp)); 39867505Sjulian scp->device = device; 39967505Sjulian 40022195Sjulian /* 401120708Sdds * Check this device for a PNP match in our table. 40267505Sjulian * There are several possible outcomes. 403120708Sdds * error == 0 We match a PNP. 40475517Sbrian * error == ENXIO, It is a PNP device but not in our table. 40575517Sbrian * error == ENOENT, It is not a PNP device.. try heuristic probes. 40667505Sjulian * -- logic from if_ed_isa.c, added info from isa/isa_if.m: 40768748Sjulian * 40868748Sjulian * If we had a list of devices that we could handle really well, 40968748Sjulian * and a list which we could handle only basic functions, then 41068748Sjulian * we would call this twice, once for each list, 41168748Sjulian * and return a value of '-2' or something if we could 41268748Sjulian * only handle basic functions. This would allow a specific 41368748Sjulian * Widgetplus driver to make a better offer if it knows how to 414120708Sdds * do all the extended functions. (See non-pnp part for more info). 41522195Sjulian */ 41668506Sjulian error = ISA_PNP_PROBE(parent, device, ${1}_ids); 41767505Sjulian switch (error) { 41867505Sjulian case 0: 41967505Sjulian /* 42067505Sjulian * We found a PNP device. 421120708Sdds * Do nothing, as it's all done in attach(). 42267505Sjulian */ 42367653Sjulian break; 42467505Sjulian case ENOENT: 42567505Sjulian /* 42667505Sjulian * Well it didn't show up in the PNP tables 42767505Sjulian * so look directly at known ports (if we have any) 42867505Sjulian * in case we are looking for an old pre-PNP card. 429101214Smarkm * 43068506Sjulian * Hopefully the 'identify' routine will have picked these 43168748Sjulian * up for us first if they use some proprietary detection 43268748Sjulian * method. 43367505Sjulian * 43468748Sjulian * The ports, irqs etc should come from a 'hints' section 43567505Sjulian * which is read in by code in isa/isahint.c 43668533Sjulian * and kern/subr_bus.c to create resource entries, 43768533Sjulian * or have been added by the 'identify routine above. 43875517Sbrian * Note that HINTS based resource requests have NO 43968748Sjulian * SIZE for the memory or ports requests (just a base) 44068748Sjulian * so we may need to 'correct' this before we 44168748Sjulian * do any probing. 44268748Sjulian */ 44368748Sjulian /* 444120708Sdds * Find out the values of any resources we 445101214Smarkm * need for our dumb probe. Also check we have enough ports 446101214Smarkm * in the request. (could be hints based). 44768748Sjulian * Should probably do the same for memory regions too. 44868748Sjulian */ 44968748Sjulian error = bus_get_resource(device, SYS_RES_IOPORT, 0, 450101214Smarkm &port_start, &port_count); 45168748Sjulian if (port_count != NUMPORTS) { 45268748Sjulian bus_set_resource(device, SYS_RES_IOPORT, 0, 453101214Smarkm port_start, NUMPORTS); 45468748Sjulian } 45568748Sjulian 45668748Sjulian /* 45768748Sjulian * Make a temporary resource reservation. 45868533Sjulian * If we can't get the resources we need then 45968533Sjulian * we need to abort. Possibly this indicates 46068748Sjulian * the resources were used by another device 46168748Sjulian * in which case the probe would have failed anyhow. 46267505Sjulian */ 46368533Sjulian if ((error = (${1}_allocate_resources(device)))) { 46468533Sjulian error = ENXIO; 46568533Sjulian goto errexit; 46668506Sjulian } 46768506Sjulian 468120708Sdds /* Dummy heuristic type probe. */ 469101214Smarkm if (inb(port_start) != EXPECTED_VALUE) { 470101214Smarkm /* 47168506Sjulian * It isn't what we hoped, so quit looking for it. 47267505Sjulian */ 47367653Sjulian error = ENXIO; 47467653Sjulian } else { 47568533Sjulian u_long membase = bus_get_resource_start(device, 47668533Sjulian SYS_RES_MEMORY, 0 /*rid*/); 47768533Sjulian u_long memsize; 47867653Sjulian /* 47968533Sjulian * If we discover in some way that the device has 48068533Sjulian * XXX bytes of memory window, we can override 48168533Sjulian * or set the memory size in the child resource list. 48268533Sjulian */ 48368533Sjulian memsize = inb(port_start + 1) * 1024; /* for example */ 48468533Sjulian error = bus_set_resource(device, SYS_RES_MEMORY, 48568533Sjulian /*rid*/0, membase, memsize); 48668533Sjulian /* 48768748Sjulian * We found one, return non-positive numbers.. 488222179Suqs * Return -N if we can't handle it, but not well. 489120708Sdds * Return -2 if we would LIKE the device. 490120708Sdds * Return -1 if we want it a lot. 491120708Sdds * Return 0 if we MUST get the device. 49268533Sjulian * This allows drivers to 'bid' for a device. 49367653Sjulian */ 49468533Sjulian device_set_desc(device, "ACME Widget model 1234"); 495120708Sdds error = -1; /* We want it but someone else 496120708Sdds may be even better. */ 49767505Sjulian } 49868533Sjulian /* 49968533Sjulian * Unreserve the resources for now because 50068533Sjulian * another driver may bid for device too. 50175517Sbrian * If we lose the bid, but still hold the resources, we will 50275517Sbrian * effectively have disabled the other driver from getting them 50368533Sjulian * which will result in neither driver getting the device. 50468533Sjulian * We will ask for them again in attach if we win. 50568533Sjulian */ 50668533Sjulian ${1}_deallocate_resources(device); 50767505Sjulian break; 50867505Sjulian case ENXIO: 509120708Sdds /* It was PNP but not ours, leave immediately. */ 51067505Sjulian default: 51167505Sjulian error = ENXIO; 51222195Sjulian } 51368533Sjulianerrexit: 51467505Sjulian return (error); 51522195Sjulian} 51622195Sjulian 51722195Sjulian/* 51868533Sjulian * Called if the probe succeeded and our bid won the device. 51922195Sjulian * We can be destructive here as we know we have the device. 52068533Sjulian * This is the first place we can be sure we have a softc structure. 52168606Sjulian * You would do ISA specific attach things here, but generically there aren't 522120708Sdds * any (yay new-bus!). 52322195Sjulian */ 52422195Sjulianstatic int 52567505Sjulian${1}_isa_attach (device_t device) 52622195Sjulian{ 52768606Sjulian int error; 52870165Simp struct ${1}_softc *scp = DEVICE2SOFTC(device); 52968606Sjulian 53068606Sjulian error = ${1}_attach(device, scp); 531101214Smarkm if (error) 53268606Sjulian ${1}_isa_detach(device); 53368606Sjulian return (error); 53468606Sjulian} 53568606Sjulian 536101214Smarkm/* 537120708Sdds * Detach the driver (e.g. module unload), 53868606Sjulian * call the bus independent version 53968606Sjulian * and undo anything we did in the ISA attach routine. 54068606Sjulian */ 54168606Sjulianstatic int 54268606Sjulian${1}_isa_detach (device_t device) 54368606Sjulian{ 54468606Sjulian int error; 54570165Simp struct ${1}_softc *scp = DEVICE2SOFTC(device); 54668606Sjulian 54768606Sjulian error = ${1}_detach(device, scp); 54868606Sjulian return (error); 54968606Sjulian} 55068606Sjulian 55170165Simp/* 55270165Simp *************************************** 55370165Simp * PCI Attachment structures and code 55470165Simp *************************************** 55570165Simp */ 55668606Sjulian 557101214Smarkmstatic int ${1}_pci_probe(device_t); 558101214Smarkmstatic int ${1}_pci_attach(device_t); 559101214Smarkmstatic int ${1}_pci_detach(device_t); 56068606Sjulian 56168606Sjulianstatic device_method_t ${1}_pci_methods[] = { 56268606Sjulian /* Device interface */ 56368606Sjulian DEVMETHOD(device_probe, ${1}_pci_probe), 56468606Sjulian DEVMETHOD(device_attach, ${1}_pci_attach), 56568606Sjulian DEVMETHOD(device_detach, ${1}_pci_detach), 56668606Sjulian { 0, 0 } 56768606Sjulian}; 56868606Sjulian 56968606Sjulianstatic driver_t ${1}_pci_driver = { 57068606Sjulian "${1}", 57168606Sjulian ${1}_pci_methods, 57268606Sjulian sizeof(struct ${1}_softc), 57368606Sjulian}; 57468606Sjulian 57568630SjulianDRIVER_MODULE(${1}, pci, ${1}_pci_driver, ${1}_devclass, 0, 0); 57670165Simp/* 57770165Simp * Cardbus is a pci bus plus extra, so use the pci driver unless special 57870165Simp * things need to be done only in the cardbus case. 57970165Simp */ 58070165SimpDRIVER_MODULE(${1}, cardbus, ${1}_pci_driver, ${1}_devclass, 0, 0); 58168606Sjulian 58268606Sjulianstatic struct _pcsid 58368606Sjulian{ 58468606Sjulian u_int32_t type; 58568606Sjulian const char *desc; 58668606Sjulian} pci_ids[] = { 58768606Sjulian { 0x1234abcd, "ACME PCI Widgetplus" }, 58870165Simp { 0x1243fedc, "Happy moon brand RIPOFFplus" }, 58968606Sjulian { 0x00000000, NULL } 59068606Sjulian}; 59168606Sjulian 59268748Sjulian/* 59375517Sbrian * See if this card is specifically mentioned in our list of known devices. 59468748Sjulian * Theoretically we might also put in a weak bid for some devices that 59570165Simp * report themselves to be some generic type of device if we can handle 59668748Sjulian * that generic type. (other PCI_XXX calls give that info). 59768748Sjulian * This would allow a specific driver to over-ride us. 59868748Sjulian * 59968748Sjulian * See the comments in the ISA section regarding returning non-positive 60068748Sjulian * values from probe routines. 60168748Sjulian */ 60268606Sjulianstatic int 60368606Sjulian${1}_pci_probe (device_t device) 60468606Sjulian{ 60568606Sjulian u_int32_t type = pci_get_devid(device); 60668606Sjulian struct _pcsid *ep =pci_ids; 60768606Sjulian 60868606Sjulian while (ep->type && ep->type != type) 60968606Sjulian ++ep; 61068606Sjulian if (ep->desc) { 61168606Sjulian device_set_desc(device, ep->desc); 61270165Simp return 0; /* If there might be a better driver, return -2 */ 613101214Smarkm } else 61468606Sjulian return ENXIO; 61568606Sjulian} 61668606Sjulian 61768606Sjulianstatic int 61868606Sjulian${1}_pci_attach(device_t device) 61968606Sjulian{ 62068606Sjulian int error; 62170165Simp struct ${1}_softc *scp = DEVICE2SOFTC(device); 62268606Sjulian 62368606Sjulian error = ${1}_attach(device, scp); 624101214Smarkm if (error) 62568606Sjulian ${1}_pci_detach(device); 62668606Sjulian return (error); 62768606Sjulian} 62868606Sjulian 62968606Sjulianstatic int 63068606Sjulian${1}_pci_detach (device_t device) 63168606Sjulian{ 63268606Sjulian int error; 63370165Simp struct ${1}_softc *scp = DEVICE2SOFTC(device); 63468606Sjulian 63568606Sjulian error = ${1}_detach(device, scp); 63668606Sjulian return (error); 63768606Sjulian} 63868606Sjulian 63970165Simp/* 64070165Simp **************************************** 64175517Sbrian * Common Attachment sub-functions 64270165Simp **************************************** 64370165Simp */ 64468606Sjulianstatic int 64570165Simp${1}_attach(device_t device, struct ${1}_softc * scp) 64668606Sjulian{ 64770165Simp device_t parent = device_get_parent(device); 64867653Sjulian int unit = device_get_unit(device); 64940591Sbde 65067653Sjulian scp->dev = make_dev(&${1}_cdevsw, 0, 65167653Sjulian UID_ROOT, GID_OPERATOR, 0600, "${1}%d", unit); 65268606Sjulian scp->dev->si_drv1 = scp; 65367653Sjulian 654101214Smarkm if (${1}_allocate_resources(device)) 65567653Sjulian goto errexit; 65667653Sjulian 65768533Sjulian scp->bt = rman_get_bustag(scp->res_ioport); 65868533Sjulian scp->bh = rman_get_bushandle(scp->res_ioport); 65967653Sjulian 660120708Sdds /* Register the interrupt handler. */ 66168533Sjulian /* 66268533Sjulian * The type should be one of: 66368533Sjulian * INTR_TYPE_TTY 66470165Simp * INTR_TYPE_BIO 66570165Simp * INTR_TYPE_CAM 66670165Simp * INTR_TYPE_NET 66770165Simp * INTR_TYPE_MISC 66870165Simp * This will probably change with SMPng. INTR_TYPE_FAST may be 66975517Sbrian * OR'd into this type to mark the interrupt fast. However, fast 67070165Simp * interrupts cannot be shared at all so special precautions are 67175517Sbrian * necessary when coding fast interrupt routines. 67268533Sjulian */ 67367568Sjulian if (scp->res_irq) { 674120708Sdds /* Default to the tty mask for registration. */ /* XXX */ 67567568Sjulian if (BUS_SETUP_INTR(parent, device, scp->res_irq, INTR_TYPE_TTY, 67667653Sjulian ${1}intr, scp, &scp->intr_cookie) == 0) { 677120708Sdds /* Do something if successful. */ 678101214Smarkm } else 67968606Sjulian goto errexit; 68067568Sjulian } 68168533Sjulian 68268533Sjulian /* 68368533Sjulian * If we want to access the memory we will need 68468533Sjulian * to know where it was mapped. 68570165Simp * 68670165Simp * Use of this function is discouraged, however. You should 68770165Simp * be accessing the device with the bus_space API if at all 68870165Simp * possible. 68968533Sjulian */ 69068533Sjulian scp->vaddr = rman_get_virtual(scp->res_memory); 69167505Sjulian return 0; 69267653Sjulian 69367653Sjulianerrexit: 69467653Sjulian /* 695120708Sdds * Undo anything we may have done. 69667653Sjulian */ 69768606Sjulian ${1}_detach(device, scp); 69867653Sjulian return (ENXIO); 69967505Sjulian} 70040591Sbde 70167505Sjulianstatic int 70270165Simp${1}_detach(device_t device, struct ${1}_softc *scp) 70367505Sjulian{ 70467568Sjulian device_t parent = device_get_parent(device); 70522195Sjulian 70667653Sjulian /* 70767653Sjulian * At this point stick a strong piece of wood into the device 708101214Smarkm * to make sure it is stopped safely. The alternative is to 709101214Smarkm * simply REFUSE to detach if it's busy. What you do depends on 71067653Sjulian * your specific situation. 71170165Simp * 71270165Simp * Sometimes the parent bus will detach you anyway, even if you 71370165Simp * are busy. You must cope with that possibility. Your hardware 71470165Simp * might even already be gone in the case of cardbus or pccard 71570165Simp * devices. 71667653Sjulian */ 71767653Sjulian /* ZAP some register */ 71867653Sjulian 71967653Sjulian /* 72067653Sjulian * Take our interrupt handler out of the list of handlers 72167653Sjulian * that can handle this irq. 72267653Sjulian */ 72367653Sjulian if (scp->intr_cookie != NULL) { 72467568Sjulian if (BUS_TEARDOWN_INTR(parent, device, 725101214Smarkm scp->res_irq, scp->intr_cookie) != 0) 72667568Sjulian printf("intr teardown failed.. continuing\n"); 72767653Sjulian scp->intr_cookie = NULL; 72867653Sjulian } 72967653Sjulian 73067653Sjulian /* 731120708Sdds * Deallocate any system resources we may have 73267653Sjulian * allocated on behalf of this driver. 73367653Sjulian */ 73468533Sjulian scp->vaddr = NULL; 73567653Sjulian return ${1}_deallocate_resources(device); 73667653Sjulian} 73767653Sjulian 73867653Sjulianstatic int 73967653Sjulian${1}_allocate_resources(device_t device) 74067653Sjulian{ 74167653Sjulian int error; 74270165Simp struct ${1}_softc *scp = DEVICE2SOFTC(device); 743120708Sdds int size = 16; /* SIZE of port range used. */ 74467653Sjulian 74567653Sjulian scp->res_ioport = bus_alloc_resource(device, SYS_RES_IOPORT, 74667653Sjulian &scp->rid_ioport, 0ul, ~0ul, size, RF_ACTIVE); 747101214Smarkm if (scp->res_ioport == NULL) 74867653Sjulian goto errexit; 74967653Sjulian 75067653Sjulian scp->res_irq = bus_alloc_resource(device, SYS_RES_IRQ, 75168533Sjulian &scp->rid_irq, 0ul, ~0ul, 1, RF_SHAREABLE|RF_ACTIVE); 752101214Smarkm if (scp->res_irq == NULL) 75367653Sjulian goto errexit; 75467653Sjulian 75567653Sjulian scp->res_drq = bus_alloc_resource(device, SYS_RES_DRQ, 75667653Sjulian &scp->rid_drq, 0ul, ~0ul, 1, RF_ACTIVE); 757101214Smarkm if (scp->res_drq == NULL) 75867653Sjulian goto errexit; 75967653Sjulian 76068506Sjulian scp->res_memory = bus_alloc_resource(device, SYS_RES_MEMORY, 76167653Sjulian &scp->rid_memory, 0ul, ~0ul, MSIZE, RF_ACTIVE); 762101214Smarkm if (scp->res_memory == NULL) 76367653Sjulian goto errexit; 76467653Sjulian return (0); 76567653Sjulian 76667653Sjulianerrexit: 76767653Sjulian error = ENXIO; 768120708Sdds /* Cleanup anything we may have assigned. */ 76967653Sjulian ${1}_deallocate_resources(device); 770120708Sdds return (ENXIO); /* For want of a better idea. */ 77167653Sjulian} 77267653Sjulian 77367653Sjulianstatic int 77467653Sjulian${1}_deallocate_resources(device_t device) 77567653Sjulian{ 77670165Simp struct ${1}_softc *scp = DEVICE2SOFTC(device); 77767653Sjulian 77867653Sjulian if (scp->res_irq != 0) { 77967568Sjulian bus_deactivate_resource(device, SYS_RES_IRQ, 78067568Sjulian scp->rid_irq, scp->res_irq); 78167568Sjulian bus_release_resource(device, SYS_RES_IRQ, 78267568Sjulian scp->rid_irq, scp->res_irq); 78367568Sjulian scp->res_irq = 0; 78467568Sjulian } 78567568Sjulian if (scp->res_ioport != 0) { 78667568Sjulian bus_deactivate_resource(device, SYS_RES_IOPORT, 78767568Sjulian scp->rid_ioport, scp->res_ioport); 78867568Sjulian bus_release_resource(device, SYS_RES_IOPORT, 78967568Sjulian scp->rid_ioport, scp->res_ioport); 79067568Sjulian scp->res_ioport = 0; 79167568Sjulian } 79268748Sjulian if (scp->res_memory != 0) { 79367568Sjulian bus_deactivate_resource(device, SYS_RES_MEMORY, 79467568Sjulian scp->rid_memory, scp->res_memory); 79567568Sjulian bus_release_resource(device, SYS_RES_MEMORY, 79667568Sjulian scp->rid_memory, scp->res_memory); 79768748Sjulian scp->res_memory = 0; 79867568Sjulian } 79967568Sjulian if (scp->res_drq != 0) { 80067568Sjulian bus_deactivate_resource(device, SYS_RES_DRQ, 80167568Sjulian scp->rid_drq, scp->res_drq); 80267568Sjulian bus_release_resource(device, SYS_RES_DRQ, 80367568Sjulian scp->rid_drq, scp->res_drq); 80467568Sjulian scp->res_drq = 0; 80567568Sjulian } 806101214Smarkm if (scp->dev) 80767568Sjulian destroy_dev(scp->dev); 80867505Sjulian return (0); 80922195Sjulian} 81022195Sjulian 81140591Sbdestatic void 81267505Sjulian${1}intr(void *arg) 81322195Sjulian{ 81470165Simp struct ${1}_softc *scp = (struct ${1}_softc *) arg; 81567505Sjulian 816101214Smarkm /* 817120708Sdds * Well we got an interrupt, now what? 81870165Simp * 81970165Simp * Make sure that the interrupt routine will always terminate, 82070165Simp * even in the face of "bogus" data from the card. 82122195Sjulian */ 822120708Sdds (void)scp; /* Delete this line after using scp. */ 82322195Sjulian return; 82422195Sjulian} 82522195Sjulian 82667505Sjulianstatic int 827161022Srik${1}ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 82822195Sjulian{ 82970165Simp struct ${1}_softc *scp = DEV2SOFTC(dev); 83067505Sjulian 831120708Sdds (void)scp; /* Delete this line after using scp. */ 83222195Sjulian switch (cmd) { 83367505Sjulian case DHIOCRESET: 834120708Sdds /* Whatever resets it. */ 83568506Sjulian#if 0 836101214Smarkm ${UPPER}_OUTB(SOME_PORT, 0xff); 83768506Sjulian#endif 83822195Sjulian break; 83967505Sjulian default: 84022195Sjulian return ENXIO; 84122195Sjulian } 84222195Sjulian return (0); 84367505Sjulian} 84422195Sjulian/* 84522195Sjulian * You also need read, write, open, close routines. 846120708Sdds * This should get you started. 84722195Sjulian */ 84867505Sjulianstatic int 849161022Srik${1}open(struct cdev *dev, int oflags, int devtype, struct thread *td) 85022195Sjulian{ 85170165Simp struct ${1}_softc *scp = DEV2SOFTC(dev); 85222195Sjulian 853101214Smarkm /* 854120708Sdds * Do processing. 85522195Sjulian */ 856120708Sdds (void)scp; /* Delete this line after using scp. */ 85722195Sjulian return (0); 85822195Sjulian} 85922195Sjulian 86067505Sjulianstatic int 861161022Srik${1}close(struct cdev *dev, int fflag, int devtype, struct thread *td) 86222195Sjulian{ 86370165Simp struct ${1}_softc *scp = DEV2SOFTC(dev); 86422195Sjulian 865101214Smarkm /* 866120708Sdds * Do processing. 86722195Sjulian */ 868120708Sdds (void)scp; /* Delete this line after using scp. */ 86922195Sjulian return (0); 87022195Sjulian} 87122195Sjulian 87267505Sjulianstatic int 873161022Srik${1}read(struct cdev *dev, struct uio *uio, int ioflag) 87422195Sjulian{ 87570165Simp struct ${1}_softc *scp = DEV2SOFTC(dev); 87667505Sjulian int toread; 87722195Sjulian 878101214Smarkm /* 879120708Sdds * Do processing. 880120708Sdds * Read from buffer. 88122195Sjulian */ 882120708Sdds (void)scp; /* Delete this line after using scp. */ 88322195Sjulian toread = (min(uio->uio_resid, sizeof(scp->buffer))); 88422195Sjulian return(uiomove(scp->buffer, toread, uio)); 88522195Sjulian} 88622195Sjulian 88767505Sjulianstatic int 888161022Srik${1}write(struct cdev *dev, struct uio *uio, int ioflag) 88922195Sjulian{ 89070165Simp struct ${1}_softc *scp = DEV2SOFTC(dev); 89122195Sjulian int towrite; 89222195Sjulian 893101214Smarkm /* 894120708Sdds * Do processing. 895120708Sdds * Write to buffer. 89622195Sjulian */ 897120708Sdds (void)scp; /* Delete this line after using scp. */ 89822195Sjulian towrite = (min(uio->uio_resid, sizeof(scp->buffer))); 89922195Sjulian return(uiomove(scp->buffer, towrite, uio)); 90022195Sjulian} 90122195Sjulian 90267505Sjulianstatic int 903161022Srik${1}mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot) 90422195Sjulian{ 90570165Simp struct ${1}_softc *scp = DEV2SOFTC(dev); 90622195Sjulian 907101214Smarkm /* 90868506Sjulian * Given a byte offset into your device, return the PHYSICAL 90968506Sjulian * page number that it would map to. 91022195Sjulian */ 911120708Sdds (void)scp; /* Delete this line after using scp. */ 912120708Sdds#if 0 /* If we had a frame buffer or whatever... do this. */ 913101214Smarkm if (offset > FRAMEBUFFERSIZE - PAGE_SIZE) 91422195Sjulian return (-1); 91522195Sjulian return i386_btop((FRAMEBASE + offset)); 91622195Sjulian#else 91722195Sjulian return (-1); 91822195Sjulian#endif 91922195Sjulian} 92022195Sjulian 92167505Sjulianstatic int 922161022Srik${1}poll(struct cdev *dev, int which, struct thread *td) 92322195Sjulian{ 92470165Simp struct ${1}_softc *scp = DEV2SOFTC(dev); 92522195Sjulian 926101214Smarkm /* 927120708Sdds * Do processing. 92822195Sjulian */ 929120708Sdds (void)scp; /* Delete this line after using scp. */ 930120708Sdds return (0); /* This is the wrong value I'm sure. */ 93122195Sjulian} 93222195Sjulian 93322195SjulianDONE 93422195Sjulian 93567505Sjuliancat >${TOP}/sys/${1}io.h <<DONE 93622195Sjulian/* 93722195Sjulian * Definitions needed to access the ${1} device (ioctls etc) 938120708Sdds * see mtio.h, ioctl.h as examples. 93922195Sjulian */ 94022195Sjulian#ifndef SYS_DHIO_H 94122195Sjulian#define SYS_DHIO_H 94222195Sjulian 94322195Sjulian#ifndef KERNEL 94422195Sjulian#include <sys/types.h> 94522195Sjulian#endif 94622195Sjulian#include <sys/ioccom.h> 94722195Sjulian 94822195Sjulian/* 949120708Sdds * Define an ioctl here. 95022195Sjulian */ 951120708Sdds#define DHIOCRESET _IO('D', 0) /* Reset the ${1} device. */ 95222195Sjulian#endif 95322195SjulianDONE 95422195Sjulian 955120708Sddsif [ ! -d ${TOP}/modules/${1} ]; then 95667505Sjulian mkdir -p ${TOP}/modules/${1} 95767505Sjulianfi 95867505Sjulian 95967505Sjuliancat >${TOP}/modules/${1}/Makefile <<DONE 96032468Sjulian# ${UPPER} Loadable Kernel Module 96132468Sjulian# 96267657Sjulian# \$${RCS_KEYWORD}: $ 963101214Smarkm 96467505Sjulian.PATH: \${.CURDIR}/../../dev/${1} 96567505SjulianKMOD = ${1} 96667505SjulianSRCS = ${1}.c 96767505SjulianSRCS += opt_inet.h device_if.h bus_if.h pci_if.h isa_if.h 968101214Smarkm 969120708Sdds# You may need to do this is your device is an if_xxx driver. 97067505Sjulianopt_inet.h: 97167505Sjulian echo "#define INET 1" > opt_inet.h 972101214Smarkm 97332468Sjulian.include <bsd.kmod.mk> 97432468SjulianDONE 97532468Sjulian 976161023Srikecho -n "Do you want to build the '${1}' module? [Y]" 977161023Srikread VAL 978161023Srikif [ "-z" "$VAL" ]; then 979161023Srik VAL=YES 980161023Srikfi 981161023Srikcase ${VAL} in 982161023Srik[yY]*) 983161023Srik (cd ${TOP}/modules/${1}; make depend; make ) 984161023Srik ;; 985161023Srik*) 986161023Srik# exit 987161023Srik ;; 988161023Srikesac 98967505Sjulian 990161023Srikecho "" 991161118Srikecho -n "Do you want to build the '${UPPER}' kernel? [Y]" 992161118Srikread VAL 993161118Srikif [ "-z" "$VAL" ]; then 994161118Srik VAL=YES 995161118Srikfi 996161118Srikcase ${VAL} in 997161118Srik[yY]*) 998161118Srik ( 999161118Srik cd ${TOP}/i386/conf; \ 1000161118Srik config ${UPPER}; \ 1001161118Srik cd ${TOP}/i386/compile/${UPPER}; \ 1002161118Srik make depend; \ 1003161118Srik make; \ 1004161118Srik ) 1005161118Srik ;; 1006161118Srik*) 1007161118Srik# exit 1008161118Srik ;; 1009161118Srikesac 101022195Sjulian 101122195Sjulian#--------------end of script--------------- 101222195Sjulian# 1013120708Sdds# Edit to your taste... 101422195Sjulian# 1015101214Smarkm# 1016