Re: [PATCH] hwmon: add fan/pwm driver for corsair h100i platinum

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi jaap,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on hwmon/hwmon-next]
[also build test ERROR on v5.8-rc5 next-20200714]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use  as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/jaap-aarts/hwmon-add-fan-pwm-driver-for-corsair-h100i-platinum/20200714-180650
base:   https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git hwmon-next
config: m68k-allmodconfig (attached as .config)
compiler: m68k-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=m68k 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@xxxxxxxxx>

All error/warnings (new ones prefixed by >>):

   In file included from arch/m68k/include/asm/io_mm.h:25,
                    from arch/m68k/include/asm/io.h:8,
                    from include/linux/io.h:13,
                    from include/linux/irq.h:20,
                    from include/asm-generic/hardirq.h:13,
                    from ./arch/m68k/include/generated/asm/hardirq.h:1,
                    from include/linux/hardirq.h:10,
                    from include/linux/interrupt.h:11,
                    from include/linux/usb.h:16,
                    from drivers/hwmon/asetek_gen6.c:23:
   arch/m68k/include/asm/raw_io.h: In function 'raw_rom_outsb':
   arch/m68k/include/asm/raw_io.h:83:7: warning: variable '__w' set but not used [-Wunused-but-set-variable]
      83 |  ({u8 __w, __v = (b);  u32 _addr = ((u32) (addr)); \
         |       ^~~
   arch/m68k/include/asm/raw_io.h:430:3: note: in expansion of macro 'rom_out_8'
     430 |   rom_out_8(port, *buf++);
         |   ^~~~~~~~~
   arch/m68k/include/asm/raw_io.h: In function 'raw_rom_outsw':
   arch/m68k/include/asm/raw_io.h:86:8: warning: variable '__w' set but not used [-Wunused-but-set-variable]
      86 |  ({u16 __w, __v = (w); u32 _addr = ((u32) (addr)); \
         |        ^~~
   arch/m68k/include/asm/raw_io.h:448:3: note: in expansion of macro 'rom_out_be16'
     448 |   rom_out_be16(port, *buf++);
         |   ^~~~~~~~~~~~
   arch/m68k/include/asm/raw_io.h: In function 'raw_rom_outsw_swapw':
   arch/m68k/include/asm/raw_io.h:90:8: warning: variable '__w' set but not used [-Wunused-but-set-variable]
      90 |  ({u16 __w, __v = (w); u32 _addr = ((u32) (addr)); \
         |        ^~~
   arch/m68k/include/asm/raw_io.h:466:3: note: in expansion of macro 'rom_out_le16'
     466 |   rom_out_le16(port, *buf++);
         |   ^~~~~~~~~~~~
   drivers/hwmon/asetek_gen6.c: At top level:
   drivers/hwmon/asetek_gen6.c:174:5: warning: no previous prototype for 'set_fan_rpm_curve' [-Wmissing-prototypes]
     174 | int set_fan_rpm_curve(struct driver *cdev, struct hwmon_fan_data *fan_data,
         |     ^~~~~~~~~~~~~~~~~
   In file included from include/linux/device.h:15,
                    from include/linux/usb/ch9.h:36,
                    from include/linux/usb.h:6,
                    from drivers/hwmon/asetek_gen6.c:23:
   drivers/hwmon/asetek_gen6.c: In function 'set_fan_rpm_curve':
>> drivers/hwmon/asetek_gen6.c:212:12: error: passing argument 1 of '_dev_info' from incompatible pointer type [-Werror=incompatible-pointer-types]
     212 |   dev_info("[*] Failled setting fan curve %d,%d,%d/%d\n",
         |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |            |
         |            char *
   include/linux/dev_printk.h:110:12: note: in definition of macro 'dev_info'
     110 |  _dev_info(dev, dev_fmt(fmt), ##__VA_ARGS__)
         |            ^~~
   include/linux/dev_printk.h:48:37: note: expected 'const struct device *' but argument is of type 'char *'
      48 | void _dev_info(const struct device *dev, const char *fmt, ...);
         |                ~~~~~~~~~~~~~~~~~~~~~^~~
>> drivers/hwmon/asetek_gen6.c:213:13: warning: passing argument 2 of '_dev_info' makes pointer from integer without a cast [-Wint-conversion]
     213 |     recv_buf[0], recv_buf[1], recv_buf[2], recv_buf[3]);
         |     ~~~~~~~~^~~
         |             |
         |             char
   include/linux/dev_printk.h:19:22: note: in definition of macro 'dev_fmt'
      19 | #define dev_fmt(fmt) fmt
         |                      ^~~
   drivers/hwmon/asetek_gen6.c:212:3: note: in expansion of macro 'dev_info'
     212 |   dev_info("[*] Failled setting fan curve %d,%d,%d/%d\n",
         |   ^~~~~~~~
   include/linux/dev_printk.h:48:54: note: expected 'const char *' but argument is of type 'char'
      48 | void _dev_info(const struct device *dev, const char *fmt, ...);
         |                                          ~~~~~~~~~~~~^~~
   drivers/hwmon/asetek_gen6.c: At top level:
   drivers/hwmon/asetek_gen6.c:217:5: warning: no previous prototype for 'set_fan_target_rpm' [-Wmissing-prototypes]
     217 | int set_fan_target_rpm(struct driver *cdev, struct hwmon_fan_data *fan_data,
         |     ^~~~~~~~~~~~~~~~~~
   In file included from include/linux/device.h:15,
                    from include/linux/usb/ch9.h:36,
                    from include/linux/usb.h:6,
                    from drivers/hwmon/asetek_gen6.c:23:
   drivers/hwmon/asetek_gen6.c: In function 'set_fan_target_rpm':
   drivers/hwmon/asetek_gen6.c:246:12: error: passing argument 1 of '_dev_info' from incompatible pointer type [-Werror=incompatible-pointer-types]
     246 |   dev_info("[*] Failled setting fan rpm %d,%d,%d/%d\n",
         |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |            |
         |            char *
   include/linux/dev_printk.h:110:12: note: in definition of macro 'dev_info'
     110 |  _dev_info(dev, dev_fmt(fmt), ##__VA_ARGS__)
         |            ^~~
   include/linux/dev_printk.h:48:37: note: expected 'const struct device *' but argument is of type 'char *'
      48 | void _dev_info(const struct device *dev, const char *fmt, ...);
         |                ~~~~~~~~~~~~~~~~~~~~~^~~
   drivers/hwmon/asetek_gen6.c:247:13: warning: passing argument 2 of '_dev_info' makes pointer from integer without a cast [-Wint-conversion]
     247 |     recv_buf[0], recv_buf[1], recv_buf[2], recv_buf[3]);
         |     ~~~~~~~~^~~
         |             |
         |             char
   include/linux/dev_printk.h:19:22: note: in definition of macro 'dev_fmt'
      19 | #define dev_fmt(fmt) fmt
         |                      ^~~
   drivers/hwmon/asetek_gen6.c:246:3: note: in expansion of macro 'dev_info'
     246 |   dev_info("[*] Failled setting fan rpm %d,%d,%d/%d\n",
         |   ^~~~~~~~
   include/linux/dev_printk.h:48:54: note: expected 'const char *' but argument is of type 'char'
      48 | void _dev_info(const struct device *dev, const char *fmt, ...);
         |                                          ~~~~~~~~~~~~^~~
   drivers/hwmon/asetek_gen6.c: At top level:
   drivers/hwmon/asetek_gen6.c:251:6: warning: no previous prototype for 'get_fan_target_rpm' [-Wmissing-prototypes]
     251 | void get_fan_target_rpm(struct hwmon_fan_data *fan_data, long *val)
         |      ^~~~~~~~~~~~~~~~~~
   drivers/hwmon/asetek_gen6.c:256:5: warning: no previous prototype for 'get_fan_current_rpm' [-Wmissing-prototypes]
     256 | int get_fan_current_rpm(struct driver *cdev, struct hwmon_fan_data *fan_data,
         |     ^~~~~~~~~~~~~~~~~~~
   In file included from include/linux/device.h:15,
                    from include/linux/usb/ch9.h:36,
                    from include/linux/usb.h:6,
                    from drivers/hwmon/asetek_gen6.c:23:
   drivers/hwmon/asetek_gen6.c: In function 'get_fan_current_rpm':
   drivers/hwmon/asetek_gen6.c:280:12: error: passing argument 1 of '_dev_info' from incompatible pointer type [-Werror=incompatible-pointer-types]
     280 |   dev_info("[*] Failled retrieving fan rmp %d,%d,%d/%d\n",
         |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |            |
         |            char *
   include/linux/dev_printk.h:110:12: note: in definition of macro 'dev_info'
     110 |  _dev_info(dev, dev_fmt(fmt), ##__VA_ARGS__)
         |            ^~~
   include/linux/dev_printk.h:48:37: note: expected 'const struct device *' but argument is of type 'char *'
      48 | void _dev_info(const struct device *dev, const char *fmt, ...);
         |                ~~~~~~~~~~~~~~~~~~~~~^~~
   drivers/hwmon/asetek_gen6.c:281:13: warning: passing argument 2 of '_dev_info' makes pointer from integer without a cast [-Wint-conversion]
     281 |     recv_buf[0], recv_buf[1], recv_buf[2], recv_buf[3]);
         |     ~~~~~~~~^~~
         |             |
         |             char
   include/linux/dev_printk.h:19:22: note: in definition of macro 'dev_fmt'
      19 | #define dev_fmt(fmt) fmt
         |                      ^~~
   drivers/hwmon/asetek_gen6.c:280:3: note: in expansion of macro 'dev_info'
     280 |   dev_info("[*] Failled retrieving fan rmp %d,%d,%d/%d\n",
         |   ^~~~~~~~
   include/linux/dev_printk.h:48:54: note: expected 'const char *' but argument is of type 'char'
      48 | void _dev_info(const struct device *dev, const char *fmt, ...);
         |                                          ~~~~~~~~~~~~^~~
   drivers/hwmon/asetek_gen6.c: At top level:
   drivers/hwmon/asetek_gen6.c:287:5: warning: no previous prototype for 'set_fan_target_pwm' [-Wmissing-prototypes]
     287 | int set_fan_target_pwm(struct driver *cdev, struct hwmon_fan_data *fan_data,
         |     ^~~~~~~~~~~~~~~~~~
   In file included from include/linux/device.h:15,
                    from include/linux/usb/ch9.h:36,
                    from include/linux/usb.h:6,
                    from drivers/hwmon/asetek_gen6.c:23:
   drivers/hwmon/asetek_gen6.c: In function 'set_fan_target_pwm':
   drivers/hwmon/asetek_gen6.c:315:12: error: passing argument 1 of '_dev_info' from incompatible pointer type [-Werror=incompatible-pointer-types]
     315 |   dev_info("[*] Failled setting fan pwm %d,%d,%d/%d\n",
         |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         |            |
         |            char *
   include/linux/dev_printk.h:110:12: note: in definition of macro 'dev_info'
     110 |  _dev_info(dev, dev_fmt(fmt), ##__VA_ARGS__)
         |            ^~~
   include/linux/dev_printk.h:48:37: note: expected 'const struct device *' but argument is of type 'char *'
      48 | void _dev_info(const struct device *dev, const char *fmt, ...);
         |                ~~~~~~~~~~~~~~~~~~~~~^~~
   drivers/hwmon/asetek_gen6.c:316:13: warning: passing argument 2 of '_dev_info' makes pointer from integer without a cast [-Wint-conversion]
     316 |     recv_buf[0], recv_buf[1], recv_buf[2], recv_buf[3]);
         |     ~~~~~~~~^~~
         |             |
         |             unsigned char
   include/linux/dev_printk.h:19:22: note: in definition of macro 'dev_fmt'
      19 | #define dev_fmt(fmt) fmt
         |                      ^~~
   drivers/hwmon/asetek_gen6.c:315:3: note: in expansion of macro 'dev_info'
     315 |   dev_info("[*] Failled setting fan pwm %d,%d,%d/%d\n",
         |   ^~~~~~~~
   include/linux/dev_printk.h:48:54: note: expected 'const char *' but argument is of type 'unsigned char'
      48 | void _dev_info(const struct device *dev, const char *fmt, ...);
         |                                          ~~~~~~~~~~~~^~~
   drivers/hwmon/asetek_gen6.c: At top level:
   drivers/hwmon/asetek_gen6.c:320:9: warning: no previous prototype for 'is_visible_func' [-Wmissing-prototypes]
     320 | umode_t is_visible_func(const void *d, enum hwmon_sensor_types type, u32 attr,
         |         ^~~~~~~~~~~~~~~
   drivers/hwmon/asetek_gen6.c:475:5: warning: no previous prototype for 'read_func' [-Wmissing-prototypes]
     475 | int read_func(struct device *dev, enum hwmon_sensor_types type, u32 attr,
         |     ^~~~~~~~~
   drivers/hwmon/asetek_gen6.c:556:6: warning: no previous prototype for 'does_fan_exist' [-Wmissing-prototypes]
     556 | bool does_fan_exist(struct driver *cdev, int channel)
         |      ^~~~~~~~~~~~~~
   drivers/hwmon/asetek_gen6.c: In function 'does_fan_exist':
   drivers/hwmon/asetek_gen6.c:569:16: warning: overflow in conversion from 'int' to 'char' changes value from '600' to '88' [-Woverflow]
     569 |  send_buf[3] = 600;
         |                ^~~
   drivers/hwmon/asetek_gen6.c: At top level:
   drivers/hwmon/asetek_gen6.c:584:5: warning: no previous prototype for 'get_fan_count' [-Wmissing-prototypes]
     584 | int get_fan_count(struct driver *dev)
         |     ^~~~~~~~~~~~~
   drivers/hwmon/asetek_gen6.c:593:6: warning: no previous prototype for 'hwmon_init' [-Wmissing-prototypes]
     593 | void hwmon_init(struct driver *dev)
         |      ^~~~~~~~~~
   drivers/hwmon/asetek_gen6.c: In function 'hwmon_init':
>> drivers/hwmon/asetek_gen6.c:650:30: error: macro "dev_info" requires 3 arguments, but only 1 given
     650 |  dev_info("[*] Setup hwmon\n");
         |                              ^
   In file included from include/linux/device.h:15,
                    from include/linux/usb/ch9.h:36,
                    from include/linux/usb.h:6,
                    from drivers/hwmon/asetek_gen6.c:23:
   include/linux/dev_printk.h:109: note: macro "dev_info" defined here
     109 | #define dev_info(dev, fmt, ...)      \
         | 
>> drivers/hwmon/asetek_gen6.c:650:2: error: 'dev_info' undeclared (first use in this function); did you mean '_dev_info'?
     650 |  dev_info("[*] Setup hwmon\n");
         |  ^~~~~~~~
         |  _dev_info
   drivers/hwmon/asetek_gen6.c:650:2: note: each undeclared identifier is reported only once for each function it appears in
   drivers/hwmon/asetek_gen6.c:596:17: warning: variable 'hwmon_dev' set but not used [-Wunused-but-set-variable]
     596 |  struct device *hwmon_dev;
         |                 ^~~~~~~~~
   drivers/hwmon/asetek_gen6.c: At top level:
   drivers/hwmon/asetek_gen6.c:653:6: warning: no previous prototype for 'hwmon_deinit' [-Wmissing-prototypes]
     653 | void hwmon_deinit(struct driver *dev)
         |      ^~~~~~~~~~~~
   drivers/hwmon/asetek_gen6.c: In function 'hwmon_deinit':
   drivers/hwmon/asetek_gen6.c:656:35: error: macro "dev_info" requires 3 arguments, but only 1 given
     656 |  dev_info("[*] HWMON DISCONNECT\n");
         |                                   ^
   In file included from include/linux/device.h:15,
                    from include/linux/usb/ch9.h:36,
                    from include/linux/usb.h:6,
                    from drivers/hwmon/asetek_gen6.c:23:
   include/linux/dev_printk.h:109: note: macro "dev_info" defined here
     109 | #define dev_info(dev, fmt, ...)      \
         | 
   drivers/hwmon/asetek_gen6.c:656:2: error: 'dev_info' undeclared (first use in this function); did you mean '_dev_info'?
     656 |  dev_info("[*] HWMON DISCONNECT\n");
         |  ^~~~~~~~
         |  _dev_info
   drivers/hwmon/asetek_gen6.c: At top level:
   drivers/hwmon/asetek_gen6.c:670:5: warning: no previous prototype for 'init_device' [-Wmissing-prototypes]
     670 | int init_device(struct usb_device *udev)
         |     ^~~~~~~~~~~
   drivers/hwmon/asetek_gen6.c: In function 'init_device':
   drivers/hwmon/asetek_gen6.c:678:3: warning: suggest braces around empty body in an 'if' statement [-Wempty-body]
     678 |   ;
         |   ^
   drivers/hwmon/asetek_gen6.c: At top level:
   drivers/hwmon/asetek_gen6.c:688:5: warning: no previous prototype for 'deinit_device' [-Wmissing-prototypes]
     688 | int deinit_device(struct usb_device *udev)
         |     ^~~~~~~~~~~~~
   cc1: some warnings being treated as errors

vim +/_dev_info +212 drivers/hwmon/asetek_gen6.c

  > 23	#include <linux/usb.h>
    24	#include <linux/slab.h>
    25	#include <linux/mutex.h>
    26	#include <linux/errno.h>
    27	#include <linux/hwmon.h>
    28	#include <linux/hwmon-sysfs.h>
    29	
    30	struct driver {
    31		struct usb_device *udev;
    32	
    33		char *bulk_out_buffer;
    34		char *bulk_in_buffer;
    35		size_t bulk_out_size;
    36		size_t bulk_in_size;
    37		char bulk_in_endpointAddr;
    38		char bulk_out_endpointAddr;
    39	
    40		struct usb_interface *interface; /* the interface for this device */
    41		struct mutex io_mutex; /* synchronize I/O with disconnect */
    42		struct semaphore
    43			limit_sem; /* limiting the number of writes in progress */
    44	
    45		struct kref kref;
    46	};
    47	
    48	struct curve_point {
    49		uint8_t temp;
    50		uint8_t pwm;
    51	};
    52	
    53	struct hwmon_fan_data {
    54		char fan_channel;
    55		long fan_target;
    56		unsigned char fan_pwm_target;
    57		long mode;
    58		struct curve_point curve[7];
    59	};
    60	
    61	struct hwmon_data {
    62		struct driver *dev;
    63		int channel_count;
    64		void **channel_data;
    65	};
    66	
    67	struct curve_point quiet_curve[] = {
    68		{
    69			.temp = 0x1F,
    70			.pwm = 0x15,
    71		},
    72		{
    73			.temp = 0x21,
    74			.pwm = 0x1E,
    75		},
    76		{
    77			.temp = 0x24,
    78			.pwm = 0x25,
    79		},
    80		{
    81			.temp = 0x27,
    82			.pwm = 0x2D,
    83		},
    84		{
    85			.temp = 0x29,
    86			.pwm = 0x38,
    87		},
    88		{
    89			.temp = 0x2C,
    90			.pwm = 0x4A,
    91		},
    92		{
    93			.temp = 0x2F,
    94			.pwm = 0x64,
    95		},
    96	};
    97	
    98	struct curve_point balanced_curve[] = {
    99		{
   100			.temp = 0x1C,
   101			.pwm = 0x15,
   102		},
   103		{
   104			.temp = 0x1E,
   105			.pwm = 0x1B,
   106		},
   107		{
   108			.temp = 0x20,
   109			.pwm = 0x23,
   110		},
   111		{
   112			.temp = 0x22,
   113			.pwm = 0x28,
   114		},
   115		{
   116			.temp = 0x24,
   117			.pwm = 0x32,
   118		},
   119		{
   120			.temp = 0x27,
   121			.pwm = 0x48,
   122		},
   123		{
   124			.temp = 0x29,
   125			.pwm = 0x64,
   126		},
   127	};
   128	
   129	struct curve_point extreme_curve[] = {
   130		{
   131			.temp = 0x19,
   132			.pwm = 0x28,
   133		},
   134		{
   135			.temp = 0x1B,
   136			.pwm = 0x2E,
   137		},
   138		{
   139			.temp = 0x1D,
   140			.pwm = 0x37,
   141		},
   142		{
   143			.temp = 0x1E,
   144			.pwm = 0x41,
   145		},
   146		{
   147			.temp = 0x1F,
   148			.pwm = 0x4C,
   149		},
   150		{
   151			.temp = 0x20,
   152			.pwm = 0x56,
   153		},
   154		{
   155			.temp = 0x21,
   156			.pwm = 0x64,
   157		},
   158	};
   159	
   160	#define default_curve quiet_curve
   161	
   162	static const char SUCCESS[2] = { 0x12, 0x34 };
   163	
   164	#define SUCCES_LENGTH 3
   165	
   166	static bool check_succes(char command, char ret[SUCCES_LENGTH])
   167	{
   168		char success[SUCCES_LENGTH] = { command };
   169	
   170		strncpy(&success[1], SUCCESS, SUCCES_LENGTH - 1);
   171		return strncmp(ret, success, SUCCES_LENGTH - 1) == 0;
   172	}
   173	
 > 174	int set_fan_rpm_curve(struct driver *cdev, struct hwmon_fan_data *fan_data,
   175			      struct curve_point point[7])
   176	{
   177		int retval;
   178		int wrote;
   179		int sndpipe = usb_sndbulkpipe(cdev->udev, cdev->bulk_out_endpointAddr);
   180		int rcvpipe = usb_rcvbulkpipe(cdev->udev, cdev->bulk_in_endpointAddr);
   181		char *send_buf = cdev->bulk_out_buffer;
   182		char *recv_buf = cdev->bulk_in_buffer;
   183	
   184		memcpy(fan_data->curve, point, sizeof(fan_data->curve));
   185	
   186		send_buf[0] = 0x40;
   187		send_buf[1] = fan_data->fan_channel;
   188		send_buf[2] = point[0].temp;
   189		send_buf[3] = point[1].temp;
   190		send_buf[4] = point[2].temp;
   191		send_buf[5] = point[3].temp;
   192		send_buf[6] = point[4].temp;
   193		send_buf[7] = point[5].temp;
   194		send_buf[8] = point[6].temp;
   195		send_buf[9] = point[0].pwm;
   196		send_buf[10] = point[1].pwm;
   197		send_buf[11] = point[2].pwm;
   198		send_buf[12] = point[3].pwm;
   199		send_buf[13] = point[4].pwm;
   200		send_buf[14] = point[5].pwm;
   201		send_buf[15] = point[6].pwm;
   202	
   203		retval = usb_bulk_msg(cdev->udev, sndpipe, send_buf, 16, &wrote, 100);
   204		if (retval != 0)
   205			return retval;
   206	
   207		retval = usb_bulk_msg(cdev->udev, rcvpipe, recv_buf, 4, &wrote, 100);
   208		if (retval != 0)
   209			return retval;
   210	
   211		if (!check_succes(send_buf[0], recv_buf))
 > 212			dev_info("[*] Failled setting fan curve %d,%d,%d/%d\n",
 > 213				 recv_buf[0], recv_buf[1], recv_buf[2], recv_buf[3]);
   214		return 0;
   215	}
   216	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@xxxxxxxxxxxx

Attachment: .config.gz
Description: application/gzip


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux